重定位(搜索KERNEL32.DLL得到API地址)
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地址)相关推荐
- 如何使用Rebase以及bind来重定位和绑定dll
dll的重定位和绑定技术可以优化应用程序的性能.我们知道,程序性能最本质的提升是算法(这里的算法绝不仅是1+1=2的问题)的改进,其他的改进只是一些配置的优化而已. 那么重定位和绑定属于哪一种呢?从原 ...
- PE学习(六)第六章 栈与重定位表 实例栈溢出、模拟加载器加载DLL、遍历重定位表
第六章 栈与重定位表 16bit OS 存在长调用 lcall push cs,ip 相应的iret pop ip, cs 而call/ret only focus ip register 3 ...
- c++ dll返回容器_Windows x86 Shellcode开发:寻找Kernel32.dll地址
前言 针对一个已经学习了Linux Shellcode开发,并开始在Windows上尝试的研究人员来说,这一过程可能要比想象的更加艰难.Windows内核与Linux完全不同.尽管如此,但Linux内 ...
- 嵌入式linux-----ARM裸机(5)-----SDRAM和重定位relocate
1.看门狗watch dog timer 现实中因为一些外部因素,电子设备经常会跑飞或者死机(譬如极端炎热.极端寒冷.工业复杂场合).在这种情况下我们希望设备自动复位而不需要人工干预(无人值守).看门 ...
- 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. ...
- 获取kernel32.dll基址
获取kernel32.dll基址 一 原理和概述 找kernel32基地址的方法一般有三种:暴力搜索法.异常处理链表搜索法.PEB法. 暴力搜索法是最早的动态查找kernel32基地址的方法.它的原理 ...
- S5PV210裸机之重定位
1.重定位相关概念 位置无关码(PIC,position independent code):汇编源文件被编译成二进制可执行文件时编码方式与位置(内存地址)无关. 位置有关码:汇编源文件被编译成二进 ...
- linux 重定位arm,Arm linxu启动过程分析(一)
本文着重分析 FS2410 平台 linux-2.6.14 内核启动的详细过程,主要包括: zImage 解压缩阶段. vmlinux 启动汇编阶段. startkernel 到创建第一个进程阶段三个 ...
- 嵌入式裸机课程之C语言程序调用和重定位学习笔记
一.汇编写启动代码之关看门狗 前期准备工作 1.1 什么是看门狗 看门狗(watchdog timer)电子设备经常会跑飞或者死机(譬如极端炎热.极端寒冷.工业复杂场合) 这种情况我们需要设备自动复位 ...
最新文章
- LA2678最短子序列
- 【计算机网络】传输层 : TCP 流量控制 ( 流量控制过程 | 持续计时器机制 )
- 非线性常微分方程组 matlab,matlab常微分方程和常微分方程组求解.doc
- 深度思考的能力,决定了你能走多远
- WSDM2022 | 数据困境: 我们究竟有多了解推荐系统数据集?(附视频、论文及代码)...
- flask开发restful api系列(7)-蓝图与项目结构
- jQuery + html + css 实现王者荣耀官网首页
- 怎么更改计算机的注册表,Windows如何一键修改注册表
- python调用gpu amd_TensorFlow使用AMD GPU实现加速(ROCm/Ubuntu 18.04)
- 三相并联功率因数校正matlab,基于并联技术的三相功率因数校正方法研究
- Android的基站、WIFI、GPS定位三点定位源码下载
- 八十二烷基笼状聚倍半硅氧烷poss无色透明黏稠液体|提高颜料分散性
- powershell安装sdkman
- xcode反汇编调试iOS模拟器程序
- fastDB CLI
- Modbus串行传输方式
- 关于printf()函数。
- 12 图浅析人口分布对经济趋势的影响
- 如何读懂交易伙伴的EDI需求
- Java进制转换之十六进制转八进制