久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Windows下HookAPI技術(shù)

 alone_star 2007-08-24
Windows下Hook API技術(shù)
    什么叫Hook API,?所謂Hook就是鉤子的意思,,而API是指Windows開放給程序員的編程接口,使得在用戶級別下可以對操作系統(tǒng)進行控制,,也就是一般的應(yīng)用程 序都需要調(diào)用API來完成某些功能,,Hook API的意思就是在這些應(yīng)用程序調(diào)用真正的系統(tǒng)API前可以先被截獲,從而進行一些處理再調(diào)用真正的API來完成功能,。在講Hook API之前先來看一下如何Hook消息,,例如Hook全局鍵盤消息,從而可以知道用戶按了哪些鍵,,這種Hook消息的功能可以由以下函數(shù)來完成,,該函數(shù)將 一個新的Hook加入到原來的Hook鏈中,當(dāng)某一消息到達后會依次經(jīng)過它的Hook鏈再交給應(yīng)用程序,。
 
HHOOK SetWindowsHookEx(
    int idHook,                     //Hook類型,,例如WH_KEYBOARD,WH_MOUSE
    HOOKPROC lpfn,             //Hook處理過程函數(shù)的地址
    HINSTANCE hMod,          //包含Hook處理過程函數(shù)的dll句柄(若在本進程可以為NULL)
    DWORD dwThreadId     //要Hook的線程ID,,若為0,,表示全局Hook所有
);
 
    這里需要提一下的就是如果是Hook全局的而不是某個特定的進程則需要將Hook過程編寫為一個DLL,以便讓任何程序都可以加載它來獲取Hook過程函數(shù),。
    而對于Hook API微軟并沒有提供直接的接口函數(shù),,也許它并不想讓我們這樣做, 不過有2種方法可以完成該功能,。第一種,,修改可執(zhí)行文件的IAT表(即輸入表),因為在該表中記錄了所有調(diào)用API的函數(shù)地址,,則只需將這些地址改為自己 函數(shù)的地址即可,,但是這樣有一個局限,因為有的程序會加殼,,這樣會隱藏真實的IAT表,,從而使該方法失效。第二種方法是直接跳轉(zhuǎn),,改變API函數(shù)的頭幾個 字節(jié),,使程序跳轉(zhuǎn)到自己的函數(shù),然后恢復(fù)API開頭的幾個字節(jié),在調(diào)用AP完成功能后再改回來又能繼續(xù)Hook了,,但是這種方法也有一個問題就是同步的問 題,,當(dāng)然這是可以克服的,并且該方法不受程序加殼的限制,。
    下面將以一個Hook指定程序send函數(shù)的例子來詳細描述如何Hook API,,以達到監(jiān)視程序發(fā)送的每個封包的目的。采用的是第二種方法,,編寫為一個dll,。首先是一些全局聲明,
 
//本dll的handle
HANDLE g_hInstance = NULL;
//修改API入口為 mov eax, 00400000;jmp eax是程序能跳轉(zhuǎn)到自己的函數(shù)
BYTE g_btNewBytes[8] = { 0xB8, 0x0, 0x0, 0x40, 0x0, 0xFF, 0xE0, 0x0 };
//保存原API入口的8個字節(jié)
DWORD g_dwOldBytes[2][2] = { 0x0, 0x0, 0x0, 0x0 };
//鉤子句柄
HHOOK   g_hOldHook = NULL;
//API中send函數(shù)的地址
DWORD g_pSend = 0;
//事務(wù),,解決同步問題
HANDLE g_hSendEvent = NULL;
//自己的send函數(shù)地址,,參數(shù)必須與API的send函數(shù)地址相同
int _stdcall hook_send( SOCKET s, const char *buf, int len, int flags );
//要Hook的進程和主線程ID號
DWORD g_dwProcessID = 0;
DWORD g_dwThreadID = 0;
 
    從聲明可以看出,我們會把API函數(shù)的首8個字節(jié)改為 mov eax, 00400000;jmp eax ,,使程序能夠跳轉(zhuǎn),,只需獲取我們自己的函數(shù)地址填充掉00400000即可實現(xiàn)跳轉(zhuǎn)。而g_dwOldBytes是用來保存API開頭原始的8個字節(jié),,在 真正執(zhí)行API函數(shù)是需要寫回,。還有一點,在聲明新的函數(shù)時,,該例中為hook_send,,除了保正參數(shù)與API的一致外,還需要聲明為 __stdcall類型,,表示函數(shù)在退出前自己來清理堆棧,因為這里是直接跳轉(zhuǎn)到新函數(shù)處,,所以必須自己清理堆棧,。下面看主函數(shù),
 
BOOL APIENTRY DllMain( HANDLE hModule,
                                   DWORD  ul_reason_for_call, 
                                   LPVOID lpReserved
                                 )
{
    if(ul_reason_for_call == DLL_PROCESS_ATTACH)
   {
      //獲取本dll句柄
      g_hInstance = hModule;
     
      //創(chuàng)建事務(wù)
      g_hSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
     
      //重寫API開頭的8字節(jié)
      HMODULE hWsock = LoadLibrary( "wsock32.dll" );
      g_pSend = ( DWORD )GetProcAddress( hWsock, "send" );
 
      //保存原始字節(jié)
      ReadProcessMemory( INVALID_HANDLE_VALUE, ( void * )g_pSend,
          ( void * )g_dwOldBytes[0], sizeof( DWORD )*2, NULL );
      //將00400000改寫為我們函數(shù)的地址
      *( DWORD* )( g_btNewBytes + 1 ) = ( DWORD )hook_send;
      WriteProcessMemory( INVALID_HANDLE_VALUE, ( void * )g_pSend,
          ( void * )g_btNewBytes, sizeof( DWORD )*2, NULL );
    }
    return TRUE;
}
 
    以上是dll的main函數(shù),,在被指定的程序加載的時候會自動運行dll的main函數(shù)來完成初始化,,這里就是改寫API的首地址來完成跳轉(zhuǎn)。當(dāng)然本程序 是對于指定程序進行Hook,,如果要進行全局Hook,,可以在main函數(shù)中用GetModuleFileName函數(shù)來獲取exe文件完整路徑,判斷當(dāng) 前進程是否是想要Hook的進程,。寫函數(shù)中使用INVALID_HANDLE_VALUE,,表示寫本進程。
 
int _stdcall hook_send( SOCKET s, const char *buf, int len, int flags )
{
   int nRet;
   WaitForSingleObject( g_hSendEvent, INFINITE );
 
   //恢復(fù)API頭8個字節(jié)
   WriteProcessMemory( INVALID_HANDLE_VALUE, ( void* )g_pSend,
      ( void* )g_dwOldBytes[0], sizeof( DWORD )*2, NULL );
 
   /*
   這里可以添加想要進行的處理過程
   */
 
   //真正執(zhí)行API函數(shù)
   nRet = send( s, buf, len, flags );
 
   //寫入跳轉(zhuǎn)語句,,繼續(xù)Hook
   WriteProcessMemory( INVALID_HANDLE_VALUE, ( void* )g_pSend,
      ( void* )g_btNewBytes, sizeof( DWORD )*2, NULL );
 
   SetEvent( g_hSendEvent );
 
   return nRet;
}
 
HOOK_API BOOL StartHook(HWND hWnd)
{
    //通過傳入的窗口句柄獲取線程句柄
    g_dwThreadID = GetWindowThreadProcessId( hWnd, &g_dwProcessID );
 
    //WH_CALLWNDPROC類型的Hook
    g_hOldHook = SetWindowsHookEx( WH_CALLWNDPROC,  HookProc,  
        ( HINSTANCE ) g_hInstance, g_dwThreadID );

    if( g_hOldHook == NULL )
        return FALSE;

    return TRUE;
}
 
static LRESULT WINAPI HookProc( int nCode, WPARAM wParam, LPARAM lParam )
{

 return CallNextHookEx( g_hOldHook, nCode, wParam, lParam );
}
 
HOOK_API void StopHook(void)
{
   if(g_hOldHook != NULL)
   {
       WaitForSingleObject( g_hSendEvent, INFINITE );

       HANDLE hProcess = NULL;
       hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, g_dwProcessID);

       DWORD dwOldProc;
       DWORD dwNewProc;
 
       //改變頁面屬性為讀寫
       VirtualProtectEx( hProcess, ( void* )g_pSend, 8, PAGE_READWRITE, &dwOldProc );
 
       //恢復(fù)API的首8個字節(jié)
       WriteProcessMemory( hProcess, ( void* )g_pSend,
            ( void* )g_dwOldBytes[0], sizeof( DWORD )*2, NULL );
 
       //恢復(fù)頁面文件的屬性
       VirtualProtectEx( hProcess, ( void* )g_pSend, 8, dwOldProc, &dwNewProc );
  
       CloseHandle(g_hSendEvent);
  
       UnhookWindowsHookEx( g_hOldHook );
    }
}
 
   可以看出,,我們創(chuàng)建的Hook類型是WH_CALLWNDPROC類型,該類型的Hook在進程與系統(tǒng)一通信時就會被加載到進程空間,從而調(diào)用dll的 main函數(shù)完成真正的Hook,,而在SetWindowsHookEx函數(shù)中指定的HookProc函數(shù)將不作任何處理,,只是調(diào)用 CallNextHookEx將消息交給Hook鏈中下一個環(huán)節(jié)處理,因為這里SetWindowsHookEx的唯一作用就是讓進程加載我們的dll,。
    以上就是一個最簡單的Hook API的例子,,該種技術(shù)可以完成許多功能。例如網(wǎng)游外掛制作過程中截取發(fā)送的與收到的封包即可使用該方法,,或者也可以在Hook到API后加入木馬功能,, 反向連接指定的主機或者監(jiān)聽某一端口,還有許多加殼也是用該原理來隱藏IAT表,,填入自己的函數(shù)地址,。
 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多