一道关于逆向的实战CTF题目分析
前言
本题自带call型花指令,考验选手对花指令的理解程度。加密属于基础的异或和左右移位加密。主要考察选手的基础能力,动态调试和写脚本的能力。在这篇文章,详细记录了我的分析过程,相信你会有很大收获。
1、查壳
PE64位,没壳程序
2、IDA分析去花指令
使用IDA打开时,发现一片红,很正常的CTF考点:花指令
sub_main
当务之急是如何去除花指令,继续向下分析,发现了一些端倪
花指令的形成是干扰编译器的分析,但又不会影响程序的正常运行。
那么显而易见,会将某个寄存器进行push(保存)然后对其进行复杂操作,最终pop(恢复)该寄存器的值,程序正常执行。
而在本程序中,可以发现该手法:
push ebx
.....
pop ebx
中间的过程均无需再看,直接NOP操作。
nop完记得保存修改。
接下来就可以分析main函数啦
而这两个函数恰好均为关键的函数。
【----帮助网安学习,以下所有学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)
sub_401040
此时,我们可以看到函数开头的位置存在多个push操作,不要急着nop。对照函数结束的部分,避免误杀友军。
可以看到pop和push是相互对应的,开头push,结束就要pop。
此时注意到:push、pop不是要nop的点,我们继续分析
熟悉混淆的朋友一定可以识别出这是一个call型混淆。
call一个地址,然后修改堆栈返回值,retn跳过混淆,相对之前的混淆需要对堆栈有一定的理解。
识别出来,进行nop即可
得到加密函数
int __cdecl sub_401040(char a1, int a2)
{
return ((a2 ^ a1) << 8) - a2;
}
sub_401080
来分析另一个函数
相同的操作
得到加密算法
int __cdecl sub_401080(char a1, int a2)
{
return a2 ^ (a1 << 8);
}
3、分析加密流程
那么现在的任务是获得加密函数的顺序,这里采用动态调试的方法来获得:
得到顺序
left
xor
xor
left
xor
left
left
xor
left
left
xor
xor
xor
left
left
left
xor
xor
xor
left
xor
xor
left
xor
left
left
left
left
xor
xor
xor
left
将left用1替代,xor用0替代,得到顺序:
int temp[32] = { 1,0,0,1,0,1,1,0,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1 };
密文可以看到是:
dword_402120 数组
unsigned int dword_402120[32] = {
0x00004408, 0x000068D8, 0x00007AD8, 0x00004308, 0x00007BD8, 0x00004608, 0x00007B08, 0x000070D8,
0x00003308, 0x00007308, 0x000076D8, 0x00005CD8, 0x000076D8, 0x00006608, 0x00006908, 0x00006E08,
0x00004BD8, 0x000076D8, 0x00003FD8, 0x00006F08, 0x00005ED8, 0x000076D8, 0x00007408, 0x000046D8,
0x00005F08, 0x00006308, 0x00003408, 0x00007408, 0x000076D8, 0x000044D8, 0x00004CD8, 0x00007D08
};
4、写出解密算法
#include <stdio.h>
void left(unsigned int a1, unsigned int a2) {
// (a1>>8)^a2
printf("%c", ((a1 ^ a2)>>8 ));
}
void xors(unsigned int a1, unsigned int a2) {
//(((a1+a2)>>8)^a2)
printf("%c", (((a1 + a2) >> 8) ^ a2));
}
int main()
{
unsigned int dword_402120[32] = {
0x00004408, 0x000068D8, 0x00007AD8, 0x00004308, 0x00007BD8, 0x00004608, 0x00007B08, 0x000070D8,
0x00003308, 0x00007308, 0x000076D8, 0x00005CD8, 0x000076D8, 0x00006608, 0x00006908, 0x00006E08,
0x00004BD8, 0x000076D8, 0x00003FD8, 0x00006F08, 0x00005ED8, 0x000076D8, 0x00007408, 0x000046D8,
0x00005F08, 0x00006308, 0x00003408, 0x00007408, 0x000076D8, 0x000044D8, 0x00004CD8, 0x00007D08
};
int temp[32] = { 1,0,0,1,0,1,1,0,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1 };
for (size_t i = 0; i < 32; i++)
{
if (temp[i]) {
//left
left(dword_402120[i], 8);
}
else {
//xor
xors(dword_402120[i], 40);
}
}
}
到此,恭喜你学会了分析一道CTF题目最基本的步骤。
更多网安技能的在线实操练习,请点击这里>>