• 19填充DOS頭、PE頭和節表中無用的部分
  • 可以在這些地方見縫插針地填入所需的東西,如程序主要的代碼、Dll名稱和函數名稱等

Untitled

  • DosStub可以整段刪掉,如下圖
  • 暫時先不修改各個RVA,最後刪完再一次過重設所有需要修改的RVA

Untitled

  • 接下來修改可選PE頭的數據目錄表,因為只需要用到數據目錄表第2項的導入表,因此後面的14項都可以直接刪除
  • 並將數據目錄表的項數設為2

Untitled

  • 節表只需留下.text節表,.rdata可以直接刪除
  • 可以直接刪除的原因是,數據目錄表能直接定位到導入表,因此不需要依靠.rdata節表也行

Untitled

  • 分析一下.rdata對應的節區
  • 可以先從原始文件中,找到.rdata對應節區的的起始位置和大小,從而在當前文件中找到.rdata對應節區
  • 整個藍色部分就是.rdata對應的節區,紅框部分是IAT,這部分不重要,暫時以9填充,重要的是綠框部分,這是一個IDT結構的數組,以20個字節的0作為IDT數組的結尾
  • IDT結構體最重要的是OriginalFirstThunkFirstThunkName這3個屬性,後續要手動將這3個屬性指向正確的地址
  • 由於只需要MessageBoxA這個函數,因此綠框部分只需留下28個字節的空間,前20個字節表示一個IDT結構,後8個字節表示IDT數組的結束
  • 然後將修改後的紅框、綠框這兩部分移到文件最下方

Untitled

  • 修改後如下圖
  • 紅框部分算是一個備用空間,之後可作刪減
  • 綠框部分中,上述提到的3個屬性要在之後手動修改

Untitled

  • 藍框部分是程序的執行代碼 + 一些無用的字符串,可以直接刪
  • 代碼部分要自己重構,然後見縫插針插入PE頭中,以節省空間

Untitled

  • 藍框部分是PE頭
  • 將其整段剪下,覆蓋到紅框

Untitled

  • 修改後如下圖

Untitled

  • 在PE頭裡插入user32.dllMessageBoxA這2個字符串,插入的位置是從填充了9的字段中選中
  • 下方保存的user32.dllMessageBoxA現在可以刪了

Untitled

  • 藍框是.text節表後幾個屬性,無用可以直接刪

Untitled

  • 為了重構代碼,要借助OD來看

Untitled

  • 代碼大概可重構成以下匯編結構,只保留了調用MessageBoxA的部分
  • E8後面跟的地址由這個公式得出:目標地址 - 當前指令地址 - 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
push 0x1040
// 68 40 10 00 00

push 0x4001F8
// 68 XX XX XX XX ( XX 要改成標題字符串的絕對地址 )

push 0x40020C
// 68 XX XX XX XX ( XX 要改成內容字符串的絕對地址 )

push 0x0
// 6A 00

call 00400264
// E8 XX 00 00 00 ( XX通過上述公式計算出來,算是個相對偏移 )

jmp dword ptr ds:[0x400274]
// FF 25 74 02 40 00 ( 74 02 40 00 是IAT,文件加載到內存時會將IAT指向函數的真實地址,即MessageBoxA的真實地址)
  • 在PE頭中合適的位置插入代碼
  • 部分指令解析:
    • 68 40 10 00 00:push參數,可與原程序一致
    • EB 0DEB是jmp指令的其中一個操作碼,操作數0D是一個偏移( 當前指令的下一條指令的起始地址 + 偏移 = 要跳轉到的地址 ),用EB的目的是為了在一片不連續的空間實現連續的代碼執行流,相當於是一個橋樑
    • 68 A4 00 40 00: push參數,A4 00 40 00是標題字符串在內存的絕對地址
    • FF 25 E8 00 40 00FF 25是jmp指令另一個操作碼,E8 00 40 00是內存中的地址,它指向MessageBoxA的真實地址( 如何讓0x4000E8指向MessageBoxA的真實地址?將PE文件IDT表的FirstThunk設為0xE8即可 )

Untitled

IAT那部分只保留前8個字節就夠用,後12個字節可以刪

Untitled

  • 之前在PE頭中插入的MessageBoxA字符串的前2個字節9D 01要刪,然後在後方補上2個字節0
  • 若不這樣做會導致PE頭中的SizeOfUninitializedData過大,會使程序崩潰

Untitled

  • 各種RVA、Size的修改,大致有以下這幾項要修改
    • NumberOfSections:節區數,改為1
    • SizeOfOptionalHeader:可選PE頭的大小,改為70h
    • AddressOfEntryPoint:程序起始位置,改為30h
    • SizeOfHeaders:這個相當於是第一個節區的起始位置,即代碼節的位置,需與AddressOfEntryPoint一致
    • 導入表起始地址改為F0h,大小改為28h
    • INT和IAT都指向E8hE8h指向1Ch( 1Ch指向PE頭中的MessageBoxA ),後面跟4個字節的0代表結束,文件加載到內存時 ( MessageBoxA的真實地址會放到IAT中,即E8h指向的就是MessageBoxA的真實地址 )
    • Dll的Name為0Ch

Untitled

  • 最後,將彈框信息改成自己的姓名和學號,這裡用的是gbk編碼

Untitled

結果如下:

Untitled