利用HOOK攔截封包原理 |
|
conundrum
尊榮會員 發表:893 回覆:1272 積分:643 註冊:2004-01-06 發送簡訊給我 |
利用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 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |