一道關於逆向的實戰CTF題目分析

蚁景网安实验室發表於2024-07-12

前言

本題自帶call型花指令,考驗選手對花指令的理解程度。加密屬於基礎的異或和左右移位加密。主要考察選手的基礎能力,動態除錯和寫指令碼的能力。在這篇文章,詳細記錄了我的分析過程,相信你會有很大收穫。

1、查殼

image

PE64位,沒殼程式

2、IDA分析去花指令

使用IDA開啟時,發現一片紅,很正常的CTF考點:花指令

sub_main

image

當務之急是如何去除花指令,繼續向下分析,發現了一些端倪

image

花指令的形成是干擾編譯器的分析,但又不會影響程式的正常執行。

那麼顯而易見,會將某個暫存器進行push(儲存)然後對其進行復雜操作,最終pop(恢復)該暫存器的值,程式正常執行。

而在本程式中,可以發現該手法:

push ebx
.....
pop ebx

中間的過程均無需再看,直接NOP操作。

image

nop完記得儲存修改。

image

接下來就可以分析main函式啦

image

而這兩個函式恰好均為關鍵的函式。

【----幫助網安學習,以下所有學習資料免費領!加vx:dctintin,備註 “部落格園” 獲取!】

 ① 網安學習成長路徑思維導圖
 ② 60+網安經典常用工具包
 ③ 100+SRC漏洞分析報告
 ④ 150+網安攻防實戰技術電子書
 ⑤ 最權威CISSP 認證考試指南+題庫
 ⑥ 超1800頁CTF實戰技巧手冊
 ⑦ 最新網安大廠面試題合集(含答案)
 ⑧ APP客戶端安全檢測指南(安卓+IOS)

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題目最基本的步驟。

更多網安技能的線上實操練習,請點選這裡>>

相關文章