博主也是CTF小白,入门ing。。。方向是RE + PWN。文章可能多有纰漏,但会持续更新更正。希望大家多多指出不足之处。
0x1. re1
解析:
这道题很简单:
打开.exe随便输点东西进去,发现不对,退出。
用IDA打开,点到十六进制视图
点IDA视图–打开子视图–字符串(英文版IDA应该就是view这种常见的单词)。或者直接按shift+F12。然后在一大堆东西中找到这个:flag get
英文应该都能看懂吧······这就是关键
双击,跳到十六进制视图窗口就可轻松获得flag:DUTCTF{We1c0met0DUTCTF}
0x2.game
n是灯的序列号,m是灯的状态
如果第N个灯的m为1,则它打开,如果不是,则关闭
起初所有的灯都关闭了
现在您可以输入n来更改其状态
但是你应该注意一件事,如果改变第N盏灯的状态,第(N-1)和第(N + 1)的状态也会改变
当所有灯都亮起时,将出现标志
现在,输入n
(来自谷歌翻译·······QAQ)
解析:
依旧什么都不用管,直接拖到IDA打开
shift+F12
Alt+T(搜索字符串),搜索: flag
直接跳出来:done!!!the flag is
双击,跳到IDA View-A(这里说一下,字符串窗口双击跳转的窗口是打开字符串窗口时停留的窗口。也就是说,当你页面停在IDA View-A时,你打开了字符串窗口,那在字符串窗口双击,就跳转到IDA View-A)
Ctrl+X(交叉引用)
F5(生成伪代码)
如下图
这里我们就初步接触到了逆向的加解密,加解密其实也就是算法的使用。这里加密比较简单,甚至都不能称为加密。*(&v2 + i)的值练起来就是flag的值
所以得到解密代码:(博主使用python,其他语言均可)
#v2:原代码v2-v58的值
v2 = [123,32,18,98,119,108,65,41,124,80,125,38,124,111,74,49,83,108,94,108,84,6,96,83,44,121,104,110,32,95,117,101,99,123,127,119,96,48,107,71,92,29,81,107,90,85,64,12,43,76,86,13,114,1,117,126,0]
#v59:原代码v59-v115的值
v59 = [18,64,98,5,2,4,6,3,6,48,49,65,32,12,48,65,31,78,62,32,49,32,1,57,96,3,21,9,4,62,3,5,4,1,2,3,44,65,78,32,16,97,54,16,44,52,32,64,89,45,32,65,15,34,18,16,0]
s = ""
for i in range(57):
v2[i] = v2[i] ^ v59[i]
v2[i] = v2[i] ^ 19
s += chr(v2[i])
print(s)
得到flag:zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}
0x3.Hello,CTF
解析:
老办法,遇到.exe直接打开看看是啥玩意儿。随便输,发现会弹出来wrong,输出巨长字符串后会直接退出
拖到IDA打开,shift+F12
发现和我们的程序中有一个东西是匹配的:“wrong!\n”,关键点get到!
双击进IDA View-A,Ctrl+X,F5
简单的逻辑推理:
v9为我们的输入,长度≤0x11(10进制的17)
v10储存的就是v9,和v13进行比较。相同就success
到这里我们就知道输入必须就是v13这个字符串相同。但是发现引号中字符数>17,所以判断这是个16进制数表示的字符串(ASCII码),用网上16进制转字符串得到flag:CrackMeJustForFun
0x4.open-source
拿到源码了嘤嘤嘤,就直接IDE打开不解释!
源码如下图:
解析:
这个题不用逆向也能做,纯源码分析就能得到答案。
逆向做法:
随便输入几个参数编译链接执行发现wrong
拖IDA,shift+F12,发现“Get your key:”,双击,Ctrl+X+确定,F5
发现v3就是key,写出代码求得v3
v3 = 11 * (25 % 17) + 1628458542 + len("h4cky0u") - 1615810207
print(v3)
得到12648430,转16进制得到flag:c0ffee
0x5.simple-unpack
解析:
从题目就知道需要脱壳,但是让我们假装不知道QAQ!依旧还是拖到IDA里面看看,果然!
什么都看不懂······那还是老步骤:shift+F12,发现了一个关键字:upx,说明他是upx压缩的文件,所以就需要upx解压
这里博主还是推荐大家装一个kali,双系统或者虚拟机都可以。如果原本就用的Ubuntu等Linux可以忽略这句话QWQ
upx -d filename脱壳
拖到IDA,shift+F12直接得到flag:flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}
0x6.logmein
解析:
日常拖IDA,shift+F12
第一次经验性进You entered the correct password!\nGreat job!\n,发现反编译出来的函数没啥用,所以第二次选择进输入点Enter your guess(类似于找OEP时先找PUSHAD和POPAD)
逻辑分析:
v8是给定的字符串,v7是long long的数据类型
s是输入,v3是s的长度,v3必须≥v8的长度17,否则会进入提示输入错误的函数sub_4007C0()
重点是:(_BYTE *)&v7的意思是,把longlong型的v7强制转化为byte型的地址,简单的说,就是把它看成字符串(C语言字符串本质都是指针首地址+偏移)。
所以我们用先用v7的值10进制转16进制,然后16进制转文本得到:ebmarah
重点来了!为什么直接套这个字符串不对,根本原因是因为在机器虚拟化内存后,规定地址排列规则时使用了小端法(最低有效字节在前面)。因此我们真正的解码文本应该是把上面的答案倒过来写:harambe
v8 = ":\"AL_RT^L*.?+6/46"
v7 = 'harambe'
for i in range(len(v8)):
char = ord(v7[i % 7]) ^ ord(v8[i])
print(chr(char),end='')
得到flag:RC3-2016-XORISGUD
当然个人感觉最简单的办法还是C++重现一遍。。。就不用考虑这么多
#include <iostream>
using namespace std;
int main(){
long long v7 = 28537194573619560;
char *p = (char*)&v7;
char v8[] = ":\"AL_RT^L*.?+6/46";
for(int i = 0;v8[i]!=0;i++){
v8[i] = v8[i]^p[i%7];
}
cout<<v8<<endl;
return 0;
}
0x7. insanity
解析:
这个真的不知道咋解析······至于为啥放这里,也许就和题目所言一样吧,希望大家身心愉悦继续肝吧·······
拖IDA,shift+F12直接拿到flag:9447{This_is_a_flag}
0x8.no-strings-attached
这个题是真的有难度QAQ
解析:
正常步骤拖到IDA静态分析,shfit+F12,发现第一行赫然出现:/lib/ld-linux.so.2。看见这个大家心里应该都有数了,和linux有关没跑了。同时也说明这是个ELF文件
字符串没有关键字,就从IDA左边函数列表找到main函数双击进去,F5反汇编,再进到authenticate函数看看(有的东西做多了就知道了),如下:
此时就真的看英语了······计算s2的函数decrypt正是非常专业的术语:解密。
粗略的看一下下面的伪码,得出:ws是输入,ws==s2时就是正确的flag
此时我们需要转变一下思维:之前我们都是各种找、各种逻辑推断正确输入。但是我们忽略了一件事,那个与输入的比较的正确答案,一定是加载到内存里面之后,才与输入比较。要是我们能跟踪到这个正确答案储存在内存的位置然后把他拿出来,这不也行嘛!!!(Reverse!)
思路有了,还需要实际的操作。这里就不能用静态分析了。这里插一句,我们逆向分析分为静态分析和动态分析,直接拖到IDA反汇编看伪代码,逻辑推断等等都属于静态分析。换言之,在没有执行程序或程序是静态时的分析。
所以要用IDA动态调试ELF—IDA remote linux debugger
环境配置参考IDA动态调试ELF写的非常清楚
为了检验连通性,可以看看kali的命令行,如下图
首先我们进入authenticate,F5,点左边设置断点,如下图(在s2刚被赋值完毕后停止,找s2的值)
然后按F9,编译链接运行到断点停止,如下图
这个时候,我们看到了s2就储存在寄存器eax中,所以我们在下面的Hex View窗口中右键,synchronized with,选eax,就能看到值啦,这就是flag,如下图
至此拿到flag:9447{you_are_an_international_mystery}
0x9.csaw2013reversing2
解析:拖到IDA中分析发现有重要的函数IsDebuggerPresent(),这个函数目的就是反调试(检测是否处于调试环境中)。既然如此千方百计阻止我们调试,那就直接OD动态走起。
我们拖到OD中,ctrl+n找到IsDebuggerPresent(),确定他的位置之后下断点开始调试程序,发现底下有两个对话框的代码(能看见注释那里有Flag,Text字样就ok),手动F8看一次,发现00C61000那里的函数没有执行。本着现在是“你不让干的事我偏要搞一次”的思想,我们修改程序跳转代码,发现flag赫然出现!
由于这样的方法强行改汇编跳转也存在“试”的成分,所以直接给修改完成的代码(修改了4处),如下图:
所以直接能拿flag啦:flag{reversing_is_not_that_hard!}
0xa.getit
解析:依旧老套路,拖IDA,shift+F12看字符串发现linux和一个很像flag形式的字符串"SharifCTF{???}",双击点进去,然后在左边的框找到主函数,反汇编成伪代码。如下图:
简单分析代码:(重点是11~20行)s长度限定,v5条件选择,v3偏移量,用参数操作s,t为最终存放数组,最后用流写入tmp文件夹下的flag.txt中。但是/tmp是linux主目录下一个存放临时文件的文件夹,程序return后写入的临时文件也一并丢弃。
这里额外说一下,这道题可以用在linux环境下运行,然后设置断点去/tmp文件夹下找,或者直接更改流写入的目标文件夹都是可以的。这里我们使用windows纯代码分析的方法。
通过分析我们发现v3,v5已知,需要知道s和t。我们在IDA的IDA View-A的窗口中找到s的值,如下图
:
找t的值,代码如下:(注意这里是题目有bug!!!t的值是SharifCTF{???},可在16进制视图窗口查看)
最后写出代码
v5 = 0
s = 'c61b68366edeb7bdce3c6820314b7498'
t = ['S','h','a','r','i','f','C','T','F','{','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','}']
v3 = 0
l = len(s)
while(v5 < l):
if( v5 & 1 ):
v3 = 1
else:
v3 = -1
t[10+v5] = chr(ord(s[v5])+v3)
v5 += 1
flag = ''
for x in t:
flag+=x
print(flag)
得到flag:SharifCTF{b70c59275fcfa8aebf2d5911223c6589}
0xB.python-trade
解析:
下载完文件发现是一个.pyc文件,百度得知.pyc文件其实是PyCodeObject的一种持久化保存方式(感兴趣可自行搜索学习)。所以思路就比较清晰了:用python反编译在线工具反编译这个.pyc文件得到源码,如下图
关键点:encode(flag) == correct
所以就很容易写出逆向解码的代码:
# encoding: utf-8
import base64
s = "XlNkVmtUI1MgXWBZXCFeKY+AaXNt"
flag = ""
#base64
b = base64.b64decode(s)# print(b)
#encode
for i in b:
i -= 16
i ^= 32
flag += chr(i)
print(flag)
拿到flag:nctf{d3c0mpil1n9_PyC}
0xC.maze
解析:ELF文件,日常拖到IDA,查找字符串,交叉引用,F5大法好。
分析代码,s1储存输入对象,比较前5位是不是"nctf{",第25位最后一位是不是"}"。之后发现asc_601060中储存的是一个8*8的迷宫,迷宫如下:
******
* * *
*** * **
** * **
** * **
* *# *
** *** *
** *
********
通过分析,发现v4是玩家输入的方向:‘O’–左,‘o’–右,’.’–上,‘0’–下,由迷宫得到轨迹:右下右右下下左下下下右右右右上上左左
所以flag就是:nctf{o0oo00O000oooo…OO}
到这里,整个攻防世界Reverse的Exercise area就解答完毕了,希望大家能多多交【pi】流【ping】!
RE真好玩~强颜欢笑.jpg