作者:朱金燦
來源:clever101的專欄
簡介
通過逆向一個C++程式來簡單介紹如何使用x64dbg進行逆向。
編寫一個C++示例程式
打開VS2013,建立一個C++控制台工程:CrackDemo,并輸入如下代碼:
#include "stdafx.h"
int check(int key)
{
if (1234 == key)
return 1;
else
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("please input the key:\n");
while (1)
{
int key = 0;
scanf("%d", &key);
if (check(key))
{
printf("You got it.\n");
break;
}
else
{
printf("Sorry,try again\n");
}
}
return 0;
}
這個程式就是一個簡單的猜數遊戲:當使用者輸出數字1234時就提示正确并退出程式,否則提示不斷輸入數字。
x64dbg上場練習
現在我們需要使用x64dbg來逆向一下這個程式,使之輸入什麼數都能輸出:You got it.我使用的x64dbg版本是Jul 1 2021。程式逆向的基本步驟如下:1.查找常量字元串;2.通過常量字元串分析彙編代碼邏輯;3.修改彙編代碼;4.驗證逆向程式。
查找常量字元串
按F9把程式運作起來,進入主子產品,然後CPU(反彙編)視窗->滑鼠右鍵->搜尋->選擇子產品(根據個人需求選擇,一般選擇目前子產品,前提是得先執行到主子產品)->字元串,分别搜尋:You got it和Sorry,try again兩個字元串,找到相關的代碼段,如下圖:
分析彙編代碼邏輯
分析一下上圖的彙編代碼:
call qword ptr ds:[<&scanf>] ; 調用scanf函數,這裡應該是讓使用者輸入一個數
cmp dword ptr ss:[rsp+40],4D2 ; 輸入的數和4D2比較,注意這個4D2是一個16進制數,換成10進制數就是1234
je crackdemo.7FF7D90D104F ;如果為0,就跳轉到7FF7D90D104F處的代碼
lea rcx,qword ptr ds:[7FF7D90D21B0] | 00007FF7D90D21B0:"Sorry,try again\n" ;給寄存器rcx送一個常量字元串Sorry,try again\n,也就是C++的指派語句了
call qword ptr ds:[<&printf>] ;列印這個常量字元串
jmp crackdemo.7FF7D90D1020 ; 無條件跳轉到7FF7D90D1020代碼處
lea rcx,qword ptr ds:[7FF7D90D21A0] | 00007FF7D90D21A0:"You got it.\n" ;給寄存器rcx送一個常量字元串You got it.\n
call qword ptr ds:[<&printf>] ;列印這個常量字元串
應該說這段代碼還是比較好閱讀的。
修改彙編代碼
通過分析,我們發現cmp dword ptr ss:[rsp+40],4D2和je crackdemo.7FF7D90D104F是一處關鍵的跳轉。是以一個取巧的辦法是改變跳轉的判斷依據,将不等于0作為跳轉一句。具體做法是選擇je 0x00007FF7D90D104F這行代碼,然後單擊右鍵,在右鍵菜單中選擇“彙編”菜單項,彈出如下視窗:
在上面視窗中将je crackdemo.7FF7D90D104F改為jnz crackdemo.7FF7D90D104F,意思為不等于0的時候跳轉,如下:
(這一步如有繼續彈出修改彙編代碼的視窗可以單擊取消按鈕退出)
然後在CPU視窗中的右鍵菜單中選擇“更新檔”->“修補檔案”:
這裡簡單提下修改彙編代碼的兩個原則:一是修改彙編代碼得盡量遵循取小不取大的原則,就是修改後的彙編指令占用的位元組數最好小于等于原有的指令,不然就會破壞原有的程式結構,也就是在上圖中把保持大小的選項選上,選上改選項後假如超出原有指令大小會有提示;二是上圖還把剩餘位元組以NOP填充,這是什麼意思呢?就是說假如修改的指令占用位元組小于原有指令,那就用90 填充,90 就是 NOP。
驗證逆向程式
在控制台視窗運作CrackDemo破解.exe,效果圖如下:
可以看到,我們的逆向是成功的!