banner
lca

lca

真正的不自由,是在自己的心中设下牢笼。

《從零開始學IDA逆向》學習筆記-18(編寫註冊機)

image

main 函數及其參數#

第 17 章中,通過遠程調試的方式對程序進行了脫殼,此處實驗的程序來自第 17 章脫殼後的程序。這裡直接用作者給的程序,而不加載自己脫殼的程序。

image

此章對上述程序進行分析並編寫註冊機。

複習下程序,32 位架構。

image

打開 ida 加載脫殼後的程序,首先查看字符串。

image

此程序運行後,在命令行輸出Pone un User,英文是Enter a user

單擊Pone un User,跳轉到程序具體位置。

image

按 “X” 鍵查看字符串引用

image

點擊 ok,進入引用具體位置

image

上圖中,在以 ebp 為基址的函數中,首先執行push ebp指令將上一層函數的 ebp 值保存到棧上,然後執行mov ebp,esp,將 ebp 作為計算函數本身的局部變量、參數、緩存區的基準。

image

之後再執行 sub esp,94h 指令從 ebp 的基址開始獲取 0x94 個字節用於存儲局部變量和緩存區

對函數任意變量或者參數雙擊,ida 會顯示函數的靜態棧視圖,下圖點擊 var_4 的顯示內容,靜態棧視圖

image

上圖中,該函數有兩個參數,也就是函數的默認參數 argc 和 argv,在函數調用之前通過 push 指令傳到了棧上,並且顯示在返回地址(r)的下方。(注:書中這裡講解一開始沒有參數,後面將 sub_201070 重命名為 main 函數後才顯示了這兩個參數)

這兩個參數雖然顯示了,但是未被引用,所以也可以當成無參

image

回到靜態棧視圖,S 表示STO RED EBP,是通過push ebp指令保存的上一層函數的 ebp,再上方就是局部變量空間,一般都有一個var_4變量來保護棧,防止緩衝區溢出。

image

var_4有兩處引用,第一處是函數的起點,用於在棧上存儲一個安全口令security cookie

image

這是一個隨機數,在函數剛運行時,跟 ebp 進行異或運算後,結果保存到var_4

image

上圖中是另一處引用,var_4的值傳給了 ecx,然後在與 ebp 進行異或運算,恢復原始值,然後再調用另一個函數檢查其值

點擊@__security_check_cookie@4,進入到這個函數內部,如下圖

image

上圖中,如果值一切正常,則返回,如果 ecx 中不是_security_cookie的值,將會終止進程,而不是執行返回,這只會發生在內存溢出將 var_4 覆蓋的時候

按 N 鍵,現在將var_4重命名為COOKIE

image

下面的函數命名為check_cookie

image

修改後最終如下:

image

回到函數起始點處,有兩個變量還不清楚作用,一個是var_90的初始值為0,另一個是size,初始值為8,如下圖

image

如下圖,查看var_7d的引用,在某個函數被調用後,var_7d的值被傳入了 AL 寄存器,然後將值傳給了 EDX 寄存器,檢查其值是否為 0,確定輸出 Good reverser 或者 Bad reverser,所以這是一個單字節的變量,重命名 SUCCESS_FLAG,也就是最終計算的 flag 值。

image

按 N 重命名對var_7d進行重命名

image

將左側註冊成功的代碼塊改成綠色,右側註冊失敗改成黃色,上圖中,只要修改 JZ 這個指令,也就能實現成功註冊。

用戶名和密碼處理#

image

上圖中,有另一個變量var_90,初始值為 0,程序將 BUF 中的每個字節讀取出來,傳入 edx(在 0x231109 指令處),並和var_90相加,第一次循環中加的是 0,結果再保存到var_90,那麼之後的循環中 edx 加的是之前所有字節的和,將var_90重命名為SUMMARY。如下圖

image

上圖中var_84是循環的計數器,計數器加 1,只循環前 4 個字節,var_84大於等於 4 會跳出循環。將其命名為COUNTADDR

image

為了讓這個循環更好的顯示,按住 ctrl 鍵,在這三個循環上單擊,右鍵選擇 group nodes

image

最終顯示如下

image

如果想取消編組,則右鍵選擇 unhide group 或者點擊圖標

image

循環之後,獲取密碼

image

程序使用 Buf 存放獲取的密碼,因為程序已經保存了用戶名前 4 個字節的和。

image

上圖中,程序接著調用strlen()函數獲取密碼的長度,如果長度小於 4,那麼就退出程序,如果不小於 4,那麼程序進入右邊綠色代碼塊。

image

右邊綠色代碼塊中,使用atoi函數將密碼字符串轉成一個十六進制數,這個函數類似 python 中的hex()

image

然後十六進制密碼和0x1234進行異或運算,然後保存到 edx 變量中。

image

上圖中,將密碼與0x1234異或的結果及用戶名前 4 個字節的和傳入sub_231010函數中進行比較,根據比較的結果決定輸出結果。

image

sub_231010函數的參數中,arg_4 參數是首先傳到棧上的,可以對這兩個參數進行重命名。

image

右鍵單擊set type,ida 會根據參數識別函數原型。

image

函數聲明如下圖所示

image

ida 自動註釋與傳入參數一致

image

sub_231010內部,在兩個參數比較之前,密碼變量傳入了 eax,執行了 shl eax,1,相當於乘以 2

image

最後進行比較,如果這兩個數相等,程序轉向綠色代碼並將 1 傳入 al,跳出循環,然後傳入SUCCESS_FLAG,最終決定是否註冊成功。

image

算法總結#

程序首先將用戶名的前 4 個字節相加
密碼轉換為 16 進制後和 0x1234 進行異或運算,結果再乘以 2

下面構建一個基於用戶名的公式,註冊機也是基於這一點,根據用戶名計算密碼

x = password (16進制數)
(x ^ 0x1234)*2 = SUCCESS_FLAG

那麼x ^ 0x1234 = (SUCCESS_FLAG/2)

由於異或運算可逆。

A ^ B = C
A = B ^ C

那麼x = (SUCCESS_FLAG/2) ^ 0x1234

使用 python 編寫註冊機#

假如用戶輸入 “pepe”,長度小於 8 字節,那麼字節之和就可以按如下方式計算

sum = 0
user='pepe'
length=len(user)

for i in range(length):
	sum+=ord(user[i])

print(hex(sum))

那麼 pepe 前 4 個字節之和就是:

sum = 0
user='pepe'

for i in range(4):
	sum+=ord(user[i])

print(hex(sum))

image

接下來編寫一個適用於任何合法用戶名的註冊機

sum = 0
user=input("input user name:")

length=len(user)

for i in range(4):
	sum+=ord(user[i])

if(length>=4):
	print(hex(sum))

使用 input () 函數獲取命令行輸入,但是現在上述代碼適用於任何合法的賬戶

根據之前總結的公式x = (SUCCESS_FLAG/2) ^ 0x1234,將用戶名的計算結果除以 2,在和 0x1234 進行異或運算,找到十六進制的密碼

sum = 0
user=input("input user name:")

length=len(user)

for i in range(4):
	sum+=ord(user[i])

print(user)

if(length>=4):
	print("success_flag",hex(sum))
	password = (sum//2)^0x1234
	print("password:",password)

image

目前註冊機已經完成,密碼也從 16 進制轉成了 10 進制,python 的默認輸出就是 10 進制

上述代碼當輸入用戶名字符數達到 8 個字符時程序會崩潰,因為字符串最後還有一個終止符 null,連同終止符在內不能超過 8 個。當然輸入 7 個字符是沒問題的。

最後還有一個問題就是如果 4 個字符的和是個奇數。因為在比較之前密碼是乘以 2 的,結果永遠是一個偶數,所以這種情況就沒有解。

加個檢查流程

sum = 0
user=input("input user name:")

length=len(user)

for i in range(4):
	sum+=ord(user[i])

print(sum)
print(user)

if(sum%2==0):
	print("偶數")
	if(length>=4):
		print("success_flag",hex(sum))
		password = (sum//2)^0x1234
		print("password:",password)
else:
	print("奇數")

檢查用戶名字節加和 sum 除以 2 的餘數,如果不等於 0,sum 是奇數,對應的密碼是無解的。

奇數的情況

image

偶數的情況

image

這樣,註冊機就完成了

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。