序
传送门:https://adworld.xctf.org.cn/task/
1、game
题目描述:菜鸡最近迷上了玩游戏,但它总是赢不了,你可以帮他获胜吗
题目思路:
-
下载获得一个exe游戏文件
翻译: 玩游戏,n是灯的序列号,m是灯的状态,若是第n个灯的m是1,它就亮,若是不是,它就灭。 起初全部的灯都关了,如今你能够输入n来改变它的状态, 可是你要注意一件事,若是你改变第N个灯的状态,(N-1)th和(N+1)th的状态也会改变, 当全部灯都亮起时,将出现flag。 如今,输入n,n的值域是[1,8]
-
拖入PE查看,是win32程序
-
丢到32位的IDA里,在函数名列表ctrl+f搜索main,然后进入main0函数F5反编译得到伪代码
-
结合第一步题意,当全部灯都亮起时,将出现flag。不难发现对应到代码就是8个if==1然后输出flag的部分。
于是就有了两种做法,一种是把sub函数的伪代码改成代码运行一遍。 -
另一种就是玩游戏比如随便输个2,发现1号和2号和3号灯亮着,其他是暗着的,所以把对应的条件改成1,2,3==1,剩下的不等于1,再去玩游戏即可输出flag。
-
对于修改,不难找到汇编指令中的代码为如下,右键修补,将jnz(等于的意思)改为jz即可。具体反汇编指令网上都可以找得到。
-
最后在编辑,修补程序,应用到输入文件。再去玩游戏就可以获得flag啦。
zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}
2、open-source
题目描述:菜鸡学逆向学得头皮发麻,终于它拿到了一段源代码
题目思路:
- 下载获得一片c语言文件。
不难发现,29行用三个argv参数计算flag,32行输出
- 对于三个argv参数,
第一个:不等于0xcafe就退出,那first=0xcafe
对于第二个,满足if条件就退出,那么第一个不满足的数就是25,second = 25
对于第三个,相等strcmp返回0,退出if条件,那argv[3]=“h4cky0u”
因此不难改出代码,把上面的都删了,对应变量设置成对应值然后运行即可。
c0ffee
3、simple-unpack
题目描述:菜鸡拿到了一个被加壳的二进制文件
题目思路:
- 获得一个文件,丢入PE中。发现:64位文件,upx壳
- 丢到64位IDA中,以二进制形式打开文件。
然后shift+F12 进入查找字符串界面,然后Ctrl+f查找flag,发现flag。
flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}
4、logmein
题目描述:菜鸡开始接触一些基本的算法逆向了
题目思路:
- 未知文件先PE一下,得到信息:64位文件,obj文件
- 丢到IDA64,将main函数反编译为C语言代码。
- 分析代码:
进入sub_4007C0)()
进入sub_4007F0();
最后sub_4007F0();
通过v4的计算代码,我们了解到flag的获取
因为v8, v7 v9 知道,所以不难写出代码。for(i =0; i < strlen(v8); ++i){ s[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]; }
RC3-2016-XORISGUD
5、insanity
题目描述:菜鸡觉得前面的题目太难了,来个简单的缓一下
题目思路:
- PE打开,32位文件
- 丢到IDA32正常打开,shift + F12搜字符串,ctrl+f搜flag。
9447{This_is_a_flag}
6、python-trade
题目描述:菜鸡和菜猫进行了一场Py交易
题目思路:
- 获得一个pyc文件,pyc文件就是py程序编译后得到的字节码文件 (py->pyc)
可以在线pyc文件反编译:https://tool.lu/pyc/
也可以下载一个离线的:pip install uncompyle
- 分析代码:
flag进行encode函数中的操作,得到‘XlNkVmtUI1MgXWBZXCFeKY+AaXNt’
所以我们只需要反向操作一遍即可。#-*- coding:utf-8 -*- import base64 def decode(message): s = '' imessage = base64.b64decode(message) for i in imessage: x = ord(chr(i))-16 x = x ^ 32 s += chr(x) return s correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt' flag = decode(correct) print(flag)
nctf{d3c0mpil1n9_PyC}
7、re1
题目描述:菜鸡开始学习逆向工程,首先是最简单的题目
题目思路:
- 先PE一下,32位
- 然后IDA32,反编译一下main函数
- 分析代码,可以看到,输入v9之后,与v5比较,判断我们输入的flag是否正确。分别进入if…else判断之后的输出。
追踪v5 进入ds:xmmword_413E34。 - 既然v5是个常量,那么肯定存在二进制中,所以01Edit直接打开搜flag和ctf,成功get flag。
DUTCTF{We1c0met0DUTCTF}
8、Hello, CTF
题目描述:菜鸡发现Flag似乎并不一定是明文比较的
题目思路:
-
先PE一下,32位
-
然后IDA一下,main函数代码
-
分析代码:
代码的的36行处进行了一个字符串比较,如果v10的值等于v13的值会反馈一个success的输出。v13的值在第15行给出,因此需要知道v10是怎么处理的。
代码的第18行对v10进行了初始化,并在32行进行了拼接处理。分析26-35行的循环,其逻辑是:依次取出用户输入字符串的字符,将字符值的ascii码值转成16进制的形式拼接到v10中。
因此,若想令v10的值等于v13的值,需将字符串v13中的值两个一组,当作16进制的值,换算成ascii码并转成对应的字符即可。得到的结果即为flag,也是要输入的内容。#-*- coding:utf-8 -*- a = '437261636b4d654a757374466f7246756e' for i in range(len(a)//2): print(chr(int(a[i*2:i*2+2],16)),end='')
CrackMeJustForFun
9、no-strings-attached
题目描述:菜鸡听说有的程序运行就能拿Flag?
题目思路:
- 先PE,32位
- 然后IDA,main函数代码
分析可知authenticate()函数储存着flag,进入函数
通过第10~13行代码,我们可以知道s2就是我们需要flag(ws为输入值)
回到authenticate()函数的汇编代码
通过第6~7行代码,我们可以知道eax储存着decryp函数返回的flag值,再保存到s2
decrypt函数
综上所述,我们需要的flag保存在eax中,因此我们可以将断点设置在decrypt函数处,单步执行后,eax保存着我们需要的值,再读取eax值即可。 - 进入GDB(Linux)
gdb 554e0986d6db4c19b56cfdb22f13c834 -q b decrypt #设置断点 r # 执行到断点 n #单步执行decrypt 函数 i r # 显示寄存器 x/6sw $eax #查看eax的值,6:显示6行数据,s:字符串形式,w:word(4字节)形式
9447{you_are_an_international_mystery}
10、csaw2013reversing2
题目描述:听说运行就能拿到Flag,不过菜鸡运行的结果不知道为什么是乱码
题目思路:
- PE一下,32位。
- IDA32一下,main函数代码
- 分析代码:
双击 sub_40102A() 查看其反编译代码,发现返回值恒为零:
而对于库函数 IsDebuggerPresent(),若程序处于调试模式下,则返回值为非零;若未处于调试模式下,则返回值为零。显然,程序不处于调试模式下,即无法满足 if 语句的条件。
双击 sub_401000() 查看其反编译代码,目测是对以上乱码数据的解密函数:
综上,解题思路大致为:进入 if 语句块,跳过调试断点,并执行解密函数,最终弹框输出 Flag。 - 修改过程:
在主函数的反汇编窗口中,核心的语句块如下方框。
int 3 中断即为调试断点指令,需将其改为空指令 nop。
将 jz short loc_4010B9 修改为 jmp short loc_401096。
将 jmp short loc_4010EF 修改为 jmp short loc_4010B9。
改完之后,在编辑修补程序,输出到应用程序, 再执行,即可获得flag。
flag{reversing_is_not_that_hard!}
11、getit
题目描述:菜鸡发现这个程序偷偷摸摸在自己的机器上搞事情,它决定一探究竟
题目思路:
-
先丢PE,64位
-
再丢IDA,看main代码。
-
接着其中一些参数的值看一下
其中值得我们注意的是t的值,t的值应该是0x53+‘harifCTF{???}’,即SharifCTF{???}
因此,t很有可能是储存flag的数组。
-
分析代码:
代码整体上可以分为3个部分
1~11 变量定义初始化
12~20 定义flag值
20~34 flag值写入文件
因此我们只需要将第二部分复现,输出flag即可。#include <stdio.h> #include <stdlib.h> #include <Windows.h> #pragma warning(disable:4996) int main(void) { char v3; __int64 v5; char s[] = "c61b68366edeb7bdce3c6820314b7498"; char t[] = "SharifCTF{????????????????????????????????}"; v5 = 0; while (v5 < strlen(s)) { if (v5 & 1) v3 = 1; else v3 = -1; *(t + v5 + 10) = s[v5] + v3; v5++; } printf("%s", t); system("PAUSE"); return 0; }
SharifCTF{b70c59275fcfa8aebf2d5911223c6589}
12、maze
题目描述:菜鸡想要走出菜狗设计的迷宫
解题思路:
-
PE,64位文件
-
IDA,main函数
-
代码分析:
打开asc_601060的字符串的视图,asc_601060 db ' ******* * **** * **** * *** *# *** *** *** *********',0。 可以判断出这一串字符实际上就是一个迷宫,通过'.', '0', 'O', 'o'来控制移动,V10实际上就是一个二维数组,一维表示X轴,二维表示Y轴。 我们能够知道,v9高位表示x轴,v9低位表示y轴, 通过函数sub_400690函数中是a2+a3*8,即a3表示行,a2表示列。返回到调用函数处,即v10高位表示列,低位表示行。那么就可以判断出'O','o'表示左右,'.','0'表示上下 通过a2+a3*8我们也能了解到这个迷宫有8行,总共64个字符,也就是8x8的迷宫,表示出来就是。
解迷宫
起点(1,1),只能走0,要走到‘#’,找到路径右下右右下下左下下下右右右右上上左左str = "右下右右下下左下下下右右右右上上左左" str = str.replace('上', '.') str = str.replace('下', '0') str = str.replace('左', 'O') str = str.replace('右', 'o') str = 'nctf{' + str + '}' print(str)
得到flag
nctf{o0oo00O000oooo..OO}