天天看點

定位未導出的函數位址(SHCreateProcess) 定位未導出的函數位址(SHCreateProcess)



定位未導出的函數位址(SHCreateProcess)

搬運自我的百度空間,文章基于windows7 64位

我們要Hook shell32.dll的SHCreateProcess這個函數,苦于他沒有被導出,也無從知道位址。

其實我們還是有辦法的。windbg有功能叫做棧回朔技術,可以看到函數的調用者,函數的調用者的調用者,函數的調用者的調用者的調用者。。。。。。。。。。。。。。。。。。(略過1000字)

原理是什麼呢?我們知道函數的調用是靠棧來完成的,每當調用一個函數,都會把函數的傳回位址存入棧中。

windbg就是看棧中的傳回位址來确定調用者的。

好,鋪叙完畢。看看SHCreateProcess這個函數,他的位址我們雖然不知道,但是我們知道他會調用CreateProcessW,那我們Hook了CreateProcessW後,假裝調用ShellExecute(内部會使用SHCreateProcess函數),回朔調用者,就能得到SHCreateProcess的大緻位址了(因為得到的是CreateProcessW傳回到SHCreateProcess内部的位址,而不是SHCreateProcess的首位址,是以我說是“大緻位址”)。

(2016-8-3更新:有朋友私信問我SHCreateProcess的原型,我當時在網上搜得到,現在看了看好像找不到了,還好我的工程裡還有,定義如下:

typedef  int (__stdcall *PSHCreateProcess)(int p1,HANDLE hToken,wchar_t *lpApplicationName,wchar_t * lpCommandLine,DWORD dwCreationFlags,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation,int p2,char p3,int p4);

先來說32位版Win7:

windbg反彙編SHCreateProcess看到,他調用了函數IsUserAnAdmin,是一個導出函數,我們Hook之

具體怎麼Hook我就不說了,直接到關鍵步驟:

//32Bit

long myIsUserAnAdmin()

{

void* aa=0;

__asm

{

mov eax, [ebp+4]

mov aa,eax

}

long i,key,key2;

bool ok=false;

for (i=(long)aa;i>=(long)aa-0x200000;i--)

{

key=*(long*)i;

key2=*(long*)(i+4);

if (key==0x8b144d8b && key2==0x8d890845 )

break;

}

for (;i>=(long)aa-0x200000;i--)

{

key=*(long*)i;

if (key==0x90909090)

{

ok=true;

break;

}

}

if(ok)

{

i+=4;

HMODULE hMod=GetModuleHandleW(L"shell32.dll");

pSHCreateProcess =(PSHCreateProcess)i;

}

else

{

pSHCreateProcess =0;

}

return 1;

}

HANDLE RunAsAdmin( HWND hWnd, WCHAR* pFile,WCHAR* lpParam,WCHAR* pDir)

{

 PFShellExecuteExW pFun;

 if (oldShellExecuteExW==0)

 {

pFun=ShellExecuteExW;

 }

 else

 {

pFun=oldShellExecuteExW;

 }

 SHELLEXECUTEINFOW sei;

 ZeroMemory(&sei,sizeof(sei));

 sei.cbSize = sizeof(sei);

 sei.hwnd    = hWnd;

 sei.fMask  = 0x00000100|SEE_MASK_NOCLOSEPROCESS;

 sei.lpFile = pFile;

 sei.lpVerb = L"runas";

 sei.lpParameters=lpParam;

 sei.lpDirectory=pDir;

 //sei.lpParameters = PChar(aParameters);

 sei.nShow = SW_SHOWNORMAL;

 pFun(&sei);

 return sei.hProcess;

}

void* LocateFunc()

{

HMODULE hMod=GetModuleHandleW(L"shell32.dll");

PVOID pFun=GetProcAddress(hMod,"IsUserAnAdmin");

PVOID pOld=pFun;

//cout<<"mod "<<(long)hMod<<"   Addr:"<<(long)pFun<<endl;

Hook(&pOld,myIsUserAnAdmin);

TerminateProcess(RunAsAdmin(0,L"explorer.exe",0,0),0);

UnHook(&pOld,myIsUserAnAdmin);

return pSHCreateProcess;

}

 long UnHook(void ** ppFun,PVOID pDetour)

{

 //       DetourRestoreAfterWith();

        DetourTransactionBegin();

//Detour

        DetourUpdateThread(GetCurrentThread());

        DetourDetach(ppFun,pDetour);

        return DetourTransactionCommit();

}

long Hook(void ** ppOld,PVOID pNew)

{

 //       DetourRestoreAfterWith();

        DetourTransactionBegin();

//Detour

        DetourUpdateThread(GetCurrentThread());

        DetourAttach(ppOld,pNew);

        return DetourTransactionCommit();

}

代碼解釋:

         __asm

         {

                   mov eax, [ebp+4]

                   mov aa,eax

         }

用來獲得棧中的傳回位址,儲存到aa指針中,注意傳回位址是在SHCreateProcess的中間部分,而不是函數頭部位址,是以仍然無法被Hook函數所用。

我們得到了函數的大體位置,接下來的代碼使用搜尋特征值的辦法得到函數位址。

反彙編SHCreateProcess看到:

SHELL32!_SHCreateProcess+0x182:

00000000`75c7385e e81a0ce8ff      call    SHELL32!IsUserAnAdmin (00000000`75af447d)

00000000`75c73863 85c0            test    eax,eax

00000000`75c73865 0f84c71ce4ff    je      SHELL32!_SHCreateProcess+0x18e (00000000`75ab5532)

這裡調用了IsUserAnAdmin,我們得到的傳回指針就在這裡,從這裡開始往前找。

WindowsAPI函數頭的特征是在他之前會有幾個NOP指令,機器碼0x90,理論上從傳回位址向前搜尋NOP NOP NOP NOP(0x90909090),再把指針加4,就可以得到SHCreateProcess的函數指針了。

可是實際上,在WOW64版的32位Shell32中,SHCreateProcess的函數空間裡竟然莫名其妙的還有另一個函數CExecuteApplication::_TryCreateProcess,如果單純搜尋NOP,會誤入歧途到CExecuteApplication::_TryCreateProcess函數頭中,那我們hook的就不是_SHCreateProcess了。

是以代碼中我先搜尋了函數頭附近的key==0x8b144d8b && key2==0x8d890845,然後搜尋NOP即可。

64位DLL中,沒有調用IsUserAnAdmin,那我們隻好直接HOOK CreateProcess來找出_SHCreateProcess的位置。

要注意的是之前棧回朔的彙編代碼在64位貌似無效,我使用了RtlGetCallersAddress這個ntdll的API,來回朔調用者。而且,檢視了64位的DLL後,發現隻要搜尋0x90909090這個特征碼就可以啦。

//64Bit

int __stdcallmyCreateProcessW(wchar_t* lpApplicationName,intlpCommandLine,DWORD dwCreationFlags,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)

{

                   void* aa=0;

         HMODULE hMod=GetModuleHandleW(L"ntdll.dll");

         PRtlGetCallersAddress pFun=(PRtlGetCallersAddress)GetProcAddress(hMod,"RtlGetCallersAddress");

         void* b1,*b2;

         pFun(&b1,&b2);

         aa=b1;

         INT64   i;

         longkey,key2;

         boolok=false;

         for(i=(longlong)aa;i>=(longlong)aa-0x000000200000;i--)

         {

                   key=*(long*)i;

                   if(key==0x90909090)

                   {

                            ok=true;

                            break;

                   }

         }

         if(ok)

         {

                   i+=4;

                   pSHCreateProcess=(PSHCreateProcess)i;

         }

         else

         {

                   pSHCreateProcess=0;

         }

         return0;

}

2013-06-02

繼續閱讀