[安洵杯 2019]crackMe

查壳儿,没有,32 位,载入 IDA

首先根据字符串定位到函数 sub_412AB0

看到对 base64 码表进行了一个大小写的变换,得到新表 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"

接着使用向量化异常处理,进入 Handler

跟进一下 sub_411172,来到了这里

注意到 0xA3B1BAC6 是 SM4 的特征值,所以这个函数应该是在进行 SM4 加密,密钥为传入的 v2 即 "where_are_u_now?"

运行完这个函数后 SetUnhandledExceptionFilter 捕获异常,进入 TopLevelExceptionFilter

有一个 for 循环将 Str2 相邻两位互换,变成了 "U1ATIOpkOyWSvGm/YOYFR4!!"

然后看到 sub_411136 如下

将 Str1 与 Str2 比较,一致则输出 right,而我们已知 Str2,接下来看看 Str1 是怎么来的

来到上个函数中对 Str1 赋值的函数中

看起来就是一个变种的 base64 加密的过程,注意到 sub_4110FF 中有一处操作

这里相当将表右移 24 位,得到新表 "yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx"

而 Str1 赋值的函数传入的参数 byte_41A180 一路往上跟会发现来到了这里

查看输入的 unk_41A1E4 地址发现其与 byte_41A180 是连续的,可以视为一个

所以总的思路就是:输入内容经过 SM4 加密后再经过变表 base64 加密,结果应当与经过变换后的 Str2 一致

写脚本解密,先利用变换后的 Str2 解 base64

import base64
base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
diy_base = 'yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx'

s = 'U1ATIOpkOyWSvGm/YOYFR4!!'
ss = ''
for i in range(len(s)-2):
	ss += base[diy_base.find(s[i])]
ss += '=='
a = base64.b64decode(ss)
print(list(map(hex,a)))

得到:

['0x59', '0xd0', '0x95', '0x29', '0xd', '0xf2', '0x40', '0x6', '0x14', '0xf4', '0x8d', '0x27', '0x69', '0x6', '0x87', '0x4e']

然后解 SM4,并将结果转换为字符串,得到 flag

from pysm4 import encrypt, decrypt
cipher_num = 0x59d095290df2400614f48d276906874e
mk = 0x77686572655f6172655f755f6e6f773f
clear_num = decrypt(cipher_num, mk) 
print('flag{'+bytes.fromhex(hex(clear_num)[2:]).decode()+'}')

flag{SM4foRExcepioN?!}

posted @ 2022-01-19 20:37  Moominn  阅读(590)  评论(0编辑  收藏  举报