剛開始學(xué)習(xí)逆向,,看著表面上“毫無規(guī)律”的代碼,,真的不知道如何下手。經(jīng)群里一位同志的推薦,看到了此文,看完后感覺思路上清晰了很多。我想這篇文章既然獲得了“看雪06年最佳逆向工程獎”自然尤其看點,,相信對于初學(xué)者來說是很好的一篇參考文章
標(biāo) 題: 【原創(chuàng)】qq反匯編日志1
作 者: freeGod
時 間: 2006-06-15,18:20
鏈 接: http://bbs./showthread.php?t=27458
2006年6月15日 9:30
oo,前兩天的反匯編記錄下來的東西都丟了(昨天重做系統(tǒng)時,,忘了),,不過還好,丟的東西大部分都是我的曲折錯誤分析
現(xiàn)在從新開始:(為寫遠(yuǎn)程暴力破解qq密碼程序而反匯編qq)
反匯編工具:OllyICE
現(xiàn)在開始:
用OllyICE加載qq.exe,,qq登錄對話框出現(xiàn),,隨便輸入密碼:123,運行,,一個錯誤對話框出現(xiàn),,
錯誤
輸入密碼與上次成功登錄得密碼不一致,
是否到服務(wù)器驗證,?
好,,打開OllyICE的模塊窗口,然后找到user32模塊,,打開右鍵菜單選中查看名稱,,OllyICE的名稱窗口出現(xiàn)了,,這里的函數(shù)都是
User32模塊中的,好,,找到MessageBoxA,,打開右鍵菜單選中反匯編窗口中跟隨,這樣就到了MessageBoxA函數(shù)的入口點,,按f2鍵設(shè)下
端點,,設(shè)好后點剛才qq跳出來的錯誤對話框上的否,qq用戶登錄又出現(xiàn)了,,再輸入123
OllyICE在我們剛才設(shè)置的MessageBoxA函數(shù)的入口點停了下來,,察看堆棧窗口
0012FC2C 60B5C8E7 /CALL 到 MessageBoxA 來自 MFC42.60B5C8E1
說明調(diào)用是MFC42庫中的60b5c8e1處的指令的前一條指令調(diào)用了MessageBoxA,在CALL 到 MessageBoxA 來自 MFC42.60B5C8E1上
右鍵,,打開右鍵菜單,,選中反匯編窗口跟隨,就到mfc42地址空間的60b5c8e7指令位置(不同的電腦,,可能值不一樣),上一條指令
就是調(diào)用MessageBoxA函數(shù)的,,如下所示
60B5C8DC |. FF7424 10 push dword ptr [esp+10] ; |Text
60B5C8E0 |. 51 push ecx ; |hOwner
60B5C8E1 |. FF15 D0B5B960 call [<&USER32.MessageBoxA>] ; \MessageBoxA
60B5C8E7 |. 5E pop esi
60B5C8E8 |. C2 0C00 retn 0C
在 60b5c8e7 pop esi上設(shè)置端點,然后點運行,剛才的那個錯誤對話框又出現(xiàn)了,,點否,,好,現(xiàn)在程序停在了我們剛才設(shè)置端點的位
置605c8e7處,,現(xiàn)在在MFC42地址空間中,,不管它,我們想到的位置是qq空間,,按兩下f8鍵,到了 00415c35 cmp eax,6 指令處,,看一
下OllyICE的標(biāo)題欄 OllyICE - QQ.exe -[cpu -主線程,,模塊 - qq]
好了這就是我們的目的地。
反匯編就從這里開始,,第一個分析的函數(shù)就是:包含 指令地址00415c35 的函數(shù)
第一步:找出 包含指令地址 00415c35 的 函數(shù)入口點
向上滾動反匯編窗口,,找到00415b55 地址
00415B52 \. C2 0400 retn 4
00415B55 /$ B8 5CD24C00 mov eax, 004CD25C
00415B5A |. E8 41A10500 call 0046FCA0
00415B5F |. 83EC 48 sub esp, 48
OllyICE 分析出這個是函數(shù)的入口點,,因為上面緊跟的是retn指令,,不過一般的函數(shù)入口處:應(yīng)該是
push ebp
mov ebp,esp
才對,如果是羅函數(shù)的話,,經(jīng)過優(yōu)化編譯的話就不是這個樣子了,,我們先在反匯編的是qq,,qq的軟件工程師水平應(yīng)該是可以
的,有可能經(jīng)過特殊處理,
004CD25C=004CD25C
eax=0012FCBC
本地調(diào)用來自 00414FE8, 00416FEE
這個交叉引用說明,,的確是函數(shù)的入口點
這樣函數(shù)入口點就確定了:004b5b55
第二步:確定函數(shù)結(jié)束地址,,按OllyICE 的提示 結(jié)束地址應(yīng)為:00415c9b retn 14,,一個函數(shù)有可能有多個出口
我們來做進(jìn)一步的鑒定,看看從004b5b55 到 00415c9b 之間的指令有無交叉引用到 00415c9b 以后的指令
答:沒有,,因此 00415c9b 即為函數(shù)的結(jié)束地址,,至此我們確定了函數(shù)的入口點和結(jié)束地址
004b5b55--00415c9b
現(xiàn)在我們開始還原 函數(shù) qq004b55 的源代碼
第三步:確定參數(shù)個數(shù)和參數(shù)類型
找到調(diào)用 004b5b55 函數(shù) 指令 :00414fe8 ------------------------------------
|
00414FD6 |. C645 FC 05 mov byte ptr [ebp-4], 5 |
00414FDA |. E8 A1A60500 call <jmp.&MFC42.#535_CString::CString> |
00414FDF |. FF75 EC push dword ptr [ebp-14] |
00414FE2 |. 8BCB mov ecx, ebx |
00414FE4 |. C645 FC 05 mov byte ptr [ebp-4], 5 |
00414FE8 |. E8 680B0000 call 00415B55 ---------------------------------
00414FED |. FFD6 call esi
00414FE2 |. 8BCB mov ecx, ebx --- ecx 應(yīng)該是個寄存器參數(shù),要不這條指令就是個垃圾指令
函數(shù)004b5b55 可能有一個寄存器參數(shù),,說可能,,是因為編譯器生成的垃圾指令到處可見,要對ecx進(jìn)一步鑒定,,要
分析004b5b55 函數(shù)的代碼
00415B55 /$ B8 5CD24C00 mov eax, 004CD25C
00415B5A |. E8 41A10500 call 0046FCA0
00415B5F |. 83EC 48 sub esp, 48
00415B62 |. 53 push ebx
00415B63 |. 56 push esi
00415B64 |. 33DB xor ebx, ebx
00415B66 |. 895D FC mov [ebp-4], ebx
00415B69 |. 895D F0 mov [ebp-10], ebx
00415B6C |. 8B81 84000000 mov eax, [ecx+84]
在函數(shù)的開始處,,調(diào)用了一個函數(shù) 0046fca0,察看一下它的代碼,看看和ecx有染沒有
0046FCA0 /$ 6A FF push -1
0046FCA2 |. 50 push eax
0046FCA3 |. 64:A1 0000000>mov eax, fs:[0]
0046FCA9 |. 50 push eax
0046FCAA |. 8B4424 0C mov eax, [esp+C]
0046FCAE |. 64:8925 00000>mov fs:[0], esp
0046FCB5 |. 896C24 0C mov [esp+C], ebp
0046FCB9 |. 8D6C24 0C lea ebp, [esp+C]
0046FCBD |. 50 push eax
0046FCBE \. C3 retn
哈哈,,這個函數(shù)挺簡練的,,和ecx無關(guān),這就好,,再看看00415b6c地址 以上的指令都與ecx無關(guān),,而在00415b6c處引用了
ecx,因此斷定ecx就是一個寄存器參數(shù),,不錯,,good
下面來看一下004b5b55 函數(shù) 有多少個堆棧參數(shù)
從函數(shù)結(jié)束地址 00415C9B \. C2 1400 retn 14
可知 堆棧參數(shù)個數(shù)為 14h / 4 = 5
到此我們確定了參數(shù)的個數(shù):一個寄存器參數(shù) + 5 個堆棧參數(shù) = 6(說明函數(shù)采用的是fastcall調(diào)用方式)
給他們編號分別為:arg1,arg2,arg3,arg4,arg5,arg6
下面我們來確定參數(shù)類型
在指令中識別參數(shù)
函數(shù)004b5b55 每有標(biāo)準(zhǔn)的函數(shù)頭 即 push ebp ; mov ebp,esp,如果是采用優(yōu)化編譯的話,參數(shù)應(yīng)該用esp寄存器來尋址
可在函數(shù)過程中只在分配局部變量時,,用了一次esp
00415B5F |. 83EC 48 sub esp, 48
其他的地方都沒有,,令人奇怪的是到處都是用ebp寄存器尋址的,對了,,函數(shù)入口點,,調(diào)用了一個函數(shù):0046fca0
看看它都實現(xiàn)了什么功能
0046FCA0 /$ 6A FF push -1
執(zhí)行指令后堆棧數(shù)據(jù)
相對esp的地址 數(shù)據(jù)
esp -1
esp+4 ret addr
0046FCA2 |. 50 push eax
執(zhí)行指令后堆棧數(shù)據(jù)
相對esp的地址 數(shù)據(jù)
esp eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
esp+4 -1
esp+8 ret addr
0046FCA3 |. 64:A1 0000000>mov eax, fs:[0] ;eax 指向 seh (結(jié)構(gòu)化異常處理)
0046FCA9 |. 50 push eax
執(zhí)行指令后堆棧數(shù)據(jù)
相對esp的地址 數(shù)據(jù)
esp eax (seh 指針)
esp+4 eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
esp+8 -1
esp+c ret addr
0046FCAA |. 8B4424 0C mov eax, [esp+C] ,;把ret addr 傳遞給eax
執(zhí)行指令后堆棧數(shù)據(jù)
相對esp的地址 數(shù)據(jù)
esp eax (seh 指針)
esp+4 eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
esp+8 -1
esp+c ret addr
0046FCAE |. 64:8925 00000>mov fs:[0], esp ,;此時esp指向一個 EXCEPTION_REGISTRATION 結(jié)構(gòu)
;表明同過寄存器eax傳遞給函數(shù)的是異?;卣{(diào)函數(shù)地址
,;-1 則是seh 的附加數(shù)據(jù)
執(zhí)行指令后堆棧數(shù)據(jù)
相對esp的地址 數(shù)據(jù)
esp eax (seh 指針)<-------------------------------fs:[0]
esp+4 eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
esp+8 -1
esp+c ret addr
0046FCB5 |. 896C24 0C mov [esp+C], ebp ;保存ebp 到 原來 ret addr 所占堆棧位置
執(zhí)行指令后堆棧數(shù)據(jù)
相對esp的地址 數(shù)據(jù)
esp eax (seh 指針)<-------------------------------fs:[0]
esp+4 eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
esp+8 -1
esp+c ebp ----- 注意發(fā)生變化了
0046FCB9 |. 8D6C24 0C lea ebp, [esp+C] ,;ebp指向 保存ebp的位置(也即原來 ret addr 的位置)
執(zhí)行指令后堆棧數(shù)據(jù)
相對esp的地址 數(shù)據(jù)
esp eax (seh 指針)<-------------------------------fs:[0]
esp+4 eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
esp+8 -1
esp+c ebp ----- 注意發(fā)生變化了<------------------------ ebp
0046FCBD |. 50 push eax
執(zhí)行指令后堆棧數(shù)據(jù)
相對ebp的地址 相對esp的地址 數(shù)據(jù)
ebp-10 esp eax(函數(shù)的返回地址)
ebp-c esp+4 eax (seh 指針)<-------------------------------fs:[0]
ebp-8 esp+8 eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
ebp-4 esp+c -1
ebp esp+10 ebp ----- 注意發(fā)生變化了<------------------------ ebp
0046FCBE \. C3 retn
執(zhí)行指令后堆棧數(shù)據(jù)
相對ebp的地址 相對esp的地址 數(shù)據(jù)
ebp-c esp eax (seh 指針)<-------------------------------fs:[0]
ebp-8 esp+4 eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
ebp-4 esp+8 -1
ebp esp+c ebp ----- 注意發(fā)生變化了<------------------------ ebp
因為 函數(shù)0046fca0沒有堆棧參數(shù),,所以 ebp+4 指向的是它的父函數(shù)即 004b5b55 結(jié)束時要返回的地址
相對ebp的地址 相對esp的地址 數(shù)據(jù)
ebp-c esp eax (seh 指針)<-------------------------------fs:[0]
ebp-8 esp+4 eax (通過寄存器eax傳遞過來的參數(shù)進(jìn)棧)
ebp-4 esp+8 -1
ebp esp+c ebp ----- 注意發(fā)生變化了<------------------------ ebp
ebp +4 esp+10 004b5b55函數(shù) 結(jié)束時要返回的地址
綜上所述:0046fca0 實現(xiàn)的功能為:《1》注冊異常回調(diào)函數(shù)
《2》實現(xiàn)了和 push ebp
mov ebp,esp
查不多的功能,,調(diào)用0046fca0函數(shù)的函數(shù)的第一個堆棧參數(shù)地址為 ebp +8
這和push ebp ;move ebp,esp 是一樣的,,但是局部變量的尋址就不一樣了
調(diào)用0046fca0 函數(shù)的函數(shù)局部變量是從ebp-d 開始的,而不是從ebp-4開始的
搞定……^_^
現(xiàn)在我們就可以很輕松的識別出參數(shù)了,開始吧
識別參數(shù)類型
首先我用32位匯編語言來實現(xiàn)00415b55,,我給他起個名字叫 _lastStep 吧,我把寄存器傳參也改成堆棧方式
_LastStep proc _arg1,_arg2,_arg3,_arg4,_arg5,_arg6
mov eax,004cd25c
call 0046fca0
sub esp,48h
push ebx
push esi
xor ebx,ebx
mov [ebp-4],ebx ;[ebp-4] 是seh附加數(shù)據(jù)的地址,,原來值為-1,現(xiàn)在要把它置零了
mov @dwVar1,ebx
mov ecx,_arg1
mov eax,[ecx+84] ,;可知_arg1 是一個指針
lea edx,@dwVar1
push edx
push 004e7460
mov ecx,[eax]
push eax
mov byte ptr[ebp-4],1 ;[ebp-4] 是seh附加數(shù)據(jù)的地址
call [ecx+1c] ;表明_arg1 是一個函數(shù)指針的指針的指針
test eax,eax
jnz lable1
mov eax,@dwVar1
lea edx,@dwVar2
push edx
push 004e8940 ;ascii "ewh.db"
mov ecx,[eax]
push eax
call [ecx+14]
test eax,eax
je label2
lable1:
mov eax,_arg4 ;可知_arg4 是一個int*
mov dword ptr[eax],2
jmp lable3
lable2:
mov eax,_arg3
push edi
mov edx,@dwVar1
push 1
mov ecx,[eax-8]
pop esi
mov edi,[edx]
push esi
push eax
push ecx
push ebx
push dword ptr _arg2
push edx
call [edi+1c]
test eax,eax
pop edi
je lable4
cmp _arg6,esi
je lable5
mov eax,_arg4
mov [eax],ebx ;可知_arg4是個指針
jmp lable3
lable5:
lea ecx,_arg6
call CString::CString
lea ecx,_arg2
mov byte ptr [ebp-4],2
call CString::CString
mov esi,BasicCtrDll.BasicLoadStr
lea eax,_arg6
push 281
push eax
mov byte prt[ebp-4],3
call esi
lea eax,_arg2
push 28d
push eax
call esi
add esp,10
lea ecx,[ebp-54] ;ebp-54 指向一個結(jié)構(gòu)
call CWNd::CWnd
push 114
lea ecx,[ebp-54]
push dword ptr _arg2
mov byte prt[ebp-4],4
push dword ptr _arg6
call CWnd::MessageBoxA
cmp eax,6
mov eax,_arg4
jnz Lable6
mov dword prt[eax],2
jmp lable7
lable6:
mov [eax],ebx
lable7:
lea ecx,[ebp-54]
mov byte ptr[ebp-4],3
call CWnd::~Cwnd
lea ecx,_arg2
mov byte ptr[ebp-4],2
call CString::~CString
lea ecx,_arg6
mov byte ptr[ebp-4],1
call CString::~Cstring
jmp lable3
lable4:
mov eax,_arg4
mov [eax],esi
lable3:
mov eax,@dwVar1
mov [ebp-4],bl
cmp eax,ebx
je lable8
mov ecx,[eax]
push eax
call [ecx+8]
lable8:
or dwword ptr[ebp-4],0ffffffffh
lea ecx,_arg3
call CString::~CString
mov ecx,[ebp-c] ; pre seh handler 指針
pop esi
pop ebx
mov fs:[0],ecx
leave
retn 14
_LastSetp enp
2006-06-17 20:00
識別函數(shù)中的參數(shù)和局部變量
經(jīng)過上面的分析我們已經(jīng)知道在qq00405b55函數(shù)中參數(shù)和局部變量都是用ebp寄存器來表示的,現(xiàn)在我們來找出函數(shù)中的參數(shù),,和局部變量
首先:我們把函數(shù)中使用ebp寄存器尋找的變量找出來,,刪除重復(fù)的并按從低地址到高地址排序,得到如下結(jié)果:
ebp-54h
ebp-14h
ebp-10h
ebp-ch
ebp-4h
ebp+8h
ebp+ch
ebp+10h
ebp+18h
我們知道堆棧參數(shù)是:從ebp+8開始向高地址方向的,,局部變量是從ebp-d開始向低地址方向的
現(xiàn)在給他們分組:
堆棧參數(shù)有:ebp+8h,ebp+ch,ebp+10h,ebp+18h,堆棧參數(shù)名我們規(guī)定從低地址開始編號_arg1,_arg2,_arg3,....,所以就有 :
ebp+8h = _arg1
ebp+ch = _arg2
ebp+10h = _arg3
ebp+18h = _arg4 少了一個 怎么沒有ebp+14h 呢,,_arg3 占了8個字節(jié)的地盤?,?,?先不管它,呆會分析參數(shù)類型的時候在看
局部變量有:ebp-10h,ebp-14h,ebp-54h,局部變量我們規(guī)定從高地址開始編號@var1,@var2,@var3,.....所以有:
ebp-10h = @var1 因為局部變量是從ebp-d開始的所以可知這個局部變量的大小為(10h-d)+1 4 byte
ebp-14h = @var2 同理:這個緊挨著@var1 可知他也為(14h-11h)+1 4 byte
ebp-54h = @var3 這是最后一個變量,,它的大小為:(54h-15h)+1 = 40h byte
還有幾個孤兒,,沒有組的,他們是ebp-ch,和ebp-4h,,日至1中已經(jīng)知道他們分別是seh指針和seh的附加數(shù)據(jù)
第二步:我們將參數(shù)名,、局部變量名替換到反匯編代碼中去,還有跳轉(zhuǎn)地址我們也用相應(yīng)的標(biāo)號替換掉就得到了
mov eax, 004CD25C
call 0046FCA0
sub esp, 48
push ebx
push esi
xor ebx, ebx
mov [ebp-4], ebx
mov @var1, ebx
mov eax, [ecx+84]
lea edx, @var1
push edx
push 004E7460
mov ecx, [eax]
push eax
mov byte ptr [ebp-4], 1
call [ecx+1C]
test eax, eax
jnz lable1 ;short 00415B9F
mov eax, @var1
lea edx, @var2
push edx
push 004E8940
mov ecx, [eax]
push eax
call [ecx+14]
test eax, eax
je lable2 ;short 00415BAD
lable1:
mov eax, _arg3
mov dword ptr [eax], 2
jmp lable3 ;00415C72
lable2:
mov eax, _arg2
push edi
mov edx, @var1
push 1
mov ecx, [eax-8]
pop esi
mov edi, [edx]
push esi
push eax
push ecx
push ebx
push dword ptr _arg1
push edx
call [edi+1C]
test eax, eax
pop edi
je lable4 ;00415C6D
cmp _arg4, esi
je lable5 ;short 00415BDF
mov eax, _arg3
mov [eax], ebx
jmp lable3 ;00415C72
lable5:
lea ecx, _arg4
call <jmp.&MFC42.#540_CString::CStrin>
lea ecx, _arg1
mov byte ptr [ebp-4], 2
call <jmp.&MFC42.#540_CString::CStrin>
mov esi, [<&BasicCtrlDll.BasicLoadSt>; BasicCtr.BasicLoadStr
lea eax, _arg4
push 281
push eax
mov byte ptr [ebp-4], 3
call esi ; <&BasicCtrlDll.BasicLoadStr>
lea eax, _arg1
push 28D
push eax
call esi
add esp, 10
lea ecx, @var3
call <jmp.&MFC42.#567_CWnd::CWnd>
push 114
lea ecx, @var3
push dword ptr _arg1
mov byte ptr [ebp-4], 4
push dword ptr _arg4
call <jmp.&MFC42.#4224_CWnd::MessageB>
cmp eax, 6
mov eax, _arg3
jnz label6 ;short 00415C45
mov dword ptr [eax], 2 ; [eax]可能保存的是某個標(biāo)志,,2代表本地登陸失敗,,到服務(wù)器上去驗證去
jmp lable7 ;short 00415C47
lable6:
mov [eax], ebx
lable7:
lea ecx, @var3
mov byte ptr [ebp-4], 3 ; [12fcac]
call <jmp.&MFC42.#818_CWnd::~CWnd>
lea ecx, _arg1
mov byte ptr [ebp-4], 2
call <jmp.&MFC42.#800_CString::~CStri>
lea ecx, _arg4
mov byte ptr [ebp-4], 1
call <jmp.&MFC42.#800_CString::~CStri>
jmp lable3 ;short 00415C72
lable4:
mov eax, _arg3
mov [eax], esi
lable3:
mov eax, _arg3
mov [ebp-4], bl
cmp eax, ebx
je lable8 ;short 00415C82
mov ecx, [eax]
push eax
call [ecx+8]
lable8:
or dword ptr [ebp-4], FFFFFFFF
lea ecx, _arg2
call <jmp.&MFC42.#800_CString::~CStri>
mov ecx, [ebp-C] ; seh 指針
pop esi
pop ebx
mov fs:[0], ecx
leave
retn 14 ; 父函數(shù)傳遞了5個參數(shù)
靠,終于整完了
下一步:去掉編譯器自己添加的或與函數(shù)功能無關(guān)的,,異常處理東東
刪掉
mov eax, 004CD25C
call 0046FCA0
注冊異常處理函數(shù),,打開堆棧頁面
sub esp, 48 ;分配局部變量空間
刪掉
mov ecx, [ebp-C] ; seh 指針
刪掉
mov fs:[0], ecx
leave
retn 14
將注冊的異常處理函數(shù)刪除掉,,堆棧平衡
剩下的就是裸函數(shù)了
push ebx
push esi
xor ebx, ebx
mov [ebp-4], ebx
mov @var1, ebx
mov eax, [ecx+84]
lea edx, @var1
push edx
push 004E7460
mov ecx, [eax]
push eax
mov byte ptr [ebp-4], 1
call [ecx+1C]
test eax, eax
jnz lable1
mov eax, @var1
lea edx, @var2
push edx
push 004E8940
mov ecx, [eax]
push eax
call [ecx+14]
test eax, eax
je lable2
lable1:
mov eax, _arg3
mov dword ptr [eax], 2
jmp lable3
lable2:
mov eax, _arg2
push edi
mov edx, @var1
push 1
mov ecx, [eax-8]
pop esi
mov edi, [edx]
push esi
push eax
push ecx
push ebx
push dword ptr _arg1
push edx
call [edi+1C]
test eax, eax
pop edi
je lable4
cmp _arg4, esi
je lable5
mov eax, _arg3
mov [eax], ebx
jmp lable3
lable5:
lea ecx, _arg4
call <jmp.&MFC42.#540_CString::CStrin>
lea ecx, _arg1
mov byte ptr [ebp-4], 2
call <jmp.&MFC42.#540_CString::CStrin>
mov esi, [<&BasicCtrlDll.BasicLoadSt>; BasicCtr.BasicLoadStr
lea eax, _arg4
push 281
push eax
mov byte ptr [ebp-4], 3
call esi ; <&BasicCtrlDll.BasicLoadStr>
lea eax, _arg1
push 28D
push eax
call esi
add esp, 10
lea ecx, @var3
call <jmp.&MFC42.#567_CWnd::CWnd>
push 114
lea ecx, @var3
push dword ptr _arg1
mov byte ptr [ebp-4], 4
push dword ptr _arg4
call <jmp.&MFC42.#4224_CWnd::MessageB>
cmp eax, 6
mov eax, _arg3
jnz label6
mov dword ptr [eax], 2
jmp lable7
lable6:
mov [eax], ebx
lable7:
lea ecx, @var3
mov byte ptr [ebp-4], 3
call <jmp.&MFC42.#818_CWnd::~CWnd>
lea ecx, _arg1
mov byte ptr [ebp-4], 2
call <jmp.&MFC42.#800_CString::~CStri>
lea ecx, _arg4
mov byte ptr [ebp-4], 1
call <jmp.&MFC42.#800_CString::~CStri>
jmp lable3
lable4:
mov eax, _arg3
mov [eax], esi
lable3:
mov eax, _arg3
mov [ebp-4], bl
cmp eax, ebx
je lable8
mov ecx, [eax]
push eax
call [ecx+8]
lable8:
or dword ptr [ebp-4], FFFFFFFF
lea ecx, _arg2
call <jmp.&MFC42.#800_CString::~CStri>
pop esi
pop ebx
讓函數(shù)光著身子不好,,現(xiàn)在給它穿上衣服吧
我先給它穿上win32asm 這套衣服,以后再給她穿c++這套衣服,給這個過程起個名字:叫 _TempName 吧,,現(xiàn)在還不知道她是做什么用的,知道了,再換
寄存器參數(shù)我用 _regArg1,_regArg2,...表示
_TempName Proc _regArg1,_arg1,_arg2,_arg3,_arg?,_arg4 (因為不知道倒數(shù)第二個為什么沒有在函數(shù)中引用過,,所以先用?表示)
push ebx
push esi
xor ebx, ebx
mov [ebp-4], ebx
mov @var1, ebx
mov eax, [ecx+84]
lea edx, @var1
push edx
push 004E7460
mov ecx, [eax]
push eax
mov byte ptr [ebp-4], 1
call [ecx+1C]
test eax, eax
jnz lable1
mov eax, @var1
lea edx, @var2
push edx
push 004E8940
mov ecx, [eax]
push eax
call [ecx+14]
test eax, eax
je lable2
lable1:
mov eax, _arg3
mov dword ptr [eax], 2
jmp lable3
lable2:
mov eax, _arg2
push edi
mov edx, @var1
push 1
mov ecx, [eax-8]
pop esi
mov edi, [edx]
push esi
push eax
push ecx
push ebx
push dword ptr _arg1
push edx
call [edi+1C]
test eax, eax
pop edi
je lable4
cmp _arg4, esi
je lable5
mov eax, _arg3
mov [eax], ebx
jmp lable3
lable5:
lea ecx, _arg4
call <jmp.&MFC42.#540_CString::CStrin>
lea ecx, _arg1
mov byte ptr [ebp-4], 2
call <jmp.&MFC42.#540_CString::CStrin>
mov esi, [<&BasicCtrlDll.BasicLoadSt>; BasicCtr.BasicLoadStr
lea eax, _arg4
push 281
push eax
mov byte ptr [ebp-4], 3
call esi ; <&BasicCtrlDll.BasicLoadStr>
lea eax, _arg1
push 28D
push eax
call esi
add esp, 10
lea ecx, @var3
call <jmp.&MFC42.#567_CWnd::CWnd>
push 114
lea ecx, @var3
push dword ptr _arg1
mov byte ptr [ebp-4], 4
push dword ptr _arg4
call <jmp.&MFC42.#4224_CWnd::MessageB>
cmp eax, 6
mov eax, _arg3
jnz label6
mov dword ptr [eax], 2
jmp lable7
lable6:
mov [eax], ebx
lable7:
lea ecx, @var3
mov byte ptr [ebp-4], 3
call <jmp.&MFC42.#818_CWnd::~CWnd>
lea ecx, _arg1
mov byte ptr [ebp-4], 2
call <jmp.&MFC42.#800_CString::~CStri>
lea ecx, _arg4
mov byte ptr [ebp-4], 1
call <jmp.&MFC42.#800_CString::~CStri>
jmp lable3
lable4:
mov eax, _arg3
mov [eax], esi
lable3:
mov eax, _arg3
mov [ebp-4], bl
cmp eax, ebx
je lable8
mov ecx, [eax]
push eax
call [ecx+8]
lable8:
or dword ptr [ebp-4], FFFFFFFF
lea ecx, _arg2
call <jmp.&MFC42.#800_CString::~CStri>
pop esi
pop ebx
ret
_TempName endp
下一步分析qq00415b55 調(diào)用的函數(shù)
第一個 call [ecx+1C] oo 是個間接調(diào)用指令,,那來動態(tài)跟蹤以下調(diào)用的是什么,?00410ee2
00410EE2 . B8 CCC84C00 mov eax, 004CC8CC
00410EE7 . E8 B4ED0500 call 0046FCA0
00410EEC . 51 push ecx
00410EED . 51 push ecx
00410EEE . 8B45 08 mov eax, [ebp+8]
00410EF1 . 56 push esi
00410EF2 . 8D4D EC lea ecx, [ebp-14]
00410EF5 . FF70 D8 push dword ptr [eax-28]
00410EF8 . 8D70 BC lea esi, [eax-44]
00410EFB . E8 94E80500 call <jmp.&MFC42.#6467_AFX_MAINTAIN_S>
00410F00 . FF75 10 push dword ptr [ebp+10] ; /Arg2
00410F03 . 8365 FC 00 and dword ptr [ebp-4], 0 ; |
00410F07 . 8BCE mov ecx, esi ; |
00410F09 . FF75 0C push dword ptr [ebp+C] ; |Arg1
00410F0C . E8 71040000 call 00411382 ; \QQ.00411382
00410F11 . 8B4D F0 mov ecx, [ebp-10]
00410F14 . 8B55 EC mov edx, [ebp-14]
00410F17 . 834D FC FF or dword ptr [ebp-4], FFFFFFFF
00410F1B . 5E pop esi
00410F1C . 8951 04 mov [ecx+4], edx
00410F1F . 8B4D F4 mov ecx, [ebp-C]
00410F22 . 64:890D 00000>mov fs:[0], ecx
00410F29 . C9 leave
00410F2A . C2 0C00 retn 0C
分析過程和 分析qq00415b55 一樣
經(jīng)分析可知 函數(shù)沒有寄存器參數(shù),,c/4=3個堆棧參數(shù),,這里要注意的是
00410EEC . 51 push ecx
00410EED . 51 push ecx
這兩條指令是分配局部變量空間的,因為函數(shù)中有兩個局部變量,,這是編譯器快速分配局部變量而使得花招
00410ee2 的函數(shù)原型為:
00410ee2 proto _arg1,_arg2,_arg3
下一個qq00415b55調(diào)用的函數(shù)是 call [ecx+14] = 0044c62b
0044C62B . B8 84424D00 mov eax, 004D4284
0044C630 . E8 6B360200 call 0046FCA0
0044C635 . 51 push ecx
0044C636 . 51 push ecx
0044C637 . 8B45 08 mov eax, [ebp+8]
0044C63A . 56 push esi
0044C63B . 8D4D EC lea ecx, [ebp-14]
0044C63E . FF70 FC push dword ptr [eax-4]
0044C641 . 8D70 E0 lea esi, [eax-20]
0044C644 . E8 4B310200 call <jmp.&MFC42.#6467_AFX_MAINTAIN_STATE2::AFX_MAINTAIN_STATE2>
0044C649 . FF75 10 push dword ptr [ebp+10]
0044C64C . 8B06 mov eax, [esi]
0044C64E . 8365 FC 00 and dword ptr [ebp-4], 0
0044C652 . FF75 0C push dword ptr [ebp+C]
0044C655 . 56 push esi
0044C656 . FF50 64 call [eax+64]
0044C659 . 8B4D F0 mov ecx, [ebp-10]
0044C65C . 8B55 EC mov edx, [ebp-14]
0044C65F . 834D FC FF or dword ptr [ebp-4], FFFFFFFF
0044C663 . 5E pop esi
0044C664 . 8951 04 mov [ecx+4], edx
0044C667 . 8B4D F4 mov ecx, [ebp-C]
0044C66A . 64:890D 00000>mov fs:[0], ecx
0044C671 . C9 leave
0044C672 . C2 0C00 retn 0C
看起來好像和上個函數(shù)長得很像
函數(shù)原型為:
0044c62b proto _arg1,_arg2,_arg3
next function: 0044c6c5
函數(shù)原型為:
0044c6c5 proto _arg1,_arg2,_arg3,_arg4,_arg5,_arg6
下一個函數(shù)是 BasicCtr.BasicLoadStr
60092057 >/$ 55 push ebp
60092058 |. 8BEC mov ebp, esp
6009205A |. 56 push esi
6009205B |. 57 push edi
6009205C |. E8 5FCD0000 call <jmp.&MFC42.#1168_AfxGetModuleState>
60092061 |. 8B70 0C mov esi, [eax+C]
60092064 |. 8B3D BC8B0B60 mov edi, [600B8BBC] ; BasicCtr.60090000
6009206A |. E8 51CD0000 call <jmp.&MFC42.#1168_AfxGetModuleState>
6009206F |. FF75 0C push dword ptr [ebp+C]
60092072 |. 8B4D 08 mov ecx, [ebp+8]
60092075 |. 8978 0C mov [eax+C], edi
60092078 |. E8 91CD0000 call <jmp.&MFC42.#4160_CString::LoadStringA>
6009207D |. E8 3ECD0000 call <jmp.&MFC42.#1168_AfxGetModuleState>
60092082 |. 8970 0C mov [eax+C], esi
60092085 |. 5F pop edi
60092086 |. 5E pop esi
60092087 |. 5D pop ebp
60092088 \. C3 retn
可算見到一個正常函數(shù),,函數(shù)有兩個堆棧參數(shù)參數(shù),沒有寄存器參數(shù),,這個函數(shù)調(diào)用方式屬于_cdel方式,,平很堆棧交給了
qq00415b55,,qq00415b55調(diào)用完這個函數(shù)后并沒有做平衡堆棧,而是在第二次調(diào)用完這個函數(shù)后一起做了堆棧平衡,,這可能是
優(yōu)化編譯的結(jié)果,,這樣節(jié)省一條指令
我們從basicCtr.BasicLoadStr中也可以找出參數(shù),[ebp+8],[ebp+c]這兩個
在qq00415b55中平衡堆棧代碼
00415C06 |. FFD6 call esi ; BasicCtr.BasicLoadStr; <&BasicCtrlDll.BasicLoadStr>
00415C08 |. 8D45 08 lea eax, [ebp+8] ; _arg2
00415C0B |. 68 8D020000 push 28D
00415C10 |. 50 push eax
00415C11 |. FFD6 call esi
00415C13 |. 83C4 10 add esp, 10 ---------------------平衡了兩次調(diào)用,一個函數(shù)的參數(shù)個數(shù)=10h/2/4=2個
所以這個函數(shù)的原型應(yīng)為:
BasicCtr.BasicLoadStr proto _arg1,_arg2
下一個,,也是qq00415b55調(diào)用qq自定義函數(shù)中的最后一個 0044cf97 函數(shù)只有一個堆棧參數(shù),,沒有寄存器參數(shù),函數(shù)原型為:
0044cf97 proc _arg1
經(jīng)過上面的分析,,qq00415b55 的win32asm 源代碼應(yīng)為:
BasicCtr.BasicLoadStr proto _arg1,_arg2
0044cf97 proto _arg1
_TempName Proc _regArg1,_arg1,_arg2,_arg3,_arg?,_arg4 (因為不知道倒數(shù)第二個為什么沒有在函數(shù)中引用過,,所以先用?表示)
local @dwVar1,@dwVar2
local @wnd:CWnd (這個以后再解釋)
push ebx
push esi
xor ebx, ebx
mov [ebp-4], ebx
mov @var1, ebx
mov eax, [ecx+84]
mov ecx, [eax]
mov byte ptr [ebp-4], 1
invoke [ecx+1c],eax,004e7460,addr @var1 (這里不管 addr 會覆蓋掉 eax的值)
test eax, eax
jnz lable1
mov eax, @var1
mov ecx, [eax]
invoke [ecx+14],eax,004e8940,addr @var2(這里不管 addr 會覆蓋掉 eax的值)
test eax, eax
je lable2
lable1:
mov eax, _arg3
mov dword ptr [eax], 2
jmp lable3
lable2:
mov eax, _arg2
push edi
mov edx, @var1
push 1
mov ecx, [eax-8]
pop esi
mov edi, [edx]
invoke [edi+1c],edx,_arg1,ebx,ecx,eax,esi
test eax, eax
pop edi
je lable4
cmp _arg4, esi
je lable5
mov eax, _arg3
mov [eax], ebx
jmp lable3
lable5:
invoke CString::CString,_arg4
mov byte ptr [ebp-4], 2
invoke CString::CString>,_arg1
mov byte ptr [ebp-4], 3
invoke BasicCtrlDll.BasicLoadStr,addr _arg4,281h
invoke BasicCtrlDll.BasicLoadStr,addr _arg1,28dh
invoke CWnd::CWnd,addr @wnd
mov byte ptr [ebp-4], 4
invoke CWnd::MessageBox,addr @wnd,_arg4,_arg1,MB_YESNO or MB_DEFBUTTON2 or MB_ICONHAND (114h) ;這個就是登錄失敗的時候的標(biāo)題和信息
cmp eax, 6
mov eax, _arg3
jnz label6
mov dword ptr [eax], 2
jmp lable7
lable6:
mov [eax], ebx
lable7:
mov byte ptr [ebp-4], 3
invoke CWnd::~CWnd,addr @wnd
mov byte ptr [ebp-4], 2
invoke CString::~CString,addr _arg1
mov byte ptr [ebp-4], 1
invoke CString::~CString,_arg4
jmp lable3
lable4:
mov eax, _arg3
mov [eax], esi
lable3:
mov eax, _arg3
mov [ebp-4], bl
cmp eax, ebx
je lable8
mov ecx, [eax]
invoke [ecx+8],eax
lable8:
or dword ptr [ebp-4], FFFFFFFF
invoke CString::~CString,_arg2
pop esi
pop ebx
ret
_TempName endp
2006-6-18 8:28
識別參數(shù)類型和局部變量類型
xor ebx, ebx
mov [ebp-4], ebx
mov @var1, ebx
由這三天指令中的上下兩條指令:@var1 應(yīng)該是個整數(shù)類型的 改名為@intVar1
mov ecx,_regArg1
mov eax, [ecx+84]
mov ecx, [eax]
mov byte ptr [ebp-4], 1
invoke [ecx+1c],eax,004e7460,addr @var1 (這里不管 addr 會覆蓋掉 eax的值)
第一次反匯編,,最少面那條指令在日至2中漏掉了
由上面可知:[ecx+1c]=[[eax]+1c]=[[[_regArg1+1c]]]=***(_regArg1+1c) 可知 _regArg1 是函數(shù)指針的指針的指針
@var2的類型現(xiàn)在還不能判斷,,80% 他和@intVar1類型一樣,只有跟進(jìn)[ecx+14]函數(shù)中才知道
0044C62B . B8 84424D00 mov eax, 004D4284
0044C630 . E8 6B360200 call 0046FCA0
0044C635 . 51 push ecx
0044C636 . 51 push ecx
0044C637 . 8B45 08 mov eax, [ebp+8]
0044C63A . 56 push esi
0044C63B . 8D4D EC lea ecx, [ebp-14]
0044C63E . FF70 FC push dword ptr [eax-4]
0044C641 . 8D70 E0 lea esi, [eax-20]
0044C644 . E8 4B310200 call <jmp.&MFC42.#6467_AFX_MAINTAIN_S>
0044C649 . FF75 10 push dword ptr [ebp+10]
0044C64C . 8B06 mov eax, [esi]
0044C64E . 8365 FC 00 and dword ptr [ebp-4], 0
0044C652 . FF75 0C push dword ptr [ebp+C]
0044C655 . 56 push esi
0044C656 . FF50 64 call [eax+64]
0044C659 . 8B4D F0 mov ecx, [ebp-10]
0044C65C . 8B55 EC mov edx, [ebp-14]
0044C65F . 834D FC FF or dword ptr [ebp-4], FFFFFFFF
0044C663 . 5E pop esi
0044C664 . 8951 04 mov [ecx+4], edx
0044C667 . 8B4D F4 mov ecx, [ebp-C]
0044C66A . 64:890D 00000>mov fs:[0], ecx
0044C671 . C9 leave
0044C672 . C2 0C00 retn 0C
@var2 對應(yīng)著第三個參數(shù)即[ebp+10]
0044C649 . FF75 10 push dword ptr [ebp+10]
0044C64C . 8B06 mov eax, [esi]
0044C64E . 8365 FC 00 and dword ptr [ebp-4], 0
0044C652 . FF75 0C push dword ptr [ebp+C]
0044C655 . 56 push esi
0044C656 . FF50 64 call [eax+64]
看來還要再跟進(jìn)去
0044D23C . B8 B4454D00 mov eax, 004D45B4
0044D241 . E8 5A2A0200 call 0046FCA0
0044D246 . 83EC 10 sub esp, 10
0044D249 . 8B45 10 mov eax, [ebp+10]
0044D24C . 53 push ebx
0044D24D . 56 push esi
0044D24E . 57 push edi
0044D24F . C700 01000000 mov dword ptr [eax], 1
0044D255 . E8 32240200 call <jmp.&MFC42.#1154_AfxGetAppModul>
0044D25A . 8B40 04 mov eax, [eax+4]
0044D25D . 33DB xor ebx, ebx
0044D25F . 8B80 D4000000 mov eax, [eax+D4]
0044D265 . 3BC3 cmp eax, ebx
0044D267 . 0F84 4C010000 je 0044D3B9
0044D26D . 895D EC mov [ebp-14], ebx
0044D270 . 8B08 mov ecx, [eax]
0044D272 . 8D55 EC lea edx, [ebp-14]
0044D275 . 52 push edx
0044D276 . 68 E06F4E00 push 004E6FE0
0044D27B . 50 push eax
0044D27C . 895D FC mov [ebp-4], ebx
0044D27F . FF51 1C call [ecx+1C]
0044D282 . 85C0 test eax, eax
0044D284 . 0F85 1E010000 jnz 0044D3A8
0044D28A . 895D F0 mov [ebp-10], ebx
0044D28D . 8B45 EC mov eax, [ebp-14]
0044D290 . 8D55 F0 lea edx, [ebp-10]
0044D293 . 52 push edx
0044D294 . 53 push ebx
0044D295 . FF75 0C push dword ptr [ebp+C]
0044D298 . 8B08 mov ecx, [eax]
0044D29A . C645 FC 01 mov byte ptr [ebp-4], 1
0044D29E . 50 push eax
0044D29F . FF51 20 call [ecx+20]
0044D2A2 . 85C0 test eax, eax
0044D2A4 . 0F85 EE000000 jnz 0044D398
0044D2AA . 8B45 F0 mov eax, [ebp-10]
0044D2AD . 8D55 E8 lea edx, [ebp-18]
0044D2B0 . 895D E8 mov [ebp-18], ebx
0044D2B3 . 52 push edx
0044D2B4 . 8B08 mov ecx, [eax]
0044D2B6 . 50 push eax
0044D2B7 . FF51 1C call [ecx+1C]
0044D2BA . 85C0 test eax, eax
0044D2BC . 0F85 D6000000 jnz 0044D398
0044D2C2 . 8B45 E8 mov eax, [ebp-18]
0044D2C5 . 40 inc eax
0044D2C6 . 50 push eax
0044D2C7 . E8 5C240200 call <jmp.&MFC42.#823_operator new>
0044D2CC . 8BF0 mov esi, eax
0044D2CE . 8B45 E8 mov eax, [ebp-18]
0044D2D1 . 40 inc eax
0044D2D2 . 8975 0C mov [ebp+C], esi
0044D2D5 . 50 push eax ; /n
0044D2D6 . 53 push ebx ; |c
0044D2D7 . 56 push esi ; |s
0044D2D8 . E8 B5290200 call <jmp.&MSVCRT.memset> ; \memset
0044D2DD . 8B45 F0 mov eax, [ebp-10]
0044D2E0 . 83C4 10 add esp, 10
0044D2E3 . 8D55 E4 lea edx, [ebp-1C]
0044D2E6 . 8B08 mov ecx, [eax]
0044D2E8 . 52 push edx
0044D2E9 . 56 push esi
0044D2EA . FF75 E8 push dword ptr [ebp-18]
0044D2ED . 50 push eax
0044D2EE . FF51 0C call [ecx+C]
0044D2F1 . 85C0 test eax, eax
0044D2F3 . 74 0C je short 0044D301
0044D2F5 . 56 push esi
0044D2F6 . E8 8B230200 call <jmp.&MFC42.#825_operator delete>
0044D2FB . 59 pop ecx
0044D2FC . E9 97000000 jmp 0044D398
0044D301 > 8B7D 08 mov edi, [ebp+8]
0044D304 . 53 push ebx ; /Arg1
0044D305 . 8D77 70 lea esi, [edi+70] ; |
0044D308 . 8BCE mov ecx, esi ; |
0044D30A . E8 A49C0500 call 004A6FB3 ; \QQ.004A6FB3
0044D30F . 8B06 mov eax, [esi]
0044D311 . 3BC3 cmp eax, ebx
0044D313 . 74 08 je short 0044D31D
0044D315 . 8B08 mov ecx, [eax]
0044D317 . 50 push eax
0044D318 . FF51 08 call [ecx+8]
0044D31B . 891E mov [esi], ebx
0044D31D > 56 push esi
0044D31E . E8 136F0700 call 004C4236
0044D323 . 8B06 mov eax, [esi]
0044D325 . 59 pop ecx
0044D326 . FF75 0C push dword ptr [ebp+C]
0044D329 . 8B08 mov ecx, [eax]
0044D32B . FF75 E4 push dword ptr [ebp-1C]
0044D32E . 50 push eax
0044D32F . FF51 78 call [ecx+78]
0044D332 . 85C0 test eax, eax
0044D334 . 74 10 je short 0044D346
0044D336 . 395D 0C cmp [ebp+C], ebx
0044D339 . 74 58 je short 0044D393
0044D33B . FF75 0C push dword ptr [ebp+C]
0044D33E . E8 43230200 call <jmp.&MFC42.#825_operator delete>
0044D343 . 59 pop ecx
0044D344 . EB 4D jmp short 0044D393
0044D346 > 395D 0C cmp [ebp+C], ebx
0044D349 . 74 09 je short 0044D354
0044D34B . FF75 0C push dword ptr [ebp+C]
0044D34E . E8 33230200 call <jmp.&MFC42.#825_operator delete>
0044D353 . 59 pop ecx
0044D354 > 8B06 mov eax, [esi]
0044D356 . 8D57 58 lea edx, [edi+58]
0044D359 . 52 push edx
0044D35A . 68 9CD75200 push 0052D79C ; ASCII "AST"
0044D35F . 8B08 mov ecx, [eax]
0044D361 . 50 push eax
0044D362 . FF51 34 call [ecx+34]
0044D365 . 85C0 test eax, eax
0044D367 . 75 2A jnz short 0044D393
0044D369 . 8B06 mov eax, [esi]
0044D36B . 8D57 5C lea edx, [edi+5C]
0044D36E . 52 push edx
0044D36F . 68 98D75200 push 0052D798 ; ASCII "EMH"
0044D374 . 8B08 mov ecx, [eax]
0044D376 . 50 push eax
0044D377 . FF51 44 call [ecx+44]
0044D37A . 85C0 test eax, eax
0044D37C . 75 15 jnz short 0044D393
0044D37E . 8B36 mov esi, [esi]
0044D380 . 83C7 6C add edi, 6C
0044D383 . 57 push edi
0044D384 . 68 94D75200 push 0052D794 ; ASCII "UIN"
0044D389 . 8B06 mov eax, [esi]
0044D38B . 56 push esi
0044D38C . FF50 34 call [eax+34]
0044D38F . 85C0 test eax, eax
0044D391 . 74 2D je short 0044D3C0
0044D393 > 8B45 10 mov eax, [ebp+10]
0044D396 . 8918 mov [eax], ebx
0044D398 > 8B45 F0 mov eax, [ebp-10]
0044D39B . 885D FC mov [ebp-4], bl
0044D39E . 3BC3 cmp eax, ebx
0044D3A0 . 74 06 je short 0044D3A8
0044D3A2 . 8B08 mov ecx, [eax]
0044D3A4 . 50 push eax
0044D3A5 . FF51 08 call [ecx+8]
0044D3A8 > 8B45 EC mov eax, [ebp-14]
0044D3AB . 834D FC FF or dword ptr [ebp-4], FFFFFFFF
0044D3AF . 3BC3 cmp eax, ebx
0044D3B1 . 74 06 je short 0044D3B9
0044D3B3 . 8B08 mov ecx, [eax]
0044D3B5 . 50 push eax
0044D3B6 . FF51 08 call [ecx+8]
0044D3B9 > B8 05400080 mov eax, 80004005
0044D3BE . EB 23 jmp short 0044D3E3
0044D3C0 > 8B45 F0 mov eax, [ebp-10]
0044D3C3 . 885D FC mov [ebp-4], bl
0044D3C6 . 3BC3 cmp eax, ebx
0044D3C8 . 74 06 je short 0044D3D0
0044D3CA . 8B08 mov ecx, [eax]
0044D3CC . 50 push eax
0044D3CD . FF51 08 call [ecx+8]
0044D3D0 > 8B45 EC mov eax, [ebp-14]
0044D3D3 . 834D FC FF or dword ptr [ebp-4], FFFFFFFF
0044D3D7 . 3BC3 cmp eax, ebx
0044D3D9 . 74 06 je short 0044D3E1
0044D3DB . 8B08 mov ecx, [eax]
0044D3DD . 50 push eax
0044D3DE . FF51 08 call [ecx+8]
0044D3E1 > 33C0 xor eax, eax
0044D3E3 > 8B4D F4 mov ecx, [ebp-C]
0044D3E6 . 5F pop edi
0044D3E7 . 5E pop esi
0044D3E8 . 5B pop ebx
0044D3E9 . 64:890D 00000>mov fs:[0], ecx
0044D3F0 . C9 leave
0044D3F1 . C2 0C00 retn 0C
函數(shù)有3個堆棧參數(shù),,沒有寄存器參數(shù)
我們要找的是第三個參數(shù)即[ebp+10]
0044D249 . 8B45 10 mov eax, [ebp+10]
0044D24C . 53 push ebx
0044D24D . 56 push esi
0044D24E . 57 push edi
0044D24F . C700 01000000 mov dword ptr [eax], 1
由上面的指令可知: [ebp+10] 是一個整形數(shù)的地址,即 我們要確定的@var2是個整形類型,,改名為@intVar2
返回_TempName繼續(xù)分析
lable1:
mov eax, _arg3
mov dword ptr [eax], 2
可知:_arg3 是個整形指針 改名為_pIntArg3
mov eax, _arg2
push edi
mov edx, @var1
push 1
mov ecx, [eax-8]
可知:_arg2 是一個指針 改名為_pArg2
invoke CString::CString,_arg4 => _arg4 是個字符串指針 改名為 _lpszArg4
invoke CString::CString,_arg1 => _arg1 是個字符串指針 改名為 _lpszArg1
invoke CWnd::CWnd,addr @var3
可知:@var3 是個隱含的this指針,函數(shù)中原來的指令為
00415C16 |. 8D4D AC lea ecx, [ebp-54]
00415C19 |. E8 569A0500 call <jmp.&MFC42.#567_CWnd::CWnd>
visual c++ 編譯器使用ecx用作this指針
所以 @var3 是個CWnd 的實例 改名為 @wnd
invoke CWnd::MessageBox,addr @wnd,_arg4,_arg1,MB_YESNO or MB_DEFBUTTON2 or MB_ICONHAND (114h) ;這個就是登錄失敗的時候的標(biāo)題和信息
由上面可知:_arg4 為:內(nèi)容 "輸入密碼與上次成功登陸的密碼不一致,,(回車符)是否到服務(wù)器驗證?"
_arg1 為:標(biāo)題 "錯誤"
invoke CString::~CString,_arg2 => _arg2 是個字符串指針 改名為_lpszArg2
看看現(xiàn)在都確定了那些
_regArg1 是個函數(shù)指針的指針的指針 改名為:_lpRegArg1 吧 ,,他終歸是個指針
_arg1 是個字符串指針 改名為:_lpszArg1
_arg2 是個字符串指針 改名為_lpszArg2
_arg3 是個整形指針 改名為_pIntArg3
_arg4 是個字符串指針 改名為 _lpszArg4
@var1 是個整形數(shù) 改名為 @intVar1
@var2 是個整形數(shù) 改名為 @intVar2
@var3 是個CWnd對象 改名為 @wndVar3
函數(shù)現(xiàn)在可以寫成:
_TempName Proc _lpRegArg1,_lpszArg1,_lpszArg2,_pIntArg3,_arg?,_lpszArg4 (因為不知道倒數(shù)第二個為什么沒有在函數(shù)中引用過,所以先用,?表示)
local @intVar1,@intVar2
local @wndVar3:CWnd
push ebx
push esi
xor ebx, ebx
mov [ebp-4], ebx
mov @intVar1, ebx
mov ecx,_lpRegArg1
mov eax, [ecx+84]
mov ecx, [eax]
mov byte ptr [ebp-4], 1
invoke [ecx+1c],eax,004e7460,addr @intVar1 (這里不管 addr 會覆蓋掉 eax的值)
test eax, eax
jnz lable1
mov eax, @intVar1
mov ecx, [eax]
invoke [ecx+14],eax,004e8940,addr @intVar2(這里不管 addr 會覆蓋掉 eax的值)
test eax, eax
je lable2
lable1:
mov eax, _lpIntArg3
mov dword ptr [eax], 2
jmp lable3
lable2:
mov eax, _arg2
push edi
mov edx, @intVar1
push 1
mov ecx, [eax-8]
pop esi
mov edi, [edx]
invoke [edi+1c],edx,_arg1,ebx,ecx,eax,esi
test eax, eax
pop edi
je lable4
cmp _lpszArg4, esi
je lable5
mov eax, _lpIntArg3
mov [eax], ebx
jmp lable3
lable5:
invoke CString::CString,_lpszArg4
mov byte ptr [ebp-4], 2
invoke CString::CString>,_lpszArg1
mov byte ptr [ebp-4], 3
invoke BasicCtrlDll.BasicLoadStr,addr _lpszArg4,281h
invoke BasicCtrlDll.BasicLoadStr,addr _lpszArg1,28dh
invoke CWnd::CWnd,addr @wnd
mov byte ptr [ebp-4], 4
invoke CWnd::MessageBox,addr @wnd,_lpszArg4,_lpszArg1,MB_YESNO or MB_DEFBUTTON2 or MB_ICONHAND (114h) ;這個就是登錄失敗的時候的標(biāo)題和信息
cmp eax, 6
mov eax, _lpIntArg3
jnz label6
mov dword ptr [eax], 2
jmp lable7
lable6:
mov [eax], ebx
lable7:
mov byte ptr [ebp-4], 3
invoke CWnd::~CWnd,addr @wndVar3
mov byte ptr [ebp-4], 2
invoke CString::~CString,addr _lpszArg1
mov byte ptr [ebp-4], 1
invoke CString::~CString,_lpszArg4
jmp lable3
lable4:
mov eax, _lpIntArg3
mov [eax], esi
lable3:
mov eax, _lpIntArg3
mov [ebp-4], bl
cmp eax, ebx
je lable8
mov ecx, [eax]
invoke [ecx+8],eax
lable8:
or dword ptr [ebp-4], FFFFFFFF
invoke CString::~CString,_lpszArg2
pop esi
pop ebx
ret
_TempName endp
2006-06-21 7:10
找出_TempName 函數(shù)的返回值,,這里的返回值,只考慮高級語言中的return 語句中的值,,不考慮其他引用返回值,、等等情況
_TempName 函數(shù)在結(jié)尾時,沒有顯示對eax,,edx進(jìn)行賦值,,可以判斷_TempName 函數(shù)的返回值為空,但也有可能_TempName返回她調(diào)用函數(shù)的值
比如:return func(arg1,..),為了進(jìn)一步確定,,看看調(diào)用_TempName函數(shù)的函數(shù)有沒有在call 00415b55 指令后緊跟著使用eax,、edx的值
00414FE8 |. E8 680B0000 call 00415B55
00414FED |. FFD6 call esi ; Kernel32.GetTickCount
結(jié)果表明:沒有使用eax,edx ,,所以_TempName 的返回值應(yīng)為void
c++表示的函數(shù)圓形應(yīng)為:
void TempName(void* regArg1,char* lpszArg1,char* lpszArg2,int* lpIntArg3,?,char* lpszArg4);
下面將匯編語言指令還原成高級語言的表達(dá)式
從函數(shù)調(diào)用語句或比較指令向上倒序還原,,例如:
push ebx
push esi
xor ebx, ebx
mov [ebp-4], ebx
mov @intVar1, ebx
mov ecx,_lpRegArg1
mov eax, [ecx+84]
mov ecx, [eax]
mov byte ptr [ebp-4], 1
invoke [ecx+1c],eax,004e7460,addr @intVar1 (這里不管 addr 會覆蓋掉 eax的值)
test eax, eax
就從invoke [ecx+1c],eax,004e7460,addr @intVar1 開始,用局部變量,,和參數(shù)替換掉寄存器,,這樣我們就去掉了臨時的寄存器
變量得到了高級語言表達(dá)式。(在高級語言中,,我把局部變量名前面的@去掉,,參數(shù)名前面的_去掉)
ecx=[eax]=[[ecx+84]]=[[lpRegArg1+84h]]=*(*(lpRegArg1+84h))
eax=[ecx+84]=[lpRegArg1+84]=*(lpRegArg1+0x84)
invoke [ecx+1c],eax,004e7460,addr @intVar1 用c++ 表示為:
*(*(*(lpRegArg1+0x84))+0x1c)(*(lpRegArg1+0x84),0x004e7460,&intVar1);
刪掉
mov ecx,_lpRegArg1
mov eax, [ecx+84]
mov ecx, [eax]
這幾個臨時的寄存器變量
上面還剩的指令有:
push ebx
push esi
,;這是保存寄存器值,與高級語言沒什么關(guān)系刪掉
xor ebx, ebx
mov [ebp-4], ebx
mov @intVar1, ebx
mov byte ptr [ebp-4], 1
可以寫成:
[ebp-4]=0;
intVar1=0;
byte ptr[ebp-4]=1;
以上的指令還原為:
[ebp-4]=0;
intVar1=0;
byte ptr[ebp-4]=1;
*(*(*(lpRegArg1+0x84))+0x1c)(*(lpRegArg1+0x84),0x004e7460,&intVar1);
跳轉(zhuǎn)指令使用條件表達(dá)式和goto替換
依次類推函數(shù)可寫為
void TempName(void* lpRegArg1,char* lpszArg1,char* lpszArg2,int* lpIntArg3,?,lpszArg4)
{
int intVar1,intVar2;
CWnd wndVar3;
mov [ebp-4],0
intVar1=0;
*(*(*(lpRegArg1+0x84))+0x1c)(*(lpRegArg1+0x84),0x004e7460,&intVar1);
if(eax) goto lable1
*(*(intVar1)+0x14)(intVar1,0x004e8940,&intVar2);
// 看來var1 不是個整形變量,,而是個指針 改名為 lpVar1,函數(shù)要改寫了
intVar1=0;這條語句可能是空指針初始化
}
void TempName(void* lpRegArg1,char* lpszArg1,char* lpszArg2,int* lpIntArg3,?,lpszArg4)
{
void* lpVar1=NULL;
int intVar2;
CWnd wndVar3;
mov [ebp-4],0
*(*(*(lpRegArg1+0x84))+0x1c)(*(lpRegArg1+0x84),0x004e7460,&lpVar1);
if(eax) goto lable1
*(*(lpVar1)+0x14)(intVar1,0x004e8940,&intVar2);
if(!eax) goto lable2;
lable1:
*lpIntArg3=2;
goto lable3;
lable2:
*(*lpVar1+0x1c)(lpVar1,0,*(lpszArg2-8),lpszArg2,1);
if(!eax) goto lable4;
if(lpszArg4==1) goto lable5;
*lpIntArg3=0;
goto lable3;
lable5:
CString(lpszArg4);
mov byte ptr[ebp-4],2;
CString(lpszArg1);
mov byte ptr[ebp-4],3;
BasicCrtDll.BasicLoadStr(lpszArg4,0x281);
BasicCrtDll.BasicLoadStr(lpszArg1,0x28d);
wndVar3.MessageBox(lpszArg4,lpszArg1,MB_YESNO or MB_DEFBUTTON2 or MB_ICONHAND);
if (eax!=6) goto lable6
*lpIntArg3=2;
goto lable7;
lable6:
*lpIntArg3=0;
lable7:
mov byte ptr[ebp-4],3
wndVar3.~CWnd();
mov byte ptr[ebp-4],2
~CString(lpszArg1);
mov byte ptr[ebp-4],1
~CString(lpszArg4);
goto lable3;
lable4:
*lpIntArg3=1;
lable3:
mov byte prt[ebp-4],0
if(lpIntArg3==0) goto lable8;
*(*lpIntArg3+8)(lpIntArg3);
lable8:
or dword ptr[ebp-4],-1
~CString(lpszArg2);
}
下一步還原控制語句:將控制語句,,從函數(shù)中看到只有向下跳轉(zhuǎn)的,沒有向上跳轉(zhuǎn)的,,可知函數(shù)中只有循環(huán)結(jié)構(gòu)
給if ... 條件編號:
給代碼快標(biāo)號
void TempName(void* lpRegArg1,char* lpszArg1,char* lpszArg2,int* lpIntArg3,?,lpszArg4)
{
void* lpVar1=NULL;
int intVar2;
CWnd wndVar3;
mov [ebp-4],0
*(*(*(lpRegArg1+0x84))+0x1c)(*(lpRegArg1+0x84),0x004e7460,&lpVar1);
if(eax) goto lable1---------------------------------------------------------------------------c1
*(*(lpVar1)+0x14)(intVar1,0x004e8940,&intVar2);
if(!eax) goto lable2;-------------------------------------------------------------------------c2
lable1:
*lpIntArg3=2;-------------------------------code1
goto lable3;
lable2:
*(*lpVar1+0x1c)(lpVar1,0,*(lpszArg2-8),lpszArg2,1);
if(!eax) goto lable4;-------------------------------------------------------------------------c3
if(*lpszArg4==1) goto lable5;------------------------------------------------------------------c4
*lpIntArg3=0;-------------------------------code2
goto lable3;
lable5:
CString(lpszArg4);---------------------------------------------------code3
mov byte ptr[ebp-4],2;
CString(lpszArg1);
mov byte ptr[ebp-4],3;
BasicCrtDll.BasicLoadStr(lpszArg4,0x281);
BasicCrtDll.BasicLoadStr(lpszArg1,0x28d);
wndVar3.MessageBox(lpszArg4,lpszArg1,MB_YESNO or MB_DEFBUTTON2 or MB_ICONHAND);
if (eax!=6) goto lable6------------------------------------------------------------------------c5
*lpIntArg3=2;-------------------------------------------------------code4
goto lable7;
lable6:
*lpIntArg3=0;-------------------------------------------------------code5
lable7:
mov byte ptr[ebp-4],3-------------------------------------------code6
wndVar3.~CWnd();
mov byte ptr[ebp-4],2
~CString(lpszArg1);
mov byte ptr[ebp-4],1
~CString(lpszArg4);
goto lable3;
lable4:
*lpIntArg3=1;--------------------------------------------------------code7
lable3:
mov byte prt[ebp-4],0---------------------------------------------code8
if(lpIntArg3==0) goto lable8;-----------------------------------------------------------------c6
*(*lpIntArg3+8)(lpIntArg3);-------------------------------------------code9
lable8:
or dword ptr[ebp-4],-1-------------------------------------------code10
~CString(lpszArg2);
}
第二步:構(gòu)造邏輯二叉樹,,當(dāng)條件為假時,執(zhí)行二叉樹的左邊,,當(dāng)條件為真時,,執(zhí)行二叉樹的右邊,無條件跳轉(zhuǎn)和順序執(zhí)行的用直線表示
如過用原來的條件畫數(shù)不好畫,,有交叉線,,就對原來的條件取反,可得到如下所示的二叉樹:
if(c1 || !c2)
{
code1
}
elseif( c3 )
{
code7;
}
elseif (c4)
{
code3;
if(c5)
{
code5;
}
else
{
code4;
}
code6;
}
else
{
code2;
}
code8;
if(!c6)
{
code9;
}
code10;
將條件編號和代碼快編號用相應(yīng)的語句替換可得:
c1 的條件為 測試eax,!=0 ,而eax就是上面函數(shù)調(diào)用的返回值
所以TempName函數(shù)可寫為:
void TempName(void* lpRegArg1,char* lpszArg1,char* lpszArg2,int* lpIntArg3,?,lpszArg4)
{
void* lpVar1=NULL;
int intVar2;
CWnd wndVar3;
mov [ebp-4],0
if(*(*(*(lpRegArg1+0x84))+0x1c)(*(lpRegArg1+0x84),0x004e7460,&lpVar1) || !*(*(lpVar1)+0x14)(intVar1,0x004e8940,&intVar2))
{
*pIntArg3=2;--------------------------------------------------------code1
}
elseif (!*(*lpVar1+0x1c)(lpVar1,0,*(lpszArg2-8),lpszArg2,1))
{
*lpIntArg3=1;--------------------------------------------------------code7
}
elseif (*lpszArg4==1)
{
CString(lpszArg4);---------------------------------------------------code3
mov byte ptr[ebp-4],2;
CString(lpszArg1);
mov byte ptr[ebp-4],3;
BasicCrtDll.BasicLoadStr(lpszArg4,0x281);
BasicCrtDll.BasicLoadStr(lpszArg1,0x28d);
wndVar3.MessageBox(lpszArg4,lpszArg1,MB_YESNO or MB_DEFBUTTON2 or MB_ICONHAND);
if(wndVar3.MessageBox(lpszArg4,lpszArg1,MB_YESNO or MB_DEFBUTTON2 or MB_ICONHAND)!=6)
{
*lpIntArg3=0
}
else
{
*lpIntArg3=2
}
mov byte ptr[ebp-4],3-------------------------------------------code6
wndVar3.~CWnd();
mov byte ptr[ebp-4],2
~CString(lpszArg1);
mov byte ptr[ebp-4],1
~CString(lpszArg4);
}
else
{
*lpIntArg3=0--------------------------------code2
}
mov byte prt[ebp-4],0---------------------------code8
if(!(lpIntArg3==0))
{
*(*lpIntArg3+8)(lpIntArg3);-------------------------------------------code9
}
or dword ptr[ebp-4],-1-------------------------------------------code10
~CString(lpszArg2);
}
今天就到這里,,這里可能會出好多錯誤,希望大家能不吝賜教,,我對c++,,mfc 不熟,只對匯編比較熟,,所以上面有些代碼,,也不知道什么樣的源程序可以編譯成這個
樣子,上面的代碼中帶有匯編指令,,不過程序大致思路是這樣的,,還有如果誰有還原分支語句的好方法,講出來,,大家分享一下,。
|