下载到程序,没有加壳,直接拖入IDA查看
main函数逻辑很简单

可以知道输入的长度是26,输入的内容不包括flag{xx},有两个判断函数。很明显第二个有些奇怪,并且进去后也是乱码。

先看第一个函数,前面有一大段复杂的代码

可以从v3判断出是处理了8个输入,不过具体干什么不清处,先放着。
紧接着又处理了2个字符

具体干什么也不清楚。

这里有一个is_input_ok判断输入是否合法,输入合法进入下一步操作,上面对lpBuffer进行了加解密操作,这里的是SSE指令。

do while循环里面就是典型的加解密操作,需要的参数就是 v20和v8,n16如果上面进行了SSE指令就会赋值为16,处理剩下的32字节。
v22和v25就是时间差反调试,__rdtsc获取当前CPU时间戳,如果出现调试,字节写入0地址引发异常。
下面就是将lpBuffer处的数据复制了96字节到lpBaseAddress中,让main函数里面lpBaseAddress恢复其功能。
目前还不知道前面10位的flag,我们可以直接在x64dbg中修改WriteProcessMemory的参数,把lpBuffer改成target_pwd地址,直接dump出副本。顺便看看上面的代码干了什么事情

输入 12345678AB,观察寄存器

可以发现前面8位直接转换成数字,剩下两位还在EDX上。这里比较难看出什么逻辑,可以观察XMM寄存器

XMM0和XMM5都被循环赋值了,上面的代码仔细静态分析也能得出这个结论。我们暂且放着
回到写入内存中,我们强行修改while循环里面的判断,让其直接进入写内存操作中。

直接dump出来,这里需要处理好OEP

这里就恢复了第二个判断函数,现在我们来分析一下第二个函数干了什么

这里是以8byte为一组做了加密,我们也能找到密钥:AFSAFCEDYCXCXACNDFKDCQXC
并且调用插件FindCrypt也能找到DES_Long常量,基本就可以判断就是DES加密
不过只是普通DES加密是不需要26字节长度的密钥的,并且密钥是分三组输入sub_401500,进入这个函数查看也能发现:

猜测是常规的DES3加密,先随便输入一个试试,再VS使用openssl加密测试
1 | DES_cblock orkey[3]; |

测试数据完全吻合,说明就是des ecb 3加密

加密的数据就在上面,一共16个字节,多出的8字节可以不用管
1 | DES_cblock orkey[3]; |
解密出

0dcc509a6f75849b
这是后面16字节的flag,现在来解决前面10位。我们已经知道了前面10位会处理为整形,并且存放再XMM寄存器中参与解密操作,我们仔细分析一下lpBuffer参与的解密代码:
1 | lpBuffer_[0] = (__int128)_mm_xor_si128( |
v20其实就是 XMM4,v8就是只有两位的。SSE的寄存器结构就是一个[x1,x2,x3,x4],每个都是32位,128bit的结构。上面代码可以简化成:
1 | lpBuffer_[0] = (XMM3+v8)^(v20+lpBuffer_[0]) |
这里的加法和异或都是4个32bit独立进行的,不会产生进位。下面的3行也是这样,只是多了一步加法。
我们可以使用z3求解器解出合适的解
1 | from z3 import * |
最终可以求解出:1324223816
最终的flag就是flag{13242238160dcc509a6f75849b}
题目还是比较有难度的,考的知识点也比较多,识别3DES还是比较有难度的,SSE指令集也比较复杂,很容易把人劝退,z3求解也是需要稍稍思考