0x00 题目分析
父进程开启一个子进程并接收子进程的异常信息,根据这些信息来执行程序流
由于这个开启的子进程是它本身,所以子进程的代码实际上是可以在程序中找到的(不过加了密,需要dump下来解密先)
但实际上没有必要去看子进程的解密结果,只要直接调父进程就可以就可以得到程序的执行流程了
0x01 解
无壳,直接拖IDA
符号加载还算比较完全,基本可以看懂在干什么,这个A10就是主函数
因为opcode不能直接获取,所以这题动调才能搞清楚流程
注意限制了输入长度
之后单步调试可以发现到了这个地方
关于ReadProcessMemory可以看微软的文档
查看ProcessInformation可以发现这个ReadProcessMemory的目标就是与题目同名的一个程序
之后根据lpBaseAddress可以找到opcode的位置,大小是0xD6
解密只是一个简单的异或,可以写个脚本解析一下
1 2 3 4 5 6 7 8 9
| with open("./opcode_enc",'rb') as f: opcode = bytearray(f.read()) print(opcode) opcode_dec = b"" for i in range(len(opcode)): opcode[i] ^= 0x44 print(opcode) with open('opcode_deced', 'wb') as fi: fi.write(opcode)
|
不过有一说一解析出来没啥大用,因为可以通过动调的方式来看清楚程序流
继续上面的动调流程,这里可以看到先把输入与0x7D进行异或
之后是一个移位运算
再之后会到这个函数里面
进去会发现是这样的(这里改了下变量名方便查看)
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
| int __cdecl sub_E22420(int entered, int entered_len, int key, int key_len) { int result; char tmp; char tmp1; int index; int i; int j; int k; unsigned __int8 index1; unsigned __int8 index2; char table[260];
__CheckForDebuggerJustMyCode(&unk_E2D0AC); for ( i = 0; i < 256; ++i ) table[i] = i; index = 0; for ( j = 0; j < 256; ++j ) { index = (*(unsigned __int8 *)(key + j % key_len) + index + (unsigned __int8)table[j]) % 256; tmp = table[j]; table[j] = table[index]; table[index] = tmp; } index2 = 0; index1 = 0; for ( k = 0; ; ++k ) { result = k; if ( k >= entered_len ) break; index1 += table[++index2]; tmp1 = table[index2]; table[index2] = table[index1]; table[index1] = tmp1; *(_BYTE *)(k + entered) ^= table[((unsigned __int8)table[index1] + (unsigned __int8)table[index2]) % 256]; } return result; }
|
首先获取一张0~255的表,然后将表根据key进行置换,置换后进入一个循环,循环内先进行表的置换,再将置换结果与输入进行异或
这是个RC4
RC4解密比较重要的就是获取与明文异或的值,这个可以使用明文和密文来获取,即将密文与明文逐位异或即可获取进行异或的key
注意这里的明文是经过了上面的所有运算之后的结果,并非是一开始的输入
所以整个小脚本来处理
1 2 3 4 5 6 7 8 9 10
| enc = bytearray(0) plain = bytearray(0) with open('./enc','rb') as f: enc = bytearray(f.read()) with open ('./plain','rb') as f: plain = bytearray(f.read()) for i in range(len(enc)): plain[i] ^= enc[i] print(plain.hex())
|
之后再继续动调,发现已经到了比较了
因此把密文dump下来之后就可以解密了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import struct enc = bytearray(0) with open("./encry","rb") as f: enc = bytearray(f.read()) enc = bytearray(struct.unpack("i"*25,enc)) key = bytes.fromhex("4b8aa9e199284d4b22b7bd8d5a49350063b6c56b6194a503") for i in range(len(key)): enc[i]^=key[i] print(enc) for i in range(len(enc)): enc[i] = (enc[i] >> 6) | (enc[i] << 2) & 0xff for i in range(len(enc)): enc[i] ^= 0x7D print(bytes(enc))
|