# Flare-on 11 # Challenge 1 Given an exe and src python code of that exe. Read the src, we see the flag is generated by function GenerateFlagText, which decrypt encrypted flag with simple xor ![image](https://hackmd.io/_uploads/Byl4Hgv-1l.png) They key decrypt is x + y * 20 where x and y are the params passed into this function Follow where this function called, we conclude that x, y will be the 10 for both ![image](https://hackmd.io/_uploads/rJAsBgPWJe.png) ![image](https://hackmd.io/_uploads/rJhTSxPWyl.png) Flag: welcom_to_11@flare-on.com # Challenge2 We're given an executed coded in Go, and lucky that it's not stripped at all. For first part, it requires user to do some math for a random number times (atmost will be 8) ![image](https://hackmd.io/_uploads/S1YQdlvW1e.png) ![image](https://hackmd.io/_uploads/rJKY_evW1l.png) ![image](https://hackmd.io/_uploads/ryg6AgPZ1x.png) After finish this first part, a checksum is required. This checksum then decoded hex. If input checksum is not a valid checksum (not in hex string format), it prints out "Not a valid checksum...". ![image](https://hackmd.io/_uploads/SyWhEZPWJl.png) Then the decode input will be checked length, if its length is 32, then it passed as key for chacha20poly1305 decrypt, else, it prints out "Maybe it's time to analyze the binary! ;)" ![image](https://hackmd.io/_uploads/BJ7OvrwZ1e.png) ![image](https://hackmd.io/_uploads/SytrPHw-Je.png) If key is wrong, it also prints out same message as above. Take a deeper look into binary, the flow of code is kinda weird, cause it pass input checksum as decrypt key but not yet check it, and the check appear after that call the chacha_open(), maybe it's intense of author. In first, it convert the hexbyte input back to hex string ![image](https://hackmd.io/_uploads/SkcGKHvW1x.png) Then it's passed into main_a, in this function, it xor input with key "FlareOn2024" then encode base64 the output, latter compare with a hardcode base64 string ![image](https://hackmd.io/_uploads/H16UcBP-Je.png) [Decrypt](https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)XOR(%7B'option':'UTF8','string':'FlareOn2024'%7D,'Standard',false)&input=Y1FvRlJRRXJYMVlBVncxelZRZEZVU3hmQVFOUkJYVU5BeEJTZTE1UUNWUlZKMXBRRXdkL1dGQlVBbEVsQ0ZCRlVubGFCMVVMQnlSZEJFRmRmVnRXVkE9PQ) it, we get the checksum: 7fd7dd1d0e959f74c133c13abb740b9faa61ab06bd0ecd177645e93b1e3825dd Decrypt flag then stored in UserCacheDir in form of JPG image. ![image](https://hackmd.io/_uploads/rJVm3BPZyx.png) ![image](https://hackmd.io/_uploads/HkuvhrvWJx.png) Flag: Th3_M4tH_Do_b3_mAthng@flare-on.com # Challenge 3: Given a yara file, we have to find a file that match that yara rule. Take a look into the yara rule, there are bunch of rules, but just some of them are required to get the flag. ![image](https://hackmd.io/_uploads/HywW48w-kx.png) After for a while, i found that only conditions where equal condition appears and the operation can be convert back like (add, sub, mul, xor) that actual help us find the flag. Wickly remove all reduntdant condition, all the left is just kind easy to find. ```python= uint8(58) + 25 == 122 uint32(52) ^ 425706662 == 1495724241 uint32(17) - 323157430 == 1412131772 hash.crc32(8, 2) == 0x61089c5c hash.crc32(34, 2) == 0x5888fc1b uint8(36) + 4 == 72 uint8(27) ^ 21 == 40 uint32(59) ^ 512952669 == 1908304943 uint8(65) - 29 == 70 uint8(45) ^ 9 == 104 uint32(28) - 419186860 == 959764852 uint8(74) + 11 == 116 hash.crc32(63, 2) == 0x66715919 hash.sha256(14, 2) == "403d5f23d149670348b147a15eeb7010914701a7e99aad2e43f90cfa0325c76f" hash.sha256(56, 2) == "593f2d04aab251f60c9e4b8bbc1e05a34e920980ec08351a18459b2bc7dbf2f6" uint8(75) - 30 == 86 uint32(66) ^ 310886682 == 849718389 uint32(10) + 383041523 == 2448764514 uint32(37) + 367943707 == 1228527996 uint32(22) ^ 372102464 == 1879700858 uint8(2) + 11 == 119 hash.md5(0, 2) == "89484b14b36a8d5329426a3d944d2983" uint32(46) - 412326611 == 1503714457 hash.crc32(78, 2) == 0x7cab8d64 uint8(7) - 15 == 82 uint32(70) + 349203301 == 2034162376 hash.md5(76, 2) == "f98ed07a4d5f50f7de1410d905f1477f" uint32(80) - 473886976 == 69677856 uint32(3) ^ 298697263 == 2108416586 uint8(21) - 21 == 94 uint8(16) ^ 7 == 115 uint32(41) + 404880684 == 1699114335 hash.md5(50, 2) == "657dae0913ee12be6fb2a6f687aae1c7" uint8(26) - 7 == 25 hash.md5(32, 2) == "738a656e8e8ec272ca17cd51e12f558b" uint8(84) + 3 == 128 ``` For hash check, because it's just two character for each check, so it can be easy crack by bruteforce The left it just recover back to from add/sub/xor Flag: 1RuleADayK33p$Malw4r3Aw4y@flare-on.com # Challenge 4 Given a html file, open it in browser, it's exactly "mememaker" ![image](https://hackmd.io/_uploads/Bk_Gc8wZJx.png) Take a look into logic javascript code, it's so long and fully obfuscated. ![image](https://hackmd.io/_uploads/rJPPqLPZ1x.png) Deobfuscate this code can be done by many tool, for me, i use [this](https://deobfuscate.relative.im/) The deobfuscated code is pretty simple, in that, a0k function is likely have the flag. ```cpp= function a0k() { const a = a0g.alt.split('/').pop() if (a !== Object.keys(a0e)[5]) { return } const b = a0l.textContent, c = a0m.textContent, d = a0n.textContent if ( a0c.indexOf(b) == 14 && a0c.indexOf(c) == a0c.length - 1 && a0c.indexOf(d) == 22 ) { var e = new Date().getTime() while (new Date().getTime() < e + 3000) {} var f = d[3] + 'h' + a[10] + b[2] + a[3] + c[5] + c[c.length - 1] + '5' + a[3] + '4' + a[3] + c[2] + c[4] + c[3] + '3' + d[2] + a[3] + 'j4' + a0c[1][2] + d[4] + '5' + c[2] + d[5] + '1' + c[11] + '7' + a0c[21][1] + b.replace(' ', '-') + a[11] + a0c[4].substring(12, 15) f = f.toLowerCase() alert(atob('Q29uZ3JhdHVsYXRpb25zISBIZXJlIHlvdSBnbzog') + f) } } ``` The decode base64 in alert ("Congratulations! Here you go: ") suggest that f is the flag we have to find. f is construct from a, b, c, d, a0c variable where: + a0c: hardcode array of string + a: a0e[5] ==> 'boy_friend0.jpg' + b: a0c[14] ==> 'FLARE On' + c: a0c[len(a0c) - 1] ==> 'Security Expert' + d: a0c[22] ==> 'Malware' ==> f: wh0A_it5_4_cru3l_j4va5cr1p7@FLARE-On.com flag is in lower form: wh0a_it5_4_cru3l_j4va5cr1p7@flare-on.com Flag: wh0a_it5_4_cru3l_j4va5cr1p7@flare-on.com We can also change the js code that always match the condition, so that the brower show the flag for us ![image](https://hackmd.io/_uploads/rJ8j7Bdbyx.png) # Challenge 5 ![image](https://hackmd.io/_uploads/rkyr4Su-Jl.png) Given us a copy of a system, with a hint is that server crashed, and it may be related to sshd. As it hints that server is crashed, searching for the coredump file, we found that it's exactly sshd coredump. ![image](https://hackmd.io/_uploads/B1QruBdW1x.png) Using gdb, we can find where the system has crashed. To make gdb regcognize all shared lib that crashed program load, we need to let gdb know the right libraty folder, not on your own system but the /usr/lib and /usr/lib64 of the given one. ``` set solib-search-path /path/usr/lib:/path/usr/lib64 ``` using two commands "info shared libarary" and "info proc mappings" we can find where librarys loaded on mem. Typically, a lib appears as deleted, but combines result of two commands, we can conlude that it's liblzma.so ![image](https://hackmd.io/_uploads/ByYYy8jWke.png) ![image](https://hackmd.io/_uploads/rk59kUobyx.png) Using bt command, we can find return address, from that, we can identify where it crashed ![image](https://hackmd.io/_uploads/SyrWJ8ob1e.png) The return address is 0x0007f4a18c8f88f which is in range of liblzma.so.5 sshd and liblzma, which lead us into the famous [CVE-2024-3094](https://securelist.com/xz-backdoor-part-3-hooking-ssh/113007/) According to the blog, it hooks the RSA_public_decrypt function. Take a look into binary liblzma.so.5, we can easy find where the backdoor located ![image](https://hackmd.io/_uploads/Sk8WjuuZ1l.png) To find key and nonce, the code reveal that it start with '\x48\x7A\x40\xC5', search the sequence bytes in coredump, we can quicky find key and nonce of that ![image](https://hackmd.io/_uploads/HJwih_O-Jl.png) key: 94 3d f6 38 a8 18 13 e2 de 63 18 a5 7 f9 a0 ba 2d bb 8a 7b a6 36 66 d0 8d 11 a6 5e c9 14 d6 6f nonce: f2 36 83 9f 4d cd 71 1a 52 86 29 55 Decrypt shellcode, we get beautiful code that can F5 easy :)) ![image](https://hackmd.io/_uploads/HyJrRcOZ1g.png) The logic kinda straight forward, connect socket, receive key, nonce for "salcha20", filename to read, read file, then encrypt "salcha20", send back to server. All the info may be still on stack, so to find the info, we have to find the stackframe of this backdoor function. Start of shellcode ![image](https://hackmd.io/_uploads/SyZD2ouZkl.png) The frame contain info is inside the main_backdoor ![image](https://hackmd.io/_uploads/ByfTnjdWJl.png) RBP of main_backdoor = RBP sub_0 - (5(push) + 1(call)) * 8 RBP of sub_0 = (RSP before call backdoor) - (1(push) + 1(call)) * 8 For now, to find key, nonce, and encrypted data is not easy as before, cause no hint or signature to find. We need to lean on the current debug status, find exactly where server crashed and trace back. ![image](https://hackmd.io/_uploads/BJgz9s_Zye.png) RIP = 0, which lead to crash, it maybe due to a call/jmp to 0, from return address find before, we can find RVA of this address, which is 0x988F (0x0007f4a18c8f88f - 0x7f4a18c86000). Follow the return RVA, the call above is call RAX, and RAX in context is exactly 0. ![image](https://hackmd.io/_uploads/rJ_zii_b1e.png) Read the assembly code, we can see that, RSP value we want to find will be plus 8 compare to the current RSP, due to call instruction. from all above info, RBP of main_backdoor = current_rsp + 8 - 8 * 8 = 0x7ffcc6601e98 - 0x38 = 0x7ffcc6601e60 ==> key ![image](https://hackmd.io/_uploads/ryV072OZ1l.png) ==> nonce: ![image](https://hackmd.io/_uploads/Sy8MN2_-1l.png) ==> file_name: ![image](https://hackmd.io/_uploads/Hy9uVndZye.png) ==> encrypted data ![image](https://hackmd.io/_uploads/HJZ6E3O-Jx.png) For encrypted data, i take until it meets the null byte (actual only 0x40 bytes from start). Try decrypt using cyberchef, but it doesn't work :) After for a while, i found that salcha20 is customized a little bit, not "expand 32-byte k" as normal, but "expand 32-byte K" :) To decrypt, me myself chose to write a program that run that shellcode, with key, nonce, and enc as above. Flag: supp1y_cha1n_sund4y@flare-on.com # Challenge 9 Given a x64 executable. Run it, it's absolute Flag checker ![image](https://hackmd.io/_uploads/SJGRj5FZJl.png) At main function ![image](https://hackmd.io/_uploads/H1VV25F-Jg.png) First, it registers an ExceptionFilter but the handler is nothing but an simple error message and exit ![image](https://hackmd.io/_uploads/BJwxactZ1l.png) Key is copied into an hardcode address, then pass into a shellcode at lpAddress is called. Find reference to lpAddress, it is used in a TLS_Callback ![image](https://hackmd.io/_uploads/HyHFT5KbJg.png) VirtualAlloc a memory range 0x800000 bytes with RXW permission, then copy the same byte from 0x140097AF0 into that address. Jump to where the shellcode locate, it's kinda weird. First instruction is "hlt", which is an previlege instruction, can only run in kernel mode. If run in userspace, it will generate an EXCEPTION_PRIV_INSTRUCTION ![image](https://hackmd.io/_uploads/SyBRkotW1l.png) As analyze before, the handler at main function just print out error message and exit, so it have to another mechanism to handle exception and it may enabled even before main function is called. IDA support to find EntryPoint, after the TLS_Callback, the main entrypoint will be called ![image](https://hackmd.io/_uploads/r1mUbitbJg.png) At start, it jump to scrt_common_main_seh, and inside this function, we find what we want. Before main is called, an array of function from First to Last is called ![image](https://hackmd.io/_uploads/S1yfzsFbkx.png) ![image](https://hackmd.io/_uploads/BJCzfjK-yl.png) + sub_140001090: Get ntdll handle + sub_140002000: Find RtlInstallFunctionTableCallback address + sub_140001030: Call RtlInstallFunctionTableCallback As [MSDN ](https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlinstallfunctiontablecallback), the API is used to add a dynamic function table to the dynamic function table list. Why is it important here ? The [x64 exception handle](https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-170) mechanism in MSDN and excellent [article](https://codemachine.com/articles/x64_deep_dive.html#exception_handling) on x64 say it all ![image](https://hackmd.io/_uploads/S1Pt5jYZ1l.png) So when exception occurs, the PGET_RUNTIME_FUNCTION_CALLBACK Callback will be called, it generates a runtime function, which used for handle exception. The struct of RUNTIME FUNCTION is defined as below: ![image](https://hackmd.io/_uploads/rJ3ypitZke.png) Let's jump into the callback, we find the logic to generate RUNTIME FUNCTION ![image](https://hackmd.io/_uploads/SkZOTiK-Jg.png) ```python= FunctionStart = exception_ocurr offset FunctionEnd = FunctionStart + 1 UnwindInfo = FunctionEnd + idc.get_wide_byte(base + FunctionEnd) + 1 UnwindInfo += (UnwindInfo & 1) ``` The UnwindInfo hold the infomations that need to handle the exception ![image](https://hackmd.io/_uploads/SJPwm3Y-Jx.png) At first, with naive thinking, i write a simple script that find the handler and jump immediately from where exception occurs into handler. That give me the flow of that code but still a lot of stubs doesn't make sense, ie: before exception, R8 hold the address of input key, but in the handle, the value of R8 in context no longer hold that value, .. After for while, reading the the MSDN again, i found that the unwind codes array is the reason i lost the track. It's kinda similar as VM obfuscate, each unwind code is contain info with normal intense to clean the stack, but in this case, it does some "magic" work. Base on the [ReactOS src](https://doxygen.reactos.org/d8/d2f/unwind_8c_source.html), i write some script that simulate that flow of unwind code (still some bug in this code, but it help me figure out the lost track). ```python= def handle(base, exception_offset): start_offset = exception_offset end_offset = start_offset + 1 unwind_offset = end_offset + get_wide_byte(base + end_offset) + 1 unwind_offset += unwind_offset & 1 unwind_info = base + unwind_offset #print('UnwindInfo: ' + hex(unwind_info)) flags = (get_wide_byte(unwind_info) & 0xf8) >> 3 #print('FLAG: ' + hex(flags)) sizeofprolog = get_wide_byte(unwind_info + 1) #print('Size of prolog: ' + hex(sizeofprolog)) countofcode = get_wide_byte(unwind_info + 2) #print('COUNT OF CODE: ' + hex(countofcode)) frame = get_wide_byte(unwind_info + 3) fram_reg = frame & 0xf #print('FRAME REG: ' + hex(fram_reg)) framoffset = (frame & 0xf0) >> 4 #print('FRAME_OFFSET: ' + hex(framoffset)) unwindcode = unwind_info + 4 i = 0 while i < countofcode: k = 0 #print('Uwincode address: ' + (hex(unwindcode))) code_offset = get_wide_byte(unwindcode) code = get_wide_byte(unwindcode + 1) opcode = (code & 0xf) #print('OPCODE: ' + hex(opcode) + ': ', end='') opinfo = (code & 0xf0) >> 4 if opcode == UWOP_PUSH_NONVOL: insn = 'pop ' + regs[opinfo] #print(insn) exception_offset += patch_asm(base + exception_offset, insn) k = 1 elif opcode == UWOP_ALLOC_LARGE: if opinfo != 0: insn = 'add rsp, ' + hex(get_wide_dword(unwindcode + 2)) #print(insn) exception_offset += patch_asm(base + exception_offset, insn) k = 3 else: insn = 'add rsp, ' + hex(get_wide_word(unwindcode + 2) * 8) #print(insn) exception_offset += patch_asm(base + exception_offset, insn) k = 2 elif opcode == UWOP_ALLOC_SMALL: insn = 'add rsp, ' + hex(8 * (opinfo + 1)) #print(insn) exception_offset += patch_asm(base + exception_offset, insn) k = 1 elif opcode == UWOP_SET_FPREG: reg = regs[fram_reg] delta = framoffset * 16 if delta: insn = 'mov rsp, ' + reg + ' - ' + hex(delta) +']' else: insn = 'mov rsp, ' + reg #print(insn) exception_offset += patch_asm(base + exception_offset, insn) k = 1 elif opcode == UWOP_SAVE_NONVOL: reg = regs[opinfo] offset = get_wide_word(unwindcode + 2) insn = 'mov ' + reg + ', [rsp + ' + hex(offset) +']' #print(insn) exception_offset += patch_asm(base + exception_offset, insn) k = 2 elif opcode == UWOP_SAVE_NONVOL_FAR: reg = regs[opinfo] offset = get_wide_dword(unwindcode + 2) insn = 'mov ' + reg + ', [rsp + ' + hex(offset) +']' #print(insn) exception_offset += patch_asm(base + exception_offset, insn) k = 3 elif opcode == UWOP_EPILOG: k = 1 elif opcode == UWOP_SPARE_CODE: k = 2 elif opcode == UWOP_PUSH_MACHFRAME: insn = 'add rsp, ' + hex(opinfo * 8) #print(insn) exception_offset += patch_asm(base + exception_offset, insn) insn = 'mov rip, [rsp]' #print(insn) insn = 'mov rsp, [rsp + 0x18]' exception_offset += patch_asm(base + exception_offset, insn) #print(insn) k = 1 i += k unwindcode += k * 2 countofcode *= 2 countofcode += countofcode % 4 handler = base + get_wide_dword(unwind_info + 4 + countofcode) # delta = handler - base - exception_offset - 5 # patch_byte(base + exception_offset, 0xe9) # patch_dword(base + exception_offset + 1, delta) # create_insn(base + exception_offset) set_cmt(base + start_offset, hex(unwind_info) + ', ' + hex(handler), 0) return handler ``` Beside that obfuscation x64 exception mechanism, the code at Exception Handler is also obfuscated ![image](https://hackmd.io/_uploads/ryW4lTYb1l.png) The inside the call always has the same logic as below ![image](https://hackmd.io/_uploads/rk8LZ6tZ1e.png) First, it pop the return address into hardcode address, then it decrypt the real instruction by moving the opcode of real instruction and the then return address is calculated. So each instruction is actual just do one instruction at a time, which is the decrypted code. For deobfuscate the call obfuscate, i use this silly code ```python= def patch_call(call, start_call, ret): ea = start_call create_insn(ea) # pop instruction poped_addr = get_operand_value(ea, 0) patch_qword(poped_addr, ret) ea += 0xe # point to mov insn_len = create_insn(ea) ah = get_wide_byte(get_operand_value(ea, 1)) << 8 ea += insn_len # point to lea insn_len = create_insn(ea) eax = ah + get_operand_value(ea, 1) ea += insn_len # point to mov addr_patch = get_operand_value(ea, 0) patch_dword(addr_patch, eax) ea = addr_patch real_insn = create_insn(ea) if print_insn_mnem(ea) == 'jmp': jmp = get_operand_value(ea, 0) delta = jmp - call - 5 patch_byte(call, 0xe9) patch_dword(call + 1, delta) return jmp #in case it not a jmp to htl for i in range(real_insn): patch_byte(call + i, get_wide_byte(ea + i)) create_insn(call) ea = poped_addr + 8 create_insn(ea) delta = get_operand_value(ea, 1) # get the real return value return ret + delta ``` Dump the deobfuscated shellcode to a file, investigate on that code, we can found some key concept below: + There' re 32 checks, everytime check fail, it jump into function sub_1400011F0 which print out "Wrong key" message and terminate program. ![image](https://hackmd.io/_uploads/SJc0qk5-yx.png) + For each check, it is a equation of operation include plus, xor, mul where input key is manage to join in mul operation, each equation take random 8 characters from input key, each character mul with a hardcode number, then xor/add with another hardcode number + The hardcode value is not show up clearly in the code but hided by some simple maths (push a number on stack, add/sub a number, the result is the actual value, ...) which can be quickly remove by find the pattern replace with coressponse value of that value. ![image](https://hackmd.io/_uploads/ByXw-g9WJe.png) + Almost value is manual construct byte by byte (except the value used to mul with input key character), each byte of the value appear in form of array, corresponse to two type of operations xor and add. the final value can be managed to collect with help of idapython script. But compare to actual value we find when debug, some of them are slicely different. At this point, we decided to debug and log the results of every operation, then convert each result back to the 'actual value' used in the operations. After debugging the first check, we can reimplement it in Python for the first case like this ```python= def c1(): result = data[0x4] * 0xef7a8c result = result + 0x9d865d8d result = result - (data[0x18] * 0x45b53c) result = result + 0x18baee57 result = result - (data[0x0] * 0xe4cf8b) result = result + 0x6ec04422 result = result - (data[0x8] * 0xf5c990) result = result + 0x6bfaa656 result = result ^ (data[0x14] * 0x733178) result = result ^ 0x61e3db3b result = result ^ (data[0x10] * 0x9a17b8) result = result + 0x35d7fb4f result = result ^ (data[0xc] * 0x773850) result = result ^ 0x5a6f68be result = result ^ (data[0x1c] * 0xe21d3d) result = result ^ 0x5c911c23 result = result + 0x7e9b8687 result &= 0xffffffffffffffff return result ``` We still have 31 functions like this left, and while debugging each one is possible, it would be extremely time-consuming. I decided to automate the process using IDAPython. My plan is to dump the values of each operation and then back-calculate them to find the hardcoded numbers. I patched the input to `\x00 * 32` to make the calculation easier. With my deobfuscated shellcode dump file, it's easy to locate the offset of any instruction. First, I found that there are only 32 test instructions, each one checking the final value in each function ![image](https://hackmd.io/_uploads/ByRqoxhW1e.png) I’ll set breakpoints at each of these 32 `test` instructions. ![image](https://hackmd.io/_uploads/Sk9Apx2ZJe.png) Each of the 32 checks will trigger a conditional jump to a Print "Wrong" function if the check fails. To automate the debugging process, you’ll need to ensure that the instruction pointer (RIP) is automatically adjusted after each failed check. To handle this, I’ll also set 32 additional breakpoints on each `cmovnz` instruction. Every time a breakpoint on a `cmovnz` instruction is hit, it will automatically adjust RIP to point to the correct jmp instruction to continue debugging smoothly. Below is my script to dump the values: ```python= test_array =[0x179fd,0x2f386,0x4751a,0x5d2cd,0x7230b,0x8917b,0xa0de8,0xb7d00,0xd0742,0xe7b7b,0xff3a3,0x1164ea,0x12ce52,0x14492b,0x15ec1e,0x176fbd,0x190732,0x1a5a58,0x1bc75d,0x1d572b,0x1ecdf1,0x205671,0x21b636,0x22f442,0x243e47,0x25a19e,0x26ec62,0x285d0b,0x29e558,0x2b5f19,0x2cd429,0x2e4b8f] cmove_array = [0x17a07, 0x2f390, 0x47524, 0x5d2d7, 0x72315, 0x89185, 0xa0df2, 0xb7d0a, 0xd074c, 0xe7b85, 0xff3ad, 0x1164f4, 0x12ce5c, 0x144935, 0x15ec28, 0x176fc7, 0x19073c, 0x1a5a62, 0x1bc767, 0x1d5735, 0x1ecdfb, 0x20567b, 0x21b640, 0x22f44c, 0x243e51, 0x25a1a8, 0x26ec6c, 0x285d15, 0x29e562, 0x2b5f23, 0x2cd433, 0x2e4b99] base = get_qword(0x14089B8E0) for i in range(len(test_array)): idaapi.create_insn(base+test_array[i]) add_bpt(base+test_array[i],0,BPT_DEFAULT); for i in range(len(cmove_array)): idaapi.create_insn(base + cmove_array[i]) add_bpt(base + cmove_array[i], 0, BPT_DEFAULT) for i in range(len(test_array)+len(cmove_array)): ida_dbg.continue_process() idaapi.wait_for_next_event(WFNE_SUSP, -1) if(idc.print_insn_mnem(get_reg_value("rip"))=="cmovnz"): set_reg_value(get_reg_value("rip")+idaapi.create_insn(get_reg_value("rip"))+idaapi.create_insn(get_reg_value("rip")+idaapi.create_insn(get_reg_value("rip"))),"rip") else: offset = get_reg_value("rip")-base value_final = get_reg_value(print_operand(get_reg_value("rip"),0)) print(hex(value_final),end=",") f.close() ``` We will got 32 final value in mỗi hàm với input is `\x00 * 32` : ``` 0x5be3e290,0x62a2a0fb,0x3ade6641,0x18d62e9b4,0xffffffffd01904a1,0xffffffffbbe5233e,0x8478c40,0xffffffffb1b9939b,0xfffffffff31da2f5,0x8c8bc76,0xffffffffd45091a6,0x1a35812a,0xffffffffd8bc839e,0xffffffffe724ad90,0x1a1d901a,0xffffffff81514d31,0xffffffff530d9146,0x5db36e01,0x6c511b62,0xffffffff4f1727a1,0x213022fe,0xfffffffff4d5f043,0xffffffff92a2ef25,0xfffffffedf1a2ab0,0xffffffff750e3b65,0x448addb5,0xfffffffffe691b35,0xffffffffed2a9d03,0x224e42c5,0xfffffffda375005b,0xfffffffe71ef098c,0xffffffffbcc44d66 ``` Similarly, I set a breakpoint on the `mul` instruction to dump the factor values in `rsp` ![image](https://hackmd.io/_uploads/BkyTMb2Zyx.png) After the first `mul`, the value is pushed to the stack. Starting from the second `mul`, it will use the result of the previous calculation to perform an `xor`, `add`, or `sub` with the newly multiplied result. It's easy to calculate the offsets of these instructions from the mul instruction's address (as they appear just a few instructions after mul) using my deobfuscated shellcode dump file. The output for the first three check functions will look like this. ![image](https://hackmd.io/_uploads/BJ9n4bnWye.png) Now, we have dumped the sign and factors of each multiplication operation. Next, I set a breakpoint on the `ldmxcsr` instruction to dump the hardcoded value used for calculations between the multiplication operations (`mul`). ![image](https://hackmd.io/_uploads/HkCvUbhZkx.png) My dump: ![image](https://hackmd.io/_uploads/SkpqFZhbJg.png) The final piece of data we need is the sign of the operations between the multiplication steps. Through debugging, I found a pattern: if the operation is an `xor`, there is an array containing the xor values, indexed accordingly: ![image](https://hackmd.io/_uploads/rJ8d3-h-1g.png) For example, if you want to XOR `0x5` with `0x32`, there is an array pre-calculated with the XOR results. By taking the address of the value `0x32` and adding 5, you get the result of `0x32 ^ 0x5 = 0x37`. The array looks like this: ```asm= addr: value 0x00: 0x32 //0x32= 0x32 ^ 0x0 0x01: 0x33 //0x33= 0x33 ^ 0x1 0x02: 0x30 //0x30= 0x32 ^ 0x2 0x03: 0x31 0x04: 0x36 0x05: 0x37 0x06: 0x34 0x07: 0x35 0x08: 0x3a 0x09: 0x3b 0x0a: 0x38 0x0b: 0x39 0x0c: 0x3e 0x0d: 0x3f 0x0e: 0x3c 0x0f: 0x3d ... ... ... ``` From all of the above, I was able to reimplement all 32 check functions and use Z3 to find the flag ```python= from z3 import * def c1(): result = data[0x4] * 0xef7a8c result = result + 0x9d865d8d result = result - (data[0x18] * 0x45b53c) result = result + 0x18baee57 result = result - (data[0x0] * 0xe4cf8b) result = result + 0x6ec04422 result = result - (data[0x8] * 0xf5c990) result = result + 0x6bfaa656 result = result ^ (data[0x14] * 0x733178) result = result ^ 0x61e3db3b result = result ^ (data[0x10] * 0x9a17b8) result = result + 0x35d7fb4f result = result ^ (data[0xc] * 0x773850) result = result ^ 0x5a6f68be result = result ^ (data[0x1c] * 0xe21d3d) result = result ^ 0x5c911c23 result = result + 0x7e9b8687 result &= 0xffffffffffffffff return result def c2(): result = data[0x11] * 0x99aa81 result = result + 0x8b1215af result = result ^ (data[0x5] * 0x4aba22) result = result + 0x598015bf result = result ^ (data[0x15] * 0x91a68a) result = result ^ 0x6df18e52 result = result ^ (data[0x1] * 0x942fde) result = result + 0x15c825ee result = result - (data[0xd] * 0xfe2fbe) result = result + 0xd5682b64 result = result - (data[0x1d] * 0xd7e52f) result = result + 0x798bd018 result = result ^ (data[0x19] * 0xe44f6a) result = result + 0x1992adc2 result = result + (data[0x9] * 0xaf71d6) result = result + 0x921121d3 result = result + 0x1eeb7552 result &= 0xffffffffffffffff return result def c3(): result = data[0xa] * 0x48c500 result = result + 0x70255e44 result = result - (data[0x1e] * 0x152887) result = result + 0x65f04e48 result = result - (data[0xe] * 0xaa4247) result = result ^ 0x3d63ec69 result = result ^ (data[0x16] * 0x38d82d) result = result ^ 0x872eca8f result = result ^ (data[0x1a] * 0xf120ac) result = result + 0x803dbdcf result = result + (data[0x2] * 0x254def) result = result ^ 0xee380db3 result = result ^ (data[0x12] * 0x9ef3e7) result = result + 0x921556f5 result = result + (data[0x6] * 0x69c573) result = result + 0x3653a3a3 result = result + 0xc45c0f3 result &= 0xffffffffffffffff return result def c4(): result = data[0xb] * 0x67dda4 result = result + 0xf4753afc result = result + (data[0x1f] * 0x5bb860) result = result ^ 0xc1d47fc9 result = result ^ (data[0x17] * 0xab0ce5) result = result + 0x544ff977 result = result + (data[0x7] * 0x148e94) result = result + 0x634c1be7 result = result - (data[0xf] * 0x9e06ae) result = result + 0x5239df9c result = result ^ (data[0x3] * 0xfb9de1) result = result ^ 0x4e3633f7 result = result - (data[0x1b] * 0xa8a511) result = result ^ 0xa61f9208 result = result + (data[0x13] * 0xd3468d) result = result + 0x4a5d7a48 result = result + 0x109bee5e result &= 0xffffffffffffffff return result def c5(): result = data[0xc] * 0x640ba9 result = result + 0x516c7a5c result = result - (data[0x0] * 0xf1d9e5) result = result + 0x8b424d6b result = result + (data[0x1c] * 0xd3e2f8) result = result + 0x3802be78 result = result + (data[0x18] * 0xb558ce) result = result + 0xccbe7372 result = result - (data[0x8] * 0x2f03a7) result = result ^ 0xe050b170 result = result + (data[0x10] * 0xb8fa61) result = result ^ 0x1fc22df6 result = result - (data[0x14] * 0xe0c507) result = result ^ 0xd8376e57 result = result + (data[0x4] * 0x8e354e) result = result + 0x2d34cdf8 result = result + 0xff187080 result &= 0xffffffffffffffff return result def c6(): result = data[0x11] * 0xa9b448 result = result ^ 0x9f938499 result = result + (data[0x5] * 0x906550) result = result + 0x407021af result = result ^ (data[0xd] * 0xaa5ad2) result = result ^ 0x77cf83a7 result = result ^ (data[0x1d] * 0xc49349) result = result ^ 0x3067f4e7 result = result + (data[0x9] * 0x314f8e) result = result + 0xcd975f3b result = result ^ (data[0x15] * 0x81968b) result = result + 0x893d2e0b result = result - (data[0x19] * 0x5ffbac) result = result ^ 0xf3378e3a result = result - (data[0x1] * 0xf63c8e) result = result + 0xe3e276d5 result = result + 0x71a14c73 result &= 0xffffffffffffffff return result def c7(): result = data[0x16] * 0xa6edf9 result = result ^ 0x77c58017 result = result - (data[0x12] * 0xe87bf4) result = result + 0x666428c0 result = result - (data[0x2] * 0x19864d) result = result + 0xbe77b413 result = result + (data[0x6] * 0x901524) result = result ^ 0x247bf095 result = result ^ (data[0xa] * 0xc897cc) result = result ^ 0xeff7eea8 result = result ^ (data[0xe] * 0x731197) result = result + 0x67a0d262 result = result + (data[0x1e] * 0x5f591c) result = result + 0x316661f9 result = result + (data[0x1a] * 0x579d0e) result = result + 0xcbd804e4 result = result + 0x6ff28cb5 result &= 0xffffffffffffffff return result def c8(): result = data[0x17] * 0x9afaf6 result = result ^ 0xdb895413 result = result + (data[0x13] * 0x7d1a12) result = result + 0x398603bc result = result + (data[0xb] * 0x4d84b1) result = result + 0xa30387dc result = result - (data[0xf] * 0x552b78) result = result ^ 0xf54a725e result = result ^ (data[0x7] * 0xf372a1) result = result + 0xb3aefc53 result = result + (data[0x1f] * 0xb40eb5) result = result ^ 0x16fa70d2 result = result ^ (data[0x3] * 0x9e5c18) result = result + 0x38784353 result = result ^ (data[0x1b] * 0xf2513b) result = result + 0xa1fc09f0 result = result + 0xfe291bf8 result &= 0xffffffffffffffff return result def c9(): result = data[0x1c] * 0xac70b9 result = result + 0xdae0a932 result = result ^ (data[0x4] * 0xc42b6f) result = result ^ 0xbc03104c result = result - (data[0x0] * 0x867193) result = result + 0xdc48c63a result = result - (data[0xc] * 0x6d31fe) result = result ^ 0x4baeb6d0 result = result - (data[0x10] * 0xaaae58) result = result + 0x328ede08 result = result + (data[0x14] * 0x9faa7a) result = result + 0xbe0a2c9c result = result + (data[0x18] * 0x354ac6) result = result ^ 0xd8ad17f1 result = result - (data[0x8] * 0x3f2acb) result = result + 0x74948177 result = result + 0x9c3ec96d result &= 0xffffffffffffffff return result def c10(): result = data[0x1d] * 0xe9d18a result = result ^ 0xcb5557ea result = result ^ (data[0x19] * 0x8aa5b9) result = result ^ 0x9125a906 result = result - (data[0x11] * 0x241997) result = result + 0x6e46fcb8 result = result + (data[0x5] * 0xe3da0f) result = result + 0x442800ec result = result + (data[0xd] * 0xa5f9eb) result = result + 0xbde8f9af result = result + (data[0x15] * 0xd6e0fb) result = result + 0x36268dbd result = result + (data[0x1] * 0x8dc36e) result = result + 0xc54b7d21 result = result ^ (data[0x9] * 0xb072ee) result = result + 0xd5e54e3f result = result + 0x40dfbc25 result &= 0xffffffffffffffff return result def c11(): result = data[0x1e] * 0xd14f3e result = result ^ 0xa06c215b result = result - (data[0x1a] * 0xc5ecbf) result = result + 0xb197c5c0 result = result ^ (data[0x6] * 0x19ff9c) result = result ^ 0x66e7d06c result = result + (data[0x2] * 0xe3288b) result = result ^ 0x80af4325 result = result ^ (data[0xa] * 0xcfb18c) result = result + 0x1ec37c6d result = result ^ (data[0x12] * 0xd208e5) result = result + 0xf96d2b51 result = result + (data[0xe] * 0x42240f) result = result + 0x78cdd8c3 result = result - (data[0x16] * 0x1c6098) result = result + 0x2c2ba3a6 result = result + 0xf4c281a5 result &= 0xffffffffffffffff return result def c12(): result = data[0xb] * 0x3768cc result = result ^ 0x19f61419 result = result - (data[0x3] * 0x43be16) result = result + 0x566cc6a8 result = result ^ (data[0xf] * 0xb7cca5) result = result + 0x6db0599e result = result + (data[0x1b] * 0xf6419f) result = result ^ 0xbd613538 result = result ^ (data[0x13] * 0xae52fc) result = result + 0x717a44dd result = result - (data[0x17] * 0x5eeb81) result = result + 0xdd02182d result = result ^ (data[0x7] * 0xec1845) result = result ^ 0xef8e5416 result = result + (data[0x1f] * 0x61a3be) result = result ^ 0x9288d4fa result = result + 0x7e4241fb result &= 0xffffffffffffffff return result def c13(): result = data[0x10] * 0x336e91 result = result + 0xa1eb20e3 result = result - (data[0x4] * 0xd45de9) result = result + 0xc7e538e6 result = result + (data[0x8] * 0x76c8f8) result = result ^ 0xd8caa2cd result = result - (data[0x14] * 0x945339) result = result + 0x524d7efa result = result + (data[0xc] * 0x4474ec) result = result + 0x1b817d33 result = result ^ (data[0x0] * 0x51054f) result = result ^ 0x3321c9b1 result = result - (data[0x18] * 0xd7eb3b) result = result + 0x36f6829d result = result - (data[0x1c] * 0xad52e1) result = result ^ 0x6ce2191a result = result + 0xc64bcbd result &= 0xffffffffffffffff return result def c14(): result = data[0x1d] * 0x725059 result = result ^ 0xa8b69f6b result = result + (data[0x11] * 0x6dcfe7) result = result ^ 0x653c249a result = result + (data[0x1] * 0x8f4c44) result = result ^ 0x68e87685 result = result - (data[0x9] * 0xd2f4ce) result = result + 0x78dc723b result = result ^ (data[0xd] * 0xe99d3f) result = result + 0xed16797a result = result + (data[0x5] * 0xada536) result = result + 0x6a5fa557 result = result - (data[0x19] * 0xe0b352) result = result ^ 0x43c00020 result = result + (data[0x15] * 0x8675b6) result = result + 0x34a29213 result = result + 0xdfe69582 result &= 0xffffffffffffffff return result def c15(): result = data[0x2] * 0x4a5e95 result = result + 0x5ed7a1f1 result = result + (data[0x16] * 0x3a7b49) result = result ^ 0x87a91310 result = result - (data[0x6] * 0xf27038) result = result ^ 0xf64a0f19 result = result + (data[0x1e] * 0xa187d0) result = result + 0x44338ca3 result = result - (data[0x12] * 0xfc991a) result = result ^ 0xf9ddd08f result = result - (data[0x1a] * 0x4e947a) result = result + 0xa656e8d2 result = result ^ (data[0xe] * 0x324ead) result = result + 0x6965859c result = result - (data[0xa] * 0x656b1b) result = result + 0x8c112443 result = result + 0x3e24bb39 result &= 0xffffffffffffffff return result def c16(): result = data[0xb] * 0x251b86 result = result + 0xa751192c result = result - (data[0x7] * 0x743927) result = result ^ 0xf851da43 result = result ^ (data[0x1f] * 0x9a3479) result = result ^ 0x335087a5 result = result ^ (data[0x3] * 0x778a0d) result = result ^ 0x4bfd30d3 result = result - (data[0x1b] * 0x7e04b5) result = result + 0xa2abfb6b result = result ^ (data[0x13] * 0xf1c3ee) result = result + 0x460c48a6 result = result + (data[0xf] * 0x883b8a) result = result + 0x7b2ffbdc result = result + (data[0x17] * 0x993db1) result = result + 0xa98b27fa result = result + 0xddf7842c result &= 0xffffffffffffffff return result def c17(): result = data[0x10] * 0xbae081 result = result + 0x2359766f result = result ^ (data[0x18] * 0xc2483b) result = result + 0xea986a57 result = result - (data[0x1c] * 0x520ee2) result = result ^ 0xa6ff8114 result = result + (data[0x8] * 0x9864ba) result = result + 0x42833507 result = result - (data[0x0] * 0x7cd278) result = result ^ 0x360be811 result = result ^ (data[0x4] * 0xbe6605) result = result + 0xb36d8573 result = result + (data[0x14] * 0x3bd2e8) result = result + 0xb790cfd3 result = result - (data[0xc] * 0x548c2b) result = result + 0x2a0e04cc result = result + 0xdecd786e result &= 0xffffffffffffffff return result def c18(): result = data[0x11] * 0xfb213b result = result + 0x988c29bd result = result ^ (data[0x9] * 0xde6876) result = result ^ 0x8649fde3 result = result ^ (data[0x1d] * 0x629ff7) result = result ^ 0xa0eeb203 result = result - (data[0x19] * 0xdbb107) result = result ^ 0x94aa6b62 result = result - (data[0x1] * 0x262675) result = result + 0x2030ab78 result = result + (data[0x5] * 0xd691c5) result = result + 0xa4c118ba result = result - (data[0xd] * 0xcafc93) result = result + 0xeee421de result = result - (data[0x15] * 0x81f945) result = result + 0x6ffcc3f8 result = result + 0x9cb62931 result &= 0xffffffffffffffff return result def c19(): result = data[0xa] * 0x52f44d result = result ^ 0x33b3d0e4 result = result ^ (data[0x1e] * 0xe6e66e) result = result + 0xd8a28650 result = result - (data[0x6] * 0xf98017) result = result ^ 0x456e6c1d result = result - (data[0xe] * 0x34fcb0) result = result ^ 0x28709cd8 result = result ^ (data[0x2] * 0x4d8ba9) result = result + 0xb5482f53 result = result ^ (data[0x12] * 0x6c7e92) result = result + 0x2af1d741 result = result + (data[0x16] * 0xa4711e) result = result ^ 0x22e79af6 result = result + (data[0x1a] * 0x33d374) result = result + 0xee8102f2 result = result + 0x6c86bd72 result &= 0xffffffffffffffff return result def c20(): result = data[0x1b] * 0x65ac37 result = result + 0x15e586b0 result = result ^ (data[0x1f] * 0xc6dde0) result = result ^ 0x2354cad4 result = result ^ (data[0xf] * 0x154abd) result = result ^ 0xfee57fd5 result = result ^ (data[0x13] * 0xa5e467) result = result + 0x315624ef result = result ^ (data[0x17] * 0xb6bed6) result = result + 0xad7a4f5b result = result - (data[0x7] * 0x832ae7) result = result + 0xe961bedd result = result + (data[0xb] * 0xc46330) result = result + 0xb561e29b result = result ^ (data[0x3] * 0x3f8467) result = result ^ 0x95a6a1c4 result = result + 0xeef1cae7 result &= 0xffffffffffffffff return result def c21(): result = data[0x18] * 0xb74a52 result = result ^ 0x8354d4e8 result = result ^ (data[0x4] * 0xf22ecd) result = result + 0xcb340dc5 result = result + (data[0x14] * 0xbef4be) result = result ^ 0x60a6c39a result = result ^ (data[0x8] * 0x7fe215) result = result + 0xb14a7317 result = result - (data[0x10] * 0xdb9f48) result = result + 0x4356fa0e result = result - (data[0x1c] * 0xbb4276) result = result + 0x6df1ddb8 result = result ^ (data[0x0] * 0xa3fbef) result = result + 0x4c22d2d3 result = result ^ (data[0xc] * 0xc5e883) result = result ^ 0x50a6e4c9 result = result + 0x271a433a result &= 0xffffffffffffffff return result def c22(): result = data[0xd] * 0x4b2d02 result = result ^ 0x4b59b93a result = result - (data[0x9] * 0x84bb2c) result = result ^ 0x42d5652c result = result ^ (data[0x19] * 0x6f2d21) result = result + 0x1020133a result = result + (data[0x1d] * 0x5fe38f) result = result + 0x9d7f84e0 result = result + (data[0x15] * 0xea20a5) result = result ^ 0x60779ceb result = result ^ (data[0x11] * 0x5c17aa) result = result ^ 0x1aaf8a2d result = result - (data[0x5] * 0xb9feb0) result = result + 0x5241fd05 result = result - (data[0x1] * 0x782f79) result = result + 0x303ed7ca result = result + 0xb77294fa result &= 0xffffffffffffffff return result def c23(): result = data[0x6] * 0x608d19 result = result + 0xd1119d14 result = result - (data[0xe] * 0xbe18f4) result = result ^ 0xb86f9b72 result = result ^ (data[0x1e] * 0x88dec9) result = result + 0xaf5cd797 result = result ^ (data[0x12] * 0xb68150) result = result + 0xc2f8c45b result = result + (data[0x16] * 0x4d166c) result = result + 0xbb1e1039 result = result - (data[0x2] * 0x495e3f) result = result + 0xe727b98e result = result - (data[0xa] * 0x5caba1) result = result + 0xe5c3093f result = result + (data[0x1a] * 0x183a4d) result = result + 0x35fc681f result = result + 0x997b5ce3 result &= 0xffffffffffffffff return result def c24(): result = data[0xb] * 0xffd0ca result = result + 0x70d93118 result = result ^ (data[0x7] * 0xbf2b59) result = result + 0xc76bad6e result = result + (data[0x17] * 0x29df01) result = result + 0xeef034a2 result = result ^ (data[0x1b] * 0xbbda1d) result = result + 0x5923194e result = result - (data[0x1f] * 0x5d24a5) result = result + 0x7eeff867 result = result + (data[0xf] * 0x3dc505) result = result + 0x9645116f result = result ^ (data[0x13] * 0x4e25a6) result = result + 0x2468b30a result = result - (data[0x3] * 0xae1920) result = result ^ 0xd3db6142 result = result + 0x44850ff1 result &= 0xffffffffffffffff return result def c25(): result = data[0x4] * 0xf56c62 result = result ^ 0x6c7d1f41 result = result + (data[0x10] * 0x615605) result = result + 0x5b52f6ee result = result + (data[0x14] * 0x828456) result = result ^ 0x6f059759 result = result - (data[0x1c] * 0x50484b) result = result + 0x84e222af result = result ^ (data[0x8] * 0x89d640) result = result + 0xfd21345b result = result - (data[0x18] * 0xe4b191) result = result + 0xfe15a789 result = result ^ (data[0x0] * 0x8c58c1) result = result ^ 0x4c49099f result = result + (data[0xc] * 0xa13c4c) result = result ^ 0x27c5288e result = result + 0xff6724f5 result &= 0xffffffffffffffff return result def c26(): result = data[0x1] * 0x73aaf0 result = result ^ 0xa04e34f1 result = result + (data[0x1d] * 0xf61e43) result = result + 0xd09b66f3 result = result + (data[0x19] * 0x8cb5f0) result = result + 0xc11c9b4b result = result ^ (data[0x11] * 0x4f53a8) result = result + 0x9b9a98d2 result = result + (data[0x9] * 0xb2e1fa) result = result ^ 0x77c07fd8 result = result - (data[0x15] * 0xb8b7b3) result = result + 0x77d3eadf result = result + (data[0xd] * 0x13b807) result = result ^ 0x758dd142 result = result ^ (data[0x5] * 0xdd40c4) result = result + 0xbb68781a result = result + 0x4fa227c4 result &= 0xffffffffffffffff return result def c27(): result = data[0xe] * 0xca894b result = result + 0xa34fe406 result = result + (data[0x12] * 0x11552b) result = result + 0x3764ecd4 result = result ^ (data[0x16] * 0x7dc36b) result = result + 0xb45e777b result = result ^ (data[0x1a] * 0xcec5a6) result = result ^ 0x2d59bc15 result = result + (data[0x1e] * 0xb6e30d) result = result ^ 0xfab9788c result = result ^ (data[0xa] * 0x859c14) result = result + 0x41868e54 result = result + (data[0x6] * 0xd178d3) result = result + 0x958b0be3 result = result ^ (data[0x2] * 0x61645c) result = result + 0x9dc814cf result = result + 0x847feabe result &= 0xffffffffffffffff return result def c28(): result = data[0x1b] * 0x7239e9 result = result + 0x89f1a526 result = result - (data[0x3] * 0xf1c3d1) result = result + 0x10d75f98 result = result ^ (data[0xb] * 0x1b1367) result = result ^ 0x31e00d5a result = result ^ (data[0x13] * 0x8038b3) result = result + 0xb5163447 result = result + (data[0x1f] * 0x65fac9) result = result + 0xe04a889a result = result - (data[0x17] * 0xd845ca) result = result + 0x5482e3a8 result = result + (data[0xf] * 0xb2bbbc) result = result ^ 0x3a017b92 result = result ^ (data[0x7] * 0x33c8bd) result = result + 0x540376e3 result = result + 0x4f17f36d result &= 0xffffffffffffffff return result def c29(): result = data[0x0] * 0x53a4e0 result = result + 0x9f9e7fc2 result = result - (data[0x10] * 0x9bbfda) result = result + 0x69b383f1 result = result - (data[0x18] * 0x6b38aa) result = result + 0x68ece860 result = result + (data[0x14] * 0x5d266f) result = result + 0x5a4b0e60 result = result - (data[0x8] * 0xedc3d3) result = result ^ 0x93e59af6 result = result - (data[0x4] * 0xb1f16c) result = result ^ 0xe8d2b9a9 result = result + (data[0xc] * 0x1c8e5b) result = result + 0x977c6d7d result = result + (data[0x1c] * 0x78f67b) result = result + 0xac22677 result = result + 0xb154dea3 result &= 0xffffffffffffffff return result def c30(): result = data[0x11] * 0x87184c result = result + 0x8d5ea528 result = result ^ (data[0x19] * 0xf6372e) result = result + 0x16ad4f89 result = result - (data[0x15] * 0xd7355c) result = result + 0x44df01cb result = result ^ (data[0x5] * 0x471dc1) result = result ^ 0x572c95f4 result = result - (data[0x1] * 0x8c4d98) result = result + 0x6b9af38c result = result - (data[0xd] * 0x5ceea1) result = result ^ 0xf703dcc1 result = result - (data[0x1d] * 0xeb0863) result = result + 0xad3bc09d result = result ^ (data[0x9] * 0xb6227f) result = result + 0xb95195e9 result = result + 0xcea17ee8 result &= 0xffffffffffffffff return result def c31(): result = data[0x1e] * 0x8c6412 result = result ^ 0xc08c361c result = result ^ (data[0xe] * 0xb253c4) result = result + 0x21bb1147 result = result + (data[0x2] * 0x8f0579) result = result + 0x596ee7a result = result - (data[0x16] * 0x7ac48a) result = result + 0xbb787dd5 result = result + (data[0xa] * 0x2737e6) result = result ^ 0xa2bb7683 result = result - (data[0x12] * 0x4363b9) result = result ^ 0x88c45378 result = result ^ (data[0x6] * 0xb38449) result = result + 0xdf623f88 result = result + (data[0x1a] * 0x6e1316) result = result + 0x1343dee9 result = result + 0x1c966ad9 result &= 0xffffffffffffffff return result def c32(): result = data[0x13] * 0x390b78 result = result + 0x7d5deea4 result = result - (data[0xf] * 0x70e6c8) result = result + 0x915cc61e result = result ^ (data[0x1b] * 0xd8a292) result = result + 0xd772913b result = result - (data[0x17] * 0x978c71) result = result + 0x1a27a128 result = result + (data[0x1f] * 0x9a14d4) result = result + 0x49698f34 result = result ^ (data[0x7] * 0x995144) result = result + 0x2d188cbe result = result ^ (data[0xb] * 0x811c39) result = result + 0xd22fca9b result = result ^ (data[0x3] * 0x9953d7) result = result ^ 0x80877669 result = result + 0x6bddb88 result &= 0xffffffffffffffff return result data = [BitVec(f'data{i}', 8) for i in range(32)] s = Solver() s.add(c1() == 0) s.add(c2() == 0) s.add(c4() == 0) s.add(c3() == 0) s.add(c5() == 0) s.add(c6() == 0) s.add(c7() == 0) s.add(c8() == 0) s.add(c9() == 0) s.add(c10() == 0) s.add(c11() == 0) s.add(c12() == 0) s.add(c13() == 0) s.add(c14() == 0) s.add(c15() == 0) s.add(c16() == 0) s.add(c17() == 0) s.add(c18() == 0) s.add(c19() == 0) s.add(c20() == 0) s.add(c21() == 0) s.add(c22() == 0) s.add(c23() == 0) s.add(c24() == 0) s.add(c25() == 0) s.add(c26() == 0) s.add(c27() == 0) s.add(c28() == 0) s.add(c29() == 0) s.add(c30() == 0) s.add(c31() == 0) s.add(c32() == 0) def print_all_sat(solver): solutions = [] while solver.check() == sat: model = solver.model() result = ''.join(chr(model[byte].as_long()) for byte in data) print("SAT Solution:") print(result) exclusion = Or([byte != model[byte] for byte in data]) solver.add(exclusion) print_all_sat(s) ``` Flag: `$$_4lway5_k3ep_mov1ng_and_m0ving@flare-on.com`