API HOOK 有不少方式,本文只介紹最經常使用的dll注入方式進程API HOOK。
dll注入方式大致分爲兩步:一、dll注入,二、修改API入口git
假設注入進程爲A,被注入的進程爲B,注入的dll名爲virus.dll。則進程A注入dll到進程B的大致步驟以下github
if ( OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken) ) { TOKEN_PRIVILEGES tkp; LookupPrivilegeValue( NULL,SE_DEBUG_NAME,&tkp.Privileges[0].Luid );//修改進程權限 tkp.PrivilegeCount=1; tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges( hToken,FALSE,&tkp,sizeof tkp,NULL,NULL );//通知系統修改進程權限 CloseHandle(hToken); }
OpenProcess( PROCESS_CREATE_THREAD | //容許遠程建立線程 PROCESS_VM_OPERATION | //容許遠程VM操做 PROCESS_VM_WRITE| //容許遠程VM寫 PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId ) )
pszLibFileRemote = (char *) VirtualAllocEx( hRemoteProcess, NULL, lstrlen(DllFullPath)+1,MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hRemoteProcess,pszLibFileRemote, (void *) DllFullPath, lstrlen(DllFullPath)+1, NULL)
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
hRemoteThread = CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL)
通過了上述步驟,virus.dll就能被成功注入到進程B的地址空間中,上面的步驟就是爲了幹一件事情,讓B進程調用LoadLibraryA("virus.dll"),爲了作這件事情須要上述6個步驟。,此處須要有幾點說明:編程
a、任何應用進程將Kerner32.dll加載到內存的虛擬地址位置都是同樣 b、dll中的方法在dll中的相對位置是固定的
因此,A進程找到的函數地址位置和在B進程中的位置是同樣的。
至此,咱們將virus.dll加載到了B進程中,接下來就是B進程中的virus.dll怎麼對本身進程空間中的API函數作HOOK的問題了。這裏涉及到兩個問題:api
咱們先看怎麼修改API函數的入口代碼,再討論執行時機的問題。這件事情是在virus.dll中作的,執行的步驟以下函數
HMODULE hmod=::LoadLibrary(_TEXT("add.dll"));
add=(AddProc)::GetProcAddress(hmod,"add");
// 將add()的入口代碼保存到OldCode裏 _asm { lea edi,OldCode mov esi,pfadd cld movsd movsb } NewCode[0]=0xe9;//第一個字節0xe9至關於jmp指令 //獲取Myadd()的相對地址 _asm { lea eax,Myadd mov ebx,pfadd sub eax,ebx sub eax,5 mov dword ptr [NewCode+1],eax } //填充完畢,如今NewCode[]裏面就至關於指令 jmp Myadd HookOn();
void HookOn() { ASSERT(hProcess!=NULL); DWORD dwTemp=0; DWORD dwOldProtect; //將內存保護模式改成可寫,老模式保存入dwOldProtect VirtualProtectEx(hProcess,pfadd,5,PAGE_READWRITE,&dwOldProtect); //將所屬進程中add的前5個字節改成Jmp Myadd WriteProcessMemory(hProcess,pfadd,NewCode,5,0); //將內存保護模式改回爲dwOldProtect VirtualProtectEx(hProcess,pfadd,5,dwOldProtect,&dwTemp); bHook=true; }
這段代碼將add函數(API函數)的前5個字節存儲到OldCode裏面(爲了之後恢復add函數),而後生成一個jmp指令到NewCode中,都存儲好以後,NewCode的5個字節的內容,替換到原來add函數入口處的5個字節內容。
注意幾個問題:ui
由於jmp XXX 指令佔用5個字節(32位體系結構中).net
xxx = Myadd - pfadd - 5線程
爲何是這個公式呢,先引用《深刻理解計算機系統-第三版》中一段話:code
當CPU計算跳轉指令的目標地址時,程序計數器的值是當前指令的後一條指令的地址,而不是跳轉指令的地址
舉個例子blog
pfadd: 01FF0000 : ?? ?? ?? ?? 01FF0004 : ?? ?? ?? ?? 01FF0008 : ?? ?? ?? ?? ... Myadd: 01FF00A0 : ?? ?? ?? ?? 01FF00A4 : ?? ?? ?? ?? 01FF00A8 : ?? ?? ?? ?? ... relpalce the first 5 bytes pfadd as jmp(E9 xx xx xx xx),the content of pfadd: pfadd: 01FF0000 : E9 xx xx xx 01FF0004 : xx ?? ?? ?? 01FF0008 : ?? ?? ?? ?? ... satisfy : 01FF00A0 = PC + XXX PC = 01FF0000 + 5 then the addr : XXX = 01FF00A0 - 01FF0000 - 5
以上就是修改api入口代碼的方法
執行時機問題就比較簡單了,咱們還記得進程A(起始就是注入器)建立了一個遠程線程,讓進程B執行了LoadLibraryA("virus.dll")函數。dll中有個入口函數
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) { HANDLE g_hModule; switch(dwReason) { case DLL_PROCESS_ATTACH: cout<<"Dll is attached!"<<endl; g_hModule = (HINSTANCE)hModule; break; case DLL_PROCESS_DETACH: cout<<"Dll is detached!"<<endl; g_hModule=NULL; break; } return true; }
當dll被加載以後,就會執行DLL_PROCESS_ATTACH後面的代碼,若是咱們將修改API入口代碼的動做放到這裏面作,則建立遠程線程加載dll後,HooK的動做就會被執行,API函數的入口代碼就會被修改。而當進程B再次調用該API時,該API就會跳轉到咱們本身寫的函數了。
以上就是API HOOK 的dll遠程注入技術的詳細步驟,若是有不明白的地方,能夠參考:
遠程注入 : http://blog.csdn.net/ithzhang...
api修改 : http://blog.csdn.net/friendan...
還能夠參考個人代碼 : https://github.com/Jasey/hook...裏面有大量的例子和解釋。