eval.blog

Breaking The Mutant Language's "Encryption (Writeup)"

Breaking The Mutant Language's "Encryption (Writeup)"

Last year, my friend Gaurav Gogia presented Mutant Programming Language at Nullcon Goa 2022 as a way to "push security left". He developed this language as a way to encrypt the code by "mutating byte code" in runtime. In his talk, he explained that the language tries to "Mutate Byte Code" and uses encryption to make reverse engineering hard. While well ambitioned, his approach seems to be security through obscurity rather than encryption.

I submitted this language as a challenge entry for CTF^2 in AppSec Village, DEF CON 31. The obfuscation technique presented as encryption was quite fun to dissect and to solve the challenge player must read the code of Mutant's compiler and develop a decompiler or you can say deobfuscator. You can find the one I developed at https://github.com/0xcrypto/mutant-cure. This is supposed to be a full-fledged decompiler in the future, so maybe give it a star or watch to keep track of changes.

Writeup

I will try to explain the challenge from the player's perspective but I have CTF developer bias so I might assume a few things while writing. Leave questions in the comments, if any.

The challenge starts with a PDF file having the password L'oreal. After entering the password, we get the letter from Lucius Malfoy to his fellow death eaters.

Subject: Urgent: Securing the NSCP Software for Our Cause

From: Lucius Malfoy

To: Death Eaters

Dear Death Eaters,

I trust this message reaches you amidst the shadows of secrecy and loyalty to our noble cause. Today, I
come forth with a matter of utmost importance, one that requires your unwavering commitment to the Dark
Lord's vision and the safeguarding of classified information.

We have acquired a weapon of immense power, the Nuclear Strike Coordination Protocol (NSCP) software.
This unparalleled tool will grant us the means to exert our dominance over the Muggle world. With this
software, we can control their ultimate weapon and hit them with their own creation. However, we must
approach this acquisition with the utmost caution and security.

The NSCP software is unlike any other program; it has been crafted using the Mutant Programming
Language (MPL), an encrypted programming language known for its impenetrable defenses against any
Wizard’s interference. This ensures that our adversaries remain oblivious to our actions until it is too late.
Muggles are stupid as always, but Dumbledore’s army is trying to find ways to beat the encryption. Those
children have no chance against us. They are unaware that this software only runs in the vm of Mutant
Programming Language which you will find at https://github.com/gaurav-gogia/mutant.

As loyal Death Eaters, I am entrusting each of you with the sacred duty of safeguarding the NSCP
software. Your first task is to ensure it remains hidden in the deepest vaults of our lairs, protected by
enchantments and ancient spells, far from the prying eyes of any outsider.

Only those among us, with the utmost loyalty and dedication to the Dark Lord, shall have access to the
software. Restrict it to a select few and never let it fall into the hands of traitors or infiltrators. Should you
detect any sign of treachery or attempted breaches, report it to me immediately.

The Dark Lord's plan hinges on the successful deployment of this powerful weapon against the Muggles.
Thus, the responsibility that comes with its possession cannot be overstated. Failure to safeguard the
software could spell doom for our cause and the glorious future that awaits us.

Remember, our allegiance binds us as one, and our success depends on our collective vigilance. I expect
each of you to uphold the highest standards of secrecy and loyalty. Any breach of trust will be met with
severe consequences.

I shall be expecting swift compliance and adherence to these instructions. We must remain one step ahead
of our enemies and ensure the triumphant rise of the Dark Lord's reign. The future of our kind rests in your
hands, dear Death Eaters. May darkness be our ally, and victory be our destiny.

Slytherin's legacy lives on in us,

Lucius Malfoy

After the letter, there's some base64 encoded text with some extra words and symbols. At this point, it is unclear what kind of code this is but as the letter tells, it is written in Mutant Programming Language. Let's see how it works.

The letter suggests downloading Mutant Language from https://github.com/gaurav-gogia/mutant. There are two ways to use mutant language. Using source code to build mutant, and using binary. After downloading and installing the compiler, we can use the command mutant to compile and run the code. To understand how to compile the code, we can read the documentation of the language which is available at https://mudocs.netlify.app. Using the documentation, I created a hello world program and saved it as hello.mut (.mut is the source code file for mutant language)

puts("Hello, World!");

Now using mutant to compile the code:

$ mutant hello.mut
Compiled in: 553.985µs

After compiling, we can see that the compiler produced hello.mu file in the same directory. Let's run the compiled code

$ mutant hello.mu
Hello, World!

The code runs, let us try to see what kind of binary it makes with the file command

$ file hello.mu 
hello.mu: ASCII text, with very long lines (1493), with no line terminators

So the compiled code is a text file. That means we can see the content with cat

$ cat hello.mu
MUT|QTVCdVo3ZWFwMjllZSt1SURnTlp5OTVtRlg0eHl2T3lmdC95LzdBeGhlVFhWRXliUDZ3N2x0TCtabzB4WlYzb3dVY1lLcFRMMVJVZTQrbUJrMmZvMzljUFN2TVRKejRyUkNKK1V4SURnek83cWl5bitlem1vTHZBUFRTWmdLWlk2Vk43d1BOa003bzhKcEQ1RnExWUQreDk3dVc3WW82eTRzUjFsTzdlbk1BMTVtK2VNS1V3RWNEOVA2QlE4Z1pnOXJUalpnSHFnbEJQZEdjRVhJRTNTUEg1emUxL2R3QWl3aUM5VnMvSVpxL3dabmhtSzZrdnUra2hxVlRWVytZemZHRklUYUk4RUJzY08wSnZObWpZZ3lVekJ4NjVVWkJoQVlSa3NnPT18NmFhM2RkNWY1ZDVkNTQxZTI1MjgzOTFmMzMzODM5NWRhM2RlNWM1ZDVlNWQ1MDE1MzIyZjI4MmUyOTNmMjgzNQ==|5154564364566f335a5746774d6a6c6c5a5374315355526e546c70354f545674526c673065486c3254336c6d644339354c7a64426547686c5646685752586c6955445a334e32783054437461627a4234576c597a6233645659316c4c6346524d4d564a565a54517262554a724d6d5a764d7a6c6a55464e325456524b656a5279556b4e4b4b3156345355526e656b383363576c356269746c656d317654485a4255465254576d644c576c6b32566b34336431424f61303033627a684b63455131526e45785755517265446b3364566333575738326554527a556a4673547a646c626b31424d5456744b32564e5331563352574e454f564132516c45345a31706e4f584a55616c706e5348466e62454a515a45646a5256684a52544e5455456731656d55784c32523351576c3361554d35566e4d76535670784c336461626d6874537a5a72646e557261326878566c52575679745a656d5a48526b6c5559556b3452554a7a59303877536e5a4f6257705a5a336c56656b4a344e6a5656576b4a6f51566c5361334e6e505431384e6d46684d32526b4e5759315a44566b4e5451785a5449314d6a677a4f54466d4d7a4d7a4f444d354e5752684d32526c4e574d315a44566c4e5751314d4445314d7a49795a6a49344d6d55794f544e6d4d6a677a4e513d3dd41d8cd98f00b204e9800998ecf8427e|ANT

So the code is similar to the one provided in the challenge. Let's put that text into death.mu file. The content of the file from the PDF is

MUT|RlZ0dUswQWxjanJ0aklsR0VlZ001Rm9VT3BVcE1SUzdIcFROdlE1dXNFRWpCVEpXeXB3dXJOekQ1NkZXekdkcXZ1N1BySnlVTDUzVk5xOE9rVVZ5QW1HRUtIaTk2ZnREbXFqWHVMSTlyU01yTjloUVpiemVPTTc0OFNZeEFINFQ0LzB1L1dLMjdsQlRxRXhzWHMrNGxhNjRVampwMm1LdmNnRE0reVo4VDZpRXNJOVkyTlBYSExydVJDRW8yQ1RXOEc2eWRiYmpNUUJUdXZud29ndloxdFdxb1RSWFFnODZRTytwODJIcUhkeFFOVDV4alB4U2VFTGVKbGlEazJwY0dGYzJIalJZUzRnTS9TanNnQ0JLd21FVTNzazBkR3hVQjRxR0IxbWNhc2JsaWEySnJ0eVZtWXVzbGh2SmszWWVQWFp5ajg4RFNzODR4UUlDUzdMaEFPVkhpZE5DM0Z4UFI1NCs4VG1RalN2VkFDZnVHMTZZdTFRMHRWVUNVVWw5Y0QzVFZ0akdweHZxSnhBRStSZmE0OEZUaTdwL1lEaUhoYkNSN0p5NFhtYzRIRjJTU2VHcG1PS0hTanhDNmhaWFdxRlpUUFNaVC9WTm9SanozK29VbHFaZWU2QTRCUHJieVRGZ05OdG1mM010OEV2dXkvMTRRWTc2Tkxmczk0eUhoRlhuZEY0K2lPUEVzZXRFZ3piaUo0MHc5bGRhUi8xNFJtbjRhUmk4QWVWbHIzTlJCM01PaDc2a1ltWXpacENOMzRlWUdPektDZmFZQ3UwRlhVZmR6RnJMaXNxQWxBR0JUdWxjNVROSVdvM2R5aWFRblh6V0tPNjRGRmE3d25aaXk2Wi9KSkNVWDdLOU5wRzJUVUhvQzdJc2dKZU80WGd4RGpvclF5OU1sUTN1czdBaDhwbk5wa2lHWmNDWkFzVDBMMjJTeHBHOEhOQk0vUzJiRWdFL3Nic2VmMjY5R0JxVFIzcnMxOGlOVUNUSUdSeUZ3SWZyNEZDUmtmSVg5V3JmblZac3grWGRQN21RcE9TT3hMelg4aGFRUEFRRnRCWFFDczdkMkYxL3pGTFp4c1EybTdTZFpQNmRHdmhEM2hpQ3U0ZHJKZ3Q3MmROaE1zTWQxZDZXVUViUUl0R0p2dDVBdTlWYksvSWk0QjYrT1ptRGZNM0x2Lzl2bjE5TTU5VUZna0ZkT21HZ1BCU3dReHh5VlErQUhBb2xFU0tYekgvcnVhM1hYVXJuUmNVaTcrVmppblVXSUk1QlFCaCt2eWdLenZoN0VoZmJYdDJJOFY5RkN1R1FHZDNQWUdZMFcxejdENkMybURMQkZCUjBranh5VTA5ZTBOa0RYNEYyNHdodnRtcjZVdlhjdUpEdE1oUFltS0paT1ZkaUsycDh2a2FjNDZvbWVvV3NxeVpHVlprT0thOFYrK2ZrMi9QQnBxQVk4djllZUVVcGxHbEJYOW4wREg3NHJQU1RnQkM0K3ovd1ZyN1BWYVRqZ2w0REVpQTVVb2l3alRUVFpYTm9PSG1rZ1hDL05odUpFOCtsdTViQzBxTXlZOE5HTnNTSkZNek5PZStkamhUOExFdnpKdlUvZXhDUXcwNU1Xb1BkY1JibVBlaW5Vb1d4MnVET1FPNU9nc09oN3lkeSswQ1hWTlRNRnk4SUQxeHM1L1NMK2RXL0U3eUN4bmU1VEhRbW1uMGkvcVhDWHJlVW96RW5BTXF3eUFTY1NrN2plNk5MZE1SM3ZxVFV3b21TVFpMK083YmNTWVFzb2E2ek8xQ0x0SG5JZ3FpV3g4aVQvTDVPTlZpMGhBeXg5VUZmRkJpVDhyV1BiWSsyRGNRTmpjcHZDZnJrb2JTWU9Xd3B3QmZ5RXY2bWJaa3JPQUNDWUdyYVhkYWtQSHVLODh0VnF3MFYzUTlUU3JHWFBrb3NGaUw4T0dwUjF1dWoyZ3dtQmVxSVdISGl6VW44L2VHamtTZmU4eFhBaEx0SXFra0lETjluV0cydVFTbTdtaFdha1ZFSW5sNzJ4RExnMUxFdmZDRmpHN3RySWVwM2xBT2hjYy9kUkcvcEdQNG5LckcwWUhLdDZPclZ4N0NOeE1yYlp0dWowQTJyNUN5TnpIakNkNU53blJXb2l3ZGljUGw4OWcvbkw4Skp5R01VaC9NYjl5ZVMxR016K0VFU3JCSHpFb3RtMGREN043TWIrVWI2d2xBclZOYU1pdTVmWncvVTFZSmFNaHpwczZKeHhxQkducmkra1h1ck8wV0syVlNxR2FVTDAzVnQzV3hBdDljUDlmM0ZwSmhzbUUzWFRISjYwM3hVam1VU3N3MTQzQVVmSG9Ebnp6bVRESDVtZ0tsalUvcjFweUM3Qk52LzRJVGpwZDZtVWpNY0tmcDhMd2VNczBiMThWVFVCM2RCeXMwMUNJZ0NvS2NkR0grMTVYVWVmZnk4VFBDMndVcHcwOE9KZHRuWDlCR0w5NEpSNjdzSUNEa25SYm1wa05qY28zV252RUd6eXZEV2tOMVpwRU9HRlFERjUvUW5sQnRIdlZZM2F2MFNqVk5NWnliS3NOQURrM3VtdzNyUFBLNzdtZnlaQU9Sc3FmaE8zUlBQOTNmbUNPNElSV3k0dzlBYjI0WktsbmQ1aFpEcFFjV3VXQXZQdjBOckN3V1VpWWRUNlJialRtUWFSekVybjFWVnhTc0ovcHM5anNUeHg3SzBseklCdkp4bUYrZmtrWnZiSjAyNWF4Z29qdy9FalljZzdJejFYSnVmNERqYXZ6MG1tY1VnRENpdlNBRmJRUCswZEw4OGc1b1c1UXhoTUxRYk4yRHBBSGRSSDFNd3RGNFZwRGd5NWxYVnQ5a2xHbjJYOTZDbG9IWVEweGxLTTZOa09sejcwOGJna1dvUDlYUWlPTjVYSHNTYTBZaWh0b05JS1ZhVlZkc0U4QmFXZkZ4enViYVlGTXU2b3N1U1NheFNsM3IwVmpRWWlqQ0ZIb25ETzl3aFRzcExUODQ0anhaSFhqMXhibnlrcjF1WmJVdW0xNk9YNXB0SHIyQ2ZzaUdSTkFlS2RkbXZhRklsQnN1RFN2aFREcDAyWFdHN3luMEV0WWlEWitmSTBCR2NqWm50TXcwYTdhVWNSdHNtQ3owTjVtR1FGWWxtMVRrS2g3Z2ZTRUE4T1RyYWwwNkx4RlMvQ0gzYjhkd05BT0RGQm0zQkpyKzNlYW9VK3dMVGkwa0N2NisvK3NzYU92NkwwWUdqMEpDUTZHMncyZXV1UitRYkNsUmFmNDdZcTFYeHNmOU1vckVwM3VNcS9xTS9XbEFidkRTNm9JWElKVFBFa0w1VGNzaDFyMTU0WTBmRXhrMjREVEh4Q1k2QUh4eGZ1QTBkM0dlNFJCYlZMdWExcWwvM25YRkE0aXpxcUdNTnUwK3RwLy9rVnpCTitLRFhZdW5JaDRhVm5CQkp1UHlwVmp4VWI1QWo1K3RpZitMMWpZbEpOWlYyRTVVODkwTUVsQ0dSc3Q1aWk5WkYzTkRoRkhzLzh0YUM1WGh6cEh1UTg3YVZONnMxb2Y4MnN4QzJwb1dUZS85cUtOUFZrVlcrNmhzUmk5WjEzNFNNbWFSdW8xV1FWWkpmdVVoTGJTQ1hjVE4wc3UrSlNhSXRVZHIxUW1qM2lCaldyekxjekNaTFM0NUFuRE96ME93bTlWcHlPZDRmY0h0WkJUdzB1amtUYVVnT0dSWkRIcEs5cnBWNnc1dlo3MzlLTnArM2U0MStXU0tydnJkdURZWnBDdWtRb0pNMmNEMjlCSFVaSU1vYlJVUzM1bUl1YlFSdVlNdjN6K2JocDFsbEVnYngwNGxMSUcxZnV4VEFveGFHUUpVdmw5YldJOVFoYk1WeUs0RGdxcmplREk2WUF4dlZYZWczZ0ZwazBHZGtpSEhuK3ZFc1dia3V0Q3lUcG1wTThEL0RVWWg2eFlyekNuMEd2K3A5NGIzREtJaVJwZnBxZk5PTG1jNWlDZ2FJL2RWZ0FqeDlnYzRDYVJaSWllSkVHSzk2WTJrdTkvQ2gzTEs1QUxra2d1Yi9xc0owYy9XSFhvamZRdWh0L2VMZDRPOHJHaHo4bFdFUFJFaDZHSTg5RzBJelh1SGxwNGFoVVp1d0pvS0FUVkMzcEh2ckxEYzl5WmFtTUZGNGFYUUxOMXpQbVVFeWx6UkJObWRMMHlVTEh2QVlJMksyZVV4WEpzcFZTZ0EzRnBVUlhXb2ZIbGVrNGhjTUh3UFBjbHZ3MjR4eTdqSXBaTUE1N1NLRktqa2Z5dnVVRWtCU2FVVGp4bFAyTERxaEtneHk0RmtIMWNEa0ZTVzR2bVEzV29iN2xLVjJwR2U4a0VWL0xYSHd4eGNyNlhJRjR1Z2ZzQ0pTU29ldWg3eStxci82MzFUVWlraytSWDJXNDFZT0JLa2tjN3puYUN5emJiTHhwVVFJcm11TnBybmNHcFhlaXlUUDBTU0RKVk1rc0s0OHFYT3JjUWNnK0tvY0F2WHVmTlNldyswc0xYQVNQMFVKaGEvM3p6Q0RWTmI2dEJxQmxOd21QR1M2Q1hrSzEwV0I4cm9LUExNKy9tWElPbDNVMDNZMTJGNWZtRTBNY3U2NGZ3aUM4N0xrTlk1WHhpdllFTXNkMlhjcWNVb1pvbnJuejdPV21sRCt6NXgvYk1adjRLLzB0WEJvYmZGVWhnR0ZGYVlsQTQ1RWtzanB1UVZFUVlKK1dzcE9rWEVCVTZiRlJDZmRBN20xQVBXRXVBVEJyN1k4My9zaTVIOEVOcmJEZ2Ntbzk4Z2RuWmttSHRQWmVCQW9iV3JuQ1UvdjFYc2ZKenVGYU10N3gzRTllYzRCeWhOT3hoQWc4ajNpdkFYNU5rV0lFQlFZbXdtVTRBaE1WOS9wQndDaGFVTnRoQ2RENlF0c2t3bmtLMFQ1SDZLSnB2M3JNU0hYYzRyTzBBaDNBTHJjejNWaHUzUGl1di96ZWFmMUNSZ2x4TUdpQUZqUjBWbUtlQVFHSGZQcVZ0MjNjZU5HWkllM0xMZGRzS29XWTkyT1hCTUQzLytybzFTS2tYSk5JQ3FuRFBJRWllcDZtQW9iS0JGeTJIalozcWtrVDZacmRWVlFIM2lkK1RLNkpUVktwNElOWEVlUUlKM1o1SDdRam5pOXFZL2tXVmtEK0ZONmlpSzY2SjFuWWlybkh1WTdMNDB6cjRvNWl3UklIUlRNV2hCMC9QZkdtUzlCMGQ1eTcvMnZoZEUvSCtwODZBMFVYNUlEc0Y2Q2VpSTl1M251WkVQYXhjSEpxSUhVWFI3OXpjK2N3VkR5M2NrT0NqSWcrb3NvcnE1d3I4WXh6OWcxV1RmQ3ppeHBkREtaSFJib2JEdWI0ZVFFMjNqek9EODh5TmtUUjdVS0FCWDBxRy9SYjFGNnp2MExFUFFZVEJkVDEyVU1wa09xdjNNS1ZFc1lFTmQ3czZUeTk1R0I1VWloQWR3N0hwRmtIZ2taYWNCaW1QVjVOaFZXQ2pNaWhkVHY4MnZtN3AwTnFod2xHZ2JRNHhZdTFvcVQ0RjhvdUQ3NHY1dzAyeGh4R25SbFIyeXQvMENucXJrTEcvb0hCMmpmckxFcy9sY3QySW5OMFE2NFpPY1RlcDhWbGtNVGhmVVdSM21uTXJZcnZoNXBEUFdnRDN4V1E0QXo4SjJGS0JvZTkzWkVZMUUzRGIzRWxTbUxQemNDc0FoSy92RWhONWFLVlp3RWFMYUgyMWN0dk9admMyaGZJM3l5ZGd6ZCtLaGYxNjdmQkhXNHFCclBtRWhpV080YkN0R0IvNURmQzNwbGRteGx3WTlKL3poaFRKUEh3TUZQNnJRTS9sUlhZaTlDMElwNFdCN1lGc1pkY0FXWlh6MzIwVnRXQlc0aFNaUnNUY1N2LzJIakxTWnpuZEtNTjNrd2JzRi95R3ZXdWx4MzRqZVA2a3hVY3IvdlNpZWN2QTRuMkhvektZU2lPSTMrRzVCVm5YMk5kbTRvc0RUd0d4V2pzUFFMSHpxSkVBNVFaRkdrVlJUOEhYMVJVRVJEMnhrdWVGOTFwMmtHZGJiQndwTXdxZXZ6ZlVnNm0vMGpUY2UyOUlFN2ROQXNjcmR6LzFGa0gra0k5K05hYzBlQVZrdVFlTmhFYzNEbmZsSnM4WE53TFZHRjZqZXJUc256a2dObUlQL3MwWFlJUE41Nm5pRWJEMVMwOFZ0ajRCNjFwRHhJNUQ4VUtuS3ZoL3d2MThQbVBIVkNHRUEySC9aTEVlODFFN01nZDFabVRDOFI2VTBPRXBQMFVvQnRSQ3FLSnk5NWZCUUZZa3ZuKzl3NmVGU1EzZ2Q5NkVnVFZaRHM3a29oMjJjUTlISUNKWE9LSHV6bU5JbGVqaGM2NWZUSWo0cVI3NVpNaVhiN1RNN2UrQ2VWcnlyOWg4d0Y2WndXR3Q4Sy9NTHp4Njhqa01zbUQwUWEvYmRZa3pJWGlwNmZhemczcWw3SEQvbWYvL3hGekpHY3RRMjNzRW5hNnlaOHFQd0g3UWFNNUhvNkdiY3g2ZlFrVGFrbG96NnBIOEc3UHJzaWlQVUZEYlZzR3E4R01tdUJWM1lUVDFDQkg2THNLcEFkdE83VVhENGVBWE1jdXk2eGJNMWVUS0xnUmhFazBvVm15NzhRWHlBeElXRFdUYXZ5aTNGWWszaFdYMGQvWkprS280MjhEaHVnUnZBcnEycHVGbEVYdjNhOEZyZFlRUVREVm83TjFVcEtid1VJTFhMc1gwOEJlOVBtaitnRUhYQlo3elljditDUDBJVHhjTEVvT3kwUVZEU0I1K2ZjWU1ORXdBY2ZJdm5rcnR0b1oxSHpYVjZHRE5iOFpHdGhkQ0EwVk81K1luUkJWUmh4bGpDakxCNHRSYklMaitqOEwvbUgwSU9OcEJWTW9TYm9KZFdOZFZYcGNJc1NpSkFvaFJGV0I2aU0zS3BHT0ZzT01BVUlzNFJ0TUZMM0prRVFJb2VDMEJEN3pQZkkycFFPZWU5dWZsM0FBY3lVWlFkbmg5VUs0Yjlla24zMmUycDdCZGM3ZHhWRTlibTFsMEtxSk1sbU5DblU0QWR0ZmhITlZhbVBad1lKaGN1UUpNZVREdkJZMmoyb005c3A2NjZhbFBZb1hrQmJYcnN1MzMrYlhhclZwRjI3U1pSMUlSemNoTFBUcllYZGg1VDNJcFhYMlRGNWthSXdXbDN0T0VRbk8vaEcvdzNQRTRXTlVwdHhTVUs0YjZud0cwcmpNSFo1ZjJLMm9ueGJlSS9ORDA2SVlvejhnUUdqMlJzeUhUbVFEU1FnblJmc3BwSlFvVm1lRFE1eDJnMnBNZ056UWw0QW16eUpPZkp5T1d3K3JsbmM3REJ6dm0wKy9tYmVaY0ZYb3hQcFgvZmN4ck9jMUduUThGQmZUbGU5NFdQd1d5eHJPMDgxQy9rby9aTHZ0cFVzdnZESzMyOGNRcjVBWEV4clAzMk52U0pjZGJ0QmJmUXhzdStKOG5ZZVI4RnA3K3JBNDlhSlFMajB3L1VCY0JBTWpYUW5nUHVOTEU2U3ArbVA2Tm1VRVRoeFlrVURTTkNzRDRyV2ZaVkxHMklmVGRlcUlIMUtmdEUzTFNHQnR2UUx3c1U3OG1aUXBvbkEycFNPOXk5Z01aSFpZajRqMFRqSTRwbUxHMEZ1dVVScW1pSmZrWUhoeS9FNXhLOVUrbUlPamZ5SGdXS1owemdnMTViWXNuZGdoWjRxWmRocVJBYkFWSUkzMGlZaFAvWmtDS1ViWWxXL29veHFCSjQ1UVNLSFZWcjlNSUdLSGpIKy83VU9FNDlGSVZqempGRkRva2F5ZGZrbWhGeUZRY2s4bUNKL0JKekJRd2NJVlBNQXZoUW1Rd25ZbnZHa1R5ZEVqeGt4RGxaOVlibnAxbklUd0JySk16NzdUODhPT1lKbjVOMy84S2k3cmxXczgrQVlZa0hMdVlvaXR6eWtHL2hUa1Y4QXVhV1FoYTVsK0RLWE1YbUo2ZHVPR1RsMVIyZUhrRy9RZ0pETXVWbFRQVm5OZHkwRldXUU93SFM5TVJmNlpDblFZeTd4eVo3WUJ0R0RMRnV6a1RQV1cydVZid3p1WW16QTlMZXUzZG02Y3IxUEFUSTdFdWl2ejUwQWVkMnhkdEVKUVRmeXVzUmtnTUZzNzVZT09ncXFWY0ZHNTZEdXVDY2p4M0d4Q1h3YTlMY3hVY1FnRXh1QnAxOFdESHFsQy9ORzlNUUk4WkdZS1h3Tmp2QlZMV3FpTWRsZGxSb2ZrQW53TjR3ZTlVQ2xSUUNsRmY2QWo4ekVPVDNvQVhSbWx3R2RSRzhTK0djMEEvSmpBUFpjLzdFNGEwUkltaGs3QlZEcm5peVN0VzMrOEJqYSs0WXdueE5mZ0ZIdHA4TFUrMGtaQ0hsdE1ucjc5Q25oL1A2UnFyS2tYenVPSjk5dHE5UW9XT25DYjhiZjh4Q1cxelFSbjB6VG9iaFhoUVFiSlVlL3gwS2tEaEVHR1o5UnRkdU5iYkZPU0ZZZVEvVjJPalVnQ1UyNTNyMExHK1RJVWFvOHZOWHRLdUZreHBpV09iNkFVeWJ1SXlzcEZoVDlmRmJzcVNjTjBlbVNZTnV0UnduUTFZVkNqcVJ0QVRyQmQ5ckxPZnVsRFhuNllhOCtVakVUcGtxVldFNnFxOTZhcjRrZEhyczlWRHBqRzhTUDlHWFpMSjhIR29XdEFNMDBhcHdoS0Y3dHNIN093dGxSdDQvYXArcW1QT0JXbmpQQzhOZnRpWFpUeHRBa2pGTnF6L1BzY3psQzAxMzhiRk5Mek5QM3ZtVXZidm1hSXFoV28rd0tNb3l6SitUeVZ6bmpSZmtEWEFieXpzQytUMW5ibUxTY0JxdHZaT2hYSFZIWGtXRW9JejR1R2JaMHlQSjE1VGRVQzFjMjg3QW9qVWxHaTJqY01qUTgvcDVPTkt5c2ZVNnh5dVdLeEEyeGlseVJDVmw5b2k4VGlmQ0FNcnB2aHlwNVJwbjkrekMvcC9pQ1hhZzMzQkdJMGMvSCsyV09XYUVwZ3NhTEx1S25hc1JFemcwZGJ5VmhUUERNM1pLdkVYUnJMNzNlQitoNExUZ0d3dTg4YnFTN1JlLzRnYmF4a1dWSis0TEVTV0VsTFVjbUl5Y2tjbXZGc253Z3FTc3dJWis4dnhITFU3MzdYZjRsSitYN0NsTDA4RjhXSW12WlFaNWp3VVl3VnJkQnZQMVRLbkJEN1ROMzF6a0lITUdPV0MwWkMrVDFxUGJPRGwxQjVVMDl2ZEVObkZLS3JvVEhJM3pOajVkbzU2M01ndHY1cU96QnJBcDBXeFdSWW9nQWgrbUpSbnR0UmxxUFFOMjdrcDN1a0pYL1hBQThRbWxpZ1Q4TjRWcWYxeE9MalpJbE1iV3NTdGNTUmxYdVpXYU42NEdWMFdxejhsQkZVc1FoWWFsYkZNQ1lmUi9EU3BEQ29qR2hzVTRsTFlUUVh2ekQ4bmcyWGF6UVQwcHlENmdNc2FLVnpPb3RVN2FNdzVHVHJ2cHIxc0czSlVLQTVqSXRFbEVRWS8xWTYyRktCb3l3THhnbTRqUldyRWp1a1hjL2YxbEJObUV5MTZGc3RsT1RVTFhmRlkrQUNMS0NTVkZ4QlNLdzF0UW5yb3ZXUmFLdmVpNmR6cndKR1NuMlJ3eVNUcTZTbjdmcnJGTGFDdVlLckZyUUgwUStLcG9NRVdlT2hhVjlzcmVZMTNkc3FVU0xwcFBPTERxdmhvbG5Zb0R6Z1JyclZCenpqakJ0L3JHQ3lJb0IrS3R0MjRuZ2RYY3hMRXE3STg2Z3piWFYrb2hsVmNPM2FoVUg5d0hGZ2xsdlRlaG5MT0tSb0QzUTYzbUFiWlk5ZjNJVFNDYzZOb3RvOU90akVDb3h2TmhjRi9xSlQxeUpCb1laQTM1Mnp4aXFXNkJtT1l1d3JQQUtRMGNVb1pZcmc0SzdidStzRXF3dk1qSTJ0cHR6dFk2b0ZycStXM1pXeTQwZXRnbmZQd3NYcUV1THA0R3FlL1J0TG5ad3RTM3VrMmI4bHhyeTNzZi9vVVF6UTI5NEZ6L0NDVnBKQjUwS1ZqYzdKbzFUUDBzZ0J6dVJ2aWNpYk1oZW9yTytRbG5zTGV0N2pTeVo3N0hxQklPUUkrSU15a2F0cU5vWTM5R2VQWXorMW9YUG1uN3ZHb3hINXVxMWNrNWJzNE1GSnBOZG9ja1BKU3dzY1RUb1pPdm56NUpzcm5NWlU5T29MSmdaNUVPeFVXUTBnYndzSVV5eHdWTTJHZmhEWUdFdGxhbHlHYWV4RkhnY0E4YnIvbmpMeUcwUHlZU2NyZGxNYUZPcm5pUHFaQ0VKQUovU3psTkZGT3ZLUmlNOG5tVC84N205UmJuYXd4cHZqZnozTnVXaXB5Si9JNFJqSVUwQjJPYWREdWdMcis1L05mNFFCMEtUdmZqMEpsbjNRMG8yc3hLZkJRV3h3U0IrZlRmaE9QNmZhU25QNG4raEhGSXdRUkdEY1RYWnB5U2V2b2V3anc1Ykkvc3R0d3pha2RIQkVoczZpbVJhaXUzbEtxYWNUNVBzb1UrclhLWnJORU03T0hobUtsN0FBem5RSnZuUElWNlo5Ump6MjMyTEpIQTQ1R2NkWTB6RE44TStFUWV4cVg3eHgyTWRnZWRhNXJpMlY3U2xJVUlRTkFYQlRva2NvMldOWFNTNDZNc3V6THVGa3dyOHkxTFNmUEdhTkE3ams3bXJ6ZVdMV0FTS25FTTltY3VyQlFQaFdTaGtaVjdtYmFhYXlxSDI0YURhTnlCd0lBblRKZzhmSnBIUTh5M2RFVXJZUFlmUjc5M01GRDFYTEFvYXNTRzZxVGp0NjdqOVRqeXhCYXIxSzJRL3hUano0RkJNeW04cDk3N1ZFaWFIMVYvTWh2c2huZzYvbU8wRU5SOENWcWRhdktac0ZHeUI2VlBUczlQOTZTbXUrL0l3V1JzaUg5ajk2c3lOc0dGZkQwaXg4TzZLZTc0Yzh0Q0NhOThYT01Vb2dtT2hyNG42d1hxTkE2endKMmJDQ2Nua1hSRmVYS0ZVbm9pakRySzVpMVFlUE5JK1NSRWZoY0RueGEwUlpNaGUrRmVRa1BoOE0wemdRL0hRWnhHc2ZiOElPbHJ1NmRWeDNoNFlldDB2T0NyNDcvbUM0QjVXRmhuVTdDTm5kQnh0cUY3SE8zSmp2bVRnYllzTjUrU3J2c1c0U0hGaHdPV0NyMEUzb2liRjFzQk1UaUZHRkY2WkxaanRheWNYVHk2VlUxMzVvbDhsOGVCVGlRRkRLS3RzQVNpTGZ5V2xMKy9FOHpZZndxUXk4Q0g4SXl0UXA5NjdBNnhOVDJMMEpmRnlsNWZRMzV1NFhCRHFSZDBkWnlhR2FGRjc2L05hUURZQURpbmpmL2pWT3d1dHRXVHltRmo2WkRkZFh2YWVGVWxRMUtXQWJyUERiSjk1ODkzOVVpNlk0YlZzT3Z0TVJ6aWZoQzVaWHZEbzFsekJDenFMRXdocHBaZUJTN1VSN3Bac1YvTlBOc0JQbE5SVk91Tnh6QTFTVmhVZXJpcFNFWFVmcytaUldFTzkzaFRiL2g3RWNXU3JuQlVGc3dXVXlUUWl1UGtRUm0ybG5XUG5qdnZjdy9wd0JRcnZXUTVkYzVoeTFkT3YyaG0rUU5kM2FXYy9hZ0FlV3NseXB0ckFWNnZES1B6M2V6YTJoUUpQZXpCVG5RSmJNOEsxVENjZ3EyTkVYclhoemJ5V0dONEg2WkU3TEQrNXRDdGRrRnZOUXVHS0E4TFlCN093ejUvTklLblZaNkpKQ1d3eE12TFZMWEpVZlBBT0dyRWVZeDkyOWxaQmtqdFJ0Vk5PZ0lmY1d3aVlUSGxUcEZkWldBZkxYYjVtWHUxWnd0SllONTVVS1R2NVFXSDhJZ01scTNIQlNtRjFKZktNaDlFZ2YzMGFvQmdCcVRmNzc1Q3laMW5JdzZMNmhuT2NaWEFBWHRPNGFYbmc4b2o1VlQ5QThzNnFEWlZpREMvT3JUNlowR2VzVTVuRnlQSWl5QktTVVhMYlRRVGRLbTNZRFZmSDFzd2VjZ1BPMkJRQldTZ0w0dGtTZnhTbWl3N0lSRmkvZzM3bFVmYll0cUdURm9ZZXgvRFZqUitvcXJwNjNFdCtqamROY3pIaXFPOWkyS0ZpZ3FEY1dkSkFrY1ZWVkIyMUtqZjBheVIyNUNJVDlmcUtXQXEybnYvYS91VGR2WVgyQVBFU3B6YmJ2eExtNUdLT2JBdjhsSmJya3JCeXVaeHhSYmFkY29mVWszNy9zZExHOHVXM0VhREFyM1V5UWpyaWJwK3F0Q3JCQlFyYXRFTEhxdFdXOHhtWTU5RDRLVXRabzJsZFp3VHlmVjMvTkJ6ZUJsZ2Z6ZDQ0YnZLUWJ2YlVIanBBUG1sYTYwSlppWjd5NjNhNy9scDZsRklsa2NXU3dMdGdwTEtKVHFhQ0IrQTYrS2YrQUJnRkhhalp6MlhVZ010UVBmcHBrWjN1cVZtY2xNcDFBeFIwbXB5WWt3eDJDVXdVblcxelVJMVMyK2paTUpwOVZwTzA2VDNabG5uWmtFeVlJVjdYQk53VlpEK0E4ZkhTMnRxTWlBbityUEZ0dzdRNnVjaVRLQUszSEpiaXJqUGZsS2R2OXphM1VOdys4bGVwY0lCV3AzREp1TXlrZmJ2UFJLU0d2aDgyclJxa3lKWHhFMldHRlVxS2hBS0d3UWx5STVzWjJjam9BUXR3NjBMU2FWbmNxRTRLWTBobk1jN014OVY2V1pOS3Awd0pwNUNWTlY4YlZxTW9CSnhDQU9IbklYbVQ4ZEJiMjBkRlFRTW1JSm9OOFJWV01XL25senQ1aDhicEpzZUNpUT09fDU4OTFlZjZkNmY2ZjY2MmMxNzFhMGIyZDAxMGEwYjZmOTFlYzZlNmY2YzZmNjIyNzAwMWQxYTFjMWIwZDFhMDc=|526c5a30645573775157786a616e4a30616b6c735230566c5a303031526d39565433425663453153557a64496346524f646c453164584e4652577043564570586558423364584a4f656b51314e6b5a58656b646b63585a314e314279536e6c565444557a566b35784f45397256565a35515731485255744961546b325a6e5245625846715748564d53546c7955303179546a6c6f55567069656d5650545463304f464e5a654546494e4651304c7a42314c31644c4d6a6473516c52785258687a57484d724e4778684e6a5256616d70774d6d314c646d4e6e5245307265566f3456445a7052584e4a4f566b79546c42595345787964564a4452573879513152584f45633265575269596d704e55554a5564585a756432396e646c6f7864466478623152535746466e4f445a52547974774f444a496355686b6546464f56445634616c4234553256465447564b62476c45617a4a7759306447597a4a49616c4a5a557a526e54533954616e4e6e51304a4c6432314656544e7a617a426b52336856516a52785230497862574e6863324a7361574579536e4a3065565a745758567a62476832536d737a5757565157467035616a673452464e7a4f44523455556c44557a644d61454650566b68705a4535444d305a34554649314e43733456473152616c4e32566b46445a6e56484d545a5a645446524d48525756554e56565777355930517a56465a30616b647765485a78536e6842525374535a6d45304f455a55615464774c316c456155686f596b4e534e3070354e466874597a5249526a4a54553256486347315053306854616e68444e6d686157466478526c705555464e6156433957546d3953616e6f7a4b323956624846615a5755325154524355484a69655652475a30354f6447316d4d3031304f45563264586b764d54525257546332546b786d637a6b306555686f526c68755a4559304b326c505545567a5a5852465a33706961556f304d48633562475268556938784e464a74626a5268556d6b34515756576248497a546c4a434d3031506144633261316c745758706163454e4f4d7a526c57556450656b74445a6d465a51335577526c68565a6d5236526e4a4d61584e785157784252304a556457786a4e56524f535664764d32523561574652626c6836563074504e6a5247526d45336432356161586b325769394b536b4e565744644c4f553577527a4a5556556876517a644a6332644b5a5538305747643452477076636c46354f55317355544e31637a644261446877626b357761326c48576d4e44576b467a5644424d4d6a4a54654842484f45684f516b3076557a4a69525764464c334e696332566d4d6a593552304a785646497a636e4d784f476c4f56554e555355645365555a3353575a794e455a44556d746d5356673556334a6d626c5a6163336772574752514e323152634539545433684d656c67346147465255454652526e524357464644637a646b4d6b59784c3370475446703463314579625464545a4670514e6d5248646d68454d326870513355305a484a4b5a3351334d6d524f6145317a545751785a445a585655566955556c30523070326444564264546c57596b737653576b30516a59725431707452475a4e4d3078324c7a6c32626a45355454553556555a6e61305a6b543231485a3142435533645265486835566c4572515568426232784655307459656b6776636e56684d31685956584a75556d4e5661546372566d7070626c565853556b31516c4643614374326557644c656e5a6f4e30566f5a6d4a5964444a4a4f465935526b4e31523146485a444e515755645a4d466378656a64454e6b4d796255524d516b5a43556a4272616e6835565441355a54424f613052594e4559794e48646f646e5274636a5a56646c686a645570456445316f55466c745330706154315a6b61557379634468326132466a4e445a766257567656334e7865567048566c7072543074684f4659724b325a724d693951516e427851566b34646a6c6c5a5556566347784862454a594f573477524567334e484a515531526e516b4d304b336f7664315a794e314257595652715a327730524556705154565662326c33616c525556467059546d3950534731725a3168444c30356f645570464f43747364545669517a427854586c5a4f453548546e4e54536b5a4e656b35505a53746b616d68554f457846646e704b646c55765a586844555863774e5531586231426b59314a696256426c61573556623164344d6e5645543146504e55396e6330396f4e336c6b6553737751316857546c524e526e6b345355517865484d314c314e4d4b3252584c30553365554e34626d553156456852625731754d476b766356684457484a6c5657393652573542545846336555465459314e724e32706c4e6b354d5a4531534d335a7856465633623231545646704d4b303833596d4e545756467a62324532656b3878513078305347354a5a334670563367346156517654445650546c5a704d4768426558673556555a6d526b4a7056446879563142695753737952474e52546d706a63485a445a6e4a7262324a545755395864334233516d5a355258593262574a6161334a5051554e44575564795956686b595774515348564c4f446830566e46334d46597a55546c5555334a485746427262334e476155773454306477556a463164576f795a336474516d56785356644953476c36565734344c325648616d74545a6d553465466842614578305358467261306c45546a6c755630637964564654625464746146646861315a46535735734e7a4a345245786e4d557846646d5a44526d70484e335279535756774d3278425432686a5979396b556b6376634564514e47354c636b63775755684c64445a50636c5a344e304e4f65453179596c703064576f7751544a794e554e35546e7049616b4e6b4e553533626c4a5862326c335a476c6a554777344f576376626b7734536b7035523031566143394e596a6c355a564d78523031364b30564655334a4353487046623352744d4752454e303433545749725657493264327842636c5a4f595531706454566d576e63765654465a536d464e61487077637a5a4b65486878516b6475636d6b7261316831636b387756307379566c4e78523246565444417a566e517a5633684264446c6a55446c6d4d305a77536d687a6255557a57465249536a59774d336856616d315655334e334d54517a5156566d53473945626e703662565245534456745a307473616c5576636a467765554d33516b35324c7a524a564770775a445a745657704e5930746d6344684d6432564e637a42694d546857564656434d32524365584d774d554e4a5a304e7653324e6b523067724d5456595657566d5a6e6b34564642444d6e6456634863774f45394b5a48527557446c43523077354e4570534e6a647a53554e4561323553596d3177613035715932387a563235325255643665585a455632744f4d56707752553948526c4645526a557655573573516e5249646c5a5a4d3246324d464e71566b354e576e6c6953334e4f515552724d335674647a4e795546424c4e7a64745a6e6c61515539536333466d6145387a556c42514f544e6d62554e504e456c5356336b30647a6c42596a4930576b7473626d5131614670456346466a5633565851585a51646a424f636b4e3356315670575752554e6c4a69616c527455574653656b5679626a4657566e685463306f7663484d35616e4e5565486733537a4273656b6c43646b7034625559725a6d7472576e5a69536a41794e5746345a32397164793946616c6c6a5a7a644a656a4659536e566d4e45527159585a364d4731745931566e52454e70646c4e42526d4a52554373775a4577344f476331623163315558686f54557852596b347952484242534752535344464e643352474e465a77524764354e577859566e513561327848626a4a594f545a4462473949575645776547784c54545a4f61303973656a63774f474a6e6131647655446c5955576c50546a565953484e545954425a615768306230354a53315a68566c5a6b63305534516d46585a6b5a34656e566959566c475458553262334e3155314e6865464e734d334977566d705257576c7151305a4962323545547a6c336146527a634578554f445130616e6861534668714d586869626e6c72636a4631576d4a56645730784e6b39594e5842305348497951325a7a61556453546b466c5332526b62585a68526b6c73516e4e3152464e326146524563444179574664484e336c754d45563057576c455769746d5354424352324e71576d3530545863775954646856574e5364484e7451336f77546a567452314647575778744d565272533267335a325a545255453454315279595777774e6b7834526c4d765130677a596a686b6430354254305247516d307a516b70794b7a4e6c595739564b33644d56476b7761304e324e6973764b334e7a595539324e6b7777575564714d45704455545a484d6e63795a58563155697452596b4e73556d466d4e44645a6354465965484e6d4f553176636b56774d33564e635339785453395862454669646b52544e6d394a57456c4b564642466130773156474e7a614446794d5455305754426d525868724d6a52455645683451316b325155683465475a315154426b4d30646c4e464a43596c5a4d64574578635777764d323559526b4530615870786355644e546e55774b3352774c793972566e70435469744c5246685a6457354a61445268566d3543516b703155486c77566d70345657493151576f314b3352705a69744d4d57705a6245704f576c5979525456564f446b7754555673513064536333513161576b35576b597a546b526f526b687a4c7a683059554d3157476836634568315554673359565a4f4e6e4d78623259344d6e4e34517a4a77623164555a5338356355744f55465a72566c63724e6d687a556d6b35576a457a4e464e4e625746536457387856314657576b706d6456566f54474a545131686a5645347763335572536c4e68535852565a484978555731714d326c43616c6479656b786a656b4e6154464d304e554675524539364d45393362546c5763486c505a44526d59306830576b4a55647a4231616d74555956566e54306453576b524963457335636e42574e6e6331646c6f334d7a6c4c546e41724d3255304d53745855307479646e4a6b6455525a576e4244645774526230704e4d6d4e454d6a6c435346566153553176596c4a56557a4d3162556c31596c465364566c4e646a4e364b324a6f634446736245566e596e67774e47784d535563785a6e5634564546766547464855557056646d7735596c644a4f56466f596b31576555733052476478636d706c52456b3257554634646c5a595a57637a5a305a77617a42485a477470534568754b335a46633164696133563051336c5563473177545468454c3052565757673265466c79656b4e754d4564324b3341354e47497a5245744a61564a775a6e42785a6b35505447316a4e576c445a32464a4c3252575a30467165446c6e597a524459564a6153576c6c536b5648537a6b3257544a7264546b765132677a5445733151557872613264315969397863306f775979395853466876616d5a52645768304c32564d5a4452504f484a4861486f346246644655464a4661445a4853546735527a424a656c6831534778774e47466f565670316430707653304655566b4d7a63456832636b7845597a6c35576d467454555a474e4746595555784f4d5870516256564665577836556b4a4f6257524d4d486c565445683251566c4a4d6b73795a5656345745707a63465a545a30457a526e4256556c685862325a49624756724e47686a545568335546426a62485a334d6a52346554647153584261545545314e314e4c526b747161325a35646e565652577443553246565647703462464179544552786145746e65486b30526d74494d574e4561305a54567a52326256457a563239694e32784c566a4a7752325534613056574c3078595348643465474e794e6c684a526a52315a325a7a513070545532396c6457673365537478636938324d7a465556576c726179745357444a584e44465a54304a4c6132746a4e33707559554e35656d4a69544868775656464a636d3131546e4279626d4e486346686c61586c55554442545530524b566b3172633073304f48465954334a6a55574e6e4b307476593046325748566d546c4e6c647973776330785951564e514d46564b614745764d33703651305257546d493264454a78516d784f6432315152314d3251316872537a457756304934636d394c5545784e4b79397457456c5062444e564d444e5a4d544a474e575a745254424e593355324e475a3361554d344e307872546c6b3157486870646c6c4654584e6b4d6c686a63574e5662317076626e4a75656a645056323173524374364e586776596b3161646a524c4c7a423057454a76596d5a475657686e52305a4759566c73515451315257747a616e423155565a4655566c4b4b31647a634539725745564356545a69526c4a445a6d52424e323078515642585258564256454a794e316b344d79397a615456494f45564f636d4a455a324e74627a6b345a325275576d747453485251576d56435157396956334a7551315576646a465963325a4b656e5647595531304e33677a52546c6c597a52436557684f5433686f51576334616a4e70646b46594e55357256306c46516c465a6258647456545242614531574f533977516e644461474656546e526f513252454e6c463063327433626d744c4d46513153445a4c536e42324d334a4e55306859597a5279547a424261444e4254484a6a656a4e576148557a55476c31646939365a57466d4d554e535a3278345455647051555a71556a42576255746c5156464853475a5163565a304d6a4e6a5a553548576b6c6c4d30784d5a47527a5332395857546b79543168435455517a4c797479627a465453327459536b354a513346755246424a52576c6c63445a745157396953304a4765544a49616c6f7a6357747256445a61636d5257566c46494d326c6b4b31524c4e6b7055566b74774e456c4f5745566c55556c4b4d316f3153446452616d35704f58465a4c327458566d74454b305a4f4e6d6c70537a5932536a467557576c79626b68315754644d4e444236636a52764e576c33556b6c49556c524e563268434d4339515a6b6474557a6c434d475131655463764d6e5a6f5a455576534374774f445a424d4656594e556c45633059325132567053546c314d323531576b56515958686a5345707853556856574649334f58706a4b324e33566b52354d324e7254304e715357637262334e76636e453164334934575868364f5763785631526d513370706548426b5245746153464a6962324a45645749305a5646464d6a4e71656b39454f446835546d7455556a6456533046435744427852793953596a46474e6e70324d4578465546465a56454a6b564445795655317761303978646a4e4e53315a4663316c46546d5133637a5a5565546b315230493156576c6f515752334e306877526d74495a32746159574e4361573151566a564f61465a585132704e6157686b564859344d6e5a744e334177546e466f643278485a324a524e48685a6454467663565130526a6876645551334e485931647a4179654768345232355362464979655851764d454e7563584a7254456376623068434d6d706d636b784663793973593351795357354f4d4645324e4670505931526c634468576247744e5647686d565664534d32317554584a5a636e5a6f4e5842455546646e52444e345631453051586f34536a4a4753304a765a546b7a576b565a4d55557a5247497a5257785462557851656d4e446330466f537939325257684f4e57464c566c70335257464d595567794d574e30646b3961646d4d7961475a4a4d336c355a4764365a43744c614759784e6a646d516b68584e484643636c42745257687056303830596b4e30523049764e55526d517a4e77624752746547783357546c4b4c33706f6146524b5545683354555a514e6e4a5254533973556c685a61546c444d456c774e4664434e316c476331706b59304658576c68364d7a4977566e5258516c633061464e61556e4e5559314e324c7a4a49616b7854576e70755a45744e546a4e7264324a7a5269393552335a58645778344d7a52715a5641326133685659334976646c4e705a574e32515452754d6b6876656b745a55326c5053544d72527a5643566d35594d6b356b6254527663305255643064345632707a5546464d53487078536b56424e564661526b6472566c4a554f4568594d564a5652564a454d6e6872645756474f5446774d6d74485a474a69516e6477545864785a585a365a6c566e4e6d30764d477055593255794f556c464e32524f51584e6a636d52364c7a46476130677261306b354b303568597a426c51565a726456466c546d6846597a4e45626d5a73536e4d345745353354465a48526a5a715a584a55633235366132644f62556c514c334d7757466c4a554534314e6d357052574a454d564d774f465a30616a52434e6a46775248684a4e5551345655747553335a6f4c3364324d54685162564249566b4e4852554579534339615445566c4f4446464e30316e5a444661625652444f46493256544250525842514d465676516e52535133464c536e6b354e575a4355555a5a61335a754b7a6c334e6d56475531457a5a3251354e6b566e56465a6152484d336132396f4d6a4a6a55546c4953554e4b5745394c534856366255354a6247567161474d324e575a5553576f30635649334e56704e615668694e31524e4e32557251325657636e6c794f57673464305932576e6458523351345379394e544870344e6a68716130317a6255517755574576596d525a6133704a57476c774e6d5a68656d637a6357773353455176625759764c336847656b7048593352524d6a4e7a525735684e6e6c614f484651643067335557464e4e5568764e6b6469593367325a6c467256474672624739364e6e42494f45633355484a7a61576c5156555a45596c5a7a523345345230317464554a574d316c5556444644516b673254484e4c6345466b64453833565668454e4756425745316a64586b3265474a4e4d5756555330786e556d6846617a4276566d31354e7a685257486c4265456c585246645559585a3561544e475757737a614664594d475176576b7072533238304d6a68456148566e556e5a42636e45796348564762455659646a4e684f455a795a466c5255565245566d3833546a4656634574696431564a5446684d633167774f454a6c4f5642746169746e52556859516c6f33656c6c6a646974445544424a5648686a5445567654336b7755565a45553049314b325a6a5755314f5258644259325a4a646d3572636e523062316f7853487059566a5a48524535694f4670486447686b51304577566b38314b316c75556b4a57556d683462477044616b78434e485253596b6c4d616974714f457776625567775355394f63454a5754573954596d394b5a46644f5a465a5963474e4a63314e70536b467661464a47563049326155307a5333424854305a7a5430314256556c7a4e464a3054555a4d4d3070725256464a623256444d454a454e3370515a6b6b79634646505a57553564575a734d30464259336c56576c466b626d673556557330596a6c6c6132347a4d6d5579634464435a474d335a48685752546c69625446734d457478536b317362553544626c5530515752305a6d6849546c5a686256426164316c4b61474e315555704e5a565245646b4a5a4d6d6f7962303035633341324e6a5a686246425a62316872516d4a59636e4e314d7a4d72596c6868636c5a77526a4933553170534d556c53656d4e6f54464255636c6c595a47673156444e4a634668594d6c52474e5774685358645862444e3054305652626b387661456376647a4e5152545258546c56776448685456557330596a5a7564306377636d704e53466f315a6a4a4c4d6d397565474a6c5353394f5244413253566c76656a686e555564714d6c4a7a65556855625646455531466e626c4a6d63334277536c4676566d316c5246453165444a6e4d6e424e5a3035365557773051573136655570505a6b7035543164334b334a73626d4d3352454a36646d30774b793974596d566159305a5962336851634667765a6d4e34636b396a4d55647555546847516d5a55624755354e4664516431643565484a504d446778517939726279396154485a306346567a646e5a45537a4d794f474e52636a564257455634636c417a4d6b35325530706a5a474a30516d4a6d5558687a6453744b4f47355a5a564934526e41334b334a424e446c68536c464d616a42334c31564359304a42545770595557356e5548564f544555325533417262564132546d31565256526f65466c7256555254546b4e7a5244527956325a61566b78484d6b6c6d5647526c63556c494d55746d6445557a54464e48516e523255557833633155334f47316155584276626b457963464e504f586b355a3031615346705a616a52714d46527153545277625578484d455a316456565363573170536d5a725755686f655339464e58684c4f56557262556c50616d5a355347645853316f77656d646e4d54566957584e755a47646f576a5278576d526f63564a42596b465753556b7a4d476c5a61464176576d744453315669575778584c32397665484643536a513155564e4c53465a57636a6c4e5355644c534770494b793833565539464e446c4753565a71656d7047526b5276613246355a475a726257684765555a525932733462554e4b4c304a4b656b4a5264324e4a566c424e51585a6f555731526432355a626e5a48613152355a45567165477434524778614f566c69626e4178626b6c5564304a79536b31364e7a64554f44685054316c4b626a564f4d79383453326b33636d7858637a677251566c5a6130684d64566c7661585236655774484c32685561315934515856685631466f595456734b30524c5745315962556f325a485650523152734d5649795a556872527939525a3070455458565762465251566d354f5a486b77526c64585555393353464d3554564a6d4e6c7044626c465a6554643465566f3357554a305230524d526e5636613152515631637964565a69643370315757313651546c4d5a58557a5a47303259334978554546555354644664576c32656a55775157566b4d6e686b6445564b5556526d6558567a556d746e54555a7a4e7a565a5430396e6358465759305a484e545a4564585644593270344d3064345131683359546c4d593368565931466e52586831516e41784f466445534846735179394f527a6c4e55556b34576b645a53316833546d7032516c5a4d56334670545752735a47785362325a7251573533546a52335a546c565132785355554e73526d593251576f34656b565056444e76515668536257783352325253527a68544b30646a4d454576536d70425546706a4c7a64464e474577556b6c7461477333516c5a45636d357065564e30567a4d724f454a7159537330575864756545356d5a305a4964484134544655724d4774615130687364453175636a63355132356f4c314132556e467953327459656e5650536a6b35644845355557395854323544596a68695a6a683451316378656c4653626a4236564739696146686f55564669536c566c4c336777533274456145564852316f35556e526b64553569596b5a5055305a5a5a564576566a4a50616c566e513155794e544e794d4578484b31524a565746764f485a4f5748524c64555a7265484270563039694e6b465665574a3153586c7a63455a6f56446c6d526d4a7a63564e6a546a426c62564e5a546e5630556e64755554465a566b4e7163564a3051565279516d5135636b78505a6e5673524668754e6c6c684f437456616b565563477478566c64464e6e46784f545a68636a52725a456879637a6c5752484271527a685455446c485746704d536a6849523239586445464e4d4442686348646f5330593364484e494e3039336447785364445176595841726357315154304a58626d7051517a684f5a6e5270574670556548524261327047546e46364c31427a59337073517a41784d7a6869526b354d656b35514d335a7456585a69646d31685358466f563238726430744e62336c365369745565565a36626d70535a6d7445574546696558707a517974554d5735696255785459304a7864485a615432685953465a49574774585257394a656a523152324a614d486c51536a453156475256517a466a4d6a6733515739715657784861544a71593031715554677663445650546b743563325a564e6e68356456644c6545457965476c7365564a44566d773562326b3456476c6d5130464e636e423261486c774e564a77626a6b72656b4d7663433970513168685a7a4d7a516b644a4d474d765343737956303958595556775a334e68544578315332356863314a46656d63775a474a35566d68555545524e4d31704c646b5659556e4a4d4e7a4e6c5169746f4e4578555a30643364546734596e46544e314a6c4c7a526e596d4634613164575369733054455654563056735446566a62556c355932746a62585a47633235335a3346546333644a57697334646e6849544655334d7a64595a6a5273536974594e304e7354444134526a685853573132576c46614e57703356566c33566e4a6b516e5a514d56524c626b4a454e31524f4d7a463661306c495455645056304d77576b4d725644467855474a5052477778516a56564d446c325a45564f626b5a4c53334a765645684a4d33704f616a566b627a55324d30316e6448593163553936516e4a4263444258654664535757396e5157677262557053626e5230556d78785546464f4d6a647263444e31613070594c31684251546852625778705a315134546a5257635759786545394d616c704a6245316956334e5464474e54556d785964567058595534324e4564574d466478656a6873516b5a566331466f57574673596b5a4e51316c6d5569394555334245513239715232687a5654527354466c5555566832656b5134626d6379574746365556517763486c454e6d644e6332464c566e7050623352564e32464e647a564856484a32634849786330637a536c564c5154567153585246624556525753387857545979526b744362336c335448686e62545271556c6479525770316131686a4c32597862454a4f625556354d545a4763335273543152565446686d526c6b7251554e4d53304e54566b5a34516c4e4c647a46305557357962335a58556d464c646d56704e6d5236636e644b52314e754d6c4a3365564e5563545a54626a646d636e4a475447464464566c4c636b5a79555567775553744c6347394e5256646c54326868566a6c7a636d565a4d544e6b63334656553078776346425054455278646d68766247355a623052365a314a79636c5a43656e7071616b4a304c334a4851336c4a62304972533352304d6a52755a3252595933684d52584533535467325a3370695746597262326873566d4e504d32466f56556735643068475a327873646c526c6147354d543074536230517a5554597a62554669576c6b355a6a4e4a56464e44597a5a4f623352764f553930616b564462336832546d686a52693978536c51786555704362316c6151544d314d6e7034615846584e6b4a7454316c3164334a51515574524d474e566231705a636d6330537a64696453747a52584633646b317153544a306348523664466b3262305a79635374584d317058655451775a58526e626d5a5164334e5963555631544841305233466c4c314a3054473561643352544d3356724d6d49346248687965544e7a5a69397656564636555449354e455a364c304e44566e424b516a557753315a71597a644b627a46555544427a5a304a3664564a3261574e70596b316f5a573979547974526247357a544756304e32705465566f334e306878516b6c5055556b7253553135613246306355357657544d355232565157586f724d573959554731754e335a48623368494e5856784d574e724e574a7a4e453147536e424f5a47396a6131424b5533647a5931525562317050646d35364e55707a636d354e576c55355432394d536d64614e555650654656585554426e596e647a535656356548645754544a485a6d6845575564466447786862486c4859575634526b686e59304534596e4976626d704d6555637755486c5a55324e795a47784e59555a50636d3570554846615130564b51556f7655337073546b5a4754335a4c556d6c4e4f473574564338344e323035556d4a755958643463485a715a6e6f7a546e5658615842355369394a4e464a7153565577516a4a50595752456457644d636973314c30356d4e4646434d457455646d5a714d457073626a4e524d4738796333684c5a6b4a5256336833553049725a6c526d614539514e6d5a68553235514e4734726145684753586452556b644559315259576e42355532563262325633616e6331596b6b76633352306433706861325249516b566f637a5a7062564a686158557a6245747859574e554e56427a62315572636c684c576e4a4f525530335430686f625574734e304642656d3552536e5a7555456c574e6c6f35556d70364d6a4d79544570495154513152324e6b5754423652453434545374465557563463566733654867795457526e5a5752684e584a704d6c59335532784a56556c52546b4659516c527661324e764d6c644f57464e544e445a4e6333563654485647613364794f486b7854464e6d55456468546b4533616d733362584a365a56644d563046545332354654546c7459335679516c46516146645461477461566a6474596d466859586c785344493059555268546e6c4364306c42626c524b5a7a686d536e4249555468354d32524656584a5a55466c6d556a63354d303147524446595445467659584e54527a5a78564770304e6a64714f5652716558684359584978537a4a524c336855616e6f30526b4a4e6557303463446b334e315a46615746494d56597654576832633268755a7a597662553877525535534f454e5763575268646b746163305a4865554932566c4255637a6c514f545a54625855724c306c3356314a7a61556735616a6b3263336c4f633064475a6b517761586734547a5a4c5a546330597a683051304e684f5468595430315662326474543268794e47343264316878546b4532656e644b4d6d4a4451324e7561316853526d565953305a56626d3970616b5279537a56704d56466c5545354a4b314e5352575a6f5930527565474577556c704e61475572526d56526131426f4f453077656d64524c306852576e684863325a694f456c5062484a314e6d525765444e6f4e466c6c6444423254304e794e44637662554d30516a5658526d687556546444546d356b516e6830635559335345387a536d70326256526e596c6c7a546a557255334a3263316330553068476148645056304e794d45557a62326c69526a467a516b315561555a48526b5932576b7861616e526865574e5956486b32566c55784d7a5676624468734f47564356476c52526b524c5333527a51564e7054475a355632784d4b7939464f48705a5a6e647855586b345130673453586c30555841354e6a64424e6e684f56444a4d4d45706d526e6c734e575a524d7a56314e466843524846535a44426b576e6c6852324647526a63324c3035685555525a51555270626d706d4c327057543364316448525856486c74526d6f32576b526b5a46683259575647565778524d55745851574a7955455269536a6b314f446b7a4f5656704e6c6b30596c5a7a54335a3054564a3661575a6f517a566157485a45627a4673656b4a44656e464d5258646f634842615a554a544e3156534e33426163315976546c424f63304a5162453553566b3931546e683651544654566d68565a584a7063464e465746566d63797461556c6446547a6b7a614652694c32673352574e5855334a75516c56476333645856586c5555576c3155477452556d30796247355855473571646e5a6a6479397764304a52636e5a585554566b597a566f6554466b54335979614730725555356b4d324658597939685a30466c56334e7365584230636b46574e6e5a45533142364d32563659544a6f555570515a58704356473552536d4a4e4f45737856454e6a5a334579546b5659636c686f656d4a355630644f4e456732576b5533544551724e58524464475272526e5a4f555856485330453454466c434e303933656a5576546b6c4c626c5a614e6b704b513164336545313254465a4d574570565a6c4242543064795257565a65446b794f577861516d747164464a30566b35505a306c6d5931643361566c555347785563455a6b576c64425a6b7859596a567457485578576e6430536c6c4f4e545656533152324e5646585344684a5a30317363544e49516c4e74526a464b5a6b744e61446c465a32597a4d474676516d64436356526d4e7a633151336c614d57354a647a5a4d4e6d687554324e6157454642574852504e474659626d633462326f31566c51355154687a4e6e4645576c5a7052454d7654334a554e6c6f775232567a56545675526e6c5153576c35516b74545656684d596c52525647524c62544e5a52465a6d5344467a6432566a5a3142504d6b4a52516c64545a307730644774545a6e685462576c334e306c53526d6b765a7a4d336246566d596c6c3063556455526d395a5a58677652465a715569747663584a774e6a4e4664437471616d524f59337049615846504f576b7953305a705a3346455931646b536b467259315a57566b49794d5574715a6a4268655649794e554e4a56446c6d6355745851584579626e59765953393156475232575667795156424655334236596d4a32654578744e55644c54324a42646a6873536d4a7961334a436558566165486853596d466b5932396d5657737a4e79397a5a4578484f4856584d305668524546794d3156355557707961574a774b33463051334a43516c46795958524654456878644664584f486874575455355244524c56585261627a4a735a46703356486c6d566a4d76546b4a365a554a735a325a365a445130596e5a4c55574a32596c5649616e42425547317359545977536c7070576a64354e6a4e684e79397363445a73526b6c7361324e585533644d644764775445744b5648466851304972515459725332597251554a6e526b6868616c70364d6c68565a3031305556426d63484272576a4e3163565a745932784e6344464265464977625842355757743365444a4456586456626c6378656c564a4d564d794b327061545570774f565a77547a413256444e6162473575576d744665566c4a566a6459516b3533566c70454b3045345a6b68544d6e527854576c426269747955455a30647a64524e6e566a6156524c5155737a5345706961584a7155475a73533252324f5870684d31564f647973346247567759306c435633417a5245703154586c725a6d4a3255464a4c5530643261446779636c4a7861336c4b574868464d6c6448526c56785332684253306433555778355354567a576a4a6a616d3942555852334e6a424d55324657626d4e785254524c5754426f626b316a4e3031344f5659325631704f53334177643070774e554e57546c5934596c5a7854573943536e684451553949626b6c59625651345a454a694d6a426b526c46525457314a536d394f4f464a57563031584c323573656e5131614468696345707a5a554e7055543039664455344f54466c5a6a5a6b4e6d59325a6a59324d6d4d784e7a46684d4749795a4441784d474577596a5a6d4f54466c597a5a6c4e6d5932597a5a6d4e6a49794e7a41774d5751785954466a4d5749775a4446684d44633dd41d8cd98f00b204e9800998ecf8427e|ANT

Now let's try to run it:

$ mutant death.mu
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⠶⠟⠛⠛⠛⠶⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢠⡾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠉⢷⡀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢠⣿⠁⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⣾⣷⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣾⠟⢉⣀⣀⡈⠃⠀⠀⠒⣉⣀⡀⠈⢻⡄⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⡏⠀⣴⣶⣿⣿⣷⠂⠀⣾⣿⣿⣿⣆⢠⡇⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢸⣿⠀⠻⠿⢿⡿⠃⣰⣆⠙⣿⡿⠿⠋⠸⣧⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣿⠁⠀⠀⠀⠈⠀⠠⣿⠿⠀⠀⣀⣀⣀⠀⣿⣦⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣼⣿⣶⣾⣿⣿⡟⢀⠀⠀⠀⢀⢀⢻⣿⣿⣿⣿⢻⡇⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣇⢸⡇⠻⢿⣿⠇⡜⢸⠀⡇⢸⠘⣼⣿⠿⠉⠙⣿⡇⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣿⣾⣿⣦⠀⣿⣷⣷⣾⣤⣷⣾⣿⣿⢋⣴⣶⣶⣿⡀⠀⠀⠀⠀⠀
⠀⠀⠀⣠⠞⠙⠻⣿⣿⣷⣿⣿⣿⠿⠿⠻⠟⠋⠀⣼⣿⣿⡿⣻⣿⣦⡀⠀⠀⠀
⠀⢀⡼⢿⡦⣠⣴⢿⣿⣿⣿⣏⣿⣤⠀⠀⢰⡔⣶⣾⣿⠏⠀⠀⠀⣿⣿⣄⠀⠀
⠀⡾⢡⣏⢰⣯⠃⣼⣿⡿⢿⡟⢿⡋⠀⠀⢸⣽⣿⣿⡿⣇⠀⠀⠀⢈⡿⡿⣆⠀
⢸⡿⠿⠏⢰⠇⢸⡿⠋⠀⠀⣿⡟⠀⠀⠀⠈⡟⠀⠉⠳⣿⣿⠆⠀⢿⣙⡇⣿⡄
⣿⠀⠀⠀⢸⢰⣿⠁⠀⠀⠀⢸⣧⣤⠀⠀⡼⡇⠀⠀⠀⢹⣾⠀⠀⠈⢻⡇⢹⡇
⣿⣿⣷⠀⢸⣸⣿⠀⠀⠀⠀⠀⢷⣿⠀⠀⠳⡇⠀⠀⠀⢸⡟⠀⠀⠀⡸⠀⢼⡇
⢿⣟⠋⠀⢸⡿⣿⠀⠀⠀⠀⠀⠘⣿⢲⣦⠀⢹⡀⠀⠀⡼⠀⣤⣤⣴⠃⢠⣾⠇
⠸⡏⣿⠆⠘⢷⣼⣷⣄⠀⠀⠀⠀⠹⣿⡇⠀⠘⢵⣤⡾⢁⡤⣡⠞⠁⠀⣸⠟⠀
⠀⠹⣧⠀⢀⣀⠀⠸⣯⣽⣷⣦⣄⡀⢻⣷⣦⣄⣤⠙⣷⡼⠞⠁⣀⢄⣾⠏⠀⠀
⠀⠀⠈⠻⣟⠙⢧⣀⣀⠀⠘⢳⣾⣿⣿⣿⣿⣮⡻⣤⡌⠛⢶⣵⣵⡿⠁⠀⠀⠀
⠀⠀⠀⠀⠈⠳⢶⣤⣿⣦⠖⡉⠕⠊⢉⣿⣿⣿⣷⣾⣧⣖⣦⠙⢿⣄⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣸⠟⠠⠈⠀⢀⣰⣿⣿⣿⣿⣿⣟⢿⣿⣿⣠⡴⢮⢳⣄⠀⠀
⠀⠀⠀⠀⠀⠀⣼⡫⠂⠀⠀⠀⣶⡿⣿⣿⣿⠁⠘⢿⣆⠙⣿⣿⣅⢺⡇⠛⢷⡄
⠀⠀⠀⠀⠀⢰⣿⠁⠀⠀⠀⣼⠏⠀⠈⢿⣿⠀⠀⢀⣿⠀⢸⣿⢿⣿⣷⢺⡆⣿
⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⢰⣿⠀⠀⠀⠈⣏⢻⡇⢷⣾⡇⢸⣿⠃⠘⢿⣼⣧⣿
⠀⠀⠀⠀⠀⢸⣇⠀⠀⠀⢉⢿⣆⠀⠀⠀⣿⡟⠀⠀⢹⣷⣿⡏⠀⠀⢽⣿⣿⠏
⠀⠀⠀⠀⠀⠀⢻⡆⠀⠀⠀⠸⢻⢿⣶⣶⣿⢻⡆⢀⣼⣿⠏⠀⠀⣠⣹⣿⠋⠀
⠀⠀⠀⠀⠀⠀⠀⠻⣷⣀⣀⠀⠈⠈⠘⣿⡇⡿⠃⣸⢸⣿⢀⣠⣦⡿⠛⠁⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠳⠶⣤⣴⣾⣿⣠⡇⠐⣇⣿⣿⠿⠛⠉⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⣿⠁⠀⠀⣹⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣧⡀⠀⣀⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⢧⡟⠁⣾⢻⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠞⠃⢠⣆⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⠃⠀⠀⠀⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⡄⠀⡀⣸⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡏⣼⠋⣸⢹⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣷⠿⠀⢫⣾⠁⠀⠀⠀⡠⠚⢉⣉⠓⣦⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⢰⡟⠀⠀⢀⣼⢱⣿⣾⣿⣷⣼⡄⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣆⠀⢠⣾⠇⠀⣼⡥⢃⣾⣿⣿⣿⡟⠈⠻⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡇⡿⠂⢸⣸⠀⢰⣏⠔⠛⠛⢻⣿⣿⣧⢠⡄⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣷⡇⠀⠘⢿⡆⠸⣇⠀⠀⠀⠀⠈⠉⠉⣩⠇⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣷⣦⡄⠸⣷⡀⢹⣷⠄⠀⠀⢠⣤⠾⠃⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡍⠳⠤⠾⠿⠛⠁⠀⠀⣨⡿⠁⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⣄⠀⠀⠀⠀⢀⠀⢤⡾⠁⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠓⠦⣴⣴⣶⠶⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀
Enter the password: password
We understand the significance of this tool in fulfilling our noble cause,
but only those with the right credentials may gain entry.

Should you require further assistance or have any concerns, get familiar with mutant's compiler
Together, we shall uphold the integrity of our mission and the safety of our fellow Death Eaters.
May the darkness guide us towards victory,

The Dark Lord's Loyal Servants

Obviously, the password fails. (Creator secret: bruteforcing the password won't work as the password is damn long). The code runs and it looks like the flag is hidden behind its source code. The code looks like base64 so maybe we can decode it. Let's try decoding with the hello world program. Looking in the hello.mu file, we can notice that the encoded code starts with MU| and ends with |ANT. The text in between looks like base64. Further, there are two strings wrapped between MUT| and |ANT in this encoded text.

QTVCdVo3ZWFwMjllZSt1SURnTlp5OTVtRlg0eHl2T3lmdC95LzdBeGhlVFhWRXliUDZ3N2x0TCtabzB4WlYzb3dVY1lLcFRMMVJVZTQrbUJrMmZvMzljUFN2TVRKejRyUkNKK1V4SURnek83cWl5bitlem1vTHZBUFRTWmdLWlk2Vk43d1BOa003bzhKcEQ1RnExWUQreDk3dVc3WW82eTRzUjFsTzdlbk1BMTVtK2VNS1V3RWNEOVA2QlE4Z1pnOXJUalpnSHFnbEJQZEdjRVhJRTNTUEg1emUxL2R3QWl3aUM5VnMvSVpxL3dabmhtSzZrdnUra2hxVlRWVytZemZHRklUYUk4RUJzY08wSnZObWpZZ3lVekJ4NjVVWkJoQVlSa3NnPT18NmFhM2RkNWY1ZDVkNTQxZTI1MjgzOTFmMzMzODM5NWRhM2RlNWM1ZDVlNWQ1MDE1MzIyZjI4MmUyOTNmMjgzNQ==

and

5154564364566f335a5746774d6a6c6c5a5374315355526e546c70354f545674526c673065486c3254336c6d644339354c7a64426547686c5646685752586c6955445a334e32783054437461627a4234576c597a6233645659316c4c6346524d4d564a565a54517262554a724d6d5a764d7a6c6a55464e325456524b656a5279556b4e4b4b3156345355526e656b383363576c356269746c656d317654485a4255465254576d644c576c6b32566b34336431424f61303033627a684b63455131526e45785755517265446b3364566333575738326554527a556a4673547a646c626b31424d5456744b32564e5331563352574e454f564132516c45345a31706e4f584a55616c706e5348466e62454a515a45646a5256684a52544e5455456731656d55784c32523351576c3361554d35566e4d76535670784c336461626d6874537a5a72646e557261326878566c52575679745a656d5a48526b6c5559556b3452554a7a59303877536e5a4f6257705a5a336c56656b4a344e6a5656576b4a6f51566c5361334e6e505431384e6d46684d32526b4e5759315a44566b4e5451785a5449314d6a677a4f54466d4d7a4d7a4f444d354e5752684d32526c4e574d315a44566c4e5751314d4445314d7a49795a6a49344d6d55794f544e6d4d6a677a4e513d3dd41d8cd98f00b204e9800998ecf8427e

Decoding the first base64 string, we get

A5BuZ7eap29ee+uIDgNZy95mFX4xyvOyft/y/7AxheTXVEybP6w7ltL+Zo0xZV3owUcYKpTL1RUe4+mBk2fo39cPSvMTJz4rRCJ+UxIDgzO7qiyn+ezmoLvAPTSZgKZY6VN7wPNkM7o8JpD5Fq1YD+x97uW7Yo6y4sR1lO7enMA15m+eMKUwEcD9P6BQ8gZg9rTjZgHqglBPdGcEXIE3SPH5ze1/dwAiwiC9Vs/IZq/wZnhmK6kvu+khqVTVW+YzfGFITaI8EBscO0JvNmjYgyUzBx65UZBhAYRksg==|6aa3dd5f5d5d541e2528391f3338395da3de5c5d5e5d5015322f282e293f2835

This again looks like two strings separated with a vertical bar. Decoding the base64 again we get gibberish code which is a binary file.

��ng·�§o^{ë���YËÞf�~1Êó²~ßòÿ°1�ä×TL�?¬;�Òþf�1e]èÁG�*�ËÕ��ãé��gèß×�Jó�'>+D"~S���3»ª,§ùìæ »À=4��¦XéS{Àód3º<&�ù�­X�ì}îå»b�²âÄu�îÞ�À5æo�0¥0�Àý? Pò�`ö´ãf�ê�POtg�\�7HñùÍí�w�" ½VÏÈf¯ðfxf+©/»é!©TÕ[æ3|aHM¢<���;Bo6hØ�%3��¹Q�a��d²

Let's run binwalk on this

$ echo "A5BuZ7eap29ee+uIDgNZy95mFX4xyvOyft/y/7AxheTXVEybP6w7ltL+Zo0xZV3owUcYKpTL1RUe4+mBk2fo39cPSvMTJz4rRCJ+UxIDgzO7qiyn+ezmoLvAPTSZgKZY6VN7wPNkM7o8JpD5Fq1YD+x97uW7Yo6y4sR1lO7enMA15m+eMKUwEcD9P6BQ8gZg9rTjZgHqglBPdGcEXIE3SPH5ze1/dwAiwiC9Vs/IZq/wZnhmK6kvu+khqVTVW+YzfGFITaI8EBscO0JvNmjYgyUzBx65UZBhAYRksg==" | base64 --decode - > /tmp/binary_found_in_mu
$ binwalk /tmp/binary_found_in_mu

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------

Looks like the file does not contain any known binary. Let's see what kind of file is it.

$ file /tmp/binary_found_in_mu
/tmp/binary_found_in_mu: data

Running strings is no luck as well. At this point, the code is just unreadable. But the compiler is reading it somehow. Let's dive into the compiler's source code to understand how it works.

$ git clone https://github.com/gaurav-gogia/mutant

Now lets start with main.go. As we know the compiler does two things, compile the code and run the code. We are interested in the running process. Looking in the main.go file, we find the following code

if strings.HasSuffix(os.Args[1], global.MutantByteCodeCompiledFileExtension) {
    cli.RunCode(os.Args[1])
    return
}

Let's dig in further by reading the cli/cli.go file as the above code is giving the file name to cli.RunCode function. Within the cli/cli.go file, we find the RunCode function

func RunCode(src string) {
    srcpath, err := filepath.Abs(src)
    if err != nil {
        fmt.Println(err)
        return
    }

    if err, errtype := runner.Run(srcpath); err != nil {
        switch errtype {
        case errrs.ERROR:
            fmt.Println(err)
        case errrs.VM_ERROR:
            errrs.PrintMachineError(os.Stdout, err.Error())
        }
    }
}

Here, the user provided file path is converted to absolute path and sent to runner.Run function. Lets look into that in file runner/runner.go

func Run(srcpath string) (error, errrs.ErrorType) {
    signedCode, err := ioutil.ReadFile(srcpath)
    if err != nil {
        return err, errrs.ERROR
    }

    if err := security.VerifyCode(signedCode); err != nil {
        return err, errrs.ERROR
    }

    bytecode, err := decode(signedCode)
    if err != nil {
        return err, errrs.ERROR
    }

    return runvm(bytecode)
}

This is an interesting function. It is verifying and decodes the code and sending the bytecode to runvm. We are interested in decoding the code. The decode function is right below this Run function and looks like this:

func decode(data []byte) (*compiler.ByteCode, error) {
    decodedData, err := decryptCode(data)
    if err != nil {
        return nil, err
    }
    reader := bytes.NewReader(decodedData)

    var bytecode *compiler.ByteCode
    registerTypes()
    dec := gob.NewDecoder(reader)
    if err := dec.Decode(&bytecode); err != nil {
        return nil, err
    }

    return bytecode, nil
}

We got another trail here, decryptCode. It seems decodedData is a serialized gob and bytecode contains the deserialized go object (struct). Gob is a serialization in Golang. Let's understand how decryptCode works now. The decryptCode function is also in the same file

func decryptCode(signedCode []byte) ([]byte, error) {
    encryptedCode := security.GetEncryptedCode(signedCode)
    decryptedData, err := security.AESDecrypt(encryptedCode)
    if err != nil {
        return nil, err
    }
    decodedData := security.XOR(decryptedData, len(decryptedData))
    return decodedData, nil
}

Here, we see that the compiler is decrypting with AES. We can also notice it calling security.GetEncryptedCode. It is calling a user-defined function security.AESDecrypt which is in mutant/security module. We should look into it as well as security.XOR, let's read security/signatures.go and security/crypto.go one by one.

In security/signatures.go, we find VerifyCode

func VerifyCode(signedCode []byte) error {
    signedCodeString := string(signedCode)
    values := strings.Split(signedCodeString, SEPERATOR)

    if values[0] != HEADER {
        return ErrWrongSignature
    }

    integrity := md5.New().Sum([]byte(values[1]))
    integString := hex.EncodeToString(integrity)
    if integString != values[2] {
        return ErrWrongSignature
    }

    if values[3] != FOOTER {
        return ErrWrongSignature
    }

    return nil
}

This just raises an error if the hexes don't match. It splits the signed code using SEPERATOR. This SEPERATOR constant can be found in security/const.go as |. So we know that we have been doing the same thing manually. After split, we get values[0] which is "MUT". Later it creates an MD5 hash to check the integrity of the code which is the second string value s[1] (base64) in the mut file. It then matches the hash with values[2] which is the hex string we had. Finally, it matches FOOTER which is "ANT". Now we know that the base64 encoded string is the code.

We also find GetEncryptedCode. This seems to be splitting the code with the same method mentioned above and returning the base64 encoded code.

func GetEncryptedCode(signedCode []byte) string {
    signedCodeString := string(signedCode)
    return strings.Split(signedCodeString, SEPERATOR)[1]
}

In security/crypto.go we have XOR which is the usual XOR function, and AESDecrypt, let's read it:

func AESDecrypt(encodedCipherData string) ([]byte, error) {
    cipData, err := base64.StdEncoding.DecodeString(encodedCipherData)
    if err != nil {
        return nil, err
    }

    values := strings.Split(string(cipData), SEPERATOR)
    cipherString := values[0]
    keyString := values[1]

    cypher, err := base64.StdEncoding.DecodeString(cipherString)
    if err != nil {
        return nil, err
    }
    key, err := hex.DecodeString(keyString)
    if err != nil {
        return nil, err
    }

    c, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }

    gcm, err := cipher.NewGCM(c)
    if err != nil {
        return nil, err
    }

    nonceSize := gcm.NonceSize()
    if len(cypher) < nonceSize {
        return nil, errors.New("wrong nonce")
    }

    nonce, cipherText := cypher[:nonceSize], cypher[nonceSize:]
    data, err := gcm.Open(nil, nonce, cipherText, []byte(ENCSIG))

    return data, nil
}

It starts with base64 decode of the data provided by GetEncryptedCode, then splits it further. We already know that the code is twice base64 encoded. Now we have two things, a cipherString and keyString. These both are used to decrypt the AES. This means that the second hex string we found was the key for AES. Now we can either create our own AES decryption script or we could just utilize what Mutant's source code provides us.

I chose the second part as it is easier. I created a new file called deobfuscate-mutant.go at the root of the mutant language. I will use this to write my deobfuscator. We know that the function decode decodes the whole code and gives a compiler.ByteCode struct. But since decode is a private function (only names with first letter uppercase are publicly accessible in go), we need to create a new publicly accessible decode. To do this, I added a wrapper function in runner/runner.go next to the decode function as follows

func Decode(data []byte) (*compiler.ByteCode, error) {
    return decode(data)
}

Now, we can call decode through runner.Decode in our deobfuscate-mutant.go.

package main

import (
    "io/ioutil"
    "mutant/runner"
    "os"
    "fmt"
)

func main() {
    signedCode, _ := ioutil.ReadFile(os.Args[1])
    byteCode, _ := runner.Decode(signedCode)
    fmt.Println(byteCode)
}

Now I tried running the code with go run new-obfuscate.go death.mu but it is stuck in an infinite loop. Looks like something's stopping the print. Let's look into the compiler.ByteCode structure returned by runner.Decode. The code is in compiler/compiler.go file

type ByteCode struct {
    Instructions code.Instructions
    Constants    []object.Object
}

This is interesting. The code is not stored as is but in assembly like code structure. There are instructions and constants. If you are familiar with the basics of assembly, you might know that each instruction has operators and operands. The same can also be called instructions and constants. There is more to it. This struct is instantiated by ByteCode function down below

func (c *Compiler) ByteCode() *ByteCode {
    return &ByteCode{
        Instructions: c.currentInstructions(),
        Constants:    c.constants,
    }
}

Here. we find that c which is Compiler object has constants and currentInstructions. We have a ByteCode object (struct). That means we can call Constants and see the constant values stored within the memory of this compiler during runtime. Let's try to print them to stdout.

package main

import (
    "io/ioutil"
    "mutant/runner"
    "os"
    "fmt"
)

func main() {
    signedCode, _ := ioutil.ReadFile(os.Args[1])
    byteCode, _ := runner.Decode(signedCode)
    fmt.Println(byteCode.Constants)
}

Running the code on hello.mu, we get:

$ go run deobfuscate-mutant.go hello.mu
[0xc00006d320]

Looks like this array of hexadecimal here. Let's try to get the first value as string.

package main

import (
    "io/ioutil"
    "mutant/runner"
    "os"
    "fmt"
)

func main() {
    signedCode, _ := ioutil.ReadFile(os.Args[1])
    byteCode, _ := runner.Decode(signedCode)
    fmt.Println(string(byteCode.Constants[0]))
}

we get

$ go run deobfuscate-mutant.go hello.mu
# command-line-arguments
./deobfuscate-mutant.go:13:24: cannot convert byteCode.Constants[0] (variable of type object.Object) to type string

So byteCode.Constants is an array of object.Object which is in file object/object.go. In object/object.go,

package object

type ObjectType string

const (
    INTEGER_OBJ      = "INTEGER"
    BOOLEAN_OBJ      = "BOOLEAN"
    NULL_OBJ         = "NULL"
    RETURN_VALUE_OBJ = "RETURN_VALUE"
    ERROR_OBJ        = "ERROR_OBJ"
    FUNCTION_OBJ     = "FUNCTION"
    STRING_OBJ       = "STRING"
    BUILTIN_OBJ      = "BUILTIN"
    ARRAY_OBJ        = "ARRAY"
    HASH_OBJ         = "HASH"
    QUOTE_OBJ        = "QUOTE"
    MACRO_OBJ        = "MACRO"
    COMPILED_FN_OBJ  = "COMPILED_FN_OBJ"
    CLOSURE_OBJ      = "CLOSURE"
    ENCRYPTED_OBJ    = "ENCRYPTED"
)

type Object interface {
    Type() ObjectType
    Inspect() string
}

we find an interface. Further, we see the data types. So ByteCode.Constants contain the data. Let's look at a few more data-type objects like string. In object/stringObj.go we find the code

package object

type String struct{ Value string }

func (s *String) Type() ObjectType { return STRING_OBJ }
func (s *String) Inspect() string  { return s.Value }

Again, there's Inspect function in this object. Let's try to call that in our deobfuscate-mutant.go

package main

import (
    "io/ioutil"
    "mutant/runner"
    "os"
    "fmt"
)

func main() {
    signedCode, _ := ioutil.ReadFile(os.Args[1])
    byteCode, _ := runner.Decode(signedCode)
    fmt.Println(byteCode.Constants[0].Inspect())
}

But the result is almost the same. We are still in an array of numerics. If you look closely, the array is of exact length as "Hello, World!" string. And there are repititve letters same as well, for example, 60 60 signifies ll in Hello. But let's try to read the code instead of doing mathematical magic here. There is not much information in objects about these numbers. To understand what these numbers are, we need to run the code the way the virtual machine does. So we move back to our runner/runner.go and try to read Run function again.

func Run(srcpath string) (error, errrs.ErrorType) {
    signedCode, err := ioutil.ReadFile(srcpath)
    if err != nil {
        return err, errrs.ERROR
    }

    if err := security.VerifyCode(signedCode); err != nil {
        return err, errrs.ERROR
    }

    bytecode, err := decode(signedCode)
    if err != nil {
        return err, errrs.ERROR
    }

    return runvm(bytecode)
}

We don't need to verify the integrity of our code, and we have used Decode that calls decode which gives us ByteCode struct in our code similar to this Run function. In the end, it uses runvm which we haven't checked out yet. So let's look into it. In the runner/runner.go we have this runvm function:

func runvm(bytecode *compiler.ByteCode) (error, errrs.ErrorType) {
    globals := make([]object.Object, global.GlobalSize)
    machine := vm.NewWithGlobalStore(bytecode, globals)

    if err := machine.Run(); err != nil {
        return err, errrs.VM_ERROR
    }

    last := machine.LastPoppedStackElement()
    io.WriteString(os.Stdout, last.Inspect())
    io.WriteString(os.Stdout, "\n")

    return nil, ""
}

Here it is doing some globals thing, creating a machine and then running it. After running, we see it also calls machine.LastPoppedStackElement which suggests there's a stack of something. You might know that a computer calls instructions from a stack from top to bottom order.

Finally, we notice that there's last.Inspect() call which we did in our deobfuscator too. We look further into the vm.NewWithGlobalStore to understand how it works. In vm/vm.go we find this code:

func NewWithGlobalStore(bc *compiler.ByteCode, globals []object.Object) *VM {
    vm := New(bc)
    vm.globals = globals
    return vm
}

and New which the above function uses to create vm is:

func New(bc *compiler.ByteCode) *VM {
    mainfn := &object.CompiledFunction{Instructions: bc.Instructions}
    frames := make([]*Frame, global.MaxFrames)

    mainClosure := &object.Closure{Fn: mainfn}
    mainFrame := NewFrame(mainClosure, 0)
    frames[0] = mainFrame

    return &VM{
        constants:    bc.Constants,
        stack:        make([]object.Object, global.StackSize),
        stackPointer: 0,
        globals:      make([]object.Object, global.GlobalSize),
        frames:       frames,
        frameIndex:   1,
        inslen:       len(bc.Instructions),
    }
}

Here, we notice that it takes a ByteCode and assigns a few things to the VM struct. We see constants, but no instructions assigned. There are also other frame and closure things we probably don't know about nor we are interested in. What we are looking for is a way to decode those numeric values. So we go back and look at the next important function call in runvm function, machine.Run. This function also is in vm/vm.go

func (vm *VM) Run() error {
    var ip int
    var ins code.Instructions
    var op code.Opcode

    for vm.currentFrame().ip < len(vm.currentFrame().Instructions())-1 {
        vm.currentFrame().ip++

        ip = vm.currentFrame().ip
        ins = vm.currentFrame().Instructions()
        ins[ip] = security.XOROne(ins[ip], vm.inslen)
        op = code.Opcode(ins[ip])
        ins[ip] = security.XOROne(ins[ip], vm.inslen)

        switch op {
        case code.OpConstant:
            constIndex := code.ReadUint16(ins[ip+1:], vm.inslen)
            vm.currentFrame().ip += 2

            if err := vm.push(vm.constants[constIndex]); err != nil {
                return err
            }
        case code.OpBang:
            if err := vm.executeBangOperation(); err != nil {
                return err
            }
        case code.OpMinus:
            if err := vm.executeMinusOperation(); err != nil {
                return err
            }
        case code.OpAdd, code.OpSub, code.OpMul, code.OpDiv:
            if err := vm.execBinaryOperation(op); err != nil {
                return err
            }
        case code.OpTrue:
            if err := vm.push(global.True); err != nil {
                return err
            }
        case code.OpFalse:
            if err := vm.push(global.False); err != nil {
                return err
            }
        case code.OpArray:
            numElements := int(code.ReadUint16(ins[ip+1:], vm.inslen))
            vm.currentFrame().ip += 2
            array := vm.buildArray(vm.stackPointer-numElements, vm.stackPointer)
            if err := vm.push(array); err != nil {
                return err
            }
        case code.OpHash:
            numElements := int(code.ReadUint16(ins[ip+1:], vm.inslen))
            vm.currentFrame().ip += 2
            hash, err := vm.buildHash(vm.stackPointer-numElements, vm.stackPointer)
            if err != nil {
                return err
            }
            vm.stackPointer = vm.stackPointer - numElements
            if err := vm.push(hash); err != nil {
                return err
            }
        case code.OpEqual, code.OpUnEqual, code.OpGreater:
            if err := vm.executeComparison(op); err != nil {
                return err
            }
        case code.OpJump:
            pos := int(code.ReadUint16(ins[ip+1:], vm.inslen))
            vm.currentFrame().ip = pos - 1
        case code.OpJumpFalse:
            pos := int(code.ReadUint16(ins[ip+1:], vm.inslen))
            vm.currentFrame().ip += 2
            condition := vm.pop()
            if !isTruthy(condition) {
                vm.currentFrame().ip = pos - 1
            }
        case code.OpSetGlobal:
            globalIndex := code.ReadUint16(ins[ip+1:], vm.inslen)
            vm.currentFrame().ip += 2
            vm.globals[globalIndex] = vm.pop()
        case code.OpGetGlobal:
            globalIndex := code.ReadUint16(ins[ip+1:], vm.inslen)
            vm.currentFrame().ip += 2
            if err := vm.push(vm.globals[globalIndex]); err != nil {
                return err
            }
        case code.OpSetLocal:
            localIndex := code.ReadUint8(ins[ip+1:], vm.inslen)
            vm.currentFrame().ip++
            frame := vm.currentFrame()
            obj := vm.pop()
            encObj, err := mutil.EncryptObject(obj, vm.inslen)
            if err != nil {
                vm.stack[frame.bp+int(localIndex)] = obj
            } else {
                vm.stack[frame.bp+int(localIndex)] = encObj
            }
        case code.OpGetLocal:
            localIndex := code.ReadUint8(ins[ip+1:], vm.inslen)
            vm.currentFrame().ip++
            frame := vm.currentFrame()
            if err := vm.push(vm.stack[frame.bp+int(localIndex)]); err != nil {
                return err
            }
        case code.OpGetBuiltin:
            builtinIndex := code.ReadUint8(ins[ip+1:], vm.inslen)
            vm.currentFrame().ip++
            definition := object.Builtins[builtinIndex]
            if err := vm.push(definition.Builtin); err != nil {
                return err
            }
        case code.OpGetFree:
            freeIndex := code.ReadUint8(ins[ip+1:], vm.inslen)
            vm.currentFrame().ip++
            currentClosure := vm.currentFrame().cl
            if err := vm.push(currentClosure.Free[freeIndex]); err != nil {
                return err
            }
        case code.OpIndex:
            index := vm.pop()
            left := vm.pop()
            if err := vm.execIndexOperation(left, index); err != nil {
                return err
            }
        case code.OpClosure:
            constIndex := code.ReadUint16(ins[ip+1:], vm.inslen)
            numFree := code.ReadUint8(ins[ip+3:], vm.inslen)
            vm.currentFrame().ip += 3
            if err := vm.pushClosure(int(constIndex), int(numFree)); err != nil {
                return err
            }
        case code.OpCurrentClosure:
            currentClosure := vm.currentFrame().cl
            if err := vm.push(currentClosure); err != nil {
                return err
            }
        case code.OpCall:
            numArgs := code.ReadUint8(ins[ip+1:], vm.inslen)
            vm.currentFrame().ip++
            if err := vm.executeCall(int(numArgs)); err != nil {
                return err
            }
        case code.OpReturnValue:
            returnValue := vm.pop()
            frame := vm.popFrame()
            vm.stackPointer = frame.bp - 1
            if err := vm.push(returnValue); err != nil {
                return err
            }
        case code.OpReturn:
            frame := vm.popFrame()
            vm.stackPointer = frame.bp - 1
            if err := vm.push(global.Null); err != nil {
                return err
            }
        case code.OpNull:
            if err := vm.push(global.Null); err != nil {
                return err
            }
        case code.OpPop:
            vm.pop()
        }
    }
    return nil
}

This is an interesting one. It is checking for the OpCode using a switch case statement. The switch is matching for op which comes from op = code.Opcode(ins[ip]). ins here is an array of instructions and ip stands for instruction pointer which tells which instruction to read.

There are a few XOROne running to flip the instruction pointer here and there. Interestingly, there are vm.push call which is very likely pushing instructions to the stack to run. Let's confirm that by looking at the code. The same file, we see

func (vm *VM) push(obj object.Object) error {
    if vm.stackPointer >= global.StackSize {
        return fmt.Errorf("stack overflow")
    }

    if encObj, err := mutil.EncryptObject(obj, vm.inslen); err == nil {
        obj = encObj
    }

    vm.stack[vm.stackPointer] = obj
    vm.stackPointer++

    return nil
}

and this push function calls EncryptObject to encrypt the object while being pushed. Let's look into that. EncryptObject comes from mutil/util.go file

func EncryptObject(obj object.Object, length int) (object.Object, error) {
    var encObj object.Object
    var err error

    switch obj.Type() {
    case object.INTEGER_OBJ:
        val := obj.(*object.Integer).Value
        bite := make([]byte, 8)
        binary.LittleEndian.PutUint64(bite, uint64(val))
        bite = security.XOR(bite, length)

        encObj = &object.Encrypted{
            EncType: object.INTEGER_OBJ,
            Value:   bite,
        }

    case object.STRING_OBJ:
        val := obj.(*object.String).Value
        bite := security.XOR([]byte(val), length)

        encObj = &object.Encrypted{
            EncType: object.STRING_OBJ,
            Value:   bite,
        }

    case object.BOOLEAN_OBJ:
        val := obj.(*object.Boolean).Value
        str := strconv.FormatBool(val)
        bite := security.XOR([]byte(str), length)

        encObj = &object.Encrypted{
            EncType: object.BOOLEAN_OBJ,
            Value:   bite,
        }

    default:
        err = errors.New("wrong obj type")
    }

    return encObj, err
}

This function is doing XOR over the values of the object and returns them as object.Encrypted which is then being used in the vm.stack. Here, we notice that this function encrypts object.Object. Since there is an EncryptObject function, there might be a DecryptObject too. We find that in the same mutil/util.go file right below EncryptObject function

func DecryptObject(obj object.Object, length int) (object.Object, error) {
    decObj := obj
    var err error

    if decObj.Type() == object.ENCRYPTED_OBJ {
        biteVal := decObj.(*object.Encrypted).Value
        bite := make([]byte, len(biteVal))
        copy(bite, biteVal)
        bite = security.XOR(bite, length)

        switch decObj.(*object.Encrypted).EncType {
        case object.INTEGER_OBJ:
            val := binary.LittleEndian.Uint64(bite)
            decObj = &object.Integer{Value: int64(val)}

        case object.STRING_OBJ:
            decObj = &object.String{Value: string(bite)}

        case object.BOOLEAN_OBJ:
            str := strings.ToLower(string(bite))
            if str == "true" {
                decObj = global.True
            } else {
                decObj = global.False
            }
        }

        return decObj, nil
    }

    err = errors.New("wrong obj type")
    return obj, err
}

Here, we see that it is taking object.Encrypted and performs the reverse of XOR and returns the exact object. Reading all these we learned two things. Let's use this in our deobfuscate-mutant.go:

package main

import (
    "io/ioutil"
    "mutant/runner"
    "os"
    "fmt"
    "mutant/mutil"
)

func main() {
    signedCode, _ := ioutil.ReadFile(os.Args[1])
    byteCode, _ := runner.Decode(signedCode)
    deobfuscatedObj, _ := mutil.DecryptObject(byteCode.Constants[0], len(byteCode.Instructions))
    fmt.Println(deobfuscatedObj.Inspect())
}

and running it:

$ go run deobfuscate-mutant.go hello.mu
Hello, World!

We got the data! But we are only reading the first constant. Let's try to decrypt all constants.

package main

import (
    "io/ioutil"
    "mutant/mutil"
    "mutant/runner"
    "os"
    "fmt"
)

func main() {
    signedCode, _ := ioutil.ReadFile(os.Args[1])
    byteCode, _ := runner.Decode(signedCode)

    for i := 0; i < len(byteCode.Constants); i++ {
        obfuscatedObj := byteCode.Constants[i]
        deobfuscatedObj, _ := mutil.DecryptObject(obfuscatedObj, len(byteCode.Instructions))
        fmt.Println(deobfuscatedObj.Inspect());
    }
}

Let's try running it on our death.mu which contains the challenge flag

$ go run deobfuscate-mutant.go death.mu
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⠶⠟⠛⠛⠛⠶⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢠⡾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠉⢷⡀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢠⣿⠁⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⣾⣷⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣾⠟⢉⣀⣀⡈⠃⠀⠀⠒⣉⣀⡀⠈⢻⡄⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⡏⠀⣴⣶⣿⣿⣷⠂⠀⣾⣿⣿⣿⣆⢠⡇⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢸⣿⠀⠻⠿⢿⡿⠃⣰⣆⠙⣿⡿⠿⠋⠸⣧⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣿⠁⠀⠀⠀⠈⠀⠠⣿⠿⠀⠀⣀⣀⣀⠀⣿⣦⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣼⣿⣶⣾⣿⣿⡟⢀⠀⠀⠀⢀⢀⢻⣿⣿⣿⣿⢻⡇⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣇⢸⡇⠻⢿⣿⠇⡜⢸⠀⡇⢸⠘⣼⣿⠿⠉⠙⣿⡇⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣿⣾⣿⣦⠀⣿⣷⣷⣾⣤⣷⣾⣿⣿⢋⣴⣶⣶⣿⡀⠀⠀⠀⠀⠀
⠀⠀⠀⣠⠞⠙⠻⣿⣿⣷⣿⣿⣿⠿⠿⠻⠟⠋⠀⣼⣿⣿⡿⣻⣿⣦⡀⠀⠀⠀
⠀⢀⡼⢿⡦⣠⣴⢿⣿⣿⣿⣏⣿⣤⠀⠀⢰⡔⣶⣾⣿⠏⠀⠀⠀⣿⣿⣄⠀⠀
⠀⡾⢡⣏⢰⣯⠃⣼⣿⡿⢿⡟⢿⡋⠀⠀⢸⣽⣿⣿⡿⣇⠀⠀⠀⢈⡿⡿⣆⠀
⢸⡿⠿⠏⢰⠇⢸⡿⠋⠀⠀⣿⡟⠀⠀⠀⠈⡟⠀⠉⠳⣿⣿⠆⠀⢿⣙⡇⣿⡄
⣿⠀⠀⠀⢸⢰⣿⠁⠀⠀⠀⢸⣧⣤⠀⠀⡼⡇⠀⠀⠀⢹⣾⠀⠀⠈⢻⡇⢹⡇
⣿⣿⣷⠀⢸⣸⣿⠀⠀⠀⠀⠀⢷⣿⠀⠀⠳⡇⠀⠀⠀⢸⡟⠀⠀⠀⡸⠀⢼⡇
⢿⣟⠋⠀⢸⡿⣿⠀⠀⠀⠀⠀⠘⣿⢲⣦⠀⢹⡀⠀⠀⡼⠀⣤⣤⣴⠃⢠⣾⠇
⠸⡏⣿⠆⠘⢷⣼⣷⣄⠀⠀⠀⠀⠹⣿⡇⠀⠘⢵⣤⡾⢁⡤⣡⠞⠁⠀⣸⠟⠀
⠀⠹⣧⠀⢀⣀⠀⠸⣯⣽⣷⣦⣄⡀⢻⣷⣦⣄⣤⠙⣷⡼⠞⠁⣀⢄⣾⠏⠀⠀
⠀⠀⠈⠻⣟⠙⢧⣀⣀⠀⠘⢳⣾⣿⣿⣿⣿⣮⡻⣤⡌⠛⢶⣵⣵⡿⠁⠀⠀⠀
⠀⠀⠀⠀⠈⠳⢶⣤⣿⣦⠖⡉⠕⠊⢉⣿⣿⣿⣷⣾⣧⣖⣦⠙⢿⣄⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣸⠟⠠⠈⠀⢀⣰⣿⣿⣿⣿⣿⣟⢿⣿⣿⣠⡴⢮⢳⣄⠀⠀
⠀⠀⠀⠀⠀⠀⣼⡫⠂⠀⠀⠀⣶⡿⣿⣿⣿⠁⠘⢿⣆⠙⣿⣿⣅⢺⡇⠛⢷⡄
⠀⠀⠀⠀⠀⢰⣿⠁⠀⠀⠀⣼⠏⠀⠈⢿⣿⠀⠀⢀⣿⠀⢸⣿⢿⣿⣷⢺⡆⣿
⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⢰⣿⠀⠀⠀⠈⣏⢻⡇⢷⣾⡇⢸⣿⠃⠘⢿⣼⣧⣿
⠀⠀⠀⠀⠀⢸⣇⠀⠀⠀⢉⢿⣆⠀⠀⠀⣿⡟⠀⠀⢹⣷⣿⡏⠀⠀⢽⣿⣿⠏
⠀⠀⠀⠀⠀⠀⢻⡆⠀⠀⠀⠸⢻⢿⣶⣶⣿⢻⡆⢀⣼⣿⠏⠀⠀⣠⣹⣿⠋⠀
⠀⠀⠀⠀⠀⠀⠀⠻⣷⣀⣀⠀⠈⠈⠘⣿⡇⡿⠃⣸⢸⣿⢀⣠⣦⡿⠛⠁⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠳⠶⣤⣴⣾⣿⣠⡇⠐⣇⣿⣿⠿⠛⠉⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⣿⠁⠀⠀⣹⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣧⡀⠀⣀⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⢧⡟⠁⣾⢻⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠞⠃⢠⣆⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⠃⠀⠀⠀⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⡄⠀⡀⣸⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡏⣼⠋⣸⢹⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣷⠿⠀⢫⣾⠁⠀⠀⠀⡠⠚⢉⣉⠓⣦⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⢰⡟⠀⠀⢀⣼⢱⣿⣾⣿⣷⣼⡄⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣆⠀⢠⣾⠇⠀⣼⡥⢃⣾⣿⣿⣿⡟⠈⠻⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡇⡿⠂⢸⣸⠀⢰⣏⠔⠛⠛⢻⣿⣿⣧⢠⡄⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣷⡇⠀⠘⢿⡆⠸⣇⠀⠀⠀⠀⠈⠉⠉⣩⠇⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣷⣦⡄⠸⣷⡀⢹⣷⠄⠀⠀⢠⣤⠾⠃⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡍⠳⠤⠾⠿⠛⠁⠀⠀⣨⡿⠁⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⣄⠀⠀⠀⠀⢀⠀⢤⡾⠁⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠓⠦⣴⣴⣶⠶⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀
sdlpfjui1wesrj3qkew4rj213k4j8(IASDH*(ADSY^(*AHSDOIJKJDFRKLW#M%RKLW#$J%)I#UIFSDJFKLSDHFOIJYU#)I$%I@#_O$KDFJHIOSDYFIO#JR%$KLJWMDSFKOSDF(I)CVXC&*V\)\(*&ERW#$(%)_@#*%()UJDFDSFJSDOPIFJ
ASV{0bfu5c4710n_15_n07_3ncryp710n}
We understand the significance of this tool in fulfilling our noble cause,
but only those with the right credentials may gain entry.

Should you require further assistance or have any concerns, get familiar with mutant's compiler
Together, we shall uphold the integrity of our mission and the safety of our fellow Death Eaters.
May the darkness guide us towards victory,

The Dark Lord's Loyal Servants
Compiled Function[0xc0000a1e60]
Enter the password: 
string

We got the flag ASV{0bfu5c4710n_15_n07_3ncryp710n}.

I hope you enjoyed it. It was a long read nearly 4200+ words including code. If you have read this far, congratulations.