2021HWS冬令营选拔赛-ChildRe-WP
前言
这种类型的题依稀记得在18年做过类似的,好久没看确实手生。
解题
考点:Debug Blocker反调试;Tea加密算法。
关于Debug Blocker原理不多写了,可以参考我之前看的一篇文章
主进程作为调试器附加调试子进程,当子进程遇到int 3
指令时会发送异常给调试器也就是主进程,然后主进程会在sub_413BE0
循环等待接收子进程的异常。
根据异常事件的不同,会进入不同的处理函数,重点关注一下sub_411023
函数
当子进程发生异常时,并且int 3
的后一个值为178
时,会进入到WriteProcessMemorry
函数进行处理,也就是在00412F39
处,这里的目的是将1946127526
这个常数写入到子进程中,而后通过SetThreadContext
和ContinueDebugEvent
函数使子进程继续运行,为了能够调试子进程,我们需要使用DebugActiveProcessStop
函数使主进程脱离对子进程的调试,以使我们可以通过IDA附加子进程进行调试。
不过为了使子进程可以被我们附加调试,而不会退出,我们可以在相应的位置,写入一个死循环。
具体为将00412F3D
地址处的值EB 00
patch为EB FE
然后apply,这样就可以使程序运行到这里的时候进入一个死循环,以便等待我们调试器的附加,当调试器附加上之后,在将其修改为原来指令,并在下一条指令处下断点,然后运行,这样我们就可以调试子进程了。
之后就是去了解加密过程。总体上如下:
子进程:
获取用户输入,判断长度 == 0x20
input = get()
if len(input) != 0x20:
exit()
else:
int 3
...
int 3 # 陷入中断,跳过垃圾指令 eip += 9 jmp junk_code
...
int 3 # 陷入中断,获取常数 get const 0x73ff8ca6
...
input[i] 占4bytes,倒序
for i in range(8):
input[i] = _byteswap_ulong(input[i])
...
根据常数,生成一组固定常数,并将input和每个常数进行异或
num = 0x73ff8ca6 # [0x19FBB4]
for i in range(8):
input[i] = input[i] ^ num
num = (num - 0x50FFE544)&0xffffffff
...
倒序
for i in range(8):
input[i] = _byteswap_ulong(input[i])
init_key:初始化key
dword_432358 = [0x82ABA3FE, 0xAC1DDCA8, 0x87EC6B60, 0xA2394568, 0x432BEEE0, 0x2392B7C0, 0xC8C7FB80, 0xE7CC394D]
将key倒序
tea(key,input,5)
经过tea加密后和固定常量逐位比较。根据比较的结果输出wrong或者correct。
最后的解密脚本如下:
from libnum import s2n,n2s
def encrypt(v, k):
v0 = v[0]
v1 = v[1]
x = 0
delta = 0x9E3779B9
k0 = k[0]
k1 = k[1]
k2 = k[2]
k3 = k[3]
for i in range(32):
x += delta
x = x & 0xFFFFFFFF
v0 += ((