• 标 题:打造MyGetProcAddress函数(Delphi源码)
  • 作 者:老王
  • 时 间:004-05-06,12:01
  • 链 接:http://bbs.pediy.com

function MyGetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;

function MyGetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC;
var
  DataDirectory: TImageDataDirectory;
  P1: ^Cardinal;
  P2: ^Word;
  Base, NumberOfNames, AddressOfFunctions, AddressOfNames, AddressOfNameOrdinals, i, Ordinal: Cardinal;
  TempStr1, TempStr2: string;
begin
  Result := nil;
  DataDirectory := PImageNtHeaders(Cardinal(hModule) + Cardinal(PImageDosHeader(hModule)^._lfanew))^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 16);
  Base := P1^; //输出函数的起始序号。一般为1。
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 24);
  NumberOfNames := P1^; //输出函数名的指针的数组中的元素个数,也是输出函数名对应的序号的数组中的元素个数。
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 28);
  AddressOfFunctions := P1^; //一个RVA,指向输出函数入口地址的数组。
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 32);
  AddressOfNames := P1^; //一个RVA,指向输出函数名的指针的数组。
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 36);
  AddressOfNameOrdinals := P1^; //一个RVA,指向输出函数名对应的序号的数组。
  Ordinal := 0;
  if Cardinal(lpProcName) > $0000FFFF then
  begin
    //lpProcName参数指向函数名
    TempStr1 := PChar(lpProcName); //要找的函数名
    for i := 1 to NumberOfNames do
    begin
      //按顺序在输出函数名中找
      P1 := Pointer(hModule + AddressOfNames + (i - 1) * 4);
      TempStr2 := PChar(hModule + P1^); //当前输出函数名
      if TempStr1 = TempStr2 then
      begin
        //找到输出函数
        P2 := Pointer(hModule + AddressOfNameOrdinals + (i - 1) * 2);
        //获得序号,不必减Base
        Ordinal := P2^;
        Break;
      end;
    end;
  end
  else
    //lpProcName传过来的是序号,需减Base
    Ordinal := Cardinal(lpProcName) - Base;
  P1 := Pointer(hModule + AddressOfFunctions + Ordinal * 4); //P1^为函数入口RVA
  if (P1^ >= DataDirectory.VirtualAddress) and (P1^ <= DataDirectory.VirtualAddress + DataDirectory.Size) then
  begin
    //!!!入口RVA在输出表中,指向另一DLL的某函数,这一点很容易被忽视,很少有教程提到,也许是没仔细看!!!
    TempStr1 := PChar(hModule + P1^); //DLL.函数
    TempStr2 := TempStr1;
    while Pos('.', TempStr2) > 0 do
      TempStr2 := Copy(TempStr2, Pos('.', TempStr2) + 1, Length(TempStr2) - Pos('.', TempStr2));
    TempStr1 := Copy(TempStr1, 1, Length(TempStr1) - Length(TempStr2) - 1); //TempStr1是DLL名,TempStr2是函数名
    //递归调用获取新的函数地址
    Base := GetModuleHandle(PChar(TempStr1));
    if Base = 0 then
      Base := LoadLibrary(PChar(TempStr1));
    if Base > 0 then
      Result := MyGetProcAddress(Base, PChar(TempStr2));
  end
  else
    //RVA+基址就是函数的真实入口了
    Result := Pointer(hModule + P1^);
  //结果Result := GetProcAddress(hModule, lpProcName);
end;

相关:
  _IMAGE_DATA_DIRECTORY = record
    VirtualAddress: DWORD;
    Size: DWORD;
  end;
  {$EXTERNALSYM _IMAGE_DATA_DIRECTORY}
  TImageDataDirectory = _IMAGE_DATA_DIRECTORY;

  PImageExportDirectory = ^TImageExportDirectory;
  _IMAGE_EXPORT_DIRECTORY = packed record
      Characteristics: DWord;
      TimeDateStamp: DWord;
      MajorVersion: Word;
      MinorVersion: Word;
      Name: DWord;
      Base: DWord;
      NumberOfFunctions: DWord;
      NumberOfNames: DWord;
      AddressOfFunctions: ^PDWORD;
      AddressOfNames: ^PDWORD;
      AddressOfNameOrdinals: ^PWord;
  end;
  {$EXTERNALSYM _IMAGE_EXPORT_DIRECTORY}
  TImageExportDirectory = _IMAGE_EXPORT_DIRECTORY;

这是我用来在EncryptPE新版壳中处理IAT的源代码,98、2003下测试通过。如果你发现问题请告诉我!
假如你是Cracker,看到这段代码,你准备如何设断,避开IAT加密呢?

EncryptPE作者老王(wfs)
2004.5.6

  • 标 题: 同一函数,我用在VB_Shell里面的。
  • 作 者:Aming
  • 时 间:004-05-06,14:27
  • 链 接:http://bbs.pediy.com

同一函数,我用在VB_Shell里面的。
Function GetProcAddressDirectly(ByVal lpImageDosHeader As IMAGE_DOS_HEADER Ptr, FuncName As Asciiz) As Dword
    Dim lpImageNtHeaders          As Local IMAGE_NT_HEADERS Ptr
    Dim lpImageExportDirectory    As Local IMAGE_EXPORT_DIRECTORY Ptr
    Dim lpNameOrdinals            As Local Word Ptr
    Dim lpFunctions               As Local Dword Ptr
    Dim lpName                    As Local Dword Ptr
    Dim lpExpFuncName             As Local Asciiz Ptr
    Dim i                         As Local Dword
    Dim j                         As Local Dword
    Dim lpFuncName                As Asciiz Ptr


    If @lpImageDosHeader.e_magic <> %IMAGE_DOS_SIGNATURE Then ' invalid DOS signature
        Function = 1
        MsgBox "Invalid DOS signature",%MB_ICONWARNING,"Error in GetProcAddressDirectly()"
        Exit Function
    End If
    lpImageNtHeaders = lpImageDosHeader + @lpImageDosHeader.e_lfanew
   '================================

    If @lpImageNtHeaders.Signature <> %IMAGE_NT_SIGNATURE Then ' Invalid NT signature
        Function = 1
        MsgBox "Invalid NT signature",%MB_ICONWARNING,"Error in GetProcAddressDirectly()"
        Exit Function
    End If
   '================================

    If @lpImageNtHeaders.FileHeader.SizeOfOptionalHeader <> SizeOf(@lpImageNtHeaders.OptionalHeader) Or _
        @lpImageNtHeaders.OptionalHeader.Magic <> %IMAGE_NT_OPTIONAL_HDR32_MAGIC Then
        Function = 0
        MsgBox "SizeOfOptionalHeader or OptionalHeader.Magic",%MB_ICONWARNING,"Error in GetProcAddressDirectly()"
        Exit Function
    End If
    lpImageExportDirectory = @lpImageNtHeaders.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).VirtualAddress
   '================================

    If lpImageExportDirectory = 0 Then
        Function = 0
        MsgBox "lpImageExportDirectory",%MB_ICONWARNING,"Error in GetProcAddressDirectly()"
        Exit Function
    End If
    lpImageExportDirectory = lpImageExportDirectory + lpImageDosHeader
   '================================

    lpNameOrdinals = @lpImageExportDirectory.AddressOfNameOrdinals + lpImageDosHeader
    lpName         = @lpImageExportDirectory.AddressOfNames        + lpImageDosHeader
    lpFunctions    = @lpImageExportDirectory.AddressOfFunctions    + lpImageDosHeader
   '================================

    lpFuncName = VarPtr(FuncName)
   '================================

    If HiWrd(lpFuncName) Then ' Name
       For i = 0 To @lpImageExportDirectory.NumberOfFunctions - 1
          If @lpFunctions[i] Then
             For j = 0 To @lpImageExportDirectory.NumberOfNames - 1
                If @lpNameOrdinals[j] = i Then
                   lpExpFuncName = @lpName[j] + lpImageDosHeader
                   If @lpExpFuncName = FuncName Then Function = @lpFunctions[i] + lpImageDosHeader : Exit Function
                End If
             Next
          End If
       Next

    Else
       For i = 0 To @lpImageExportDirectory.NumberOfFunctions - 1
          If lpFuncName = @lpImageExportDirectory.nBase + i Then
             If  @lpFunctions[i] Then Function = @lpFunctions[i] + lpImageDosHeader
             Exit Function
          End If
       Next
    End If
   '================================

End Function

VC:
DWORD GetProcAddressDirectly(PIMAGE_DOS_HEADER lpImageDosHeader, char * FuncName)
{
    PIMAGE_NT_HEADERS lpImageNtHeaders;
    PIMAGE_EXPORT_DIRECTORY pExportDir;
    PWORD lpNameOrdinals;
    unsigned char * lpFunctions;
    DWORD * lpName;
    char * lpExpFuncName;
    DWORD i;
    DWORD j;
    char * lpFuncName;

    if(lpImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  {
        MessageBox(NULL,"Invalid DOS signature",0,0);
        return 1;
  }
    
    lpImageNtHeaders = (PIMAGE_NT_HEADERS)(lpImageDosHeader + lpImageDosHeader->e_lfanew);
  
    if (lpImageNtHeaders->Signature != IMAGE_NT_SIGNATURE)
  {
    MessageBox(NULL,"Invalid NT signature",0,0);
        return 1;
    }
  
    if ((lpImageNtHeaders->FileHeader.SizeOfOptionalHeader != sizeof(lpImageNtHeaders->OptionalHeader)) ||
        (lpImageNtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC))
  {
    MessageBox(NULL,"SizeOfOptionalHeader or OptionalHeader->Magic",0,0);
        return 0;
    }

  DWORD exportsStartRVA, exportsEndRVA;
    PIMAGE_NT_HEADERS pNTHeader;
  //PIMAGE_NT_HEADERS64 pNTHeader64;
    PBYTE pImageBase = (PBYTE)lpImageDosHeader;
    
  // Make pointers to 32 and 64 bit versions of the header.
    pNTHeader = MakePtr( PIMAGE_NT_HEADERS, lpImageDosHeader,
                                lpImageDosHeader->e_lfanew );


    exportsStartRVA = GetImgDirEntryRVA(pNTHeader,IMAGE_DIRECTORY_ENTRY_EXPORT);
    exportsEndRVA = exportsStartRVA +
             GetImgDirEntrySize(pNTHeader, IMAGE_DIRECTORY_ENTRY_EXPORT);

    // Get the IMAGE_SECTION_HEADER that contains the exports.  This is
    // usually the .edata section, but doesn't have to be.
  PIMAGE_SECTION_HEADER header;
    header = GetEnclosingSectionHeader( exportsStartRVA, pNTHeader );
    if ( !header ) return 0;

  INT delta;
    delta = (INT)(header->VirtualAddress - header->PointerToRawData);
    pExportDir = (PIMAGE_EXPORT_DIRECTORY)GetPtrFromRVA(exportsStartRVA, pNTHeader, pImageBase);

  
    pExportDir =(PIMAGE_EXPORT_DIRECTORY) (lpImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  
    if (pExportDir == 0)
  {
    MessageBox(NULL,"Error in GetProcAddressDirectly()",0,0);
        return 0;
    }
  
    pExportDir =(PIMAGE_EXPORT_DIRECTORY) (DWORD)pExportDir + (DWORD)lpImageDosHeader;
  
    lpNameOrdinals =(unsigned short *)(pExportDir->AddressOfNameOrdinals + lpImageDosHeader);
    //lpNameOrdinals =  (PWORD)  GetPtrFromRVA( pExportDir->AddressOfNameOrdinals, pNTHeader, pImageBase );
    lpName         =(DWORD *) (pExportDir->AddressOfNames        + lpImageDosHeader);
    lpFunctions    =(unsigned char *) (pExportDir->AddressOfFunctions    + lpImageDosHeader);

  //PDWORD pdwFunctions;

    lpFuncName = FuncName;
  
    if(HIWORD(lpFuncName)!=0 )
  {
    for( i = 0;i<=pExportDir->NumberOfFunctions - 1;i++)
    {
      DWORD entryPointRVA = *lpFunctions;
      
      if ( entryPointRVA == 0 ) continue;  // Skip over gaps in exported function
                                         // ordinals (the entrypoint is 0 for
      
      for( j = 0;j<=pExportDir->NumberOfNames - 1;j++)
      {
        if( lpNameOrdinals[j] == i)
        {
          lpExpFuncName = (char *) (lpName[j] + lpImageDosHeader);
          if(lpExpFuncName = FuncName)  return (unsigned long) (lpFunctions[i] + lpImageDosHeader);
        }
      }
    }
  }
    else
  {
    for (i = 0 ;i<=pExportDir->NumberOfFunctions - 1;i++)
    {
      if (lpFuncName == (char *)(pExportDir->Base + i))
      {
        if (lpFunctions[i]) return (unsigned long) (lpFunctions[i] + lpImageDosHeader);
      }
    }
    }
  return 0;
}

function MyGetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall
将导致调用的时候是
push lpProcName
push hModule
call MyGetProcAddress
形式
一般我会断LoadLibrary函数(此函数我想一般人不会自己去实现它),然后
观察对kenerl32.dll等重要函数的loalibray.得到的返回值,下对这个值得
内存访问断点.很容易找到你实现的MyGetProcAddress函数,一开始可能看不出来但是看几次堆栈后ret就知道你这个玩意就是模仿getprocaddress了,