当前位置: 首页 > 技术干货 > 一道关于逆向的实战CTF题目分析

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

发表于:2024-07-12 16:18 作者: Ba0 阅读数(4688人)

前言

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

1、查壳

image

PE64位,没壳程序

2、IDA分析去花指令

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

sub_main

image

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

image

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

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

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

push ebx
.....
pop ebx

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

image

nop完记得保存修改。

image

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

image

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

sub_401040

image

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

image

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

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

image

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

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

识别出来,进行nop即可

image

得到加密函数

image

int __cdecl sub_401040(char a1, int a2)
{
 return ((a2 ^ a1) << 8) - a2;
}

sub_401080

来分析另一个函数

相同的操作

image

image

得到加密算法

int __cdecl sub_401080(char a1, int a2)
{
 
 return a2 ^ (a1 << 8);
}

3、分析加密流程

image

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

image

得到顺序

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

image

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题目最基本的步骤。