攻防世界逆向新手训练
本来是搞Web的(虽然菜的抠脚),但是战队缺reverse和pwn的人,正好自己对这方面也很有兴趣,于是就转了方向。刚学几天,先做上几道攻防世界的新手训练题。把自己做题的过程和学到的知识记录下来。由于我在做的过程中很多时候都是瞎试试出来的,所以记录的时候分成两部分,第一部分是【做题实录】,就是我做题的真实思考过程,flag可能是瞎猜猜出来的,有很多的运气成分在。第二部分是【分析总结】,是我在网上查阅大佬的“正确做法”,即通过分析和思考,用正统做法得出flag。分析总结中我会把我复现的写出来。由于我实在是逆向小白,可能大部分都是靠运气做出来的,大佬勿喷,估计以后再回头看自己的解法自己都要笑死了。
re1
题目描述:菜鸡开始学习逆向工程,首先是最简单的题目
做题实录
双击点开,让我输入flag

随便输一个:

看样子是要比较字符串的,放到OD里面看看,找到了比较字符串的地方,下断点

随便输入什么字符之后继续往下走,发现flag已经进入到了ESP中

分析总结
这个题非常简单,没什么好说的,其实放到OD里还可以直接搜索字符串,一步到位……

当然了,还可以用IDA直接看源码

看到strcmp()
函数,输入的是v9,和v5比较,所以数据就应该在v5里面,再看第10行,把xmmword_413E34
的值赋给v5,所以双击xmmword_413E34
看它的数据。把qword_413E44
和xmmword_413E34
的数据拼起来

你可以把qword_413E44
和xmmword_413E34
的数据拼起来用python把16进制的数转化成文本然后反向写出flag就可以了。
1 | print ('7D4654435455443074656D30633165577B465443545544'.decode('hex')) |
或者光标点击xmmword
的数据,按下a键,

确认就可以直接把它转化成字符串。(我也是后来才知道的,看来ida还是要好好学)

game
题目描述:菜鸡最近迷上了玩游戏,但它总是赢不了,你可以帮他获胜吗
做题实录
一个exe文件,打开如下:

让你玩游戏,赢了就有flag,于是玩三个小时玩通关拿到flag。放到OD里动态调试
一路走到这里让你输入n,估计接下来就是字符串比较了,随便输一个继续调试

这部分一整段都在判断灯的情况,调试的过程中发现只要判断出灯没有全亮,就会跳转回003EF4FB,没有进入game.003E7AB4,所以猜测是成功了就进入这里,于是进去看看

进来之后,果不其然,是成功的函数

接下来就运行这个函数,就可以得到flag

分析总结
这个题还是比较简单的,没啥好说的。再用IDA来试一下

进入main_0()
函数,看到判断语句,逻辑很简单

进入sub_457AB4()

这个程序就疯狂跳转,不知道要干啥
进去之后就是这样

可以直接写个脚本跑,在这里我选择改程序的逻辑,让它跳过判断直接执行这个函数

这一部分就是判断语句,只要把cmp edx, 1
改成cmp edx edx
那么条件就恒为真。
特别注意的是:
cmp edx, 1
占3个字节而cmp edx edx
占两个字节,所以最后一个字节用nop
填充。否则会出错
修改后如下:

保存之后双击运行,随便输入一个n,就可以得出flag

Hello,CTF
题目描述:菜鸡发现Flag似乎并不一定是明文比较的
做题实录
一个exe,运行结果如下:

要找序列号,IDA看一下:

看来flag就是这个绿色的字符串了,看到有字母有数字且字母不超过f,所以16进制解码试一下,得到flag:
CrackMeJustForFun
分析总结
这个题比较简单,我开始是用动态调试做的,都差不多,只要看到这个字符串基本上就可以解决了。
open-source
题目描述:菜鸡学逆向学得头皮发麻,终于它拿到了一段源代码
做题实录
源代码如下:
1 |
|
看到就是要输入规定的参数运行就可以了,注意这个参数要在命令行中输入。第一个参数直接跑个脚本:
1 | print(str(0xcafe)) |
第二个参数最小的是25,第三个参数h4cky0u
编译之后cmd运行,得到flag:

分析总结
分析源码,没啥可说的。
simple-unpack
题目描述:菜鸡拿到了一个被加壳的二进制文件
做题实录
UltraEdit打开看一下,搜索flag:

去掉中间的乱码,得到flag:
flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}
分析总结
直接查找确实是歪门邪道,毕竟这题是关于加壳的,所以UE看一下:

看到这是个upx的壳,那直接用upx脱壳就行了:

脱完壳查找flag即可:

logmein
题目描述:菜鸡开始接触一些基本的算法逆向了
做题实录
IDA里看一下:

第26行就是加密算法,写个解密算法就行了:
1 |
|
分析总结
这个题就是简单的算法逆向,没啥可说的。
insanity
题目描述:菜鸡觉得前面的题目太难了,来个简单的缓一下
做题实录
IDA打开,查找flag,得到flag:

分析总结
实际上这个题就直接运行,等上几秒它会随机给你输出一些字符串,我第一次运行就直接得到了flag……

no-strings-attached
题目描述:菜鸡听说有的程序运行就能拿Flag?
做题实录
这是个32位的elf文件,ubuntu里跑一下,出来一堆不知道是啥的东西。

IDA打开

这个authenticate()
看着很可疑,进去看看:

看到一个decrypt(...)
,估计就是它了,进去看看

看样子是一个解密函数,在decrypt(...)
下断点进行动态
调试,进入while循环Hex
View跟踪EAX(因为函数返回值就存在EAX里),可以看到flag正在被解密出来,继续往下走

解密完成,得出flag,去掉0x00就是最终的flag,由于题目来源9447CTF,所以没有前面的1。

分析总结
我看了一下,基本上都差不多,不过很多都是用gdb调试的,没用过gdb,正好趁这个机会学习一下,写一下gdb调试的方法。
进入gdb后输入 file no-strings-attached 开始调试程序
然后在decrypt()
下断点,用命令 break decrypt
按n是单步步过,s是单步步进,啥也不输直接按回车默认执行上一条指令
单步执行到这里发现EAX里面存了9,是flag的开头

记下此时EAX的位置0x804cff0,输入 finish 让程序执行完当前的函数并返回

查看EAX的内容,输入命令 x/100u $eax (该命令具体使用方式参见GDB下查看内存命令(x命令))

写个脚本跑出来就行了
1 | s=[57,52,52,55,123,121,111,117,95,97,114,101,95,97,110,95, |
getit
题目描述:菜鸡发现这个程序偷偷摸摸在自己的机器上搞事情,它决定一探究竟
做题实录
这是个elf文件,在ubuntu里跑了一下发现没反应,放到IDA里看一下

看样子估计是个解密flag的,看了看数据段发现了t是flag(IDA里面按a把ASCII码变成字符串),但是内容不知道


我猜while循环应该就是解密的,于是动态调试一下。

可以看到在循环的过程中下面flag就已经出现了,继续调试得出flag

分析总结
这个题其实也可以不用动态调试,因为while循环里转换算法都写好了,自己按照源码写个脚本跑就行了。
1 | s = 'c61b68366edeb7bdce3c6820314b7498' |
python-trade
题目描述:菜鸡和菜猫进行了一场Py交易
做题实录
下下来是pyc文件,放到ubuntu里面,用uncompyle反编译(下载过程也踩了很多坑……)并保存到tes.py
1 | uncompyle6 Py.pyc > tes.py |
得到源码:
1 | # uncompyle6 version 3.3.5 |
是一个加密的程序,那按照它的步骤解密就行了,是一个算法逆向的题。
解密代码如下:
1 | import base64 |
分析总结
这题没啥好说的,就是算法逆向。但是安装使用uncompyle遇到点问题,也记下来吧。
1 | pip install uncompyle |
然后使用的时候需要输compyle6,我在输了之后一直提示我“command not found”,后来发现需要执行这两条命令安装环境变量
1 | export PATH=$HOME/bin:/usr/local/bin:$PATH |
csaw2013reversing2
题目描述:听说运行就能拿到Flag,不过菜鸡运行的结果不知道为什么是乱码
做题实录
拿到的是个exe文件,双击运行结果如图:

正如描述所说,是一堆乱码,放到OD里看一下。
发现这个位置就是弹出flag的位置。

在这儿设个断点,然后进去仔细看。
进来之后看这个函数,发现有两个MessageBox函数,觉得有蹊跷,于是在00B01094处取消跳转,让它往下走看看有什么反应。

在走的时候把int3用nop填充,00B010A3处的jmp跳转也用nop填充
走到第一个MessageBox,弹出了一个flag,但是什么也没有

于是点击忽略继续往下走,又遇到了jmp跳转,同样nop填充
走到这flag已经加载进内存了。

分析总结
方法一:直接修改程序逻辑
参考【XCTF 攻防世界】 Reverse —— csaw2013reversing2
由于是个32位的PE文件(linux下用file命令查看),所以用ida pro打开,F5反编译,生成类C语言的伪代码如下:

lpMem就是flag的内容。看第10行if语句,如果sub_40102A()
或IsDebuggerPresent()
返回值为真则执行__debugbreak()
调试断点函数、子函数sub_401000(...)
和退出进程函数ExitProcess(...)
函数,否则直接执行MessageBoxA(...)
函数弹出flag框。
打开sub_40102A()
函数看一下:

发现返回值恒等于零,那就是说只有在调试状态下才会执行if里面的语句。由于直接双击运行没有在调试环境下,弹出乱码的flag,所以可以肯定if里面的语句是关键点,应该包含解密flag的函数。
打开sub_401000(...)
看一下:

看样子是个解密函数,那应该就是它了。那么思路就很清晰了,我们要让程序跳过if判断,直接执行sub_401000(...)
函数,然后再跳过ExitProcess(...)
函数执行MessageBoxA(...)
函数弹出解密后的flag框。
既然思路已经清晰那么就开始修改程序吧。
这是原本的逻辑:

使用IDA修改指令的方法是将光标放在要修改的指令上,依次点击Edit -> Patch program -> Assemble,弹出指令修改框进行修改。
修改之后逻辑如下:

红色标注的就是修改过的地方。修改完成后要保存到文件,依次点击 Edit -> Patch program -> Apply patches to input file…,弹出设置框,选择待打补丁程序进行修改。
最后双击运行修改后的程序,直接弹出已解密的flag框。

方法二:DLL注入
maze
题目描述:菜鸡想要走出菜狗设计的迷宫
做题实录
打开IDA看了半天源码,不知道和迷宫有啥关系,以前没做过这种题,还以为是代码不停跳转什么的,还是最后看了wp才明白,真的是个迷宫(吐血)。还是要做题,提高自己的姿势水平,不然就太naive了。
分析总结
这是个64位的elf文件,放IDA里看一下main函数

(请无视我刚开始看的时候做的注释)首先看第13行,判断输入的字符串,从这里可以看出要求输入的flag长度为24,且以 'nctf{' 开头,以 '}' 结尾(最后的 '}' 本来是ASCII码,在IDA里把光标选择ASCII码按R键就可以把ASCII码变成字符了)。
由于是迷宫,一般是二维的,所以应该有一个记录坐标的变量,看到v9,在判断中有一个&v9
和(&v9)+1
(也就是v9跟着的的下一个字节的地址),那么可以猜想v9就是一个记录位置坐标信息的二维数组。那么while循环就是在判断输入的字符来改变坐标信息,也就是用户输入字符来走迷宫。
正常来说,v9和v9+1对应着迷宫的行和列(别问我为啥不是列和行,我觉得正常讲话就是行在前,所以自然而然想到行和列。就算不对那到时候再改吗,反正就两种情况。而且下面的分析可以确定就是对应的行和列)。
既然是走迷宫,当然就得判断走没走到终点,看到了第72行的“Congratulations!”,那看一下它前面第70行的判断,判断坐标所在,如果是“#”,就到终点了,说明“#”号就代表终点。而且看一下asc_601060

有个“#”,看来这应该就是迷宫的地图了。我们的目标就是要走到“#”处。再回过头来看8*v9+SHIDWORD(V9),既然是坐标,说明v9就代表行,而v9+1代表列,而且可以知道迷宫的地图应该是8个字符一行的(因为行增加一,数就增加8)。
至于这个LABLE_15,每走一步都要进入这里,应该就是判断有没有越界什么的函数。
现在基本上就已经理清楚了这个迷宫,只要知道怎么走就行了。while循环里的函数如下:
1 | //因为是&v9+1,所以是判断列,也就是左右走 |
总结一下:“.”往上走、“0”往下走、“O”往左走、“o”往右走
拿个脚本把地图写出来(python是真的好用)
1 | map = ' ******* * **** * **** * *** *# *** *** *** *********' |
要求步长为18,从左上角开始走,走到“#”的位置,走就行了,最后结果为
nctf{o0oo00O000oooo..OO}