天天看點

新160個CrackMe分析-第1組:1-10(上)

作者:selph

目錄:

•001-前言1

•002-abexcm52

•003-CrueheadCM33

•004-AcidBytes.24

•005-Andrénalin.15

•006-ArturDents-CrackMe26

•007-reg7

•008-Afkayas.18

•009-Boonz-KeygenMe1

•010-ceycey10

6-10(關注下期文章)

1.001-前言

新160個CM來自:新160個CrackMe算法分析-001-簡介_哔哩哔哩_bilibili

前言

這位師傅整理了新160個CrackMe和配套的逆向視訊來幫助新手練習逆向技能,逆向的基礎便是閱讀反彙編的能力,這正是本練習的核心所在

以前我想過去堅持把160個做完,但沒堅持下來,近期總想着每天多多少少做點逆向練習,于是我打算去再次挑戰,本次以這個師傅整理的為準進行逆向的練習,去紮實自己的逆向功底

這個師傅提供了逆向的講解視訊,主要是基于OD動态調試分析的以及VB版本的注冊機編寫

這裡我從另一個視角去完成本系列文章:以IDA靜态分析為主,x86dbg動态分析為輔,完成程式的調試和分析,使用C++/C# 編寫注冊機

歡迎有興趣的童鞋來探讨交流~

本系列難度星級:

CM難度評星标準按視訊裡的走:

算法:

–⭐:明文字元串操作

–⭐⭐:很容易看懂的算法

–⭐⭐⭐:算法複雜但容易看懂,or 算法簡單但不容易看懂

–⭐⭐⭐⭐:算法難,看懂難

–⭐⭐⭐⭐⭐:分析不出來,以後回來做

爆破:

–⭐:靜态分析就能找到關鍵跳

–⭐⭐:回追一層,或修改2個點的

–⭐⭐⭐:回追二層以上,或修改超過2個點的

–⭐⭐⭐⭐:回追多層,修改點難找且多

–⭐⭐⭐⭐⭐:暫時無法破解,以後回來做

2. 002-abexcm5

爆破難度:⭐

算法難度:⭐

資訊收集

運作情況:輸入序列号,輸入錯誤會提示錯誤并退出程式,這是個驗證序列号的程式

新160個CrackMe分析-第1組:1-10(上)

查殼:無殼

新160個CrackMe分析-第1組:1-10(上)

查字元串:有提示語,疑似寫死的字元串

新160個CrackMe分析-第1組:1-10(上)

查導入表:使用了字元串操作類的函數,以及GetVolumeInformationA函數,不知道序列号生成跟這個有無關系

新160個CrackMe分析-第1組:1-10(上)

到現在已經知道了軟體大概的運作流程:擷取使用者輸入,對使用者輸入進行一些處理,然後彈框提示

逆向分析

IDA裡選擇MessageBoxA函數查交叉引用,跟蹤到函數sub_401056中,這是CM的校驗邏輯所在:

首先先擷取使用者輸入,然後生成兩個字元串:(注釋寫錯了,應該是do-while循環而不是while循環)

新160個CrackMe分析-第1組:1-10(上)

然後把剛剛生成的兩個字元串拼接到一起,生成序列号,與使用者輸入進行比對,序列号幾乎是寫死

新160個CrackMe分析-第1組:1-10(上)

暴力破解

驗證邏輯是:生成序列号,通過與使用者輸入的比對來進行驗證

暴力破解的思路是:修改跳轉條件即可,把jz改成jmp即可:

新160個CrackMe分析-第1組:1-10(上)

算法分析

注冊碼生成算法:

#include

#include

int main()

{

char VolumeNameBuffer[MAX_PATH] = { 0 };

DWORD VolumeSerialNumber = 0;

DWORD MaximumComponentLength = 0;

DWORD FileSystemFlags = 0;

int i = 2;

char Series[MAX_PATH] = { 0 };

GetVolumeInformationA(
    0,
    VolumeNameBuffer,
    0x32u,
    &VolumeSerialNumber,
    &MaximumComponentLength,
    &FileSystemFlags,
    0,
    0);


lstrcatA(VolumeNameBuffer, "4562-ABEX");
  
do{
    VolumeNameBuffer[0]++;
    VolumeNameBuffer[1]++;
    VolumeNameBuffer[2]++;
    VolumeNameBuffer[3]++;
} while (--i);

lstrcatA(Series, "L2C-5781");
lstrcatA(Series, VolumeNameBuffer);

std::cout << Series << std::endl;
system("pause");
return 0;
           

}

效果:

新160個CrackMe分析-第1組:1-10(上)

總結

字元串拼接生成序列号,通過判斷+跳轉進行校驗,很簡單,沒啥好說的

參考資料

–[1] GetVolumeInformationA擷取磁盤卷标、檔案系統,_上善若水pjf的部落格-CSDN部落格_getvolumeinformationa

3. 003-CrueheadCM3

爆破難度:⭐⭐

算法難度:⭐⭐

資訊收集

運作情況:是一個空白界面,可能要經過某些操作才能讓内容顯示出來

新160個CrackMe分析-第1組:1-10(上)

查殼:無殼

新160個CrackMe分析-第1組:1-10(上)

查字元串:看到了一些提示語

新160個CrackMe分析-第1組:1-10(上)

查導入表:除去視窗繪制,消息循環用到的函數,這裡還出現了檔案操作相關函數,可能跟檔案有關,結合上面的字元串搜尋資訊,應該需要一個CRACKME3.KEY的檔案

新160個CrackMe分析-第1組:1-10(上)

逆向分析

根據之前對檔案進行靜态的資訊收集之後,這個檔案操作很可疑,就從檔案操作函數CreateFileA去搜尋交叉引用看看這裡在幹嘛

首先打開名為CRACKME3.KEY的檔案,然後讀取其中的内容儲存到緩沖區

新160個CrackMe分析-第1組:1-10(上)

然後判斷讀取的位元組數如果是0x12就往下走,對讀取到的内容進行一頓操作,然後通過某種計算方法進行校驗,然後把校驗結果儲存在al裡入棧了

新160個CrackMe分析-第1組:1-10(上)

然後經過一段視窗建立的操作之後,在進入消息循環之前,做了這樣一個校驗,校驗檔案内容是否正确,正确就彈框提示,正是通過剛剛push的al進行校驗的

新160個CrackMe分析-第1組:1-10(上)

暴力破解

整個校驗流程最後還是通過判斷+跳轉進行執行的,暴力破解老樣子,直接修改跳轉條件即可:

新160個CrackMe分析-第1組:1-10(上)

前面還有個判斷讀取到的内容是否為0x12位元組,把那個跳轉也nop改掉即可,這裡就不示範了

算法分析

這裡的校驗算法主要是這幾行:

新160個CrackMe分析-第1組:1-10(上)

這裡調用了兩個自寫的函數,首先是sub_401311:這裡計算一個前14位元組的校驗和,然後對前14位元組依次與ABCD...進行異或操作,将異或的結果儲存起來,校驗和也儲存起來

新160個CrackMe分析-第1組:1-10(上)

然後是下一個函數sub_40133C:就是取後4位元組出來

現在這個校驗算法已經清晰了起來:

–計算一個校驗和,校驗和與0x12345678進行異或,得到的結果與輸入裡的最後4位元組進行比較

–對輸入的前14位元組進行異或操作,異或後的結果作為參數去調用顯示驗證成功提示框

那麼序列号的生成就是:

a.随便輸入一個14位元組的字元串作為使用者名

b.對這14位元組依次異或ABCD...,儲存起來

c.對校驗和異或0x12345678,然後拼接到異或結果後面,即可完成生成

注冊碼生成算法:

#include

#include

void generateSeriesFile(const char* in_pwd) {

char pwd[0x13] = { 0 };

int i;

char var_bl = 'A';

unsigned int sum = 0;

memcpy(pwd, in_pwd, 0x13);

i = 0;
do {
    sum += pwd[i];
    pwd[i] ^= var_bl;
    i++;
    var_bl++;
    if (!pwd[i])break;
} while (var_bl != 'O');

sum ^= 0x12345678;
*(unsigned int *)&pwd[0xE] = sum;

for (int k = 0; k < 18; k++)
{
    unsigned char* tmp = (unsigned char*) & pwd;
    printf("%02x ",tmp[k]);
}

HANDLE hFile = CreateFileA("CRACKME3.KEY", GENERIC_ALL, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD retNum = 0;
WriteFile(hFile, pwd, sizeof(pwd), &retNum, NULL);
CloseHandle(hFile);
           

}

int main()

{

const char *pwd= "[email protected]";

generateSeriesFile(pwd);

system("pause");

return 0;

}

效果:

總結

序列号算法和校驗依然很簡單,這裡有意思的是:這個程式的校驗邏輯位于視窗進入消息循環之前,校驗行為發生在了軟體正常運作之前,根據校驗結果再選擇是否正常運作程式

參考資料

–[1] ASCII碼一覽表,ASCII碼對照表 (biancheng.net)

–[2] setz_ccboby的部落格-CSDN部落格_setz指令

4. 004-AcidBytes.2

算法難度:⭐

爆破難度:⭐

脫殼難度:⭐

資訊收集

運作情況:

依然是序列号驗證,輸入序列号點選Check,會顯示提示資訊

新160個CrackMe分析-第1組:1-10(上)

查殼與脫殼:

出現殼了,Die查出來是Upx壓縮殼

新160個CrackMe分析-第1組:1-10(上)

對于Upx殼使用ESP定律即可完成脫殼,過程相當簡單,這裡簡述一下就不截圖示範了:

a.運作到OEP,運作到pushad的下一行(執行這個指令隻有esp的值會被修改)

b.在記憶體中檢視esp指向的位址,對該位址下通路硬體斷點,然後運作,此時會運作到popad指令的下一行,是跳轉到真正OEP的jmp,跳轉過去

c.使用Scylla進行Dump和修複PE,得到脫殼後的程式

再次查殼驗證:

新160個CrackMe分析-第1組:1-10(上)

查字元串:

有點幫助的字元串是這些,是驗證提示資訊

新160個CrackMe分析-第1組:1-10(上)

查導入表:

沒有什麼特别的點,看起來都是圖形界面相關的内容,程式使用MessageBoxA彈窗提示

調試分析

這個程式的傳參方式比較特别,根據查閱資料[1],前三個資料儲存在eax,edx,ecx寄存器裡,超過三個參數部分放在堆棧傳遞

這裡以字元串作為入口進行突破,搜尋字元串Congrats!...的交叉引用,找到按鈕控件的處理例程:

首先是注冊了SEH異常鍊,然後擷取使用者輸入

新160個CrackMe分析-第1組:1-10(上)

接下來就是比較+彈窗三連:

輸入字元串和寫死字元串進行對比,如果相同,就彈窗提示成果

如果不相同,就判斷是否輸入的有内容,如果無内容,提示輸入為空,否則提示輸入錯誤

新160個CrackMe分析-第1組:1-10(上)

暴力破解

直接Nop掉關鍵跳即可:

新160個CrackMe分析-第1組:1-10(上)

算法分析

寫死密碼,無算法效果:

新160個CrackMe分析-第1組:1-10(上)

總結

處理該CM的要點就是脫殼,脫殼之後就是寫死判斷跳轉,算是個入門級脫殼練習

參考資料

–[1] Delphi的參數傳遞約定以及動态參數個數(轉載筆記) - 不得閑 - 部落格園 (cnblogs.com)

5. 005-Andrénalin.1

算法難度:⭐

爆破難度:⭐

資訊收集

運作情況:

功能就是輸入密碼,然後驗證

新160個CrackMe分析-第1組:1-10(上)

查殼與脫殼:

無殼,是 VB 編寫的 GUI 程式,需要使用 VB 反編譯工具進行逆向分析

新160個CrackMe分析-第1組:1-10(上)

調試分析

對于 VB 程式,可以使用 VB Decompiler 進行逆向,本例驗證邏輯較為簡單,估計主要是練習