1 ;-------------------------
2 ; 补丁代码
3 ; 本段代码使用了API函数地址动态获取以及重定位技术
4 ; 程序功能:弹出对话框
5 ; 作者:戚利
6 ; 开发日期:2011.2.22
7 ;-------------------------
8
9 .386
10 .model flat,stdcall
11 option casemap:none
12
13 include windows.inc
14
15 ;注意此处不静态包含引入任何其他动态链接库
16
17 _ProtoGetProcAddress typedef proto :dword,:dword
18 _ProtoLoadLibrary typedef proto :dword
19
20 _ApiGetProcAddress typedef ptr _ProtoGetProcAddress
21 _ApiLoadLibrary typedef ptr _ProtoLoadLibrary
22
23
24 ;-------------------------------------------
25 ; 补丁代码中引入的其他动态链接库的函数的声明
26 ;-------------------------------------------
27
28
29 _ProtoMessageBox typedef proto :dword,:dword,:dword,:dword
30 _ApiMessageBox typedef ptr _ProtoMessageBox
31
32
33 ;被添加到目标文件的代码从这里开始,到APPEND_CODE_END处结束
34
35 .code
36
37 jmp _NewEntry
38
39 ; 以下内容为两个重要函数名
40 ; 几乎所有补丁都必须使用的
41 szGetProcAddr db ‘GetProcAddress‘,0
42 szLoadLib db ‘LoadLibraryA‘,0
43
44 ;------------------------------------------------------
45 ; 补丁代码中其他全局变量的定义
46 ;------------------------------------------------------
47
48 szUser32Dll db ‘user32.dll‘,0
49 szMessageBox db ‘MessageBoxA‘,0 ;该方法在kernel32.dll中
50 szHello db ‘HelloWorldPE‘,0 ;要创建的目录
51
52
53 ;-----------------------------
54 ; 错误 Handler
55 ;-----------------------------
56 _SEHHandler proc _lpException,_lpSEH,_lpContext,_lpDispatcher
57 pushad
58 mov esi,_lpException
59 mov edi,_lpContext
60 assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
61 mov eax,_lpSEH
62 push [eax+0ch]
63 pop [edi].regEbp
64 push [eax+8]
65 pop [edi].regEip
66 push eax
67 pop [edi].regEsp
68 assume esi:nothing,edi:nothing
69 popad
70 mov eax,ExceptionContinueExecution
71 ret
72 _SEHHandler endp
73
74 ;------------------------------------
75 ; 获取kernel32.dll的基地址
76 ;------------------------------------
77 _getKernelBase proc
78 local @dwRet
79
80 pushad
81
82 assume fs:nothing
83 mov eax,fs:[30h] ;获取PEB所在地址
84 mov eax,[eax+0ch] ;获取PEB_LDR_DATA 结构指针
85 mov esi,[eax+1ch] ;获取InInitializationOrderModuleList 链表头
86 ;第一个LDR_MODULE节点InInitializationOrderModuleList成员的指针
87 lodsd ;获取双向链表当前节点后继的指针
88 mov eax,[eax+8] ;获取kernel32.dll的基地址
89 mov @dwRet,eax
90 popad
91 mov eax,@dwRet
92 ret
93 _getKernelBase endp
94
95 ;-------------------------------
96 ; 获取指定字符串的API函数的调用地址
97 ; 入口参数:_hModule为动态链接库的基址
98 ; _lpApi为API函数名的首址
99 ; 出口参数:eax为函数在虚拟地址空间中的真实地址
100 ;-------------------------------
101 _getApi proc _hModule,_lpApi
102 local @ret
103 local @dwLen
104
105 pushad
106 mov @ret,0
107 ;计算API字符串的长度,含最后的零
108 mov edi,_lpApi
109 mov ecx,-1
110 xor al,al
111 cld
112 repnz scasb
113 mov ecx,edi
114 sub ecx,_lpApi
115 mov @dwLen,ecx
116
117 ;从pe文件头的数据目录获取导出表地址
118 mov esi,_hModule
119 add esi,[esi+3ch]
120 assume esi:ptr IMAGE_NT_HEADERS
121 mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
122 add esi,_hModule
123 assume esi:ptr IMAGE_EXPORT_DIRECTORY
124
125 ;查找符合名称的导出函数名
126 mov ebx,[esi].AddressOfNames
127 add ebx,_hModule
128 xor edx,edx
129 .repeat
130 push esi
131 mov edi,[ebx]
132 add edi,_hModule
133 mov esi,_lpApi
134 mov ecx,@dwLen
135 repz cmpsb
136 .if ZERO?
137 pop esi
138 jmp @F
139 .endif
140 pop esi
141 add ebx,4
142 inc edx
143 .until edx>=[esi].NumberOfNames
144 jmp _ret
145 @@:
146 ;通过API名称索引获取序号索引再获取地址索引
147 sub ebx,[esi].AddressOfNames
148 sub ebx,_hModule
149 shr ebx,1
150 add ebx,[esi].AddressOfNameOrdinals
151 add ebx,_hModule
152 movzx eax,word ptr [ebx]
153 shl eax,2
154 add eax,[esi].AddressOfFunctions
155 add eax,_hModule
156
157 ;从地址表得到导出函数的地址
158 mov eax,[eax]
159 add eax,_hModule
160 mov @ret,eax
161
162 _ret:
163 assume esi:nothing
164 popad
165 mov eax,@ret
166 ret
167 _getApi endp
168
169 ;------------------------
170 ; 补丁功能部分
171 ; 传入三个参数:
172 ; _kernel:kernel32.dll的基地址
173 ; _getAddr:函数GetProcAddress地址
174 ; _loadLib:函数LoadLibraryA地址
175 ;------------------------
176 _patchFun proc _kernel,_getAddr,_loadLib
177
178 ;------------------------------------------------------
179 ; 补丁功能代码局部变量定义
180 ;------------------------------------------------------
181
182 local hUser32Base:dword
183 local _messageBox:_ApiMessageBox
184
185
186 pushad
187
188
189 ;------------------------------------------------------
190 ; 补丁功能代码,以下只是一个范例,功能为弹出对话框
191 ;------------------------------------------------------
192
193
194 ;获取user32.dll的基地址
195 mov eax,offset szUser32Dll
196 add eax,ebx
197
198 mov edx,_loadLib
199 push eax
200 call edx
201 mov hUser32Base,eax
202
203
204 ;使用GetProcAddress函数的首址,
205 ;传入两个参数调用GetProcAddress函数,
206 ;获得MessageBoxA的首址
207 mov eax,offset szMessageBox
208 add eax,ebx
209
210 mov edx,_getAddr
211 mov ecx,hUser32Base
212 push eax
213 push ecx
214 call edx
215 mov _messageBox,eax
216
217 ;调用函数MessageBox !!
218 mov eax,offset szHello
219 add eax,ebx
220 mov edx,_messageBox
221
222 push MB_OK
223 push NULL
224 push eax
225 push NULL
226 call edx
227
228
229 popad
230 ret
231 _patchFun endp
232
233
234 _start proc
235 local hKernel32Base:dword ;存放kernel32.dll基址
236
237 local _getProcAddress:_ApiGetProcAddress ;定义函数
238 local _loadLibrary:_ApiLoadLibrary
239
240 pushad
241
242 ;获取kernel32.dll的基地址
243 lea edx,_getKernelBase
244 add edx,ebx
245 call edx
246 mov hKernel32Base,eax
247
248 ;从基地址出发搜索GetProcAddress函数的首址
249 mov eax,offset szGetProcAddr
250 add eax,ebx
251
252 mov edi,hKernel32Base
253 mov ecx,edi
254 lea edx,_getApi
255 add edx,ebx
256
257 push eax
258 push ecx
259 call edx
260 mov _getProcAddress,eax
261
262 ;从基地址出发搜索LoadLibraryA函数的首址
263 mov eax,offset szLoadLib
264 add eax,ebx
265
266 mov edi,hKernel32Base
267 mov ecx,edi
268 lea edx,_getApi
269 add edx,ebx
270
271 push eax
272 push ecx
273 call edx
274 mov _loadLibrary,eax
275
276 ;调用补丁代码
277 lea edx,_patchFun
278 add edx,ebx
279
280 push _loadLibrary
281 push _getProcAddress
282 push hKernel32Base
283 call edx
284
285 popad
286 ret
287 _start endp
288
289 ; EXE文件新的入口地址
290
291 _NewEntry:
292 call @F ; 免去重定位
293 @@:
294 pop ebx
295 sub ebx,offset @B
296
297 invoke _start
298 jmpToStart db 0E9h,0F0h,0FFh,0FFh,0FFh
299 ret
300 end _NewEntry
时间: 2024-11-06 02:34:58