1 ;--------------------------------
  2 ;动态加载功能实现
  3 ;moriarty
  4 ;2012/04/13
  5 ;--------------------------------
  6 .386
  7 .model flat,stdcall
  8 option casemap:none
  9
 10 include windows.inc
 11
 12 ;声明函数
 13 _QLGetProcAddress    typedef proto     :dword, :dword
 14
 15 ;声明函数引用
 16 _ApiGetProcAddress     typedef     ptr     _QLGetProcAddress
 17
 18 _QLLoadLib     typedef        proto    :dword
 19 _ApiLoadLib     typedef        ptr    _QLLoadLib
 20
 21 _QLMessageBoxA    typedef        proto    :dword, :dword, :dword
 22 _ApiMessageBoxA    typedef        ptr    _QLMessageBoxA
 23
 24
 25 ;代码段
 26 .code
 27 szText        db    'HelloWorldPE',0
 28 szGetProcAddr    db    'GetProcAddress',0
 29 szLoadLib    db    'LoadLibraryA',0
 30 szMessageBox    db    'MessageBoxA',0
 31
 32 user32_DLL    db    'user32.dll',0,0
 33
 34 ;定义函数
 35 _getProcAddress        _ApiGetProcAddress    ?
 36 _loadLibrary        _ApiLoadLib        ?
 37 _messageBox        _ApiMessageBoxA        ?
 38
 39 hKernel32Base    dd    ?
 40 hUser32Base    dd    ?
 41 lpGetProcAddr    dd    ?
 42 lpLoadLib    dd    ?
 43
 44 ;------------------------------------------
 45 ;根据kernel32.dll中的一个地址获取它的基址
 46 ;------------------------------------------
 47 _getKernelBase    proc    _dwKernelRetAddress
 48
 49     LOCAL    @dwRet
 50     pushad
 51     mov     @dwRet, 0
 52
 53     mov    edi, _dwKernelRetAddress
 54     and    edi, 0ffff0000h
 55
 56     .repeat
 57         ;找到kernel32.dll的dos头
 58         .if word ptr [edi] == IMAGE_DOS_SIGNATURE
 59             mov     esi, edi
 60             add    esi, [esi+003ch]
 61
 62             ;找到kernel32.dll的pe头标示
 63             .if word ptr [esi] == IMAGE_NT_SIGNATURE
 64                 mov    @dwRet, edi
 65                 .break
 66             .endif
 67         .endif
 68
 69         sub    edi, 010000h
 70         .break    .if edi < 070000000h
 71     .until FALSE
 72
 73     popad
 74     mov     eax, @dwRet
 75
 76     ret
 77
 78 _getKernelBase endp
 79
 80
 81 ;--------------------------------------------------------
 82 ;获取指定字符串的api函数的调用地址
 83 ;入口参数:    _hModule 为动态链接库的基址
 84 ;        _lpApi 为api函数名的首地址
 85 ;出口参数:eax为函数在虚拟地址空间中的真实地址
 86 ;--------------------------------------------------------
 87 _getApi    proc    _hModule, _lpApi
 88
 89     LOCAL    @ret
 90     LOCAL    @dwLen
 91
 92     pushad
 93     mov    @ret, 0
 94
 95     ;计算api字符串的长度 (包括最后的0在内)
 96     mov    edi, _lpApi
 97     mov    ecx, -1
 98     xor    al , al
 99     cld
100
101     repnz    scasb ;比较edi与al  直到内容相同退出(即最后一个 0 时退出)
102
103     mov    ecx, edi ;在repnz  比对过程中 edi 最终指向 字符串末尾的地址
104     sub    ecx, _lpApi ;尾地址-首地址=字符串长度
105     mov    @dwLen, ecx
106
107     ;从pe文件头的数据目录表 取出导出表首地址
108     mov    esi, _hModule
109     add    esi, [esi+3ch] ;[esi+3ch]指向dos头的e_lfaNew字段
110
111     assume    esi :ptr IMAGE_NT_HEADERS ;esi指向IMAGE_NT_HEADERS 的结构
112
113     mov    esi, [esi].OptionalHeader.DataDirectory.VirtualAddress; 指向数据目标表第一项(即DataDirectory[0]导出表)
114     add    esi, _hModule ;导出表的虚拟地址VA=偏移+基址
115
116     assume    esi :ptr IMAGE_EXPORT_DIRECTORY ;
117
118     ;查找指定名称的导出函数
119     mov    ebx, [esi].AddressOfNames; 导出函数名地址 数组
120     add    ebx, _hModule ;得到真实VA
121
122     xor    edx, edx
123     .repeat
124         push     esi
125         mov    edi, [ebx]
126         add    edi, _hModule ;得到函数名的VA
127
128         mov    esi, _lpApi
129         mov    ecx, @dwLen
130         repz    cmpsb    ;比较[edi]、[esi]的内容,将比对结果写入标志位,直到不相同或者ecx为0
131
132         .if    ZERO? ;标志位为0 表示上面的的字符串比对 是匹配的
133             pop    esi
134             jmp    @F
135
136         .endif
137
138         pop    esi
139         add    ebx, 4 ;比对 函数名地址数组的 下一项函数名
140         inc    edx
141     .until    edx >=  [esi].NumberOfNames
142     jmp    _ret
143
144 @@:
145     ;通过上面步骤得到的AddressOfNames的数组索引  获取函数调用的VA
146     sub    ebx, [esi].AddressOfNames
147     sub    ebx, _hModule    ;获得 指定函数名地址 到函数名数组首地址的偏移
148
149     shr    ebx, 1    ;偏移值 移位操作 =ebx/2
150
151     add    ebx, [esi].AddressOfNameOrdinals ;首地址+索引值   即 为指定 AddressOfNameOrdinals 的RVA
152     ;指定的AddressOfNameOrdinals 的VA
153     ;注:AddressOfNameOrdinals里面存储的是AddressOfFunctions的索引
154     ;AddressOfFunctions里面存储的是函数调用的地址
155     add    ebx, _hModule
156
157     movzx    eax, word ptr [ebx]
158     shl    eax, 2    ;根据AddressOfNameOrdinals里面的索引值*2 = AddressOfFunctions首地址的偏移量
159
160     add    eax, [esi].AddressOfFunctions ;函数调用数组首地址+偏移量= 所需求的那个 函数调用地址
161     add    eax, _hModule ;得到 指定函数调用的 VA
162
163     mov    eax, [eax]
164     add    eax, _hModule
165     mov    @ret, eax
166
167 _ret:
168     assume    esi :nothing
169     popad
170     mov    eax, @ret
171
172     ret
173 _getApi endp
174
175 ;------------------------------------------
176 ;函数真正开始执行的地方
177 ;------------------------------------------
178 start:
179     ;取当前函数的栈顶数据
180     ;函数刚开始的时候栈顶地址 一定存在于kernel32.dll地址空间内
181     ;正合适以此寻找kernel32.dll的基址
182     mov    eax, dword ptr [esp]
183     push    eax
184     call    @F
185 @@:
186     pop    ebx
187     sub    ebx, @B ;重定位功能:ebx存储基址
188
189     pop    eax
190
191     ;获取kernel32.dll的基址
192     invoke    _getKernelBase,eax
193     mov    [ebx + offset hKernel32Base], eax
194
195     ;从基地址出发搜索GetProcAddress函数的地址
196     mov    eax, offset szGetProcAddr
197     add    eax, ebx ;eax存储的是 加了基址之后的szGetProcAddr的绝对地址VA
198
199     mov    edi, offset hKernel32Base
200     mov    ecx, [edi + ebx]
201
202     ;调用函数  获取GetProcAddress的调用地址
203     invoke    _getApi, ecx, eax
204
205     mov    [ebx + offset lpGetProcAddr], eax
206
207     ;将GetProcAddress的真实调用地址 存入_getProcAddress变量中
208     mov    [ebx + offset _getProcAddress], eax
209
210     ;下面使用GetProcAddress函数的基址 调用该函数的功能
211     ;参数1:获取  LoadLibraryA 函数名字符串的地址
212     mov    eax, offset szLoadLib
213     add    eax, ebx
214
215     ;参数2:获取 Kernel32.dll的基址
216     mov    edi, offset hKernel32Base
217     mov    ecx, [edi + ebx]
218
219     ;获取GetProcAddress的函数调用地址
220     mov    edx, offset _getProcAddress
221     add    edx, ebx
222
223     ;调用函数GetProcAddress  获取LoadLibraryA的调用地址
224     ;GetProcAddress hKernel32Base,LoadLibraryA
225     push    eax
226     push    ecx
227     call    dword ptr [edx]
228
229     ;将函数LoadLibraryA的调用地址存入_loadLibrary变量
230     mov    [ebx + offset _loadLibrary], eax
231
232     ;使用LoadLibrary载入user32.dll
233     ;参数1:获取user32.dll字符串的地址
234     mov    eax, offset user32_DLL
235     add    eax, ebx
236
237     ;函数LoadLibrary的调用地址
238     mov    edi, offset _loadLibrary
239     mov    edx, [ebx + edi]
240
241     ;调用函数LoadLibraryA
242     ;LoadLibraryA "user32.dll"
243     push    eax
244     call    edx
245
246     ;保存user32.dll的基址
247     mov    [ebx + offset hUser32Base], eax
248
249     ;获取MessageBoxA的函数调用地址
250     ;参数1:MessageBoxA函数名的地址
251     mov    eax, offset szMessageBox
252     add    eax, ebx
253
254     ;参数2:user32.dll的基址
255     mov     edi, offset hUser32Base
256     mov    ecx, [edi + ebx]
257
258     ;参数3:GetProcAddress地址
259     mov    edx, offset _getProcAddress
260     add    edx, ebx
261
262     ;模仿调用:GetProcAddress hUser32Base,MessageBoxA
263     push    eax
264     push    ecx
265     call    dword ptr [edx]
266
267     ;保存MessageBoxA的函数调用地址
268     mov    [ebx + offset _messageBox], eax
269
270     ;调用MessageBoxA这个方法
271     ;参数1:字符串szText
272     mov    eax, offset szText
273     add    eax, ebx
274
275     ;参数2:函数MessageBoxA的地址
276     mov    edx, offset _messageBox
277     add    edx, ebx
278
279     ;模仿调用MessageBoxA NULL, addr szText,Null,MB_OK
280     push     MB_OK
281     push     NULL
282     push     eax
283     push     NULL
284     call    dword ptr [edx]
285
286     ret
287
288     end start
289
290
291         

重定位(搜索KERNEL32.DLL得到API地址)相关推荐

  1. 如何使用Rebase以及bind来重定位和绑定dll

    dll的重定位和绑定技术可以优化应用程序的性能.我们知道,程序性能最本质的提升是算法(这里的算法绝不仅是1+1=2的问题)的改进,其他的改进只是一些配置的优化而已. 那么重定位和绑定属于哪一种呢?从原 ...

  2. PE学习(六)第六章 栈与重定位表 实例栈溢出、模拟加载器加载DLL、遍历重定位表

    第六章 栈与重定位表 16bit OS 存在长调用 lcall push cs,ip    相应的iret pop ip, cs  而call/ret only focus ip register 3 ...

  3. c++ dll返回容器_Windows x86 Shellcode开发:寻找Kernel32.dll地址

    前言 针对一个已经学习了Linux Shellcode开发,并开始在Windows上尝试的研究人员来说,这一过程可能要比想象的更加艰难.Windows内核与Linux完全不同.尽管如此,但Linux内 ...

  4. 嵌入式linux-----ARM裸机(5)-----SDRAM和重定位relocate

    1.看门狗watch dog timer 现实中因为一些外部因素,电子设备经常会跑飞或者死机(譬如极端炎热.极端寒冷.工业复杂场合).在这种情况下我们希望设备自动复位而不需要人工干预(无人值守).看门 ...

  5. S5PV210体系结构与接口04:代码重定位 SDRAM初始化

    目录 1. C语言环境初始化 1.1 C语言运行所需环境 1.2 初始化栈 1.2.1 栈的概念 1.2.2 栈的作用 1.2.3 如何初始化 1.3 初始化bss段 1.3.1 bss段的作用 1. ...

  6. 获取kernel32.dll基址

    获取kernel32.dll基址 一 原理和概述 找kernel32基地址的方法一般有三种:暴力搜索法.异常处理链表搜索法.PEB法. 暴力搜索法是最早的动态查找kernel32基地址的方法.它的原理 ...

  7. S5PV210裸机之重定位

    1.重定位相关概念 位置无关码(PIC,position independent code):汇编源文件被编译成二进制可执行文件时编码方式与位置(内存地址)无关.  位置有关码:汇编源文件被编译成二进 ...

  8. linux 重定位arm,Arm linxu启动过程分析(一)

    本文着重分析 FS2410 平台 linux-2.6.14 内核启动的详细过程,主要包括: zImage 解压缩阶段. vmlinux 启动汇编阶段. startkernel 到创建第一个进程阶段三个 ...

  9. 嵌入式裸机课程之C语言程序调用和重定位学习笔记

    一.汇编写启动代码之关看门狗 前期准备工作 1.1 什么是看门狗 看门狗(watchdog timer)电子设备经常会跑飞或者死机(譬如极端炎热.极端寒冷.工业复杂场合) 这种情况我们需要设备自动复位 ...

最新文章

  1. LA2678最短子序列
  2. 【计算机网络】传输层 : TCP 流量控制 ( 流量控制过程 | 持续计时器机制 )
  3. 非线性常微分方程组 matlab,matlab常微分方程和常微分方程组求解.doc
  4. 深度思考的能力,决定了你能走多远
  5. WSDM2022 | 数据困境: 我们究竟有多了解推荐系统数据集?(附视频、论文及代码)...
  6. flask开发restful api系列(7)-蓝图与项目结构
  7. jQuery + html + css 实现王者荣耀官网首页
  8. 怎么更改计算机的注册表,Windows如何一键修改注册表
  9. python调用gpu amd_TensorFlow使用AMD GPU实现加速(ROCm/Ubuntu 18.04)
  10. 三相并联功率因数校正matlab,基于并联技术的三相功率因数校正方法研究
  11. Android的基站、WIFI、GPS定位三点定位源码下载
  12. 八十二烷基笼状聚倍半硅氧烷poss无色透明黏稠液体|提高颜料分散性
  13. powershell安装sdkman
  14. xcode反汇编调试iOS模拟器程序
  15. fastDB CLI
  16. Modbus串行传输方式
  17. 关于printf()函数。
  18. 12 图浅析人口分布对经济趋势的影响
  19. 如何读懂交易伙伴的EDI需求
  20. Java进制转换之十六进制转八进制

热门文章

  1. Mac OS X下使用C++ JSON库
  2. onethink封装arclist调用文章列表!
  3. ORACLE分区表详解
  4. OpenCV检测图像轮廓
  5. iOS-----Xcode-Debug尝试
  6. 转: 从微信的故障谈谈服务可用性
  7. React脚手架搭建及目录结构介绍
  8. 索尼诺基亚持股公司告赢苹果,获300万美元赔偿
  9. 《JavaScript应用程序设计》一一2.8 闭包
  10. 工具04_SQL Trace/DBMS_SYSTEM