又感觉好久没写WP。–2022.9.15
0x00 Daily Shell Check 无壳32位
0x01 Analyze Main 首先是 sub_401121 函数,第一个知识点就是Socket通信,这里可知接收了数据然后返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 SOCKET __cdecl sub_401121 (char *buf) { SOCKET v2; SOCKET v3; SOCKET v4; struct WSAData WSAData ; struct sockaddr name ; if ( WSAStartup(0x202 u, &WSAData) ) return 0 ; v2 = socket(2 , 1 , 6 ); if ( v2 != -1 ) { name.sa_family = 2 ; *(_DWORD *)&name.sa_data[2 ] = inet_addr("127.0.0.1" ); *(_WORD *)name.sa_data = htons(2222u ); if ( bind(v2, &name, 16 ) != -1 && listen(v2, 0x7FFFFFFF ) != -1 ) { v3 = accept(v2, 0 , 0 ); v4 = v3; if ( v3 != -1 ) { if ( recv(v3, buf, 4 , 0 ) > 0 ) return v4; closesocket(v4); } } closesocket(v2); } WSACleanup(); return 0 ; }
(更多的Socket通信逆向可以看 DASCTF2022 X SU-login 该题)
随后在主函数,程序进程SMC解密,而这里的解密实际只异或了一个字节 ,那么只有256种可能性
同时 sub_4011E6 会验证 40107C 地址的数据是否正确解密,如果成功进入了判断会发送 Congratulations!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 int __usercall sub_401008@<eax>(int _EDI@<edi>, _DWORD *a2@<esi>){ _BYTE *v2; char copy_buf; int _EBX; bool v5; unsigned int v6; int v7; int v9; char buf[4 ]; SOCKET s; int savedregs; s = sub_401121(buf); if ( !s ) return 0 ; v2 = &loc_40107C; copy_buf = buf[0 ]; do { *v2 = (copy_buf ^ *v2) + 34 ; ++v2; } while ( (int )v2 < (int )&loc_40107C + 0x79 ); if ( (unsigned __int16)sub_4011E6((unsigned __int8 *)&loc_40107C, 0x79 u) == 0xFB5E ) { _EBX = *(_DWORD *)(v9 + 377554449 ); __asm { lock xor bl, [edi+61791 C4h] } v5 = __CFADD__(*(_DWORD *)(8 * (_DWORD)a2 + 0xFB5E ), -250248954 ); *(_DWORD *)(8 * (_DWORD)a2 + 0xFB5E ) -= 250248954 ; if ( v9 == 1 ) { v6 = v5 + 427886322 ; v5 = MEMORY[0xFB5E ] < v6; MEMORY[0xFB5E ] -= v6; } __asm { icebp } *a2 -= v5 + 530171120 ; v7 = *(_DWORD *)(v9 - 1 + 494994972 ); __outbyte(6u , 0x5E u); *(_DWORD *)(v7 - 17 ) &= 0xF2638106 ; MEMORY[0xFB41 ] &= 0x66199C4 u; *(a2 - 17 ) &= 0xE6678106 ; *(_DWORD *)(8 * (_DWORD)&savedregs + 0xFB5E + 6 ) &= 0x69D6581 u; *(_DWORD *)(v7 - 14 ) -= 107715012 ; MEMORY[0xFB07 ] += 278298362 ; *(_DWORD *)((char *)a2 - 18 ) += 1368424186 ; *(_DWORD *)(_EBX + 6 ) -= 116354433 ; *(_DWORD *)(v7 - 23 ) ^= 0x7C738106 u; send(s, "Congratulations! But wait, where's my flag?" , 43 , 0 ); } else { send(s, "Nope, that's not it." , 20 , 0 ); } closesocket(s); return WSACleanup(); }
0x02 GetFlag 那么了解以上,就可以开始去想方法获得我们的flag了,首先是第一个方法,爆破我们的发送过去的值,如果返回Congratulations 就打印我们所爆破的值
Crack Socket 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import sysimport osimport timeimport socketTCP_IP = '127.0.0.1' TCP_PORT = 2222 BUFFER_SIZE = 1024 for i in range (0 ,256 ): os.startfile(sys.argv[1 ]) time.sleep(0.1 ) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TCP_IP, TCP_PORT)) s.send(chr (i)) data = s.recv(BUFFER_SIZE) s.close() if 'Congratulations' in data: print (i) break
从这里我们可以直接知道我们要的值是0xA2,但不能直接拿到flag,估计是在SMC解密后的内容,于是我们可以IDA调试,随后这里发送字节过去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import sysimport osimport timeimport socketTCP_IP = '127.0.0.1' TCP_PORT = 2222 BUFFER_SIZE = 1024 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TCP_IP, TCP_PORT)) print (type (b'\xA2' ))s.send(b'\xA2' ) data = s.recv(BUFFER_SIZE) print (data)s.close()
调试至此,GetFlag!
unicorn 那么还有个方法就是 unicorn 模拟执行
参考文章:
https://bbs.pediy.com/thread-223473-1.htm
那么unicorn的本意就是帮我们模拟执行代码,稍稍回忆两个点
loc_40107C 为我们要解密的代码
sub_4011E6 为我们验证解密是否成功的代码
那么与之前思路相同,我们模拟执行 sub_4011E6 的代码让该函数验证我们的 loc_40107C(我们尝试解密后的) 是否正确
先取出我们需要的数据并转成字节
1 2 3 4 5 6 7 8 9 10 11 12 13 CHECKSUM_CODE = binascii.unhexlify( '55 8B EC 51 8B 55 0C B9 FF 00 00 00 89 4D FC 85 D2 74 51 53 8B 5D 08 56 57 ' '6A 14 58 66 8B 7D FC 3B D0 8B F2 0F 47 F0 2B D6 0F B6 03 66 03 F8 66 89 7D ' 'FC 03 4D FC 43 83 EE 01 75 ED 0F B6 45 FC 66 C1 EF 08 66 03 C7 0F B7 C0 89 ' '45 FC 0F B6 C1 66 C1 E9 08 66 03 C1 0F B7 C8 6A 14 58 85 D2 75 BB 5F 5E 5B ' '0F B6 55 FC 8B C1 C1 E1 08 25 00 FF 00 00 03 C1 66 8B 4D FC 66 C1 E9 08 66 ' '03 D1 66 0B C2 8B E5 5D' .replace(' ' , '' )) ENCODED_BYTES = binascii.unhexlify( '33 E1 C4 99 11 06 81 16 F0 32 9F C4 91 17 06 81 14 F0 06 81 15 F1 C4 91 1A ' '06 81 1B E2 06 81 18 F2 06 81 19 F1 06 81 1E F0 C4 99 1F C4 91 1C 06 81 1D ' 'E6 06 81 62 EF 06 81 63 F2 06 81 60 E3 C4 99 61 06 81 66 BC 06 81 67 E6 06 ' '81 64 E8 06 81 65 9D 06 81 6A F2 C4 99 6B 06 81 68 A9 06 81 69 EF 06 81 6E ' 'EE 06 81 6F AE 06 81 6C E3 06 81 6D EF 06 81 72 E9 06 81 73 7C' .replace(' ' , '' ))
那么我们模拟执行的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def emulate_checksum (decoded_bytes ): address = 0x400000 stack_addr = 0x410000 dec_bytes_addr = 0x420000 mu = Uc(UC_ARCH_X86, UC_MODE_32) mu.mem_map(address, 2 * 1024 * 1024 ) mu.mem_write(address, CHECKSUM_CODE) mu.mem_write(dec_bytes_addr, decoded_bytes) mu.reg_write(UC_X86_REG_ESP, stack_addr) mu.mem_write(stack_addr + 4 , struct.pack('<I' , dec_bytes_addr)) mu.mem_write(stack_addr + 8 , struct.pack('<I' , 0x79 )) mu.emu_start(address, address + len (CHECKSUM_CODE)) checksum = mu.reg_read(UC_X86_REG_AX) return checksum
最后利用 capstone 打印出SMC后的语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import binasciiimport structfrom unicorn import *from unicorn.x86_const import *from capstone import *CHECKSUM_CODE = binascii.unhexlify( '55 8B EC 51 8B 55 0C B9 FF 00 00 00 89 4D FC 85 D2 74 51 53 8B 5D 08 56 57 ' '6A 14 58 66 8B 7D FC 3B D0 8B F2 0F 47 F0 2B D6 0F B6 03 66 03 F8 66 89 7D ' 'FC 03 4D FC 43 83 EE 01 75 ED 0F B6 45 FC 66 C1 EF 08 66 03 C7 0F B7 C0 89 ' '45 FC 0F B6 C1 66 C1 E9 08 66 03 C1 0F B7 C8 6A 14 58 85 D2 75 BB 5F 5E 5B ' '0F B6 55 FC 8B C1 C1 E1 08 25 00 FF 00 00 03 C1 66 8B 4D FC 66 C1 E9 08 66 ' '03 D1 66 0B C2 8B E5 5D' .replace(' ' , '' )) ENCODED_BYTES = binascii.unhexlify( '33 E1 C4 99 11 06 81 16 F0 32 9F C4 91 17 06 81 14 F0 06 81 15 F1 C4 91 1A ' '06 81 1B E2 06 81 18 F2 06 81 19 F1 06 81 1E F0 C4 99 1F C4 91 1C 06 81 1D ' 'E6 06 81 62 EF 06 81 63 F2 06 81 60 E3 C4 99 61 06 81 66 BC 06 81 67 E6 06 ' '81 64 E8 06 81 65 9D 06 81 6A F2 C4 99 6B 06 81 68 A9 06 81 69 EF 06 81 6E ' 'EE 06 81 6F AE 06 81 6C E3 06 81 6D EF 06 81 72 E9 06 81 73 7C' .replace(' ' , '' )) def decode_bytes (i ): decoded_bytes = [] for byte in ENCODED_BYTES: decoded_bytes.append(((int (byte) ^ i) + 34 ) & 0xFF ) return bytes (decoded_bytes) def emulate_checksum (decoded_bytes ): address = 0x400000 stack_addr = 0x410000 dec_bytes_addr = 0x420000 mu = Uc(UC_ARCH_X86, UC_MODE_32) mu.mem_map(address, 2 * 1024 * 1024 ) mu.mem_write(address, CHECKSUM_CODE) mu.mem_write(dec_bytes_addr, decoded_bytes) mu.reg_write(UC_X86_REG_ESP, stack_addr) mu.mem_write(stack_addr + 4 , struct.pack('<I' , dec_bytes_addr)) mu.mem_write(stack_addr + 8 , struct.pack('<I' , 0x79 )) mu.emu_start(address, address + len (CHECKSUM_CODE)) checksum = mu.reg_read(UC_X86_REG_AX) return checksum for i in range (0 , 256 ): decoded_bytes = decode_bytes(i) checksum = emulate_checksum(decoded_bytes) if checksum == 0xFB5E : print ('Checksum matched with byte %X' % i) print ('Decoded bytes disassembly:' ) md = Cs(CS_ARCH_X86, CS_MODE_32) for j in md.disasm(decoded_bytes, 0x40107C ): print ("0x%x:\t%s\t%s" % (j.address, j.mnemonic, j.op_str)) break
GetFlag!!
Angr 那么该题当然也能 Angr 解题
参考文章
https://blog.csdn.net/qq_42680294/article/details/112976617
思路与unicorn一样,从我们的 sub_4011E6 开始模拟执行,再验证该函数返回值是否为 0xFB5E
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 import angrimport sysimport binasciip = angr.Project('greek_to_me.exe' , load_options={'auto_load_libs' : False }) f2 = None ENCODED_BYTES = binascii.unhexlify( '33 E1 C4 99 11 06 81 16 F0 32 9F C4 91 17 06 81 14 F0 06 81 15 F1 C4 91 1A ' '06 81 1B E2 06 81 18 F2 06 81 19 F1 06 81 1E F0 C4 99 1F C4 91 1C 06 81 1D ' 'E6 06 81 62 EF 06 81 63 F2 06 81 60 E3 C4 99 61 06 81 66 BC 06 81 67 E6 06 ' '81 64 E8 06 81 65 9D 06 81 6A F2 C4 99 6B 06 81 68 A9 06 81 69 EF 06 81 6E ' 'EE 06 81 6F AE 06 81 6C E3 06 81 6D EF 06 81 72 E9 06 81 73 7C' .replace(' ' , '' )) for buf in range (0 , 256 ): print (("Trying buf = {0}" .format (buf))) asm = None b2 = [] dl = buf for byte in ENCODED_BYTES: bl = int (byte) bl = bl ^ dl bl = bl & 0xff bl = bl + 0x22 bl = bl & 0xff b2.append(bl) s = p.factory.blank_state(addr = 0x4011E6 ) s.mem[s.regs.esp+4 :].dword = 1 s.mem[s.regs.esp+8 :].dword = 0x79 asm = bytes (b2) s.memory.store(1 , s.se.BVV(int .from_bytes(asm, byteorder='big' , signed=False ), 0x79 * 8 )) simgr = p.factory.simulation_manager(s) simgr.explore(find = 0x401268 ) for found in simgr.found: print ((' ax = %s' % hex (found.solver.eval (found.regs.ax)))) if hex (found.solver.eval (found.regs.ax)) == '0xfb5e' : code = ("%x" % found.solver.eval_upto(found.memory.load(1 , 0x79 ), 1 )[0 ]) print (('\n Winner is: {0}\n\n' .format (buf))) print ((' %s' % code)) bl = None dl = None flag = [] from capstone import * md = Cs(CS_ARCH_X86, CS_MODE_32) code = binascii.unhexlify(code) for i in md.disasm(code, 0x1000 ): flag_char = None try : if i.op_str.split(',' )[0 ].startswith("byte ptr" ): flag_char = chr (int (i.op_str.split(',' )[1 ], 16 )) if i.op_str.split(',' )[0 ].startswith('bl' ): bl = chr (int (i.op_str.split(',' )[1 ], 16 )) if i.op_str.split(',' )[0 ].startswith('dl' ): dl = chr (int (i.op_str.split(',' )[1 ], 16 )) except : if i.op_str.split(',' )[1 ].strip() == 'dl' : flag_char = dl if i.op_str.split(',' )[1 ].strip() == 'bl' : flag_char = bl if (flag_char): flag.append(flag_char.strip()) print ((" 0x%x\t%s\t%s\t%s" %(i.address, i.mnemonic, i.op_str, flag_char))) print ('\n\n' ) print (('' .join(flag))) sys.exit(0 )
GetFlag!!!