平时也经常在buu练题,练到后面收获越发的多。便想着记录下来。
0x00 初步分析
尝试运行的时候发现不可以,好吧,直接查壳:
0x01 查壳脱壳
简单的upx壳,但是由于也不能运行,直接自动脱壳吧:
脱完壳还是不能运行,估计是需要修复,懒人直接上IDA,shift+F12可以看到关键字符:
0x02 代码分析
直接转过去试试能不能反编译,直接进入查看伪代码。那就直接分析它的算法吧:
可以看到我们的输入保存在Source字符串里面;返回上一层看看对这个字符有哪些调用:
可以看到在main函数里sub_4110FF就是刚刚调用输入的函数,注意这里有一个strcpy操作,此时Dest和Source都是输入。CreateThread则是Windows下创建多线程的操作。这里创建了两个线程,可以看看这两个线程分别在干嘛:
可以看到这两个线程唯一的区别就是StartAddress函数里有一个神秘的sub_41112C函数,这里猜测可能是对Source的加密过程。直接进去看看就知道了,然后这里就遇到问题了:
这里的栈顶指针有问题,需要修复,这里alt+K快捷修复就好(本来的SP是 -0x4,我改为了-0x8。but 这里我不太懂 /手动狗头),再次反编译就可以看到伪代码啦:
这里逻辑还是比较简单的,输入的字符串Source依次进入这里加密,加密的过程为:
- 当为大写字母时,转换为ascall码,减去38后的值作为off_418000字符串的下标,取出对应的字符作为返回值;
- 当为小写字母时,转换为ascall码,减去96后的值作为off_418000字符串的下标,取出对应的字符作为返回值。
这里唯一的区别就是减去的值不同,这么做的目的就是:
- 大写的范围为 65 ~ 90 减去38之后为 27 ~ 52;
- 小写的范围为 97 ~ 122 减去96之后为 1 ~ 26。
刚好1 ~ 52 不会重复,需要注意的是,这里不是0开头。反正大家懂就好。
这里需要特别注意的是 ,因为创建了两个线程,根据多线程的调用原则,这里是两个线程一次运行,既加密线程和空线程轮流运行。最开始是从29逆序开始的,所以Source下标为奇数的则加密,偶数则保留。顺序在这里并不会影响加解密 。
现在只需要确认加密后的Source就可以解密出原flag了。回到main函数可以看到最后还有一个sub_411190函数,点进去康康。
这里的Dest则是最初的Input,而Source则是加密后的Input。off_418004可以查看,是 “TOiZiZtOrYaToUwPnToBsOaOapsyS”。
0x03 exp
分析到这里,已经知道了这个程序的基本过程,写exp解密就好:
M = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
puts = "TOiZiZtOrYaToUwPnToBsOaOapsyS"
flag = ""
for i in range(len(puts)):
if i%2 != 0:
j = M.index(puts[i])
if j <= 26:
flag += chr((j + 96) )
else:
flag += chr((j + 38) )
else:
flag += puts[i]
print(flag)
#ThisisthreadofwindowshahaIsES
0x04 番外
你以为这就结束啦?No~ No~ No~ 在Source加密处理的过程中,是从下标29开始的,也就是说,应该有30个字符才对,但是解出来的flag只有29位。在我提交的时候就一直提示不对,看了大佬们的wp才知道最后需要补充一个E,
既flag{ThisisthreadofwindowshahaIsESE}
至于为什么,我也不知道……