0x00 分析
两个反调+魔改TEA
总体流程不难
0x01 解
无壳,直接拖IDA
发现main里面有个经典的检测调试器的函数IsDebuggerPresent

Tab查看汇编

这边patch直接将判断条件改为IsDebuggerPresent < 2即可
即将cmp eax, 1改为cmp eax, 2即可
之后再看看其他

发现调用了两次chrono::system_clock::now()这里使用的是一种反调试,具体原理可以看这个:RDTSC时钟检测反调试
也就是说在这两个之间如果做了中断行为,则if的结果就会不同,可以在这里下断点进行测试,尝试在call _ZNSt6chrono3_V212system_clock3nowEv之前下断点和不下断点观察结果

这边就不测试了(懒)
总之正常的结果应该走右边,即不使用mov rax, 22002200220022h所在的这块
这边改jle为jmp就行
之后apply patch就可以愉快调试了
patch之后断在try again上面的判断,一般来说这里存的就是密文了

执行两次,输入两个不同的值,发现v8的值都不变,大概就能判断出v8里面就是密文了
dump下来
1
| bytearray(b'vq\x9d\xe7pw?\xa3\x02\xf1\x8d\xc9\x02\xc6\xa2K\xba\x19V\x05\xf2\x89^\xe0')
|
然后就可以开始倒着看了
首先是这里一大堆__mm_xor_si128(),而且还给了个0x330033003300330033003300330033

合理怀疑这个0x330033003300330033003300330033就是异或的key了
去汇编验证一下发现确实是这么回事

所以第一步就是异或这些个0x33
然后往上走,可以发现这两个函数

调试一下可以发现他俩将数据进行了一个置换,置换的结果如下所示
1 2 3 4
| 输入为 0x666c6167,0x7b616161,0x61616161,0x6161617d 置换结果为 0x6161617d,0x61616161,0x7b616161,0x666c6167
|
相当于变成倒序了
这里看到有个24,据此可以判断flag长度应该为24
不过dump下来的密文长度也可以说明这点
之后再往上可以看到连续调用了一个函数sub_401E80三次

进去滑到最下面可以发现是TEA加密
不过魔改得挺多

那么接下来就是找key了
key好找,直接看xmmword_408040就好,不过需要注意使用的顺序


不过这还没有结束
往上看可以找到这个密钥的来源
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
| v1 = dword_404010; v2 = &xmmword_408040; xmmword_408040 = (__int128)_mm_load_si128((const __m128i *)&xmmword_405050); v3 = dword_404010 + 4; do { v4 = v1; if ( v1 <= 0 ) { v12 = 1; } else { v5 = 0; v6 = 0; v7 = 1; v8 = 1; v9 = 1; do { if ( (v4 & 1) != 0 ) { v10 = v6; v6 = v7 * v8 + v5 * v6; v8 = v7 * v10 + v9 * v8; } v11 = v7 * v7; v7 *= v5 + v9; v5 = v11 + v5 * v5; v4 >>= 1; v9 = v9 * v9 + v11; } while ( v4 ); v12 = v8; } ++v1; *(_DWORD *)v2 = v12; v2 = (__int128 *)((char *)v2 + 4); } while ( v1 != v3 ); dword_404010 = v1;
|
程序会将刚刚改的三目运算符的结果dword_404010丢进去进行运算才得出的密钥,而且每次运算后dword_404010的结果都会被保留,下次再调用加密函数的时候会用新的结果进行密钥的运算
这个时候就需要用动调获取出所有的key了
这里就不做过多的演示了,直接上三次的密钥
1 2 3
| k1=[0x5,0x3,0xD,0x8] k2=[0x22,0x15,0x59,0x37] k3=[0xE9,0x90,0x262,0x179]
|
之后就可以写脚本了,将原始的TEA按题目改一下,然后注意一下密文的顺序,按正确的顺序进行解密就可以了
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
| from ctypes import * import struct def decrypt(v,k): for i in range(2): v[i]^=0x33333333 v.reverse() v0=c_uint32(v[0]) v1=c_uint32(v[1]) delta=0x9E3449B8 sum1=0x987E55D0 while(sum1 != 0): v1.value-=((v0.value+sum1)^((v0.value>>4)+k[2])^((v0.value<<5)+k[3]))& 0xFFFFFFFF v0.value-=((v1.value+sum1)^((v1.value>>4)+k[0])^((v1.value<<5)+k[1]))& 0xFFFFFFFF sum1-=delta sum1 &= 0xFFFFFFFF return v0.value,v1.value ba = bytearray(b'vq\x9d\xe7pw?\xa3\x02\xf1\x8d\xc9\x02\xc6\xa2K\xba\x19V\x05\xf2\x89^\xe0') enc = struct.unpack(">"+"i"*6,ba) enc=list(enc) for i in range(len(enc)): enc[i] &= 0xFFFFFFFF k1=[0x5,0x3,0xD,0x8] k2=[0x22,0x15,0x59,0x37] k3=[0xE9,0x90,0x262,0x179]
e1 = enc[0:2] e2 = enc[2:4] e3 = enc[4:6] flag = bytearray()
res = decrypt(e3,k1) tmp = struct.pack("ii",res[0],res[1]) flag += tmp
res = decrypt(e2,k2) tmp = struct.pack("ii",res[0],res[1]) flag += tmp
res = decrypt(e1,k3) tmp = struct.pack("ii",res[0],res[1]) flag += tmp
print(flag)
|