在 DLL 中定位函数的地址

逆向工程 dll Python 断点 地址
2021-06-14 03:34:50

我需要在运行时在未导出的 DLL 中找到函数的地址。有问题的 DLL 是与 Visual Basic(和宏)相关的 vbe7.dll。___vbaInStr如果符号是从 Microsoft 下载的,则可以在 IDA 中找到该函数

在 IDA 中定位它以获得偏移量并不是什么大问题,但我想在 Python 中使用它并且即使它在其他机器上运行也能够定位它。原因是我正在使用 winappdbg 并且需要在特定函数上放置一个断点以访问推送到堆栈的参数。

到目前为止,我的理论是:

  1. 查找在调用目标函数附近使用的导出函数并计算偏移量。不过没试过。
  2. 找到围绕目标函数调用的指令模式。这取决于所使用的 DLL 版本和编译器。
  3. 查看目标函数以定位起始地址,失败的原因与上述相同。

那么获取导出函数的地址很容易,但是获取非导出函数的地址呢?目标是.text:102242E3

.text:10224212 ; int __stdcall sub_10224212(int, LCID Locale, VARIANTARG *, VARIANTARG *pvarSrc, int)
.text:10224212 sub_10224212    proc near               ; CODE XREF: sub_1000B164+859p
.text:10224212                                         ; rtcInStrChar+52p
.text:10224212
.text:10224212 arg_0           = dword ptr  8
.text:10224212 Locale          = dword ptr  0Ch
.text:10224212 arg_8           = dword ptr  10h
.text:10224212 pvarSrc         = dword ptr  14h
.text:10224212 arg_10          = dword ptr  18h
.text:10224212
.text:10224212                 mov     edi, edi
.text:10224214                 push    ebp
.text:10224215                 mov     ebp, esp
.text:10224217                 push    ebx
.text:10224218                 push    edi
.text:10224219                 mov     edi, [ebp+pvarSrc]
.text:1022421C                 push    edi
.text:1022421D                 call    rtcIsNull
.text:10224222                 test    ax, ax
.text:10224225                 jnz     loc_10224330
.text:1022422B                 mov     ebx, [ebp+arg_8]
.text:1022422E                 push    ebx
.text:1022422F                 call    rtcIsNull
.text:10224234                 test    ax, ax
.text:10224237                 jnz     loc_10224330
.text:1022423D                 push    esi
.text:1022423E                 push    8
.text:10224240                 pop     esi
.text:10224241                 cmp     [edi], si
.text:10224244                 jnz     short loc_1022424B
.text:10224246                 mov     edi, [edi+8]
.text:10224249                 jmp     short loc_10224261
.text:1022424B ; ---------------------------------------------------------------------------
.text:1022424B
.text:1022424B loc_1022424B:                           ; CODE XREF: sub_10224212+32j
.text:1022424B                 push    edi             ; pvarSrc
.text:1022424C                 call    sub_1006D9C8
.text:10224251                 mov     edi, eax
.text:10224253                 mov     eax, esi
.text:10224255                 mov     word ptr pvarg.anonymous_0, ax ; jumptable 1000BE78 cases 56231,63056
.text:1022425B                 mov     dword ptr pvarg.anonymous_0+8, edi ; jumptable 1000BE78 cases 56231,63056
.text:10224261
.text:10224261 loc_10224261:                           ; CODE XREF: sub_10224212+37j
.text:10224261                 movzx   eax, word ptr [ebx]
.text:10224264                 cmp     ax, si
.text:10224267                 jnz     short loc_1022426E
.text:10224269                 mov     eax, [ebx+8]
.text:1022426C                 jmp     short loc_102242DB
.text:1022426E ; ---------------------------------------------------------------------------
.text:1022426E
.text:1022426E loc_1022426E:                           ; CODE XREF: sub_10224212+55j
.text:1022426E                 cmp     word ptr pvarg.anonymous_0, si ; jumptable 1000BE78 cases 56231,63056
.text:10224275                 jnz     short loc_102242C7
.text:10224277                 cmp     ax, 9
.text:1022427B                 jnz     short loc_102242C7
.text:1022427D                 xor     eax, eax
.text:1022427F                 mov     esi, offset pvarSrc
.text:10224284                 push    esi
.text:10224285                 mov     word ptr pvarg.anonymous_0, ax ; jumptable 1000BE78 cases 56231,63056
.text:1022428B                 push    dword ptr [ebx+8]
.text:1022428E                 call    sub_1022103A
.text:10224293                 mov     ebx, eax
.text:10224295                 test    ebx, ebx
.text:10224297                 jz      short loc_102242A6
.text:10224299                 push    edi             ; bstrString
.text:1022429A                 call    ds:__imp_SysFreeString ; jumptable 1000BE78 cases 171,16878,16935,30141,31177,32098,43703,61383,65216
.text:102242A0                 push    ebx
.text:102242A1                 call    sub_1005DCF1
.text:102242A6
.text:102242A6 loc_102242A6:                           ; CODE XREF: sub_10224212+85j
.text:102242A6                 push    8
.text:102242A8                 pop     eax
.text:102242A9                 push    eax             ; vt
.text:102242AA                 push    esi             ; pvarSrc
.text:102242AB                 push    esi             ; pvargDest
.text:102242AC                 mov     word ptr pvarg.anonymous_0, ax ; jumptable 1000BE78 cases 56231,63056
.text:102242B2                 mov     dword ptr pvarg.anonymous_0+8, edi ; jumptable 1000BE78 cases 56231,63056
.text:102242B8                 call    sub_10082A4C
.text:102242BD                 mov     eax, dword ptr pvarSrc.anonymous_0+8
.text:102242C2                 push    8
.text:102242C4                 pop     esi
.text:102242C5                 jmp     short loc_102242DB
.text:102242C7 ; ---------------------------------------------------------------------------
.text:102242C7
.text:102242C7 loc_102242C7:                           ; CODE XREF: sub_10224212+63j
.text:102242C7                                         ; sub_10224212+69j
.text:102242C7                 push    ebx             ; pvarSrc
.text:102242C8                 call    sub_1006D9C8
.text:102242CD                 mov     ecx, esi
.text:102242CF                 mov     word ptr pvarSrc.anonymous_0, cx
.text:102242D6                 mov     dword ptr pvarSrc.anonymous_0+8, eax
.text:102242DB
.text:102242DB loc_102242DB:                           ; CODE XREF: sub_10224212+5Aj
.text:102242DB                                         ; sub_10224212+B3j
.text:102242DB                 push    [ebp+arg_10]    ; int
.text:102242DE                 push    edi             ; LPCWSTR
.text:102242DF                 push    eax             ; lpSrcStr
.text:102242E0                 push    [ebp+Locale]    ; Locale
.text:102242E3                 call    sub_10083C60 
.text:102242E8                 mov     edi, eax
.text:102242EA                 cmp     word ptr pvarg.anonymous_0, si ; jumptable 1000BE78 cases 56231,63056
.text:102242F1                 jnz     short loc_10224307
.text:102242F3                 push    dword ptr pvarg.anonymous_0+8 ; bstrString
4个回答

如果您有 pdb,那么此代码可以从中获取 Symbol 或 Type

#include <windows.h>
#include <stdio.h>
#include <dbghelp.h>
#pragma comment(lib , "dbghelp.lib")

HANDLE hProcess;

BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo,ULONG ,PVOID UserContext){
  size_t maxcmplen = strlen((PCHAR)UserContext);
  if( maxcmplen == pSymInfo->NameLen ) {
    if((strncmp(pSymInfo->Name,(PCHAR)UserContext,pSymInfo->NameLen)) == 0) {
      TI_FINDCHILDREN_PARAMS childs = {0};
      SymGetTypeInfo(hProcess,pSymInfo->ModBase,pSymInfo->TypeIndex,
      TI_GET_CHILDRENCOUNT,&childs.Count);
      printf("%8s%10s%10s%16s %s" , "Size" ,"TypeIndex","Childs","Address","Name\n");
      printf ("%8x %8x %8x %16I64x %10s\n",pSymInfo->Size,pSymInfo->TypeIndex,
      childs.Count,pSymInfo->Address , pSymInfo->Name );
    }
  }
  return TRUE;
}
void main(int argc , char *argv[]) {
  hProcess = GetCurrentProcess();
  SymInitialize(hProcess, NULL, FALSE);  
  DWORD64 BaseOfDll=SymLoadModuleEx(hProcess,NULL,argv[1],NULL,
  0x400000,0x20000,NULL,0);
  SymEnumSymbols(hProcess , BaseOfDll , "*!*" , EnumSymProc , argv[2]);
  SymEnumTypes(hProcess, BaseOfDll, EnumSymProc, argv[2]);  
  SymCleanup(hProcess);
}

用法

symenumtype.exe .\vbe7.pdb __vbaInStr
    Size TypeIndex    Childs         Address Name
       0        0        0           4c3e4f __vbaInStr

如果您的目标是已知版本,您可以对找到的地址进行硬编码 Ida。如果您不知道不同的版本,那么最好的方法是通过 api 获取 pdb 并以这种方式查找地址。

这可能会帮助您开始:https ://stackoverflow.com/questions/3092609/how-to-get-field-names-and-offsets-of-a-struct-using-dbghlp-and-pdb

这里最好的选择可能是你的第一个建议——找到一个调用你的函数的导出函数,然后在运行时反汇编它以找出调用指向的位置。

这很容易通过使用 IDA 的交叉引用来完成,例如(当您的光标位于 IDA 中的函数名称时ctrl+ x)。请记住,您希望避免/减少用于查找所需函数的某些参数的数量。例如,您应该寻找解引用最少的路径。

您可以查找指向您要查找的函数的构造,而不是函数(如果该函数用于函数指针)。

我设法使用 pefile 和 capstone 解决了它。找到通向我的目标的导出函数(如上所述),然后使用 capstone 反汇编该函数并找到通往目标的路。

简而言之,我做了什么(当然可以美化等):

import sys
import pefile
from capstone import Cs, CS_ARCH_X86, CS_MODE_32

dll = pefile.PE(sys.argv[1])
#dll = pefile.PE('C:\Program Files\Common Files\microsoft shared\VBA\VBA7\VBE7.DLL')


for export in dll.DIRECTORY_ENTRY_EXPORT.symbols:
    if export.name == 'rtcInStrChar':
        exp_addr = export.address
        break

for imp in dll.DIRECTORY_ENTRY_IMPORT:
    for entry in imp.imports:
        if entry.name == 'SysFreeString':
            imp_addr = entry.address
            break
            #print('0x%x - %s' % (entry.address, entry.name))

memory = dll.get_memory_mapped_image()

dsm = Cs(CS_ARCH_X86, CS_MODE_32)

for op in dsm.disasm(memory[exp_addr:exp_addr + 0xA0], (exp_addr + dll.OPTIONAL_HEADER.ImageBase)):
    if op.mnemonic == 'call':
        last_call = op.op_str[2:]
    if op.mnemonic == 'ret':
        break
    #print("0x%x:\t%s\t%s" %(op.address, op.mnemonic, op.op_str))

next_func = int(last_call, 16) - dll.OPTIONAL_HEADER.ImageBase

calls = 0
call_free = 0
for op in dsm.disasm(memory[next_func:next_func + 0x100], (next_func + dll.OPTIONAL_HEADER.ImageBase)):
    print("0x%x:\t%s\t%s" %(op.address, op.mnemonic, op.op_str))
    if op.mnemonic == 'call' and '0x%x' % imp_addr in op.op_str:
        call_free += 1
    if call_free == 2:
        print('GOT IT: 0x%x' % last_call)
        break
    if op.mnemonic == 'call':
        last_call = op.address