線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:3269
推到 Plurk!
推到 Facebook!

利用HOOK攔截封包原理

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-05-22 18:54:14 IP:218.175.xxx.xxx 未訂閱
 利用HOOK攔截封包原理
http://www.czvc.com/view.asp?id=300
截獲API是個很有用的東西,比如你想分析一下別人的程式是怎樣工作的。這裏我介紹一下一種我自己試驗通過的方法。 
首先,我們必須設法把自己的代碼放到目的程式的進程空間裏去。Windows Hook可以幫我們實現這一點。SetWindowsHookEx的聲明如下: 
HHOOK SetWindowsHookEx( 
int idHook, // hook type 
HOOKPROC lpfn, // hook procedure 
HINSTANCE hMod, // handle to application instance 
DWORD dwThreadId // thread identifier 
); 
具體的參數含義可以翻閱msdn,沒有msdn可謂寸步難行。 
這裏Hook本身的功能並不重要,我們使用它的目的僅僅只是?了能夠讓Windows把我們的代碼植入別的進程裏去。hook Type我們任選一種即可,只要保證是目的程式肯定會調用到就行,這裏我用的是WH_CALLWNDPROC。lpfn和hMod分別指向我們的?子代碼及其所在的dll,dwThreadId設?0,表示對所有系統內的線程都挂上這樣一個hook,這樣我們才能把代碼放到別的進程裏去。     之後,我們的代碼就已經進入了系統內的所有進程空間了。必須注意的是,我們只需要截獲我們所關心的目的程式的調用,因此還必須區分一下進程號。我們自己的?子函數中,第一次運行將進行最重要的API重定向的工作。也就是通過將所需要截獲的API的開頭幾個位元組改?一個跳轉指令,使其跳轉到我們的API中來。這是最關鍵的部分。這裏我想截三個調用,ws2_32.dll中的send和recv、user32.dll中的GetMessageA。     DWORD dwCurrentPID = 0; 
HHOOK hOldHook = NULL; 
DWORD pSend = 0; 
DWORD pRecv = 0; 
GETMESSAGE pGetMessage = NULL;     BYTE btNewBytes[8] = { 0x0B8, 0x0, 0x0, 0x40, 0x0, 0x0FF, 0x0E0, 0 }; 
DWORD dwOldBytes[3][2];     HANDLE hDebug = INVALID_HANDLE_value;     LRESULT CALLBACK CallWndProc( int nCode, WPARAM wParam, LPARAM lParam ) 
{ 
DWORD dwSize; 
DWORD dwPIDWatched; 
HMODULE hLib;     if( dwCurrentPID == 0 ) 
{ 
dwCurrentPID = GetCurrentProcessId(); 
HWND hwndMainHook; 
hwndMainHook = ::FindWindow( 0, "MainHook" ); 
dwPIDWatched = ::SendMessage( hwndMainHook, (WM_USER 100), 0, 0 ); 
hOldHook = (HHOOK)::SendMessage( hwndMainHook, (WM_USER 101), 0, 0 );     if( dwCurrentPID == dwPIDWatched ) 
{ 
hLib = LoadLibrary( "ws2_32.dll" ); 
pSend = (DWORD)GetProcAddress( hLib, "send" ); 
pRecv = (DWORD)GetProcAddress( hLib, "recv" );     ::ReadProcessMemory( INVALID_HANDLE_value, (void *)pSend, (void *)dwOldBytes[0], sizeof(DWORD)*2, &dwSize ); 
*(DWORD *)( btNewBytes   1 ) = (DWORD)new_send; 
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pSend, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );     ::ReadProcessMemory( INVALID_HANDLE_value, (void *)pRecv, (void *)dwOldBytes[1], sizeof(DWORD)*2, &dwSize ); 
*(DWORD *)( btNewBytes   1 ) = (DWORD)new_recv; 
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pRecv, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );     hLib = LoadLibrary( "user32.dll" ); 
pGetMessage = (GETMESSAGE)GetProcAddress( hLib, "GetMessageA" ); 
::ReadProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)dwOldBytes[2], sizeof(DWORD)*2, &dwSize ); 
*(DWORD *)( btNewBytes   1 ) = (DWORD)new_GetMessage; 
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );     hDebug = ::CreateFile( "C:\\Trace.log", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 ); 
} 
}     if( hOldHook != NULL ) 
{ 
return CallNextHookEx( hOldHook, nCode, wParam, lParam ); 
}     return 0; 
}     上面的?子函數,只有第一次運行時有用,就是把三個函數的首8位元組修改一下(實際上只需要7個)。btNewBytes中的指令實際就是 
mov eax, 0x400000 
jmp eax 
這裏的0x400000就是新的函數的位址,比如new_recv/new_send/new_GetMessage,此時,偷梁換柱已經完成。再看看我們的函數中都幹了些什?。以GetMessageA?例:     BOOL _stdcall new_GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax ) 
{ 
DWORD dwSize; 
char szTemp[256]; 
BOOL r = false;     //Watch here before it's executed. 
sprintf( szTemp, "Before GetMessage : HWND 0x%8.8X, msgMin 0x%8.8X, msgMax 0x%8.8x \r\n", hWnd, wMsgFilterMin, wMsgFilterMax ); 
::WriteFile( hDebug, szTemp, strlen(szTemp), &dwSize, 0 ); 
//Watch over     // restore it at first 
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)dwOldBytes[2], sizeof(DWORD)*2, &dwSize );     // execute it 
r = pGetMessage( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax );     // hook it again 
*(DWORD *)( btNewBytes   1 ) = (DWORD)new_GetMessage; 
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );     //Watch here after it's executed 
sprintf( szTemp, "Result of GetMessage is %d.\r\n", r ); 
::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 ); 
if( r ) 
{ 
sprintf( szTemp, "Msg : HWND 0x%8.8X, MSG 0x%8.8x, wParam 0x%8.8X, lParam 0x%8.8X\r\nTime 0x%8.8X, X %d, Y %d\r\n", 
lpMsg->hwnd, lpMsg->message, 
lpMsg->wParam, lpMsg->lParam, lpMsg->time, 
lpMsg->pt.x, lpMsg->pt.y ); 
::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 ); 
} 
strcpy( szTemp, "\r\n" ); 
::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 );     //Watch over     return r; 
}     先將截獲下來的參數,寫入到一個log文件中,以便分析。然後恢復原先保留下來的GetMessageA的首8位元組,然後執行真正的GetMessageA調用,完畢後再將執行結果也寫入log文件,然後將GetMessageA的執行結果返回給調用者。 
整個截獲的過程就是這樣。你可以把其中的寫log部分改成你自己想要的操作。這裏有個不足的地方是,截獲動作是不能夠並發進行的,如果目標進程是多線程的,就會有問題。解決辦法是,可以在每次new_GetMessage中加入一個CriticalSection的鎖和解鎖,以使調用變?串列進行,但這個我沒有試驗過。     WriteProecssMemory 在win9x下不能對2g以上的空間寫操作,NT內核的可以; WSOCKET32.DLL等不是在2g以上,可以對它們用WriteProecssMemory
系統時間:2024-05-03 19:11:57
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!