写在前头
本题来自安洵杯2019 crackMe,涉及到的知识点较多,Mark一下
分析
从main开始
反编译main函数,9行这里触发了一个内存写异常,有点奇怪哈
发现SEH
查看汇编,哦这里注册了一个SEH函数,sub4100F
跟进去看一下,很简单的算法,input划分为4个4字节的值,赋给v5,v5数组按照往后递推的方式,由前4个单元生成后1个单元的值,最后逐个字节取v5[32]到v5[35]的值赋给out
sub_411700长这样,第一个v5单元的值和sub_41170函数异或,函数的参数为v5后三个单元和key的异或,最后计算的值再赋给第5个v5单元
都是异或运算,这个算法要逆过来也很简单,知道最后4个单元的值,往前一个个推就能知道v5[0]到v5[3]的值了,递推规则如下,sub_411760都不用逆,照着IDA抄一下就行
v5[i] = v5[i+4]^sub_411760(v5[i+1]^v5[i+2]^v5[i+3]^(key+4*i))
后面才知道sub_4119f0这个算法叫做sm4,有现成的求逆API可以直接调用
input是用scanf读进来的,如果知道key和out,就可以恢复input
sm4生成box
看一下对key的引用,定位到了Handler_0,一个字符串拷贝到v2,经过运算生成key,和输入没关系是吧,那key可以直接动调获取
其实sub_411172就是用来生成sm4 box的函数,第19行那个异或的数是sm4的一个特征值
发现UEH
继续看一下Handler_0第9行,这里注册了一个UEH函数,点进去分析一下,这里的Str2是固定的一串字符串,顺便还看到了sm4生成的output,output经过sub_41126c计算得到Str1
进入sub_41126c看一下,一眼base64,28行这里=换成!,30行这里对编码表凯撒右移了24位
字符串比较
UEH这个函数返回时eip被修改为sub_411136,点进去看一下,发现是最终的字符串比较,Str2是固定的,Str1由input经过sm4加密和变种base64加密生成
发现VEH
还有一点没搞清,Handler0是如何被调用的,查找交叉引用,定位到sub_412AB0,该函数对base64编码表大小写进行了变换,然后注册了VEH函数来调用Handler
IAT hook
继续向上找引用,这里传入了User32.dll和MessageBoxW,是要搞什么鬼
对里面调用的函数进行符号还原,前面就是找到 user32.dll 对应的 IMAGE_IMPORT_DESCRIPTOR 结构体地址,然后找到 MessageBoxW 对应的 IMAGE_THUNK_DATA 结构体地址,用VirtualProtect修改页属性为可写,用WriteProcessMemory将IMAGE_THUNK_DATA字段覆写为sub_411023函数地址
总结一下,典型的IAT hook,将MessageBoxW的IAT地址替换为了sub_411023的函数地址,该函数完成了VEH的注册
mainCRTStartup对构造函数的初始化
还没完,继续分析这个IAT hook函数是被谁调用的,引用回溯到了rdata这里,往上翻翻
这个地方被tmainCRTStartup调用了
看看tmainCRTStartUp函数,32行这里initterm_e调用了rdata区域里保存的函数,对全局/静态C++类的构造函数进行了初始化
总结
上面的分析是根据结果查找原因,倒着推回去的比较乱,下面再梳理总结下
异常处理的注册
- 程序初始化时,调用链为start->tmainCRTStartUp->initterm_e->IAT hook,修改MessageBoxW函数的IAT表,在主函数中调用MessageBoxW,实际调用的是注册VEH的函数,并对base64编码表进行了变换
- 在main函数中对SEH进行了注册
- 在VEH handler中对UEH进行了注册
异常处理的回调
-
需要知道一个知识点,Windows 用户态异常发生先找调试器,没有再找 VEH,VEH 处理不了再找 SEH, SEH 还处理不了找 UEF
-
main函数中触发内存写异常,本程序各级异常处理的返回状态都是未完成处理,会继续往下级调异常处理函数,所以本程序的调用顺序为VEH->SEH->UEH
-
VEH中对sm4的box进行了初始化
-
SEH中对input进行sm4加密,获得output
-
UEH中对output进行变种的base64加密,获得Str1,并且和变换过的固定字符串Str2进行比较
总之,题目的算法分析和还原很简单,麻烦的是这些算法没有集中在main中,而是分散到了各个异常处理函数里面,跳来跳去的对分析造成了干扰,不过只要足够有耐心,不断向上查找引用,还是能分析完的
题解
import base64
import sm4
ori = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
now = ''
# sub_412AB0
for c in ori:
tmp = ord(c)
if 97 <= tmp <= 122:
now += chr(tmp - 32)
elif 65 <= tmp <= 90:
now += chr(tmp + 32)
else:
now += c
ori += '='
now = now[24:] + now[:24] + '!' # sub_4110FF -> sub_412760
# ori = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
# now = yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx!
# sub_412C30
str2 = "1UTAOIkpyOSWGv/mOYFY4R!!"
str2_swap = ''
for i in range(0, len(str2), 2):
str2_swap += str2[i+1] + str2[i]
# sub_41126C -> sub_413090
b64string = ''
for s in str2_swap:
b64string += ori[now.find(s)]
sm4_encoded = base64.b64decode(b64string)
# sub_412EA0
key = sm4.SM4Key(b"where_are_u_now?")
print key.decrypt(sm4_encoded)
标签:buuctf,sub,sm4,re,v5,key,刷题,VEH,函数
From: https://www.cnblogs.com/z5onk0/p/17506136.html