前言

本题自带call型花指令,考验选手对花指令的理解程度。加密属于基础的异或和左右移位加密。主要考察选手的基础能力,动态调试和写脚本的能力。在这篇文章,详细记录了我的分析过程,相信你会有很大收获。

1、查壳

一道关于逆向的实战CTF题目分析_花指令


PE64位,没壳程序

2、IDA分析去花指令

使用IDA打开时,发现一片红,很正常的CTF考点:花指令

sub_main

一道关于逆向的实战CTF题目分析_CTF赛题_02


当务之急是如何去除花指令,继续向下分析,发现了一些端倪

一道关于逆向的实战CTF题目分析_逆向实战_03


花指令的形成是干扰编译器的分析,但又不会影响程序的正常运行。

那么显而易见,会将某个寄存器进行push(保存)然后对其进行复杂操作,最终pop(恢复)该寄存器的值,程序正常执行。

而在本程序中,可以发现该手法:

push ebx
.....
pop ebx
  • 1.
  • 2.
  • 3.

中间的过程均无需再看,直接NOP操作。

一道关于逆向的实战CTF题目分析_堆栈_04


nop完记得保存修改。

一道关于逆向的实战CTF题目分析_堆栈_05


接下来就可以分析main函数啦

一道关于逆向的实战CTF题目分析_花指令_06


而这两个函数恰好均为关键的函数。

帮助网安学习,全套资料S信免费领取:
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

sub_401040

一道关于逆向的实战CTF题目分析_动态调试_07


此时,我们可以看到函数开头的位置存在多个push操作,不要急着nop。对照函数结束的部分,避免误杀友军。

一道关于逆向的实战CTF题目分析_堆栈_08


可以看到pop和push是相互对应的,开头push,结束就要pop。

此时注意到:push、pop不是要nop的点,我们继续分析

一道关于逆向的实战CTF题目分析_堆栈_09


熟悉混淆的朋友一定可以识别出这是一个call型混淆。

call一个地址,然后修改堆栈返回值,retn跳过混淆,相对之前的混淆需要对堆栈有一定的理解。

识别出来,进行nop即可

一道关于逆向的实战CTF题目分析_逆向实战_10


得到加密函数

一道关于逆向的实战CTF题目分析_堆栈_11


int __cdecl sub_401040(char a1, int a2)
{
  return ((a2 ^ a1) << 8) - a2;
}
  • 1.
  • 2.
  • 3.
  • 4.
sub_401080

来分析另一个函数

相同的操作

一道关于逆向的实战CTF题目分析_逆向实战_12


一道关于逆向的实战CTF题目分析_动态调试_13


得到加密算法

int __cdecl sub_401080(char a1, int a2)
{
  
  return a2 ^ (a1 << 8);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

3、分析加密流程

一道关于逆向的实战CTF题目分析_动态调试_14


那么现在的任务是获得加密函数的顺序,这里采用动态调试的方法来获得:

一道关于逆向的实战CTF题目分析_花指令_15


得到顺序

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
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.

将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 };
  • 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
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

一道关于逆向的实战CTF题目分析_逆向实战_16


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);

        }
    }



}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

到此,恭喜你学会了分析一道CTF题目最基本的步骤。