攻防世界Reverse(3)
gametime
看题目描述是个游戏时间,应该有关游戏的,下载是个exe文件,运行起来有点看不懂,那我们先记录下来里面的一些字符,等反编译时去针对性的查看。
这里的文件查看是没有得到什么信息的,那我们就用ida打开它去看看里面到底是些什么:
(伪代码有点长,我们就一段一段的来分析)
而下面这个函数sub_4012D5(0xC8u)则是它输入的下面的一串字符。
代码有点长,不过此时我们其实就应该可以想到这道题可能用到了动态调试了,不过我们还是要找到我们所需的代码处。后来也看不下了,实在有点多,不过下面的key应该是flag了,我们就要得到它就行了。
然后程序中就出现了:
这样子flag就得到了,不过一直运行起来挺费时间的,我们一不小心就又得重来。
知识点
这道题就是考察OD,不过刚开始确实不容易想出了,因为我刚开始就不知道它这个到底是说明意思,后来才发现s和m出现的太快以至于我根本没有看到,所以我们要静态和动态结合起来来看!
知识点上并没有什么要说的。
reverse-for-the-holy-grail-350
打开,发现是用C++写的,在攻防世界里面,越往后越是用的C++。
userIn这个是个字符串要用到。qword_601AE8也是个。但是这里仔细看发现是不能够得到flag的。所以我们往上看,去找找我们要的。
此时我们就要去看看这个函数了,它里面有三个数组了。分析来看,v4是一个关键,不能为负值。
stringMod:
上面的无法完全找到,所以:
再来看看下面的:
此时我们就可以开始写脚本了,由下向上的开始吧。但是这样子不好写,而且它也并非是线性关系,而是这个三个数组负责不同的位数。
脚本:
此时我们再来分析一下代码,因为这个思路可能比较难理解这个脚本。
此时我们假如输入的是flag了,它们会进入stringMod这个关键函数,而里面有三个数组《firstchar thirdchar masterArray》这三个。然后首先要对3的倍数进行核对(0,3,6…)然后有个必经的循环(上面提到过),此时说明下两个数组要经过这个加密:
有难点,不过还是能够做出来的。
tt3441810
这道题我首先用ida打开,发现是不行的,所以我们就EP探测下,看看
其实到这里我有点想用linus系统去查看这个文件(因为windows系统是根据后缀明来判断文件的)后来发现它是个txt的,就是个数据,从这些数据里面发现一些我要的flag。
柑橘它不该分到re,应该是mics或crypto
然后就解出来了,不过这个还有些其它的干扰字符,如下:
hflHH4$HHhagHH4$HHh{pHH4$HHhopHH4$HHhpoHH4$HHhprHH4$HHhetHH4$HHh}HH4$HHH1H<
HH4$HH这个应该是干扰的,还有h这个也是个干扰项,最后提交的时候还不行,必须把flag{}这个去掉,即 poppopret
知识点
这个主要考察我们去分析文件(以二进制来),这样我们就需要去除一些干扰的字符,去找到我们想要的数据(data层)
re2-cpp-is-awesome
这道题有个提示:
应该就是C++的逆向了,不过C++的逆向必须要精简代码一下,这样子才好分析了:
这个关键的判断,有几个关键的地方,off_6020A0和dword_6020C0这个。然后去追踪一下,找到这两个数组的内容就好了。
align 8 就是8个字节对齐,在这里就是间隔了8个0,就是这里还有一个0的意思:
然后就写出脚本了。
知识点
其实这道题也没什么要讲的,主要是熟悉一下C++写的脚本。
流浪者
打开时个cm.exe文件,运行一下看看大致内容是什么:
此时我们可以打开ida来分析一下:(这时需要搜索字符串来发现它的主函数)
此时我们再去sub_4017F0这个函数里面看看:
此时我们就可以写出脚本了:
此时就解出flag了。
知识点
没有太难的地方,有几个加密需要了解一下。
re4-unvm-me
下载开发现是个pyc文件。这里要用到一个工具啦,EasyPythonDecompiler这个啦。
会出现一个文件,改掉后缀名为txt,就可以查看代码了。
如下:
有个原始的数据,是十进制,那我们进制转换为十六进制,在逐一(每一行的)进行md5解密,最后拼凑到一起就十flag了:
ALEXCTF{dv5d4s2vj8nk43s8d8l6m1n5l67ds9v41n52nv37j481h3d28n4b6v3k}
知识点
这里十接触到了pyc的反编译了,用的是 EasyPythonDecompiler 这个工具进行反编译,将pyc文件直接拖进去,就可以了,还是很简单的。
ReverseMe-120
打开是个.exe的文件,运行起来如下:
然后我们就用ida去打开,开始静态分析啦:
最主要的便是flag_crypto这个函数了( 注 该函数我修改过,请从上图寻找),还有就是那个for循环,有个异或啦。
而且上面还有个循环,才和那串字符比较啦。所以猜测上面的循环是那个加密函数啦:
然后从十六进制去看一下啦:
以后记住啦,原来base表还有这个呀!
此时就可以写脚本了:
flag: XEpQek5LSlJ6TUpSelFKeldASEpTQHpPUEtOekZKQUA=
知识点
1. load(set)系列,用于加载数据,从内存到暂存器。
__m128i _mm_load_si128(__m128i *p);
__m128i _mm_loadu_si128(__m128i *p);
2. store系列,用于将计算结果等SSE暂存器的数据保存到内存中。
void _mm_store_si128 (__m128i *p, __m128i a);
void _mm_storeu_si128 (__m128i *p, __m128i a);
_mm_load_si128 函数表示从内存中加载一个128bits值到暂存器,也就是16字节,注意 p必须是一个16字节对齐的一个变量的地址。返回可以存放在代表寄存器的变量中的值。
_mm_loadu_si128 函数和 _mm_load_si128 一样的,但是不要求地址p是16字节对齐。
store系列的 _mm_store_si128 和 _mm_storeu_si128 函数,与上面的load系列的函数是对应的。 表示将__m128i 变量a的值存储到p所指定的地址中去。
_mm_xor_si128 用于计算128位(16字节)的按位异或,然后通过v14控制循环结束的条件,可以看到v14增长的步长为16,而且通过上面得到的flag值解码得到的字符串为32个字节大小,正好是16的整数倍。
easyre-153
这次用到了EP,平时我都不用,没想到这时用到了,不过打比赛时要用到,以防万一。
然后upx去壳。
然后就可以用ida打开它啦,没想到第一次去壳没去好,得再去一遍才行。直接找到mian函数:
pipe 是个linus编程函数,是个管道,也就是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法。
复刻(英语:fork,又译作派生、分支)是UNIX或类UNIX中的分叉函数,fork 函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
对了write是写入,就好像赋值一样,read就是读取,也可以理解为输入。
此时我们看看not_flag这个函数,也就是lol函数,因为我改了一下名字:
此时我们写个脚本,也是个猜测,因为也没什么明显的提示,所以我们猜测最后会输出flag,因为它最后说你获得了key,也就是flag:
不过flag是RCTF{rhelheg}
notsequence
EP了一下,没有加壳。那我们就用ida打开它,直接找到main函数:
然后我们来看看着两个函数,先来第一个:
其实到这里的数据就变成了1,2,4,8,16…了,此时我们再来看看第二个函数:
然后总结一下,v2是20,也就是第一个函数赋值是20,并且里面也说明数据为1,2,4,8,16…等,第二个函数,其实也就是1+1=2,1+2=3,2+2=4,2+3=6。
hint:上面有个图标错了,就是第二个函数的图,它其实a1[v3*(v3+1)][i]这样子的,它也就是个杨辉三角,20位的杨辉三角:
那么此时flag就有了。
RCTF{37894beff1c632010dd6d524aa9604db}
Replace
打开是个rar的压缩包,刚开始看的文件名有点长,没看到后缀名,以为直接是个文件,直接逆向,实力眼瞎!!!
哈哈,解压是个exe文件,用EP看看:
然后去壳它:
此时就可以用ida去逆向了,不过我们也可以再用EP看看是否去壳成功。此时我们打开exe文件发现输入什么都没有显示,ida打开发现mian函数很好的弄清逻辑:
第一个判断其实没有精确的判断到长度是多少,所以我们就进入sub_401090这个函数里看看:
这个是历遍每一个数字,然后我们就可以用枚举法进行爆破每一个数字。还有byte_402150这个函数包含byte_402151了这个函数,看看这三个数据的内容:
此时我们就可以尝试去写脚本了。
byte1 = [ 50, 97, 52, 57, 102, 54, 57, 99, 51, 56,
51, 57, 53, 99, 100, 101, 57, 54, 100, 54,
100, 101, 57, 54, 100, 54, 102, 52, 101, 48,
50, 53, 52, 56, 52, 57, 53, 52, 100, 54,
49, 57, 53, 52, 52, 56, 100, 101, 102, 54,
101, 50, 100, 97, 100, 54, 55, 55, 56, 54,
101, 50, 49, 100, 53, 97, 100, 97, 101, 54]
byte2 = [97, 52, 57, 102, 54, 57, 99, 51, 56, 51,
57, 53, 99, 100, 101, 57, 54, 100, 54, 100,
101, 57, 54, 100, 54, 102, 52, 101, 48, 50,
53, 52, 56, 52, 57, 53, 52, 100, 54, 49,
57, 53, 52, 52, 56, 100, 101, 102, 54, 101,
50, 100, 97, 100, 54, 55, 55, 56, 54, 101,
50, 49, 100, 53, 97, 100, 97, 101, 54]
byte3 = [99, 124, 119, 123, 242, 107, 111, 197, 48, 1,
103, 43, 254, 215, 171, 118, 202, 130, 201, 125,
250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
114, 192, 183, 253, 147, 38, 54, 63, 247, 204,
52, 165, 229, 241, 113, 216, 49, 21, 4, 199,
35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
235, 39, 178, 117, 9, 131, 44, 26, 27, 110,
90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
190, 57, 74, 76, 88, 207, 208, 239, 170, 251,
67, 77, 51, 133, 69, 249, 2, 127, 80, 60,
159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
188, 182, 218, 33, 16, 255, 243, 210, 205, 12,
19, 236, 95, 151, 68, 23, 196, 167, 126, 61,
100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
224, 50, 58, 10, 73, 6, 36, 92, 194, 211,
172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
141, 213, 78, 169, 108, 86, 244, 234, 101, 122,
174, 8, 186, 120, 37, 46, 28, 166, 180, 198,
232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
181, 102, 72, 3, 246, 14, 97, 53, 87, 185,
134, 193, 29, 158, 225, 248, 152, 17, 105, 217,
142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104, 65, 153,
45, 15, 176, 84, 187, 22]
for i in range(35):
for j in range(32,126):
v5 = j
v6 = (v5 >> 4) % 16
v7 = (16 * v5 >> 4) % 16
v8 = byte1[2 * i]
if ( v8 < 48 or v8 > 57 ):
v9 = v8 - 87
else:
v9 = v8 - 48
v10 = byte2[2 * i]
v11 = 16 * v9
if ( v10 < 48 or v10 > 57 ):
v12 = v10 - 87
else:
v12 = v10 - 48
if ( byte3[16 * v6 + v7] == ((v11 + v12) ^ 0x19) ):
print(chr(j),end='')
break
flag{Th1s_1s_Simple_Rep1ac3_Enc0d3}
这样子就好了。