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.