国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
VC實現(xiàn)【API鉤取】【調(diào)試法】附加調(diào)試器
最近在學(xué)習(xí)逆向核心,在論壇也發(fā)了幾篇帖子說說自己的經(jīng)驗,幫助自己鞏固知識,也方便了大家。
如果帖子中有什么疏漏甚至不對的地方,請大牛們指出,我會積極改正的!

廢話不多說,還是我【Miss丿小沫】,上教程!
-----------------------------------------------------------------------------------------------------
我在DLL注入里面也提到了API鉤取這一概念,涉及的知識點比較多,也上了難度,我準備細致的介紹,講解。
我能力有限,如果有錯誤的地方,歡迎大家指正!
-----------------------------------------------------------------------------------------------------
鉤?。℉ook)是一種截取信息(比如SetWindowsHook()獲取鍵盤記錄),更改程序執(zhí)行流,添加新功能(DLL注入)的技術(shù)。
列一下流程:
①:使用反匯編器(IDA)或者調(diào)試器(OD)了解程序的結(jié)構(gòu)和工作原理
②:開發(fā)Hook代碼
③:靈活操作可執(zhí)行文件和進程內(nèi)存,執(zhí)行Hook
其中,鉤取API的技術(shù)就叫做API鉤取,它將鉤取API,改變程序執(zhí)行流,達到某些我們想要的目的。


關(guān)于API的概念就不贅述了,(百度百科:http://baike.baidu.com/link?url= ... 9n63O8bV7We25xVyz-7
API封裝在DLL中,程序運行時就會加載各種DLL(kernel32.dll,ntdll.dll等),上節(jié)DLL注入中就可以看出來了
-----------------------------------------------------------------------------------------------------

以notepad為例,要打開一個文件,notepad會發(fā)生如下調(diào)用:


程序正常調(diào)用API:

當我們HookAPI后:

利用上節(jié)的知識,將hook.dll注入目標進程后,hook.dll將鉤取目標API,并執(zhí)行我們自己的代碼,改變程序執(zhí)行流,這樣,每當程序調(diào)用目標API后,都會經(jīng)由我們自己的代碼

下面給出一張技術(shù)圖表:

①:【方法】API鉤取一般都采用動態(tài)方法
②:【位置】指出API鉤取時操作哪部分
        <1>:IAT 將其內(nèi)部的API函數(shù)地址修改為Hook函數(shù)地址,實施起來簡單,但無法鉤取不在IAT而在程序中動態(tài)加載的DLL中的API。(關(guān)于IAT的詳細講解,大家可以參考驛站的【PE文件格式解析】)
        <2>:代碼 *.dll映射到內(nèi)存是,從中查找目標API地址,并直接修改代碼,應(yīng)用廣泛。
        <3>:EAT 并不常用,不在贅述
③:【技術(shù)】從表中也可以看出,API鉤取可分為兩種方法:調(diào)試法和注入法(代碼注入和DLL注入)
        調(diào)試法:
        調(diào)試通過向目標進程附加調(diào)試器鉤取API,調(diào)試器擁有被調(diào)試進程的所有權(quán)限
        注入法:
                DLL注入:
                (詳細見我上一章【VC實現(xiàn)DLL注入】)在Dll中創(chuàng)建Hook代碼和設(shè)置代碼,并在DllMain()中調(diào)用,注入的同時也就完成了Hook
                代碼注入:
                (我準備再開一章專講代碼注入)
④:【API】列舉了幾個各自技術(shù)要用到的API
-----------------------------------------------------------------------------------------------------
大致了解完枯燥的理論后,開始實例講解!
利用【調(diào)試法】向notepad附加調(diào)試器,嘗試鉤取WriteFile()API
在這之前,我們有必要了解一下調(diào)試器。

調(diào)試器工作原理:
被調(diào)試進程注冊后,每當被調(diào)試進程發(fā)生調(diào)試事件(DebugEvent)時,OS就會暫停進程執(zhí)行,并匯報給調(diào)試器,當調(diào)試器處理完相關(guān)事件后,使被調(diào)試程序繼續(xù)執(zhí)行。
一張圖說明調(diào)試器的異常處理(EXCEPTION):

列舉調(diào)試事件(DebugEvent)(共9個):
EXCEPTION_DEBUG_EVENT
CREATE_THREAD_DEBUG_EVENT
CREATE_PROCESS_DEBUG_EVENT
EXIT_THREAD_DEBUG_EVENT
EXIT_PROCESS_DEBUG_EVENT
LOAD_DLL_DEBUG_EVENT
UNLOAD_DLL_DEBUG_EVENT
OUTPUT_DEBUG_STRING_EVENT
RIP_EVENT
我們主要關(guān)注EXCEPTION_DEBUG_EVENT,列舉出與其相關(guān)的異常事件列表:
EXCEPTION_ACCESS_VIOLATION
EXCEPTION_ARRAY_BOUNDS_EXCEEDED
EXCEPTION_BREAKPOINT
EXCEPTION_DATATYPE_MISALIGNMENT
EXCEPTION_FLT_DENORMAL_OPERAND
EXCEPTION_FLT_DIVIDE_BY_ZERO
EXCEPTION_FLT_INEXACT_RESULT
EXCEPTION_FLT_INVALID_OPERATION
EXCEPTION_FLT_OVERFLOW
EXCEPTION_FLT_STACK_CHECK
EXCEPTION_FLT_UNDERDLOW
EXCEPTION_ILLEGAL_INSTRUCTION
EXCEPTION_IN_PAGE_ERROR
EXCEPTION_INT_DIVIDE_BY_ZERO
EXCEPTION_INT_OVERFLOW
EXCEPTION_INVALID_DISPOSITION
EXCEPTION_PRIV_INSTRUCTION
EXCEPTION_SINGLE_STEP
EXCEPTION_STACK_OVERFLOW
(FUCK!我想罵人!剛寫好的帖子渣B瀏覽器崩潰了,結(jié)果一堆都沒了。。從頭開始吧。。。)
我們只關(guān)心EXCEPTION_BREAKPOINT這個事件,因為要用int3下斷點(斷點的IA-32指令是0xCC。),通過這個事件反饋給調(diào)試器。
-----------------------------------------------------------------------------------------------------
下面講解一下整個調(diào)試流程:
①:對目標進程附加調(diào)試器,開始調(diào)試
②:下斷點,將目標API函數(shù)的起始地址第一個字節(jié)設(shè)置為0xCC
③:程序調(diào)用目標API,斷下,反饋信息給調(diào)試器
④:執(zhí)行我們自己的代碼
⑤:恢復(fù)0xCC,使API正常執(zhí)行
⑥:再次下斷,將目標API函數(shù)的起始地址第一個字節(jié)設(shè)置為0xCC
這就是基本的流程了
-----------------------------------------------------------------------------------------------------
OK,開始真正的實戰(zhàn),
我們對notepad進行API鉤取,在其保存文件時,將文本中所有小寫字母替換成大寫字母。
第一步:
先來用OD分析一下notepad.exe的執(zhí)行流
(這利用的是XP的notepad.exe,WIN7的貌似有保護,我OD調(diào)試后立即崩潰)

(大家要掌握一定的OD基礎(chǔ))
好,OD附加notepad.exe

我們的目標是WriteFile()API,
OD代碼區(qū)右鍵->Search For->name in all modules
查找WriteFile()
雙擊 export WriteFile()進入代碼區(qū)

在 752b75d5 處F2下斷,F(xiàn)9運行
回到notepad.exe,輸入我們的內(nèi)容,然后保存

程序斷在了752b75d5,
查看棧

緩沖區(qū)地址是2D9968,存放在ESP + 8處

在Dump中查看,發(fā)現(xiàn)就是我們的文本
我們用調(diào)試方法來APIHook,在WriteFile()起始地址設(shè)置int3后,此時被調(diào)試者的EIP(存儲著CPU下一條指令)是多少呢?
EIP = 752b75d5 + 1 = 752b75d6,我們在WriteFile()起始地址設(shè)置int3后,EIP值+1,等遇到Breatpoint異常后,會反饋給調(diào)試器處理,等我們處理完之后,EIP會恢復(fù)WriteFile()起始值,

但這里還有一個問題,如果執(zhí)行流只返回到WriteFile()起始地址,再次遇到int3還是會返回異常,就進入了無限死循環(huán)!為此,我們還應(yīng)該恢復(fù)0xCC處的原始值,以保證API得正常執(zhí)行。
-----------------------------------------------------------------------------------------------------
好,這一系列問題分析完之后,就可以動手寫代碼啦!
界面還是上次DLL注入的界面,只是多加了一個APIHook按鈕。

  1. void CCodeInjectDlg::OnBnClickedButtonApihook()
  2. {
  3.         CString str;

  4.         //獲取進程PID
  5.         GetDlgItemText(IDC_EDIT_PID,str);
  6.         dwPID = FindPID(str);
  7.         //附加調(diào)試器
  8.         if(!DebugActiveProcess(dwPID))
  9.         {
  10.                 AfxMessageBox(_T("附加調(diào)試器失??!"),MB_ICONSTOP | MB_OK);
  11.                 return ;
  12.         }
  13.         //進入調(diào)試器循環(huán)
  14.         DebugLoop();
  15. }
復(fù)制代碼

這段代碼很簡單,就是獲取進程ID,附加調(diào)試器,進入循環(huán),處理來自進程的各種消息
下面著重講解一下,DebugLoop()

剛剛講到OnBnClickedButtonApihook()這個函數(shù),這次我們修改一下這個函數(shù)
  1. void CCodeInjectDlg::OnBnClickedButtonApihook()
  2. {
  3.         HANDLE hThread = CreateThread(NULL,0,ThreadProc,(LPVOID)this,0,NULL);
  4.         CloseHandle(hThread);
  5. }
復(fù)制代碼

把主要代碼(DebugLoop)放在了ThreadProc()里面,因為DebugLoop()這個循環(huán)會阻塞主程序。
ThreadProc()函數(shù):
  1. DWORD WINAPI ThreadProc(LPVOID lpDlg)
  2. {
  3.         CCodeInjectDlg* pDlg = (CCodeInjectDlg*)lpDlg;
  4.         CString str;

  5.         //獲取進程PID
  6.         pDlg->GetDlgItemText(IDC_EDIT_PID,str);
  7.         pDlg->dwPID = pDlg->FindPID(str);
  8.         //附加調(diào)試器
  9.         if(!DebugActiveProcess(pDlg->dwPID))
  10.         {
  11.                 AfxMessageBox(_T("附加調(diào)試器失??!"),MB_ICONSTOP | MB_OK);
  12.                 return 0;
  13.         }
  14.         //進入調(diào)試器循環(huán)
  15.         pDlg->DebugLoop();
  16.         return 0;
  17. }
復(fù)制代碼

----------------------------------------------------------------------------------
下面來看一下DebugLoop()函數(shù):
  1. void CCodeInjectDlg::DebugLoop()
  2. {
  3.         DEBUG_EVENT DE;

  4.         //等待調(diào)試事件
  5.         while(WaitForDebugEvent(&DE,INFINITE))
  6.         {
  7.                 switch(DE.dwDebugEventCode)
  8.                 {
  9.                         //附加到調(diào)試進程
  10.                         case CREATE_PROCESS_DEBUG_EVENT:
  11.                                 CreateProcessDebugEvent(&DE);
  12.                                 break;
  13.                         //返回異常
  14.                         case EXCEPTION_DEBUG_EVENT:
  15.                                 ExceptionDebugEvent(&DE);
  16.                                 break;
  17.                         //進程退出
  18.                         case EXIT_PROCESS_DEBUG_EVENT:
  19.                                 return ;
  20.                 }
  21.                 ContinueDebugEvent(DE.dwProcessId,DE.dwThreadId,DBG_CONTINUE);
  22.         }
  23. }
復(fù)制代碼

WaitForDebugEvent()就是暫停進程,等待被調(diào)試者反饋的調(diào)試事件了。
DEBUG_EVENT結(jié)構(gòu):
typedef struct _DEBUG_EVENT {
  DWORD dwDebugEventCode;
  DWORD dwProcessId;
  DWORD dwThreadId;
  union {
    EXCEPTION_DEBUG_INFO      Exception;
    CREATE_THREAD_DEBUG_INFO  CreateThread;
    CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
    EXIT_THREAD_DEBUG_INFO    ExitThread;
    EXIT_PROCESS_DEBUG_INFO   ExitProcess;
    LOAD_DLL_DEBUG_INFO       LoadDll;
    UNLOAD_DLL_DEBUG_INFO     UnloadDll;
    OUTPUT_DEBUG_STRING_INFO  DebugString;
    RIP_INFO                  RipInfo;
  } u;
} DEBUG_EVENT, *LPDEBUG_EVENT;
當程序接收到被調(diào)試者反饋的調(diào)試事件后就將調(diào)試事件設(shè)置為DEBUG_EVENT的第一個參數(shù)dwDebugEventCode
前面也說過了,共有9種調(diào)試事件,dwDebugEventCode就是這9種中的一種,根據(jù)事件的種類,也會相應(yīng)設(shè)置DEBUG_EVENT.u中的結(jié)構(gòu)體成員
ContinueDebugEvent()就是使暫停的進程繼續(xù)執(zhí)行。
----------------------------------------------------------------------------------
當調(diào)試器附加到進程上后,調(diào)試事件為CREATE_PROCESS_DEBUG_EVENT,并調(diào)用CreateProcessDebugEvent(&DE)函數(shù),該函數(shù)的作用就是獲取信息(WriteFile()起始地址首字節(jié)指令),并下int3斷點
當我們保存文件時,就會觸發(fā)斷點,調(diào)試事件為EXCEPTION_DEBUG_EVENT,并調(diào)用ExceptionDebugEvent(&DE)函數(shù),該函數(shù)就取消int3斷點,改變代碼的執(zhí)行流,替換小寫字母為大寫字母,并且再次下int3斷點
----------------------------------------------------------------------------------
CreateProcessDebugEvent(&DE)函數(shù):
  1. void CCodeInjectDlg::CreateProcessDebugEvent(LPDEBUG_EVENT lpDE)
  2. {
  3.         BYTE bInt3 = 0xCC;

  4.         //獲取WriteFile()函數(shù)地址
  5.         lpThread = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32.dll"),_T("WriteFile"));
  6.         //下斷點,更改WriteFile()起始地址為0xCC,并備份原內(nèi)容
  7.         memcpy(&CPDbg_Info,&lpDE->u.CreateProcessInfo,sizeof(CREATE_PROCESS_DEBUG_INFO));
  8.         ReadProcessMemory(CPDbg_Info.hProcess,lpThread,&bOriByte,sizeof(BYTE),NULL);
  9.         WriteProcessMemory(CPDbg_Info.hProcess,lpThread,&bInt3,sizeof(BYTE),NULL);
  10. }
復(fù)制代碼

獲取WriteFile()起始地址(DLL注入章節(jié)中已經(jīng)講解了)
CREATE_PROCESS_DEBUG_INFO結(jié)構(gòu)體:
typedef struct _CREATE_PROCESS_DEBUG_INFO {
  HANDLE                 hFile;
  HANDLE                 hProcess;
  HANDLE                 hThread;
  LPVOID                 lpBaseOfImage;
  DWORD                  dwDebugInfoFileOffset;
  DWORD                  nDebugInfoSize;
  LPVOID                 lpThreadLocalBase;
  LPTHREAD_START_ROUTINE lpStartAddress;
  LPVOID                 lpImageName;
  WORD                   fUnicode;
} CREATE_PROCESS_DEBUG_INFO, *LPCREATE_PROCESS_DEBUG_INFO;
結(jié)構(gòu)體里面存儲著關(guān)于進程的信息
ReadProcessMemory()用來獲取WriteFile()起始地址首字節(jié)指令,用來取消斷點是恢復(fù)
WriteProcessMemory()就是下int3斷點的
----------------------------------------------------------------------------------
ExceptionDebugEvent(&DE)函數(shù):
  1. void CCodeInjectDlg::ExceptionDebugEvent(LPDEBUG_EVENT lpDE)
  2. {
  3.         PEXCEPTION_RECORD per = &lpDE->u.Exception.ExceptionRecord;
  4.         CONTEXT cText;
  5.         DWORD dwBuf_Num = 0,dwBuf_Buf = 0;
  6.         PBYTE pbBuf = NULL;
  7.         BYTE bInt3 = 0xCC;

  8.         //斷點int3,并且當前地址為WriteFile()
  9.         if(per->ExceptionCode == EXCEPTION_BREAKPOINT && per->ExceptionAddress == lpThread)
  10.         {
  11.                 //恢復(fù)0xCC
  12.                 WriteProcessMemory(CPDbg_Info.hProcess,lpThread,&bOriByte,sizeof(BYTE),NULL);
  13.                 //獲取線程上下文
  14.                 cText.ContextFlags = CONTEXT_CONTROL;
  15.                 GetThreadContext(CPDbg_Info.hThread,&cText);
  16.                 //獲取WriteFile()第2、3參數(shù)
  17.                 ReadProcessMemory(CPDbg_Info.hProcess,(LPVOID)(cText.Esp + 0x8),&dwBuf_Buf,sizeof(DWORD),NULL);
  18.                 ReadProcessMemory(CPDbg_Info.hProcess,(LPVOID)(cText.Esp + 0xC),&dwBuf_Num,sizeof(DWORD),NULL);
  19.                 //分配臨時緩沖區(qū)
  20.                 pbBuf = (PBYTE)malloc(dwBuf_Buf + 1);
  21.                 memset(pbBuf,0,dwBuf_Buf + 1);
  22.                 //復(fù)制WriteFile()緩沖區(qū)到臨時緩沖區(qū)
  23.                 ReadProcessMemory(CPDbg_Info.hProcess,(LPVOID)dwBuf_Buf,pbBuf,dwBuf_Num,NULL);
  24.                 //小寫轉(zhuǎn)大寫(ASCII)
  25.                 for(int i = 0;i < dwBuf_Num;i ++)
  26.                 {
  27.                         //判斷是否是小寫字母
  28.                         if(pbBuf[i] >= 0x61 && pbBuf[i] <= 0x7A)
  29.                         {
  30.                                 pbBuf[i] -= 0x20;
  31.                         }
  32.                 }
  33.                 //變換后緩沖區(qū)寫到WriteFile()緩沖區(qū)
  34.                 WriteProcessMemory(CPDbg_Info.hProcess,(LPVOID)dwBuf_Buf,pbBuf,dwBuf_Num,NULL);
  35.                 //釋放緩沖區(qū)
  36.                 free(pbBuf);
  37.                 //修改線程上下文
  38.                 cText.Eip = (DWORD)lpThread;
  39.                 SetThreadContext(CPDbg_Info.hThread,&cText);
  40.                 //繼續(xù)運行被調(diào)試進程
  41.                 ContinueDebugEvent(lpDE->dwProcessId,lpDE->dwThreadId,DBG_CONTINUE);
  42.                 Sleep(0);
  43.                 //再次寫入int3斷點
  44.                 WriteProcessMemory(CPDbg_Info.hProcess,lpThread,&bInt3,sizeof(BYTE),NULL);
  45.         }
  46. }
復(fù)制代碼

PEXCEPTION_RECORD里面儲存著異常信息,我們判斷該異常是不是斷點并且是斷在WriteFile()處的
首先我們用開始保存的原始信息恢復(fù)0xCC斷點
CONTEXT線程上下文里面存儲著有關(guān)線程的信息(CPU中各寄存器的值)
typedef struct _CONTEXT {
DWORD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs;
DWORD EFlags;
DWORD Esp;
DWORD SegSs;
} CONTEXT;
(具體分析見前面OD分析部分)
下面用WriteProcessMemory()獲取WriteFile()的兩個參數(shù),第一個參數(shù)(ESP + 0x8)里面保存著緩沖區(qū)的地址,第二個參數(shù)(ESP + 0xC)就是緩沖區(qū)大小
接下來就是復(fù)制WriteFile()緩沖區(qū)數(shù)據(jù)到臨時緩沖區(qū),并轉(zhuǎn)換大小寫后,回寫到WriteFile()緩沖區(qū),并且將EIP值修改為WriteFile()起始地址,保證API正常運行,ContinueDebugEvent()使進程繼續(xù)執(zhí)行,
Sleep(0)呢,會釋放當前線程的剩余時間片。。BALABALABALA。。。。如果沒有Sleep(0)的話,有時會發(fā)生崩潰
最后再次寫入int3斷點,以保證下次保存時再次鉤取API
----------------------------------------------------------------------------------
好了,主要代碼就結(jié)束了,不知道當大家看到自己寫出來的API HOOK有沒有一點小激動呢?
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
C# 的快捷鍵匯總(一)
如何調(diào)試Android Framework? | Weishu's Notes
[Python] 手把手教你寫Windows64位平臺調(diào)試器 | 教程大全
詳解反調(diào)試技術(shù)
利用Win32 Debug API打造自己的調(diào)試器Debugger
VC++ 6.0 中如何使用 CRT 調(diào)試功能來檢測內(nèi)存泄漏(轉(zhuǎn)) - bairny的專欄...
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服