首页 > 代码库 > 嵌入补丁框架

嵌入补丁框架

  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