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

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

    • Y Combinator
      Reddit
      Mastodon
    AppSec Village DEF CON 31 CTF^2 (developer) winning entry. Bypassed the encryption and mutation techniques of the Mutant Language.

    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.

    References