Analyse
文件分析
exe程序,可以通过exeinfo对其架构进行查看
可以看到程序为64位,检测出存在UPX加壳
解题
1. 脱壳
存在UPX加壳,尝试使用UPX脱壳工具,但是均未果
这道题采用了一些技巧防止直接脱壳,也是一个可以学习的知识点,具体可以看参考链接
使用010editor打开Re2.exe,观察发现
这里需要对UPX加壳后的数据特征有一定的了解。UPX在加壳时,会修改文件的结构,以便在运行时动态地解压原始的代码和数据。为实现这一点,UPX会在加壳后的文件中添加一些新的段。
-
UPX0:这个段包含了被压缩的原始数据,在文件中,这个段的大小通常是0,因为它只是一个占位符,当程序运行时,这个段会被解压到内存中
-
UPX1:这个段包含了被压缩的原始代码。和UPX0一样,它在文件中的大小也可能是0,但在程序运行时,这个段会被压到内存中
-
UPX2:(如果存在的话)这个段包含了UPX的解压缩代码。当加了壳的程序启动时,这段代码首先会被执行,以解压UPX0,UPX1的数据和代码
所以这里UPX脱壳失败的原因应该是将区段名UPX0
,UPX1
修改成了FUK0
,FUK1
通过010editor或者winhex修改这两个段名,保存
就可以对程序进行正常的UPX脱壳了,比如我们可以使用kali在终端upx -d
进行脱壳
2. 逆向分析
拖进IDA分析
main_0()
看到程序会先要求用户输入flag,并最多获取200个字符。接着进入sub_1400112235()
这个函数,并且传入刚才用户输入的字符,如果返回为0,则输出"Wrong."并且程序退出了。那么sub_1400112235()
这个函数应该会对用户输入进行判断
跟进sub_1400112235
可以看到v7 = j___intrinsic_setjmp(Buf, v6);
,这个j__intrinsic_setjmp
是什么作用呢,我们来看看setjump
和longjmp
setjmp
和longjmp
是C语言中实现非本地跳转的两个函数,它们允许程序从一个函数直接跳转到另一个函数,而不需要正常的函数调用和返回机制。这种跳转机制通常用于处理错误和异常的情况。(现代编程相对较少,可能会导致代码难以维护)
-
setjmp
-
setjmp 用于保存当前的执行环境(包括程序计数器,堆栈指针,和其他重要的寄存器)
-
首次调用setjmp时返回0
-
后续使用longjmp跳转到这个setjmp的位置,setjmp将返回一个非零值,这个值是longjmp提供
-
-
longjmp
- longjmp主要用于恢复之前由setjmp保存的执行环境,这导致程序从setjmp的位置重新开始执行,就好像setjmp刚刚返回的一样
- longjmp需要两个参数,一个是jmp_buf(保存的环境变量)和一个整数值,这个值将成为setjmp的返回值(不为01)
那么这里首次setjmp
,返回值(v7)为0,则会进入sub_140011230()
绕了半天, 终于发现这里会对用户输入的字符串进行长度判断,要求长度等于20。接着对字符串每一位和0x66进行异或,异或完跳转到setjmp处,并返回20
好的,sub_1400112235
这条线跟完了,接着回到main_0()
程序又进行了setjmp v7 = j__intrinsic_setjmp(stru_14001D330)
并且进入sub_1400111E5()
for ( j = 0i64; j < v8; ++j )
sub_140011276((unsigned int)j, (*(char *)(j + a1) + 10) ^ 0x50u);
注意这里,v8也就是a2,也就是20。程序将字符串的逐个+10后和0x50异或,再传递给函数sub_140011276()
这个函数将异或的值与dword_14001D000
进行比较,如果存在不同,则会跳转到上一个setjmp的位置,并且返回1
查看dword_14001D000
4Bh, 48h, 79h, 13h, 45h, 30h, 5Ch, 49h, 5Ah, 79h, 13h, 70h, 6Dh, 78h, 13h, 6Fh, 48h, 5Dh, 2 dup(64h)
综合一系列的过程,总结一下,该程序实现了对字符串的长度判断(20),接着与0x66
进行了异或,每位加上10再与0x50
进行了异或,最后与dword_14001D000
进行比较
3. Reverse script
key = [0x4B, 0x48, 0x79, 0x13, 0x45, 0x30, 0x5C, 0x49, 0x5A, 0x79, 0x13, 0x70, 0x6D, 0x78, 0x13, 0x6F, 0x48, 0x5D, 0x64, 0x64]
flag = []
for i in range(20):
flag.append(((key[i] ^ 0x50) - 10) ^ 0x66)
for i in flag:
print(chr(i), end="")
#why_m0dify_pUx_SheLL