題目:
一、將_text,_rdata,_data合并成一個EXE文件,重建一個PE頭
二、在第一步的基礎(chǔ)上加入一個菜單
三、加入點擊菜單調(diào)用MessageBox
*************************************************************
因為最終結(jié)果是一個用WIN32API(非MFC)編寫窗口程序,所以建議用匯編一個差不多的程序,做為比較。
一、合成PE文件:
1、從名字上看_text,_rdata,_data分別應(yīng)該是代碼段,只讀數(shù)據(jù)段(輸入表之類)和可讀寫數(shù)據(jù)段。所以用WINHEX按順序加上PE頭后,復(fù)制粘貼就可以了。
?
WINHEX也用一個合成文件的功能。這時記做1.exe。
2、修改PE頭數(shù)據(jù)。用STUD_PE打開1.exe,先修改“區(qū)段數(shù)目”,后區(qū)段的偏移和大小。這里題目沒有規(guī)定文件大小,所以PE頭大小最好為0X1000。分析如下:
DOS和PE頭-0X0000-->┌┈┈┈┈┐
?????????????????? │??????? │
?????? ????????????│0X1000 │
.text---0X1000---->├────┤
?????????????????? │??????? │
?????????????????? │0X6000 │
.rdata--0X7000---->├────┤
?????????????????? │??????? │
?????????????????? │0X1000 │
.data---0X8000---->├────┤
?????????????????? │??????? │
?? ????????????????│0X3000 │
.rsrc---0XB000---->├────┤<---未加資源段時這里是文件結(jié)尾
?????????????????? │??????? │
?????????????????? │0X0200 │
文件尾--0XB200---->└────┘
?
根據(jù)以上圖表得如下:???
No? | 名稱????? | 虛擬大小?? | 虛擬偏移量| 原始大小?? | 原始偏移量| 特性?????? |
01? | .text???? | 00006000?? | 00001000?? | 00006000?? | 00001000?? | E0000020?? |
02? | .rdata??? | 00001000?? | 00007000?? | 00001000?? | 00007000?? | C0000040?? |
03? | .data???? | 00003000?? | 00008000?? | 00003000?? | 00008000?? | C0000040?? |
04? | .rsrc???? | 00000200?? | 0000B000?? | 00000200?? | 0000B000?? | 40000040?? |
注:.rsrc段為加入菜單時才加入的,合成PE文件可以不看
?
根據(jù)文件的大小修改“鏡像大小”。保存后,重新用STUD_PE載入,看它的提示,一般會提示“資源表”和“輸入表”錯誤,“資源表”錯誤會讓PE加載器無法
?
識別PE文件,所以先把“數(shù)據(jù)目錄:IMAGE_DIR_ENTRY_RESOURCE”改成0。“輸入表”錯誤只會至程序運行錯誤。
?
現(xiàn)在分析.rdata段,找到輸入表的正確地址和大小。輸入表是什么東西呢?
輸入表的地址是:
IMAGE_OPTIONAL_HEADER.DataDirectory[1].VirtualAddress
輸入表的大小是:
IMAGE_OPTIONAL_HEADER.DataDirectory[1].Size
?
VirtualAddress里存的是一個指向IMAGE_IMPORT_DESCRIPTOR數(shù)組的指針,該數(shù)組以一個全是0的IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)結(jié)束。
?
IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)的大小為0x14,所以輸入DLL的個數(shù)等于輸入表大小除以0x14后得的商再減1。
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
??? union {
??????? DWORD?? Characteristics;??????????? // 0 for terminating null import descriptor
??????? DWORD?? OriginalFirstThunk;???????? // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
??? };
??? DWORD?? TimeDateStamp;????????????????? // 0 if not bound,
??????????????????????????????????????????? // -1 if bound, and real date\time stamp
??????????????????????????????????????????? //???? in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
??????????????????????????????????????????? // O.W. date/time stamp of DLL bound to (Old BIND)
?
??? DWORD?? ForwarderChain;???????????????? // -1 if no forwarders
??? DWORD?? Name;
??? DWORD?? FirstThunk;???????????????? ????// RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)主要看最后兩個變量,DWORD?? Name為指向DLL名字的指針,DWORD?? FirstThunk指向一個數(shù)組,數(shù)組里存有該DLL函數(shù)名的指針。
?
分析正常EXE文件的輸入表后發(fā)現(xiàn),輸入表一般是在調(diào)用函數(shù)名字的前面,用WINHEX打開1.exe,看地址0x77A0的地方,這里全是一些函數(shù)名,如:lstrcpyA和系統(tǒng)
?
,所以輸入表應(yīng)該在這0x77A0的前面(注意與正常文件對比),還有就是注意看DLL的名字,如:user32.dll的位置是0x788A,那么我們從0x7000的地方開始找0x8A
?
,找到后看看0x8A前面是不是0x78,這樣就容易多了。在這里應(yīng)該是0x7618,大小為0x50。
?
現(xiàn)在就差程序的“入口點”了,用PEID打開1.exe應(yīng)該顯示為VC6寫的,這樣我們就找一個VC6寫的程序來看看它的入口,這是一個正常VC6程序的入口:
math.<Mod>/$? 55??????????? push??? ebp
00409657? |.? 8BEC????????? mov???? ebp, esp
00409659? |.? 6A FF???????? push??? -1
0040965B? |.? 68 F8474200?? push??? 004247F8
00409660? |.? 68 20CD4000?? push??? 0040CD20???????????????????????? ;? SE 處理程序安裝
00409665? |.? 64:A1 0000000>mov???? eax, dword ptr fs:[0]
0040966B? |.? 50??????????? push??? eax
0040966C? |.? 64:8925 00000>mov???? dword ptr fs:[0], esp
00409673? |.? 83EC 58?????? sub???? esp, 58
00409676? |.? 53??????????? push??? ebx
00409677? |.? 56??????????? push??? esi
00409678? |.? 57??????????? push??? edi
00409679? |.? 8965 E8?????? mov???? dword ptr ss:[ebp-18], esp
0040967C? |.? FF15 14224200 call??? dword ptr ds:[<&KERNEL32.GetVers>;? kernel32.GetVersion
?
math.<Mod>/$? 55??????????? push??? ebp
00409657? |.? 8BEC????????? mov???? ebp, esp
這句是每個函數(shù)都有的,不看它,看這里
00409659? |.? 6A FF???????? push??? -1
0040965B? |.? 68 F8474200?? push??? 004247F8
00409660? |.? 68 20CD4000?? push??? 0040CD20???????????????????????? ;? SE 處理程序安裝
三個PUSH在函數(shù)里可不多呀,所在用WINHEX打開1.EXE,從0X1000開始找0X6A FF 68,會停在地址0X152A,看看前0X1527的地方,就是0X55 8B EC,所以這里應(yīng)
?
該就是入口。修改完后一個PE格式的可執(zhí)行文件就合成成功了。
?
二、加入菜單
剛才合成的程序是沒有資源段的,所以要給它加入一個資源,里面只要有一個菜單就行了。資源文件這樣寫
?
#include??? <resource.h>
#define pediy.com?????? 0x30
#define? IDM_ABOUT? 0x20
pediy.com? MENU
BEGIN
? popup? "HELP"
? BEGIN
??? menuitem "ABOUT",IDM_ABOUT
? END
END
?
但程序是怎樣把菜單加載到窗口里的呢?這里有幾種方法:
1、用LoadMenu加載菜單并取得句柄后,設(shè)置CreateWindow.hMenu等于該句柄,但看看輸入表,沒有LoadMenu函數(shù),所以用這種方法的話又要改輸入表,太麻煩。
2、在寫資源文件(.RC)的時候菜單名設(shè)置一個編號,在RegisterClass之前設(shè)置WNDCLASS.lpszMenuName等于這個編號或菜單名。
?
這里可先看看代碼,看看它是怎樣設(shè)置WNDCLASS.lpszMenuName的,用OD打開1.EXE,下斷點在40125A,運行程序,停下后看ESP(我這是12FEAC),它是一個指
?
向WNDCLASS的指針,在內(nèi)存窗口找到這個地址:
?
0012FEAC? 03 00 00 00 D5 12 40 00 00 00 00 00 00 00 00 00? .?@....
0012FEBC? 00 00 40 00 27 00 01 00 03 00 01 00 10 00 90 01? .@'?
0012FECC? F0 FE 12 00 A0 80 40 00????????????????????????? ?腸@
?
WNDCLASS結(jié)構(gòu)有10個成員,第9個就是菜單,所以12FEAC+(4*(9-1))=12FECC=》0012FECC? F0 FE 12 00。看看12FEF0是什么,原來是一個字串"pediy.com"
?
,所以我用第2種方法,寫資源時把菜單名寫成"pediy.com"就不用改代碼了。把資源寫好后,生成EXE,用WINHEX剝離.RSRC段,粘貼到1.EXE后,再用STUD_PE改
?
一改段數(shù)據(jù)和“鏡像大小”就可以了。
?
三、加入提示窗口
先看看正常的菜單是怎樣響應(yīng)單擊事件的。單擊菜單后,會由WM_COMMAND(0X111)消息處理,它的wParam參數(shù)就是被單擊控件的ID,如果這個ID下有處理函數(shù)
?
就處理,沒有就返回,我們要做的就是增加這個處理函數(shù)。
?
用OD打開1.EXE,找到消息循環(huán):
0040120B? |.? 57??????????? push??? edi????????????????????????????? ; /RsrcName => IDI_APPLICATION
0040120C? |.? 56???????? ???push??? esi????????????????????????????? ; |hInst => NULL
0040120D? |.? 891D ACAB4000 mov???? dword ptr ds:[40ABAC], ebx?????? ; |
00401213? |.? C745 B0 03000>mov???? dword ptr ss:[ebp-50], 3???????? ; |
0040121A? |.? C745 B4 D5124>mov???? dword ptr ss:[ebp-4C], 004012D5? ; |<========================這里面就是設(shè)置消息循環(huán)的地方
00401221? |.? 8975 B8?????? mov???? dword ptr ss:[ebp-48], esi?????? ; |
00401224? |.? 8975 BC?????? mov???? dword ptr ss:[ebp-44], esi?????? ; |
00401227? |.? 895D C0?????? mov???? dword ptr ss:[ebp-40], ebx?????? ; |
0040122A? |.? FF15 04714000 call??? dword ptr ds:[<&USER32.LoadIconA>; \LoadIconA
00401230? |.? 57??????????? push??? edi????????????????????????????? ; /RsrcName => IDC _ARROW
00401231? |.? 56??????????? push??? esi?????????????? ???????????????; |hInst => NULL
00401232? |.? 8945 C4?????? mov???? dword ptr ss:[ebp-3C], eax?????? ; |
00401235? |.? FF15 08714000 call??? dword ptr ds:[<&USER32.LoadCurso>; \LoadCursorA
0040123B? |.? 56??????????? push??? esi??????????????????????????? ??; /ObjType => WHITE_BRUSH
0040123C? |.? 8945 C8?????? mov???? dword ptr ss:[ebp-38], eax?????? ; |
0040123F? |.? FF15 18704000 call??? dword ptr ds:[<&GDI32.GetStockOb>; \GetStockObject
00401245? |.? 8945 CC?????? mov???? dword ptr ss:[ebp-34], eax
00401248? |.? 8D45 F4?????? lea???? eax, dword ptr ss:[ebp-C]
0040124B? |.? 8945 D0?????? mov???? dword ptr ss:[ebp-30], eax
0040124E? |.? 8D45 B0?????? lea???? eax, dword ptr ss:[ebp-50]
00401251? |.? BF A0804000?? mov???? edi, 004080A0?????????????????? ?;? ASCII "pediy.com"
00401256? |.? 50??????????? push??? eax????????????????????????????? ; /pWndClass
00401257? |.? 897D D4?????? mov???? dword ptr ss:[ebp-2C], edi?????? ; |
0040125A? |.? FF15 0C714000 call??? dword ptr ds:[<&USER32.RegisterC>; \RegisterClassA
?
來到消息循環(huán),發(fā)現(xiàn)沒有WM_COMMAND:
?
004012D5? /.? 55??????????? push??? ebp
004012D6? |.? 8BEC????????? mov???? ebp, esp
004012D8? |.? 83EC 40?????? sub???? esp, 40
004012DB? |.? 8B45 0C?????? mov???? eax, dword ptr ss:[ebp+C]
004012DE? |.? 48??????????? dec ????eax????????????????????????????? ;? Switch (cases 2..F)
004012DF? |.? 48??????????? dec???? eax
004012E0? |.? 74 68???????? je????? short 0040134A
004012E2? |.? 83E8 03?????? sub???? eax, 3
004012E5? |.? 74 4D???????? je????? short 00401334
004012E7? |.? 83E8 0A?????? sub???? eax, 0A
004012EA? |.? 74 14???????? je????? short 00401300
004012EC? |.? FF75 14?????? push??? dword ptr ss:[ebp+14]??????????? ; /lParam; Default case of switch 004012DE
004012EF? |.? FF75 10?????? push??? dword ptr ss:[ebp+10]?? ?????????; |wParam
004012F2? |.? FF75 0C?????? push??? dword ptr ss:[ebp+C]???????????? ; |Message
004012F5? |.? FF75 08?????? push??? dword ptr ss:[ebp+8]???????????? ; |hWnd
004012F8? |.? FF15 F4704000 call??? dword ptr ds:[<&USER32.DefWindow>; \DefWindowProcA
004012FE? |.? EB 54???????? jmp???? short 00401354
?
?
注意看有三個JE,JE前面是SUB和DEC命令,不是平時的CMP命令,有貓膩。CMP是不保存結(jié)果的,但SUB和DEC是保存結(jié)果的,所以可以寫成這樣:
CMP EAX,2
je????? short 0040134A
CMP EAX,2+3
je????? short 00401334
CMP EAX,2+3+A
je????? short 00401300
?
所以就要在這些比較之前用"跳出跳回法”寫入WM_COMMAND消息處理。問題又來了,輸入表里面沒有MessageBox怎么辦。我是用風(fēng)險比較大的方法,就是絕對地
?
址,因為大多數(shù)程序在加載USER32.DLL等函數(shù)的時候,它的分配的空間90%都是一樣的,所以直接使用USER32.DLL的空間加上MessageBox函數(shù)的偏移就可以了。
?
至于字串,可以在數(shù)據(jù)段加入,注意換行符為0X0A。最終如下:
004012D5?? .? 55??????????? push??? ebp
004012D6?? .? 8BEC????????? mov???? ebp, esp
004012D8?? .? 83EC 40?????? sub???? esp, 40
004012DB?? .? E9 A0580000?? jmp???? 00406B80??????? 《=====跳出
?
00406B80?? > \8B45 0C?????? mov???? eax, dword ptr ss:[ebp+C]
00406B83?? .? 3D 11010000?? cmp???? eax, 111????????????? ???????????;? Switch (cases 2..111)
00406B88?? .? 74 0D???????? je????? short 00406B97
00406B8A?? .? 48??????????? dec???? eax
00406B8B?? .? 48??????????? dec???? eax
00406B8C?? .^ 0F84 B8A7FFFF je????? 0040134A
00406B92?? .^ E9 4BA7FFFF?? jmp???? 004012E2???????? 《=====跳回
00406B97?? >? 6A 40???????? push??? 40?????????????????????????????? ;? Case 111 of switch 00406B83
00406B99?? .? 68 8C804000?? push??? 0040808C???????????????????????? ;? ASCII "pediy"
00406B9E?? .? 68 50804000?? push??? 00408050
00406BA3?? .? 6A 00???????? push??? 0
00406BA5?? .? E8 06000000?? call??? 00406BB0
00406BAA?? .^ E9 A3A7FFFF?? jmp???? 00401352
00406BAF????? 00??????????? db????? 00
00406BB0?? $- FF25 B86B4000 jmp???? dword ptr ds:[406BB8]??????????? ;? user32.7696EA11
00406BB6????? 00??????????? db????? 00
00406BB7????? 00??????????? db????? 00
00406BB8?? .? 11EA9676????? dd????? user32.7696EA11
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
