• <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>
            面對現實,超越自己
            逆水行舟,不進則退
            posts - 269,comments - 32,trackbacks - 0

            我們截獲函數執行最直接的目的就是為函數增添功能,修改返回值,或者為調試以及性能測試加入附加的代碼,或者截獲函數的輸入輸出作研究,破解使用。通過訪 問源代碼,我們可以輕而易舉的使用重建(Rebuilding)操作系統或者應用程序的方法在它們中間插入新的功能或者做功能擴展。然而,在今天這個商業 化的開發世界里,以及在只有二進制代碼發布的系統中,研究人員幾乎沒有機會可以得到源代碼。本文主要討論Detour在Windows二進制PE文件基礎 上的API截獲技術。對于Linux平臺,作這件事情將會非常的簡單,由于最初的操作系統設計者引入了LD_PRELOAD。如果你設置  LD_PRELOAD=mylib.so ,那么應用程序在載入 dll時,會先查看mylib.so的符號表,在relocation 的時候會優先 使用mylib.so 里的 symbol 。假如你在mylib.so里有個printf() ,那么這個printf就會替代libc的 printf。 而在mylib.so里的這個printf可以直接訪問 libc.so里的printf函數指針來獲得真正的 printf的入口地 址。 這樣,所有的dll的API HOOK在loader加載dll的時候就已經完成,非常自然,和平臺相關的部分全部交給loader去處理。
            一、  Detour開發庫:
            ?  簡介
            Detours是一個在x86平臺上截獲任意Win32函數調用的工具庫。中斷代碼可以在運行時動態加載。Detours使用一個無條件轉移指令來替換目 標函數的最初幾條指令,將控制流轉移到一個用戶提供的截獲函數。而目標函數中的一些指令被保存在一個被稱為“trampoline” (譯注:英文意為蹦 床,雜技)的函數中,在這里我覺得翻譯成目標函數的部分克隆/拷貝比較貼切。這些指令包括目標函數中被替換的代碼以及一個重新跳轉到目標函數的無條件分 支。而截獲函數可以替換目標函數,或者通過執行“trampoline”函數的時候將目標函數作為子程序來調用的辦法來擴展功能。
            Detours是執行時被插入的。內存中的目標函數的代碼不是在硬盤上被修改的,因而可以在一個很好的粒度上使得截獲二進制函數的執行變得更容易。例如, 一個應用程序執行時加載的DLL中的函數過程可以被插入一段截獲代碼(detoured),與此同時,這個DLL還可以被其他應用程序按正常情況執行(譯 注:也就是按照不被截獲的方式執行,因為DLL二進制文件沒有被修改,所以發生截獲時不會影響其他進程空間加載這個DLL)。不同于DLL的重新鏈接或者 靜態重定向,Detours庫中使用的這種中斷技術確保不會影響到應用程序中的方法或者系統代碼對目標函數的定位。
            如果其他人為了調試或者在內部使用其他系統檢測手段而試圖修改二進制代碼,Detours將是一個可以普遍使用的開發包。據我所知,Detours是第一 個可以在任意平臺上將未修改的目標代碼作為一個可以通過“trampoline”調用的子程序來保留的開發包。而以前的系統在邏輯上預先將截獲代碼放到目 標代碼中,而不是將原始的目標代碼做為一個普通的子程序來調用。我們獨特的“trampoline”設計對于擴展現有的軟件的二進制代碼是至關重要的。
            出于使用基本的函數截獲功能的目的,Detours同樣提供了編輯任何DLL導入表的功能,達到向存在的二進制代碼中添加任意數據節表的目的,向一個新進 程或者一個已經運行著的進程中注入一個DLL。一旦向一個進程注入了DLL,這個動態庫就可以截獲任何Win32函數,不論它是在應用程序中或者在系統庫 中。
            ?  基本原理
            1.  WIN32進程的內存管理
            眾所周知,WINDOWS NT實現了虛擬存儲器,每一WIN32進程擁有4GB的虛存空間, 關于WIN32進程的虛存結構及其操作的具體細節請參閱WIN32 API手冊, 以下僅指出與Detours相關的幾點:
            (1) 進程要執行的指令也放在虛存空間中
            (2) 可以使用QueryProtectEx函數把存放指令的頁面的權限更改為可讀可寫可執行,再改寫其內容,從而修改正在運行的程序
            (3) 可以使用VirtualAllocEx從一個進程為另一正運行的進程分配虛存,再使用 QueryProtectEx函數把頁面的權限更改為可讀可寫可執行,并把要執行的指令以二進制機器碼的形式寫入,從而為一個正在運行的進程注入任意的代碼 。
            2. 攔截WIN32 API的原理
            Detours定義了三個概念:
                (1) Target函數:要攔截的函數,通常為Windows的API。
            (2) Trampoline函數:Target函數的部分復制品。因為Detours將會改寫Target函數,所以先把Target函數的前5個字節復制保存好,一方面仍然保存Target函數的過程調用語義,另一方面便于以后的恢復。
            (3) Detour 函數:用來替代Target函數的函數。
            Detours在Target函數的開頭加入JMP Address_of_ Detour_ Function指令(共5個字節)把對Target函數 的調用引導到自己的Detour函數, 把Target函數的開頭的5個字節加上JMP Address_of_ Target _ Function+ 5共10個字節作為Trampoline函數。請參考下面的圖1和圖2。
            (圖1:Detour函數的過程)
             
            (圖2: Detour函數的調用過程)
             
            說明:
            ?  目標函數:
            目標函數的函數體(二進制)至少有5個字節以上。按照微軟的說明文檔Trampoline函數的函數體是拷貝前5個字節加一個無條件跳轉指令的話(如果沒 有特殊處理不可分割指令的話),那么前5個字節必須是完整指令,也就是不能第5個字節和第6個字節是一條不可分割的指令,否則會造成Trampoline 函數執行錯誤,一條完整的指令被硬性分割開來,造成程序崩潰。對于第5字節和第6個字節是不可分割指令需要調整拷貝到雜技函數(Trampoline)的 字節個數,這個值可以查看目標函數的匯編代碼得到。此函數是目標函數的修改版本,不能在Detour函數中直接調用,需要通過對Trampoline函數 的調用來達到間接調用。
            ?  Trampoline函數:
            此函數默認分配了32個字節,函數的內容就是拷貝的目標函數的前5個字節,加上一個JMP Address_of_ Target _ Function+5指令,共10個字節。
            此函數僅供您的Detour函數調用,執行完前5個字節的指令后再絕對跳轉到目標函數的第6個字節繼續執行原功能函數。
            ?  Detour函數:
            此函數是用戶需要的截獲API的一個模擬版本,調用方式,參數個數必須和目標函數相一致。如目標函數是__stdcall,則Detour函數聲明也必須 是__stdcall,參數個數和類型也必須相同,否則會造成程序崩潰。此函數在程序調用目標函數的第一條指令的時候就會被調用(無條件跳轉過來的),如 果在此函數中想繼續調用目標函數,必須調用Trampoline函數(Trampoline函數在執行完目標函數的前5個字節的指令后會無條件跳轉到目標 函數的5個字節后繼續執行),不能再直接調用目標函數,否則將進入無窮遞歸(目標函數跳轉到Detour函數,Detour函數又跳轉到目標函數的遞歸, 因為目標函數在內存中的前5個字節已經被修改成絕對跳轉)。通過對Trampoline函數的調用后可以獲取目標函數的執行結果,此特性對分析目標函數非 常有用,而且可以將目標函數的輸出結果進行修改后再傳回給應用程序。
            Detour提供了向運行中的應用程序注入Detour函數和在二進制文件基礎上注入Detour函數兩種方式。本章主要討論第二種工作方式。通過 Detours提供的開發包可以在二進制EXE文件中添加一個名稱為Detour的節表,如下圖3所示,主要目的是實現PE加載器加載應用程序的時候會自 動加載您編寫的Detours DLL,在Detours Dll中的DLLMain中完成對目標函數的Detour。
            (圖3)
             
            二、  Detours提供的截獲API的相關接口
            Detours的提供的API 接口可以作為一個共享DLL給外部程序調用,也可以作為一個靜態Lib鏈接到您的程序內部。
            Trampoline函數可以動態或者靜態的創建,如果目標函數本身是一個鏈接符號,使用靜態的trampoline函數將非常簡單。如果目標函數不能在鏈接時可見,那么可以使用動態trampoline函數。
            ?  要使用靜態的trampoline函數來截獲目標函數,應用程序生成trampoline的時候必須使用
            DETOUR_TRAMPOLINE宏。DETOUR_TRAMPOLINE有兩個輸入參數:trampoline的原型和目標函數的名字。
            注意,對于正確的截獲模型,包括目標函數,trampoline函數,以及截獲函數都必須是完全一致的調用形式,包括參數格式和調用約定。當通過 trampoline函數調用目標函數的時候拷貝正確參數是截獲函數的責任。由于目標函數僅僅是截獲函數的一個可調用分支(截獲函數可以調用 trampoline函數也可以不調用),這種責任幾乎就是一種下意識的行為。
            使用相同的調用約定可以確保寄存器中的值被正確的保存,并且保證調用堆棧在截獲函數調用目標函數的時候能正確的建立和銷毀。
            可以使用DetourFunctionWithTrampoline函數來截獲目標函數。這個函數有兩個參數:trampoline函數以及截獲函數的指針。因為目標函數已經被加到trampoline函數中,所有不需要在參數中特別指定。
            ?  我們可以使用DetourFunction函數來創建一個動態的trampoline函數,它包括兩個參數:一個指向目標函數的指針和一個截獲函數的指針。DetourFunction分配一個新的trampoline函數并將適當的截獲代碼插入到目標函數中去。
            當目標函數不是很容易使用的時候,DetourFindFunction函數可以找到那個函數,不管它是DLL中導出的函數,或者是可以通過二進制目標函數的調試符號找到。
            DetourFindFunction接受兩個參數:庫的名字和函數的名字。如果DetourFindFunction函數找到了指定的函數,返回該函數 的指針,否則將返回一個NULL指針。DetourFindFunction會首先使用Win32函數LoadLibrary 和 GetProcAddress來定位函數,如果函數沒有在DLL的導出表中找到,DetourFindFunction將使用ImageHlp庫來搜索有 效的調試符號(譯注:這里的調試符號是指Windows本身提供的調試符號,需要單獨安裝,具體信息請參考Windows的用戶診斷支持信息)。 DetourFindFunction返回的函數指針可以用來傳遞給DetourFunction以生成一個動態的trampoline函數。
            我們可以調用DetourRemoveTrampoline來去掉對一個目標函數的截獲。
            注意,因為Detours中的函數會修改應用程序的地址空間,請確保當加入截獲函數或者去掉截獲函數的時候沒有其他線程在進程空間中執行,這是程序員的責任。一個簡單的方法保證這個時候是單線程執行就是在加載Detours庫的時候在DllMain中呼叫函數。
            三、  使用Detours實現對API的截獲的兩種方法
            建立一個MFC對話框工程,在對話框的OK按鈕的單擊事件中加入對MessageBoxA函數的調用,編譯后的程序名稱MessageBoxApp,效果如圖。
             
            (圖4)
            ?  靜態方法
            建立一個Dll工程,名稱為ApiHook,這里以Visual C++6.0開發環境,以截獲ASCII版本的MessageBoxA函數來說明。在Dll的工程加入:
            DETOUR_TRAMPOLINE(int WINAPI Real_Messagebox(HWND hWnd ,
                LPCSTR lpText,
                LPCSTR lpCaption,
            UINT uType), ::MessageBoxA);
            生成一個靜態的MessageBoxA的Trampoline函數,在Dll工程中加入目標函數的Detour函數:
            int WINAPI MessageBox_Mine( HWND hWnd ,
                LPCSTR lpText,
                LPCSTR lpCaption,
                UINT uType)
            {
              CString tmp= lpText;
              tmp+=” 被Detour截獲”;
              return Real_Messagebox(hWnd,tmp,lpCaption,uType);
            //  return ::MessageBoxA(hWnd,tmp,lpCaption,uType);  //Error
            }
            在Dll入口函數中的加載Dll事件中加入:
            DetourFunctionWithTrampoline((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
            在Dll入口函數中的卸載Dll事件中加入:
            DetourRemove((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
            ?  動態方法
            建立一個Dll工程,名稱為ApiHook,這里以Visual C++6.0開發環境,以截獲ASCII版本的MessageBoxA函數來說明。在Dll的工程加入:
            //聲明MessageBoxA一樣的函數原型
            typedef int  (WINAPI * MessageBoxSys)( HWND hWnd ,
                LPCSTR lpText,
                LPCSTR lpCaption,
                UINT uType);
            //目標函數指針
            MessageBoxSys SystemMessageBox=NULL;
            //Trampoline函數指針
            MessageBoxSys Real_MessageBox=NULL;
            在Dll工程中加入目標函數的Detour函數:
            int WINAPI MessageBox_Mine( HWND hWnd ,
                LPCSTR lpText,
                LPCSTR lpCaption,
                UINT uType)
            {
              CString tmp= lpText;
              tmp+=” 被Detour截獲”;
              return Real_Messagebox(hWnd,tmp,lpCaption,uType);
            //  return ::MessageBoxA(hWnd,tmp,lpCaption,uType);  //Error
            }
            在Dll入口函數中的加載Dll事件中加入:
              SystemMessageBox=(MessageBoxSys)DetourFindFunction("user32.dll","MessageBoxA");
              if(SystemMessageBox==NULL)
              {
                return FASLE;
              }
              Real_MessageBox=(MessageBoxSys)DetourFunction((PBYTE)SystemMessageBox, (PBYTE)MessageBox_Mine);
            在Dll入口函數中的卸載Dll事件中加入:
            DetourRemove((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
            ?  重寫二進制可執行文件
            使用Detours自帶的SetDll.exe重寫二進制可執行文件,可以在需要截獲的程序中加入一個新的Detours的PE節表。對于本文就是新建一個批處理文件調用SetDll.exe。
            @echo off
            if not exist MessageBoxApp.exe (
            echo 請將文件解壓到MessageBoxApp.exe的安裝目錄, 然后執行補丁程序
            ) else (
            setdll /d:ApiHook.dll MessageBoxApp.exe
            )
            Pause
            調用后使用depends.exe(微軟VC6.0開發包的工具之一)觀察MessageBoxApp.exe前后變化, 可以看到Setdll已經重寫MessageBoxApp.exe
            成功,加入了對ApiHook.dll的依賴關系。
             
                  (執行SetDll.exe前)                                                       (執行SetDll.exe后)
            執行SetDll.exe重寫后的MessageBoxApp.exe,點擊確定后可以看到結果如下:
            至此,MessageBoxApp.exe對MessageBoxA函數的調用已經被截獲,彈出的對話框內容已經明顯說明這一點。


            本文轉自:http://www.cnblogs.com/flying_bat/archive/2008/04/18/1159996.html

            posted on 2012-11-02 14:32 王海光 閱讀(657) 評論(0)  編輯 收藏 引用 所屬分類: 其他
            亚洲级αV无码毛片久久精品| 久久久久无码精品| 久久线看观看精品香蕉国产| 久久久久一区二区三区| 久久精品无码一区二区app| 久久久久久久久波多野高潮| 国产精品对白刺激久久久| 亚洲综合久久综合激情久久| 伊人久久大香线蕉综合影院首页 | 久久综合久久综合久久| 亚洲精品成人网久久久久久| 久久久久亚洲精品无码蜜桃 | 欧美精品丝袜久久久中文字幕| 亚洲AV无码久久精品成人| 久久高清一级毛片| 国产人久久人人人人爽| 伊人久久无码精品中文字幕| 亚洲国产成人久久综合一 | 热久久视久久精品18| 国产精品久久久99| 国产精品久久毛片完整版| 久久热这里只有精品在线观看| 精品久久久久一区二区三区| 精品熟女少妇a∨免费久久| 欧美日韩精品久久免费| 久久久91人妻无码精品蜜桃HD| 久久777国产线看观看精品| 色偷偷88888欧美精品久久久| 亚洲欧美国产日韩综合久久| 日韩一区二区久久久久久 | 国内精品伊人久久久久妇| 人妻少妇精品久久| 久久伊人精品青青草原日本| 久久精品成人欧美大片| 久久婷婷色综合一区二区| 欧美麻豆久久久久久中文| 久久香蕉国产线看观看猫咪?v| 久久青青草原精品国产不卡| 亚洲国产天堂久久综合| 久久亚洲精品国产亚洲老地址| 午夜精品久久久久久影视riav|