HWS计划2021硬件安全冬令营线上选拔赛逆向部分wp
没有参加比赛,赛后复现一波re,感觉题都还可以,别的师傅说难度不大,但是我感觉对我来说挺难的😵
babyre
一道hook题,ida打开代码还是比较清晰的,首先判断长度然后在加密,但是我没有搞清楚这个hook的流程,听别的师傅说的在CRT的时候,从r3到r0时候hook的😥(听的不是很懂),但是我瞎找找到这两个函数
资源解密
资源加载
可以看出程序加载了一个叫CIPHER_DLL的资源,这个资源其实就是经过加密的DLL,我用ResourceHacker(一个可以查看程序资源的工具)来查看程序中的资源
程序中确实有一个叫CIPHER_DLL的资源,且这个资源需要解密才能使用,图中 wow! 就是证明,把这个资源的二进制文件提出来,在解密回去,得到一个DLL
import struct
import os
//解密资源
def ResourceDecrypt():
filepath = 'C:\\Users\\86180\\Desktop\\CIPHER_DLL101'
dllpath = 'C:\\Users\\86180\\Desktop\\DLL.dll'
key = 'wow!'
size = os.path.getsize(filepath) # 获得文件大小
with open(filepath, 'rb') as cipher_stream:
with open(dllpath, 'wb') as dll_stream:
for i in range(size):
data = struct.unpack('B', cipher_stream.read(1))[0] ^ ord(key[i%4])
dll_stream.write(struct.pack('B', data))
把DLL用ida打开,查看加密函数,字符串已经告诉我们是SM4加密,没有魔改.
from ida import ida_bytes
import pysm4
# 从ida中提取加密后的数据
def Dump_ida_data():
addr = 0x00BFA808
res = []
for i in range(32):
res.append(get_byte(addr + i))
print(bytes(res).hex())
# 利用GitHub上找的sm4脚本,写的解密函数
def Decrypt():
string = b'Ez_5M4_C1pH@r!!!'.hex()
key = 0x457a5f354d345f433170484072212121
cipher1 = 0xea6358b78ce2a1e9c5298f53e8083259
cipher2 = 0xaf1b67aed9dacfc472ffb1ec7673f306
plain1 = hex(pysm4.decrypt(cipher1, key))[2:]
plain2 = hex(pysm4.decrypt(cipher2, key))[2:]
for i in range(0,len(plain1),2):
print(chr(int(plain1[i:i+2],16)),end='')
for i in range(0,len(plain1),2):
print(chr(int(plain2[i:i+2],16)),end='')
# flag{42b061b4cb41cfa89ca78047bde1856e}
child_protect
参考看雪的一篇文章:https://bbs.pediy.com/thread-95082.htm
这道题考的是双进程守护问题,上面的文章和这道题类似,但是难点在于调试。
ida打开后发现主函数无法正常反编译,而且看到了int3中断异常指令。由于是双进程守护,需要找到创建子进程的地方
通过搜索CreateProcess函数,确定子进程由函数sub_413670创建
继续跟踪,确定了两个函数调用子进程,分别是sub_413BE0和sub_413950
而函数sub_413950是一个关键函数,他对子进程做了修改。如果想让ida正确的反编译,我们需要nop掉所有的int3指令,且按照程序修改部分指令,这里我用010Editor进行修改。
首先找到所有的int3指令
上图就是需要我们首先nop掉的地方,用010Editor修改后再次用ida打开可以发现主函数已经可以正常反编译,但是还不能够动态调试,
因为所有的过程都是在子进程中进行,但是我们现在已经修改了父进程的数据和子进程一样,所以可以跳过调用子进程的步骤,这需要修改一部分数据。
经过多次下断点调试后,定位到函数sub_413D10,修改过后就可以进行调试,但是还有一个坑。。
每次调试到这里的时候都会闪退,无论怎么调都没有用,最后我选择的办法是直接patch掉调用这个函数的指令,因为这步比较简单,且不影响后面的数据。
在可以动调后,就可以分析算法了,算法有两处,一处异或,一处tea加密,异或函数我将他pach,直接看tea处
tea加密的key是在运行时生成的,但是如果不动态调试也可以直接复制整个函数跑一遍也可以,我喜欢动态调试(懒)
生成了8个数据,但是只用到了前四个,后面只需要找到加密后的数据就ok了,这里我用idapython
import idc
from ida_bytes import *
import idaapi
def DumpCipher():
addr = []
res = []
start = 0x4122C8
end = 0x4123AE
curr_addr = start
dword = ''
while curr_addr <= end:
addr.append(curr_addr)
curr_addr = idc.next_head(curr_addr,end)
for i in range(32):
if i%4==0 and i != 0:
print(dword)
res.append(int(dword, 16))
dword = ''
data = idc.print_operand(addr[i], 1).replace('h', '')
if len(data) == 1:
data = '0' + data
elif len(data) == 3:
data = data[1:]
dword = dword + data
# print(dword)
res.append(int(dword, 16))
print(res)
#include <stdio.h>
#include <stdint.h>
void TEA_decrypt(uint32_t* v, uint32_t* k)
{
uint32_t sum = 0xC6EF3720, delta = 0x9E3779B9;
uint32_t v0 = v[0], v1 = v[1];
for (int i = 0; i < 32; i++) {
v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^