接下来我们做一个稍微复杂一些的实验,实验需要四个程序:
HelloWorld.exe:弹出MessageBox窗口(实验1已实现)。
Regedit.exe:添加注册表启动项。
LockTray.exe:锁定任务栏窗口。
UnLockTray.exe:解锁任务栏窗口。
【注】为了减少不必要的麻烦,上述四个程序都使用32位汇编代码实现。
实验二十八:手工重构导入表
■实验要求
●分别编译实现上述四个实验程序。
●Regedit.exe程序的功能是将LockTray.exe添加到注册表启动项中。
●手工实现,将Regedit.exe程序的代码、数据、IAT表和导入表添加到HelloWorld.exe程序中,并可以正确运行。
●HelloWorld.exe源码:(略)
●LockTray.exe源码:
;------------------------
;Filename:LockTray.asm
;实验28:锁定任务栏
;by:bcdaren
;编写日期:2021.04.26
;========================================================
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;数据段
.data
szClassName db 'Shell_TrayWnd',0
hTray dd ?
;代码段
.code
start:
invoke FindWindow,addr szClassName,0
mov hTray,eax
invoke ShowWindow,hTray,SW_HIDE;SW_SHOW解锁
invoke EnableWindow,hTray,FALSE
invoke ExitProcess,NULL
end start
●UnLockTray.exe源码:(略)
●Regedit.exe源码:
;------------------------
;Filename:regedit.asm
;实验28:添加注册表启动项
;by:bcdaren
;编写日期:2021.04.26
;========================================================
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include advapi32.inc
includelib advapi32.lib
;数据段
.data
szSubKey db 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run',0
szValueName db 'NewValue',0
szData db 'D:\code\winpe\ch04\LockTray\LockTray.exe',0 ;41个字节
hKey dd ?
;代码段
.code
start:
invoke RegCreateKey,HKEY_LOCAL_MACHINE,addr szSubKey,addr hKey
invoke RegSetValueExA,hKey,addr szValueName,NULL,REG_SZ,addr szData,41
invoke RegCloseKey,hKey
invoke ExitProcess,NULL
end start
●手工重构导入表
第一步:新建一个HelloWorld.exe程序的副本。在WinHex中新建一个空白文件,并将HelloWorld.exe复制到空白文件中。
第二步:定位副本文件中的.data节区,将Regedit.exe程序的.data节区数据写入到副本文件.data节区的结尾处。
00000800 68 65 6C 6C 6F 00 48 65 6C 6C 6F 2C 77 65 6C 63 hello.Hello,welc
00000810 6F 6D 65 20 74 6F 20 50 45 21 00 53 4F 46 54 57 ome to PE!.SOFTW
00000820 41 52 45 5C 57 4F 57 36 34 33 32 4E 6F 64 65 5C ARE\WOW6432Node\
00000830 4D 69 63 72 6F 73 6F 66 74 5C 57 69 6E 64 6F 77 Microsoft\Window
00000840 73 5C 43 75 72 72 65 6E 74 56 65 72 73 69 6F 6E s\CurrentVersion
00000850 5C 52 75 6E 00 4E 65 77 56 61 6C 75 65 00 44 3A \Run.NewValue.D:
00000860 5C 63 6F 64 65 5C 77 69 6E 70 65 5C 63 68 30 34 \code\winpe\ch04
00000870 5C 4C 6F 63 6B 54 72 61 79 5C 4C 6F 63 6B 54 72 \LockTray\LockTr
00000880 61 79 2E 65 78 65 00 00 00 00 00 00 00 00 00 00 ay.exe..........
【注意】下面的步骤中只需要插入advapi32.dll模块中3个注册表函数的IAT、INT、函数名和模块名数据,剔除重复的ExitProcess导入函数数据。
第三步:将Regedit.exe程序的IAT表数据插入到副本文件IAT表的结尾处。
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000600 76 20 00 00 00 00 00 00 5C 20 00 00 00 00 00 00 v ......\ ......
00000610 A6 20 00 00 88 20 00 00 96 20 00 00 00 00 00 00 ?..?..?......
第四步:将Regedit.exe程序的导入表描述符数据插入到副本文件导入表描述符结尾处。
00000620 54 20 00 00 00 00 00 00 00 00 00 00 6A 20 00 00 T ..........j ..
00000630 08 20 00 00 4C 20 00 00 00 00 00 00 00 00 00 00 . ..L ..........
00000640 84 20 00 00 00 20 00 00 54 20 00 00 00 00 00 00 ?... ..T ......
00000650 00 00 00 00 B8 20 00 00 00 20 00 00 00 00 00 00 ....?... ......
第五步:将Regedit.exe程序的INT表数据插入到副本文件INT表的结尾处。
00000670 76 20 00 00 00 00 00 00 5C 20 00 00 00 00 00 00 v ......\ ......
00000680 A6 20 00 00 88 20 00 00 96 20 00 00 00 00 00 00 ?..?..?......
第六步:将Regedit.exe程序的函数名和DLL名数据写入到副本文件函数名和DLL名数据的结尾处。
00000690 B1 01 4D 65 73 73 61 67 65 42 6F 78 41 00 75 73 ?MessageBoxA.us
000006A0 65 72 33 32 2E 64 6C 6C 00 00 9B 00 45 78 69 74 er32.dll..?Exit
000006B0 50 72 6F 63 65 73 73 00 6B 65 72 6E 65 6C 33 32 Process.kernel32
000006C0 2E 64 6C 6C 00 00 B7 01 52 65 67 43 6C 6F 73 65 .dll..?RegClose
000006D0 4B 65 79 00 BA 01 52 65 67 43 72 65 61 74 65 4B Key.?RegCreateK
000006E0 65 79 41 00 E7 01 52 65 67 53 65 74 56 61 6C 75 eyA.?RegSetValu
000006F0 65 45 78 41 00 00 61 64 76 61 70 69 33 32 2E 64 eExA..advapi32.d
00000700 6C 6C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ll..............
第七步:删除.rdata节区多余空字节,使.data节区保持00000800H地址不变。修正IAT表、导入表描述符和INT表。
00000600 AA 20 00 00 00 00 00 00 90 20 00 00 00 00 00 00 ?....... ......
00000610 C6 20 00 00 D4 20 00 00 E4 20 00 00 00 00 00 00 ?..?..?......
00000620 70 20 00 00 00 00 00 00 00 00 00 00 B8 20 00 00 p ..........?..
00000630 00 20 00 00 78 20 00 00 00 00 00 00 00 00 00 00 . ..x ..........
00000640 9E 20 00 00 08 20 00 00 80 20 00 00 00 00 00 00 ?... ..€ ......
00000650 00 00 00 00 F6 20 00 00 10 20 00 00 00 00 00 00 ....?... ......
00000660 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000670 AA 20 00 00 00 00 00 00 90 20 00 00 00 00 00 00 ?....... ......
00000680 C6 20 00 00 D4 20 00 00 E4 20 00 00 00 00 00 00 ?..?..?......
第八步:将Regedit.exe程序的.text节区数据复制到.text节区,并修正参数地址以及FF25跳转地址。
00000400 68 87 30 40 00 68 1B 30 40 00 68 02 00 00 80 E8 h?@.h.0@.h...€?
00000410 52 00 00 00 6A 29 68 5D 30 40 00 6A 01 6A 00 68 R...j)h]0@.j.j.h
00000420 55 30 40 00 FF 35 87 30 40 00 E8 3D 00 00 00 FF U0@.5?@.?...
00000430 35 87 30 40 00 E8 2B 00 00 00 6A 00 68 00 30 40 5?@.?...j.h.0@
00000440 00 68 06 30 40 00 6A 00 E8 07 00 00 00 6A 00 E8 .h.0@.j.?...j.?
00000450 06 00 00 00 FF 25 08 20 40 00 FF 25 00 20 40 00 ....%. @.%. @.
00000460 FF 25 10 20 40 00 FF 25 14 20 40 00 FF 25 18 20 %. @.%. @.%.
00000470 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @.%. @.........
【注】需要修改灰色背景的字节。
第九步:删除.text节区多余空字节,使.rdata节区起始位置00000600H地址不变。修正数据目录项导入表项的RVA地址为00002020H。
【可选项】可以选择修改的字段包括导入表的大小、IAT表的大小、.text节区的实际大小、.rdata节区的实际大小和.data节区的实际大小。如果不修改上述字段,不影响程序的运行。说明加载PE时不会检查上述字段。
总结
实验二十八等于手动将两个程序合并为一个新的程序。也可以理解为在原程序的基础上,手动添加了一个新的功能。
需要特别注意的是:
1..rdata节区内的字符串都是ASCII字符串,且偶数字节对齐。
2..text节区内FF 25跳转到函数地址表的顺序必须与IAT表内的顺序相对应。
3.IAT表内RVA地址的顺序可以任意排列,但是必须与.text节区内FF 25跳转到函数地址表的顺序一致。
4.在未绑定的情况下,IAT表和INT表完全一致。
5.可以增加节区内的数据,但是尽量不要改变节区文件偏移地址的起始位置,并保持512个字节对齐。
6.手工重构导入表,需要将两个程序的各个节区进行合并。其中较为复杂的就是IAT表和导入表的重构。