hook api 反OD調試的一種思路

標 題: 【原創】hook api 反OD調試的一種思路
作 者: 藍雲
時 間: 2007-07-23,15:32
鏈 接: http://bbs.pediy.com/showthread.php?t=48413

hook api 反OD調試的一種思路
by胡華

本程序在backer的耐心指導下完成,非常感謝backer的幫助!!!
關於OD怎樣在程序中下斷點相信大家都知道,就是用WriteProcessMemory函數在要下斷點的地方寫入0xCC,也就是int 3的中斷,
如果我們掛鉤OD的WriteProcessMemory函數不讓它下斷點是不是就可以讓OD不能正常跟蹤了呢?有了這個思路,下面就是實踐了。

首先得解決幾個問題:
1.我們的目標是最好在OD正常加載本程序後就已經被hook,怎麼解決?

這個問題其實很簡單,我們知道全局類的初始化工作在main函數之前,OD正常加載後會停在WinMain函數處,如果把hook api 代
碼放在一個全局類的構造函數中就可以了,呵呵,就這麼簡單。


2.要得到OD的輸入表中的WriteProcessMemory函數的跳轉地址

呵呵,用OD來調試OD不就很容易得到了麼?
用OD調試OD後我們得到WriteProcessMemory函數的跳轉地址放在0x0050D450這個地方。

3.如果前面的兩個問題解決,現在剩下的就是程序在運行期間要判斷自己的父進程是否是OD,如果是OD那麼就可以肯定被OD加載,
問題是怎麼方便的取得父進程?如果用列取進程列表的方式來獲的父進程,這比較麻煩,但是的確是一種思路。我們不採取這種
思路,其實在ntdll.dll中有一個函數可以得到父進程,下面用代碼來說話吧:

NTDLL.DLL中有一個函數叫NtQueryInformationProcess,用它可以將指定類型的進程信息拷貝到某個緩衝。其原型如下:
NTSYSAPI
NTSTATUS
NTAPI
NtQueryInformationProcess (
IN HANDLE ProcessHandle, // 進程句柄
IN PROCESSINFOCLASS InformationClass, // 信息類型
OUT PVOID ProcessInformation, // 緩衝指針
IN ULONG ProcessInformationLength, // 以字節爲單位的緩衝大小
OUT PULONG ReturnLength OPTIONAL // 寫入緩衝的字節數
);
     第一個參數是希望操作的進程句柄,這個句柄必須以PROCESS_QUERY_INFORMATION模式存取。爲了取得一個句柄,我們必須用
OpenProcess函數:
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,dwProcessID);
     第二個參數是請求信息的類型,這個參數可以有許多個值,本文例子中將用ProcessBasicInformation (值爲0)。
     因此,如果第二個參數是ProcessBasicInformation的話,則第三個參數必須爲一個指針指向結構PROCESS_BASIC_INFORMATION:
typedef struct
{
       DWORD ExitStatus; // 接收進程終止狀態
       DWORD PebBaseAddress; // 接收進程環境塊地址
       DWORD AffinityMask; // 接收進程關聯掩碼
       DWORD BasePriority; // 接收進程的優先級類
       ULONG UniqueProcessId; // 接收進程ID
       ULONG InheritedFromUniqueProcessId; //接收父進程ID
} PROCESS_BASIC_INFORMATION;

   這個結構的最後一個參數是InheritedFromUniqueProcessId,它就是我們所要的東西。

得到了父進程id之後,呵呵,現在開始打開進程了
         DWORD dwId=GetCurrentProcessId();
   DWORD dwParentId;
         dwParentId=GetParentProcessID(dwId); //獲取父進程id
   hParentProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwParentId);
又有一個問題怎麼判斷是否是OD呢?
我們可以用讀取內存的方式查看某一段代碼是不是OD的就行了,要檢查哪段代碼那就隨你了,
我這裏是讀取OD的0x00401000開始的幾個字節。
更簡單的方法是讀取0x0050D450這個地址判斷是不是WriteProcessMemory這個函數的真實跳轉地址,如果是那就基本可以斷定是OD了,呵呵,不會那麼巧其它的有的程序也會是這個地址吧!

判斷是OD後,現在要做的就是在OD中申請一段空間把要執行的代碼寫在這個地址了
BYTE bRet=0xC3; //這是hook api後轉到這要執行的代碼
LPVOID lpWriteFunAddress=(void*)0x0050D450;
LPVOID lpNewWriteFunAddress=NULL;
lpNewWriteFunAddress=VirtualAllocEx(hParentProcess,NULL,sizeof(bRet),MEM_COMMIT,PAGE_READWRITE);
//插入函數返回代碼
if(lpNewWriteFunAddress==NULL)
{
    MessageBox(NULL,"virtualalloc err","error",MB_OK);
      
}
if(WriteProcessMemory(hParentProcess, lpNewWriteFunAddress, &bRet, sizeof(bRet), NULL)==0)
{
   MessageBox(NULL,"insert retn err","error",MB_OK);      
}
寫入後現在就是把0x0050D450這個地址的WriteProcessMemory函數的真實跳轉地址改爲我們上面申請的地址了:
        //改變api地址
    
   DWORD flOldProtect;
   VirtualProtect(lpWriteFunAddress,sizeof                (lpWriteFunAddress),PAGE_READWRITE,&flOldProtect);
   if(WriteProcessMemory(hParentProcess, lpWriteFunAddress, &lpNewWriteFunAddress,                                                 sizeof(lpNewWriteFunAddress), NULL)==0)
   {
        MessageBox(NULL,"insert fun addr err","error",MB_OK);
      
   }

不知道大家注意沒,我插入的要執行的代碼只有一個字節BYTE bRet=0xC3,
其實就是ret,呵呵,知道了吧,只要在OD中按F2下斷點就會執行WriteProcessMemory這個函數,而這個函數現在是什麼都不做就直接返 回了,也不用考慮堆棧平衡,我們要的就是OD悄無聲息的掛掉!如果想忽悠一下而不讓OD掛掉,那就用ret14了,大家盡情的發揮吧!!!

好了,到這裏已經結束了,再次感謝backer的指導!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章