如何在没有它们的情况下获取GetProcAdress和LoadLibrary?

时间:2015-09-28 06:39:35

标签: c windows winapi dll reverse-engineering

假设我没有导入.lib库 我希望通过手工编写原始的一切 调用(如汇编或纯c)

GetProcAdress LoadLibrary是winapi dll的一部分 一般来说,加载dll并获取指针 功能我需要调用那两个,但作为我 不知道我可以用它来获取它们吗?

这有点像悖论,可能它可以通过其他一些机制来解决,但在这里我缺乏知识表明,我不知道这种机制是什么,有人可以解释一下吗?

2 个答案:

答案 0 :(得分:6)

以下工作假设从kernel32.dll内部调用mainCRTStartup()。 它使用返回地址来定位模块的开头,并从那里搜索其EAT以获取GetProcAddress()。

#include <windows.h>

static HMODULE findModuleBase( void *ptr )
{
  ULONG_PTR addr = (ULONG_PTR)ptr;
  addr &= ~0xffff;
  const UINT32 *mod = (const UINT32*)addr;
  while( mod[0]!=0x00905a4d ) // MZ.. header
    mod -= 0x4000; // 0x10000/4
  return( (HMODULE)mod );
}

#define REL_PTR( base,ofs ) ( ((PBYTE)base)+ofs )
static void *findGetProcAddress( HMODULE mod )
{
  PIMAGE_DOS_HEADER idh = (PIMAGE_DOS_HEADER)mod;
  PIMAGE_NT_HEADERS inh = (PIMAGE_NT_HEADERS)REL_PTR( idh,idh->e_lfanew );
  PIMAGE_EXPORT_DIRECTORY ied =
    (PIMAGE_EXPORT_DIRECTORY)REL_PTR( idh,inh->OptionalHeader.
        DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress );
  DWORD *names = (DWORD*)REL_PTR( idh,ied->AddressOfNames );
  unsigned int i;
  for( i=0; i<ied->NumberOfNames; i++ )
  {
    const UINT32 *name32 = (const UINT32*)REL_PTR( idh,names[i] );
    const UINT16 *name16 = (const UINT16*)name32;
    const UINT8 *name8 = (const UINT8*)name32;
    if( name32[0]!=0x50746547 || // GetP
        name32[1]!=0x41636f72 || // rocA
        name32[2]!=0x65726464 || // ddre
        name16[6]!=0x7373 ||     // ss
        name8[14]!=0x00 )
      continue;
    WORD *ordinals = (WORD*)REL_PTR( idh,ied->AddressOfNameOrdinals );
    DWORD *funcs = (DWORD*)REL_PTR( idh,ied->AddressOfFunctions );
    return( REL_PTR(idh,funcs[ordinals[i]]) );
  }
  return( NULL );
}

#ifdef __MINGW32__
#define RETURN_ADDRESS() __builtin_return_address(0)
#else
#define RETURN_ADDRESS() _ReturnAddress()
#endif
void mainCRTStartup( void )
{
  HMODULE kernel = findModuleBase( RETURN_ADDRESS() );

  typedef LPVOID WINAPI func_GetProcAddress( HMODULE,LPCSTR );
  func_GetProcAddress *fGetProcAddress = findGetProcAddress( kernel );

  typedef HMODULE WINAPI func_LoadLibraryA( LPCSTR );
  typedef VOID WINAPI func_ExitProcess( UINT );
  func_LoadLibraryA *fLoadLibraryA = fGetProcAddress( kernel,"LoadLibraryA" );
  func_ExitProcess *fExitProcess = fGetProcAddress( kernel,"ExitProcess" );

  typedef int func_printf( const char*,... );
  HMODULE msvcrt = fLoadLibraryA( "msvcrt.dll" );
  func_printf *f_printf = fGetProcAddress( msvcrt,"printf" );
  f_printf( "is this working?\n" );

  fExitProcess( 1 );
}

答案 1 :(得分:5)

我之前已经设法做到了这一点。这确实是可能的。解决方案是基本上手动实施LdrGetDllHandle 并使用它来搜索LdrLoadDll内的LdrUnloadDll / LdrGetProcedureAddressNTDLL通过PEB_LDR_DATA指向进程NtCurrentPeb数据结构的指针,这是一个读取FS或GS CPU寄存器的宏。
一旦有了这三个函数的指针,就可以使用它们来加载你需要的其他DLL。

我不打算为你发布代码,但如果你看看ReactOS的源代码,你应该能够逐步弄清楚如何实现这个 - 我认为这些应该是足够的指针(没有双关语)意图)让你开始。 :)