[C++][PEB][ASM]硬幹取得指定函數的內存地址、透過PEB枚舉獲取指定內存地址之函數名稱

這篇是個人筆記啦XD
基本上就是因為網路上要找到寫這種奇怪的東西,實在找不到
所以就去網路上東抓西抓然後改一改弄出來的東西了

首先是
透過指定模組取得函數名稱的地址(其實就是GetProcAddress API的功能啦)

DWORD GetFuncAddr(HMODULE hModule,char* FuncName)
{
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_EXPORT_DIRECTORY pExportDirectory;
HMODULE hModuleBase = hModule;
pDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)hModuleBase + pDosHeader->e_lfanew);
pExportDirectory = PIMAGE_EXPORT_DIRECTORY(pNtHeader->OptionalHeader.DataDirectory[0].VirtualAddress + (PBYTE)hModuleBase);
PDWORD pAddressName = PDWORD((PBYTE)hModuleBase+pExportDirectory->AddressOfNames); //函数名称表指针
PWORD pAddressOfNameOrdinals = (PWORD)((PBYTE)hModuleBase+pExportDirectory->AddressOfNameOrdinals); //函数名称序号表指针
PDWORD pAddresOfFunction = (PDWORD)((PBYTE)hModuleBase+pExportDirectory->AddressOfFunctions); //函数地址表指针
 for (int index = 0; index < (pExportDirectory->NumberOfNames); index++)
 {
  PCHAR pFunc = (PCHAR)((long)hModuleBase + *pAddressName);
  pAddressName ++ ;
  if (!strcmp(pFunc, FuncName)) return (DWORD)( (PBYTE)hModuleBase + pAddresOfFunction[*pAddressOfNameOrdinals]);
  pAddressOfNameOrdinals++;//ENT和函数名序号数组两个并行数组同时滑动指针(序号数组中的序号就对应函数名对应的函数地址的数组索引)
 }
 return (NULL);
}
再來就是
網路上找不太到該怎麼實做的
"從指定函數地址取得函數名稱"(應該說是GetProcAddress的反函數吧?)
實際做法其實就是把上面的暴力枚舉模組的API反過來檢測而已
AnsiString GetFuncName(HMODULE hModule,DWORD FuncAddr)
{
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_EXPORT_DIRECTORY pExportDirectory;
HMODULE hModuleBase = hModule;
pDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)hModuleBase + pDosHeader->e_lfanew);
pExportDirectory = PIMAGE_EXPORT_DIRECTORY(pNtHeader->OptionalHeader.DataDirectory[0].VirtualAddress + (PBYTE)hModuleBase);
PDWORD pAddressName = PDWORD((PBYTE)hModuleBase+pExportDirectory->AddressOfNames); //函数名称表指针
PWORD pAddressOfNameOrdinals = (PWORD)((PBYTE)hModuleBase+pExportDirectory->AddressOfNameOrdinals); //函数名称序号表指针
PDWORD pAddresOfFunction = (PDWORD)((PBYTE)hModuleBase+pExportDirectory->AddressOfFunctions); //函数地址表指针
 for (int index = 0; index < (pExportDirectory->NumberOfNames); index++)
 {
  PCHAR pFunc = (PCHAR)((long)hModuleBase + *pAddressName);
  pAddressName ++ ;
  DWORD CurrentFuncAddr = ( (DWORD)hModuleBase + pAddresOfFunction[*pAddressOfNameOrdinals]) ;
  if ( !(CurrentFuncAddr - FuncAddr) )
  {
   return pFunc;
  }
  pAddressOfNameOrdinals++;
 }
 return ("");
}
最後就是
萬一如果知道內存地址但是不知道它在哪個模組上的時候
 要馬可以透過VirtualQueryEx取得模組基址
但要是VirtualQueryEx沒辦法取得的時候就得透過PEB表暴力列舉所有模組然後去搜索
AnsiString EnumGetFuncName(DWORD FuncAddr)
{
 MEMORY_BASIC_INFORMATION mbi;
 VirtualQueryEx((void*)-1,(void *)FuncAddr,&mbi,sizeof(MEMORY_BASIC_INFORMATION));
 if (mbi.BaseAddress && mbi.AllocationBase) return (GetFuncName((HMODULE)mbi.AllocationBase ,FuncAddr));
 void *PEB = NULL,
 *Ldr = NULL,
 *Flink = NULL,
 *p = NULL,
 *BaseAddress = NULL,
 *FullDllName = NULL;
 asm
 {
  mov eax,fs:[0x30]
  mov PEB,eax
 }
 Ldr = *( ( void ** )( ( unsigned char * )PEB+0x0c ) );
 Flink = *( ( void ** )( ( unsigned char * )Ldr+ 0x1c ) );
 p = Flink;
 do
 {
  BaseAddress = *( ( void ** )( ( unsigned char * )p+ 0x08 ) );
  FullDllName = *( ( void ** )( ( unsigned char * )p+ 0x18) );
  AnsiString CurrentFoundName = GetFuncName((HMODULE)BaseAddress,FuncAddr);
  if (CurrentFoundName != "") return CurrentFoundName ;
  p = *( ( void ** )p);
 }
 while ( Flink != p );
 return "";
}

留言

這個網誌中的熱門文章

[C#] Lambda花式應用噁爛寫法(跨UI委派秒幹、多線程處理...etc)

[Black Asia Arsenal] puzzCode: 專注開發後門的編譯器, 自帶反逆向、對抗病毒特徵碼定位技術

[Windows] 逆向工程 C++ 中入口函數參數 main(argc, argv) 與如何正確的進行參數劫持