重定位(搜索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         

你可能感兴趣的:(api,image,user,dos,null,存储)