• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Xiao.Zhu C++

            Xiao.Zhu C++

              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
              29 隨筆 :: 14 文章 :: 17 評論 :: 0 Trackbacks
            截獲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的鎖和解鎖,以使調用變為串行進行,但這個我沒有試驗過。
            posted on 2007-04-28 16:00 Xiao.Zhu 閱讀(810) 評論(0)  編輯 收藏 引用
            久久久久人妻一区二区三区| 97久久国产综合精品女不卡| 久久精品无码一区二区日韩AV| 国内精品久久久久久久涩爱| 久久精品国产99久久丝袜| 欧美精品九九99久久在观看| 亚洲综合伊人久久大杳蕉| 久久亚洲国产中v天仙www| 亚洲国产成人久久一区WWW| 久久国产精品无码一区二区三区 | 99久久无码一区人妻| 亚洲欧美国产日韩综合久久| 99久久这里只有精品| 久久婷婷五月综合国产尤物app| 久久精品国产亚洲网站| 久久亚洲国产精品成人AV秋霞| 超级碰久久免费公开视频| 久久婷婷成人综合色综合| 狠狠色丁香久久婷婷综合蜜芽五月 | 一本一本久久A久久综合精品| 91久久香蕉国产熟女线看| 国内精品久久久久久99| 成人久久免费网站| 亚洲中文字幕伊人久久无码 | 久久久SS麻豆欧美国产日韩| 午夜精品久久久久成人| 久久国产三级无码一区二区| 91久久九九无码成人网站| 久久国产乱子伦精品免费强| 久久99热只有频精品8| 色婷婷综合久久久久中文| 亚洲av成人无码久久精品| 色播久久人人爽人人爽人人片AV| 久久精品成人影院| 国产99久久久国产精品小说| 久久亚洲精品国产精品婷婷| 亚洲性久久久影院| 色婷婷综合久久久久中文| 国内精品人妻无码久久久影院| 国产∨亚洲V天堂无码久久久| 精品久久一区二区|