攻防世界-re2-cpp-is-awesome
题干如下

C++逆向,main逻辑如下
1 | __int64 __fastcall main(int n2, char **a2, char **a3) |
这里就是在进行一个索引提取,逆向脚本如下
1 |
|
值得注意的一点是这里在数据提取时会得到如下的数据
1 | dd 24h ; DATA XREF: main+DD↑r |
三个0来当分隔符时老生常谈了,最重要的地方是在于align8的作用在于对齐地址,由于这里定义的是dwrod数据且大多数编译器的地址选择都是8的倍数,而下一个数据所在的地址是0x6020C4,这不是8的倍数,所以这里就自动填充了4个字节让下一个数据的地址是8的倍数,所以这里在提取数据时除了正常能看到的,不要忘了还有align8的0x0数据也要写进逆向脚本中。
攻防世界-BABYRE
一道陷阱题,字节码。main逻辑相当简洁
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
将judge数据异或之后输出一堆乱码,那么大抵是异或出字节码然后再看内容,字节码一键梭哈脚本如下
1 | #!/usr/bin/env python3 |
输出得到
1 | 0x1000: push rbp |
可得逆向脚本
1 | # 原始的 judge 数据 |
当然,如果能实现linux远程调试的话,下个断点然后CUP直接就能得到反汇编过后的代码,比静态分析更快更好用。(仍然不会Linux远程调试的屑)
攻防世界-流浪者
一道windows逆向,进入程序后发现删除对照表,所以只能通过查找字符串的方式来定位main逻辑,梳理后main逻辑如下
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
其中change_base64为
1 | BOOL __cdecl chage_base64(int v8) |
这里会有一些关于IDA的特性:
譬如在引用某一数组时,会使用类似于*(v8+4*v4)的表达式,这里表示v8数组中的四个字节四个字节地递增,由于v8是dword数据类型占四个字节,所以这里就用乘数四来表示字节的递进。
这里也是一个小点:在IDA中,是以字节为单位进行递进地,而不是像常规一样以索引来进行递进的。
对于change_base64的逆向我们直接逆向出其索引就行,后面的逆向脚本如下
1 | #include <bits/stdc++.h> |
攻防世界-tt3441810
一道很逆天的题目。打开来发现是一堆字节码,编译出来后可以得到字符串flag{poppopret},结果发现不对,纳闷了。把flag头去掉发现是对的(无语中…)
攻防世界-reverse_re3
一道别出新意的迷宫题,main逻辑如下

第一个函数没什么用(据说是反调试?没懂)第二个函数才是迷宫的重点
1 | __int64 sub_940() |
可以看到,这里使用了wasd,经典的游戏操作。
进入第一个函数
1 | unsigned __int64 sub_86C() |
可以看到出现了两个循环,都是循环十五次,大致可以推断是15*15的一个迷宫
dword_202020如下

观察可得,只出现了0,1,4,3四个数据,上面的函数逻辑一定是迷宫生成逻辑,所以3必然是迷宫起点。
接着观察wasd的逻辑,可以看到wasd中都存在将方才走过的路赋值为1的操作,并且有条件判断是否为4。
那么不难得出一下结论,这个迷宫是15*15的,走过的路径为1,当前位置(初始为起点)为3,终点为4。那么可以得到以下三个迷宫
1 | 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, |
于是就能得到flag。别忘了把最后得到的字符串md5加密.
攻防世界-happyctf
一道C++逆向,看起来很难其实是徒有其表,main逻辑如下
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
看起来非常难,但其实核心锁定在
1 | while ( v14 != v13 ) |
其中逻辑如下
1 | void __thiscall lambda_1b3a4e77a09e1a7ed440bad3aa4c443b_::operator()( |
厨子梭哈

攻防世界-easyre-xctf
一道似曾相识的题

然后查找字符串

得到flag。
攻防世界-crackme
一道新壳题(NS壳),必须手脱,但是我手脱的好像不太完全导致一些数据出现错误,但是仍然可以做出题。首先x32dbg老样子脱壳,追ESP的内存变化就能脱壳,但是不知道为什么脱不完全。
脱壳后进入IDA,main逻辑如下

可以清晰地看到核心计算是异或,查询得知%16的key为

dword数据为



提取以上三张图中的数据,发现有很多0x0,很反常,去掉所有的0x0后运行脚本可得数据如下

有flag头了!再试一次不删0x0的数据进行逆向

出现flag尾,但是这个时候就纳闷了,明明两次数据开头都一样,为什么删了0x0的数据能跑出flag头,但是不删0x0的数据就跑不出flag头?两次脚本运行的enc数据如下
1 | 0x12, 0x4,0x8, 0x14, 0x24, 0x5c, 0x4a, 0x3d, 0x56, 0xa, 0x10, 0x67, 0x41, |
最终搜索博客时正确的数据如下
1 | 0x12, 0x4, 0x8, 0x14, 0x24, 0x5c, 0x4a, 0x3d, 0x56, 0xa, 0x10, 0x67, 0x0, |
通过对比删0x0和不删0x0跑出来的数据我们可以得到最终的flag
flag{59b8ed8-kb8ed8f-af22-11e7-bb4a-3cf862d1ee75}
攻防世界-debug
主要逻辑如下
1 | using System; |
函数的主要逻辑是将一个固定的种子与一个和时间有关的随机数以及一个空的字符列表传入中间的函数中。细看第二个函数发现传入的与时间有关的函数,即A_1,在计算过程中完全没有出现,所以大致可以断定这道题与时间动态性无关,flag是静态的。
第二个函数中的语句c = Convert.ToChar(.(Convert.ToInt32©, num2));则是在调用最顶上的函数,即num2是所给数组的索引,将a_与一直数组的某一个数进行异或,然后传到空字符列表中,集合后转为md5,然后将 - 替换为空字符就能得到flag。
逆向脚本如下
1 | import hashlib |
SHCTF-trace(好好学习此题!!)
一道很有新意的题目,打的是trace脚本(尚在学习中)和对普通运算法则的特异性写法,当然也可以静态分析。
题目附件给了40W行的汇编语言,代码量惊人。
首先可以看到exec这个陌生的函数,发现出现了key和seed。然后综合来看发现 o 只有0~4五个值。
0的运算逻辑如下
1 | uint32_t v1 = 0; |
搜索可得这是典型的位运算加法器。
1的运算逻辑如下
1 | key[2] = exec(1, key[0], key[1]); |
搜索可得这是异或
2的运算逻辑为左移动,3的运算逻辑为右移。4的运算逻辑如下
1 | key[0] = exec(4, seed1 & 0xFFFF, 0x1337); |
搜索可得4的运算逻辑为乘法
以上都是对基础算法的奇异型描述,在日常过程中需要经常性理解。
注意到其中一行有代码
1 | uint32_t v3 = 40503 << 16 | 31161; |
这里运算后可以得到TEA算法的标志数0x9E3779B9,那基本就可以得到我们的算法主体了。
注意到
1 | exec(2, v1, 2) |
那么就是将左4右5变成了左2右4。
这里我感觉出的不是很好,这种题就只能这样子去找,有很多地方和运算的细节其实很难找到,但或许考点就在这里,利用trace来提取出最关键的信息来简化极为复杂且巨大的代码量(trace尚在学习中,后面会整理为文档)。
然后现在就能知道正向逻辑其实是魔改的TEA算法
1 | sum += delta |
那么可得逆向脚本如下
1 |
|