2021HWS冬令营选拔赛-ChildRe-WP

  • Post author:
  • Post category:其他




2021HWS冬令营选拔赛-ChildRe-WP



前言

这种类型的题依稀记得在18年做过类似的,好久没看确实手生。



解题

考点:Debug Blocker反调试;Tea加密算法。

关于Debug Blocker原理不多写了,可以参考我之前看的一篇

文章

主进程作为调试器附加调试子进程,当子进程遇到

int 3

指令时会发送异常给调试器也就是主进程,然后主进程会在

sub_413BE0

循环等待接收子进程的异常。

1

根据异常事件的不同,会进入不同的处理函数,重点关注一下

sub_411023

函数

2

当子进程发生异常时,并且

int 3

的后一个值为

178

时,会进入到

WriteProcessMemorry

函数进行处理,也就是在

00412F39

处,这里的目的是将

1946127526

这个常数写入到子进程中,而后通过

SetThreadContext



ContinueDebugEvent

函数使子进程继续运行,为了能够调试子进程,我们需要使用

DebugActiveProcessStop

函数使主进程脱离对子进程的调试,以使我们可以通过IDA附加子进程进行调试。

3

不过为了使子进程可以被我们附加调试,而不会退出,我们可以在相应的位置,写入一个死循环。

具体为将

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。

4

最后的解密脚本如下:

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 += ((v1 << 4) + k0) ^ (v1 + x) ^ ((v1 >> 5) + k1)
        v0 = v0 & 0xFFFFFFFF
        v1 += ((v0 << 4) + k2) ^ (v0 + x) ^ ((v0 >> 5) + k3)
        v1 = v1 & 0xFFFFFFFF
    v[0] = v0
    v[1] = v1
    return v
def decrypt(v, k):
    v0 = v[0]
    v1 = v[1]
    x = 0xC6EF3720
    delta = 0x9E3779B9
    k0 = k[0]
    k1 = k[1]
    k2 = k[2]
    k3 = k[3]
    for i in range(32):
        v1 -= ((v0 << 4) + k2) ^ (v0 + x) ^ ((v0 >> 5) + k3)
        v1 = v1 & 0xFFFFFFFF
        v0 -= ((v1 << 4) + k0) ^ (v1 + x) ^ ((v1 >> 5) + k1)
        v0 = v0 & 0xFFFFFFFF
        x -= delta
        x = x & 0xFFFFFFFF
    v[0] = v0
    v[1] = v1
    return v

# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

# how to DebugActiveProcessStop()
# 0x413BE0
# 0x413A8E:           EB FE jmp self
# push 0              6A 00        ; lpNumberOfBytesWritten
# push 2              6A 02      ; nSize
# push 0x00413a8e     68 8E 3A 41 00        ; lpBuffer
# push 0x00413E73     68 73 3E 41 00 ; lpBaseAddress
# push 0xFC           68 FC 00 00 00 ; hProcess
# call    ds:WriteProcessMemory

# push 0x00010002    ; dwContinueStatus
# push 0x00001D84     ; dwThreadId
# push 0x000003D0      ; dwProcessId
# call    ds:ContinueDebugEvent

# push 0x00000368         ; dwProcessId
# call 0x76C32F40    ;DebugActiveProcessStop

# re_1 = [0 for i in range(32)]
# for i in range(4):
#     for j in range(8):
#         re_1[j*4+i] = inp[j*4+i] | re_1[j*4+i]
#         if i == 3:
#             break
#         else:
#             re_1[j*4+i] = re_1[j*4+i] >> 8
# example
# 61 62 63 64 65 66 67 68
# ==>
# 64 63 62 61 68 67 66 65
# change bytes to 8 round into 4 tytes
# inp = [0x12131415,0x12131415,0x12131415,0x12131415,0x12131415,0x12131415,0x12131415,0x12131415]
# for i in range(8):
#     re_inp = _byteswap_ulong(inp[i])

# 412F3A  breakpoint
# 19FCE0
# [0x73ff8ca6,0x22ffa762,0xd1ffc21e,0x80ffdccda]
# num  = 0x73ff8ca6 # [0x19FBB4]
# for i in range(8):
#     inp[i] = inp[i] ^ num
#     num = (num - 0x50FFE544)&0xffffffff

# reverse
# 61 62 63 64 65 66 67 68
# ==>
# 64 63 62 61 68 67 66 65
# for i in range(8):
#     re_3 = ((re_2[i*4] & 0xff000000)>>0x18)&0xff
# for i in range(8):
#     re_inp[i] = _byteswap_ulong(inp[i])

# init_dword_432358
# dword_432358 = [0x82ABA3FE, 0xAC1DDCA8, 0x87EC6B60, 0xA2394568, 0x432BEEE0, 0x2392B7C0, 0xC8C7FB80, 0xE7CC394D]
# reverse dword_432358
# 61 62 63 64 65 66 67 68
# ==>
# 64 63 62 61 68 67 66 65
# for i in range(8):
#     re_dword_432358[i] = _byteswap_ulong(dword_432358[i])

# tea(,,5)
# for i in range(8):
#     re_inp_1[i] = _byteswap_ulong(re_inp[i])
# inp = [0xC7ED9E12, 0x03C69E43, 0x7FA39EB0, 0xBBBD9EE1, 0xF7969E4E, 0x337361BE, 0x6F4C61EF, 0xAB26615C]
# print(len(inp))

# dec
print("----------------- dec --------------------")
dword_432358 = [0x82ABA3FE, 0xAC1DDCA8, 0x87EC6B60, 0xA2394568, 0x432BEEE0, 0x2392B7C0, 0xC8C7FB80, 0xE7CC394D]
cm = [0x000000ED, 0x000000E9, 0x0000008B, 0x0000003B, 0x000000D2, 0x00000085, 0x000000E7, 0x000000EB, 0x00000051, 0x00000016, 0x00000050, 0x0000007A, 0x000000B1, 0x000000DC, 0x0000005D, 0x00000009, 0x00000045, 0x000000AE, 0x000000B9, 0x00000015, 0x0000004D, 0x0000008D, 0x000000FF, 0x00000050, 0x000000DE, 0x000000E0, 0x000000BC, 0x0000008B, 0x0000009B, 0x000000BC, 0x000000FE, 0x000000E1]
# cm_1 = [0xEDE98B3B,0xD285E7EB,0x5116507A,0x]
cm_1 = [0 for i in range(8)]
for i in range(8):
    cm_1[i] = cm[i*4]<<24 | cm[i*4+1]<<16 | cm[i*4+2]<<8 | cm[i*4+3]
# print(cm_1)
dec = [0 for i in range(8)]
for i in range(4):
    enc = cm_1[i*2:i*2+2]
    dec[i*2],dec[i*2+1] = decrypt(enc,dword_432358)
print(dec)
num  = 0x73ff8ca6 # [0x19FBB4]
for i in range(8):
    dec[i] = dec[i] ^ num
    num = (num - 0x50FFE544)&0xffffffff
print(dec)
flag = b""
for i in range(8):
    flag += n2s(dec[i])
print(flag)



总结

主要是绕过Debug Blocker,附加子进程花了很多时间,下次再遇到类似的题目,应该会快很多。



版权声明:本文为qq_33438733原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。