首页
社区
课程
招聘
[原创]理解OD的F4,F7,F8,F9
发表于: 2008-11-22 22:56 57975

[原创]理解OD的F4,F7,F8,F9

2008-11-22 22:56
57975

这个小程序只是hook(IAT hook)了OD的四个关键调试API:WaitForDebugEvent(),GetThreadContext(),SetThreadContext(),ContinueDebugEvent()
当程序运行时,OD通过WaitForDebugEvent等待系统调试事件,WaitForDebugEvent返回时代表有一个调试事件发生了,hook了它就可以轻而易举的知道所发生的具体事件。GetThreadContext得到一个CONTEXT结构,OD寄存器面板里的各个值就来源于这里,但是OD寄存器面板里的值不一定是原始真实的,hook了这个函数就可以看清清楚楚。最重要的是SetThreadContext,OD中F4,F7,F8,F9,shift+F7,shift+F9的功能就是设置CONTEXT结构,然后调用这个函数,设置线程环境,hook了这个函数就能弄清楚OD的调试花招。ContinueDebugEvent后系统就恢复执行被调试线程。

以最简单的F7为例:


看到图中EFLAGE:00000346(0…… 0011 0100 0110)
TF单步标志位是第9位,显然TF=1,表明执行完这条指令后引发单步异常
点确定后出现:


要恢复执行被调试线程了!
再点确定后出现:


图中可以清楚的看到ExceptionCode和ExceptionAddress,80000004就是上面提到单步异常(果然发生了),当然这个异常OD是自己处理的,不会发给被调试程序的!要注意的是硬件断点产生的异常也是80000004,所以最后要通过Dr6的最后四位来判断!

F7固然简单,F9就比我想象的要复杂,大家可以试一试,它们的第一步居然也是单步,然后才把TF置零,正真运行。原因是要落实各个断点(关键是刚刚命中的那个断点(如果有)),包括硬件断点!
F4跟F9一样,只是多设了一个硬件断点(如果用完只能用CC了)
F8最复杂,如果是call指令,则在call后面设置硬件断点(如果用完只能用CC了),否则就是单步。
shift+F7,shift+F9很奇特大家自己看看!
另外popfd是条奇怪的指令,F7、F8时会在下一条指令设置硬件断点!!恐怕OD作者怕popfd改变TF位而跑飞吧,,但这实际上是不可能的,去Intel手册上看看。

需要说明的是:各个OD版本处理可能并不一样!

Dllinject:

#include <windows.h>
#define BaseAddr 0x00400000
#define Dll_Export _declspec(dllexport)
extern "C"
{
  Dll_Export BOOL __stdcall My_ContinueDebugEvent(DWORD dwProcessId,
    DWORD dwThreadId,
    DWORD dwContinueStatus);
  Dll_Export BOOL __stdcall My_GetThreadContext(HANDLE hThread,
    LPCONTEXT lpContext);
  Dll_Export BOOL __stdcall My_SetThreadContext(HANDLE hThread,
    const CONTEXT* lpContext);
  Dll_Export BOOL __stdcall My_WaitForDebugEvent(
    LPDEBUG_EVENT lpDebugEvent,  // pointer to debug event structure
    DWORD dwMilliseconds         // milliseconds to wait for event
    );

}
DWORD *GetFuncAddrIAT(char *func_name);

DWORD *p1=NULL;  //kernel32.ContinueDebugEvent
DWORD *p2=NULL;  //kernel32.GetThreadContext
DWORD *p3=NULL;  //kernel32.SetThreadContext
DWORD *p4=NULL;  //kernel32.WaitForDebugEvent
DWORD old_p1,old_p2,old_p3,old_p4;

DWORD ExceptionAddress=0;
DWORD ExceptionCode=0;


BOOL WINAPI DllMain(
          HINSTANCE hinstDLL,  // handle to DLL module
          DWORD fdwReason,     // reason for calling function
          LPVOID lpReserved )  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason ) 
    { 
  case DLL_PROCESS_ATTACH:
    // Initialize once for each new process.
    // Return FALSE to fail DLL load.

    p1=GetFuncAddrIAT("ContinueDebugEvent");
    p2=GetFuncAddrIAT("GetThreadContext");
    p3=GetFuncAddrIAT("SetThreadContext");
    p4=GetFuncAddrIAT("WaitForDebugEvent");
    if (!(p1&&p2&&p3&&p4))
    {
      MessageBox(NULL,"At Least One Func Hook Fail!","Exit",MB_ICONERROR);
      return FALSE;
    }

    //保存原来的值
    old_p1=*p1;
    old_p2=*p2;
    old_p3=*p3;
    old_p4=*p4;
    //Hook
    *p1=(DWORD)My_ContinueDebugEvent;
    *p2=(DWORD)My_GetThreadContext;
    *p3=(DWORD)My_SetThreadContext;
    *p4=(DWORD)My_WaitForDebugEvent;
    MessageBox(NULL,"Dll Inject Success!!","Injected!",MB_OK);
    break;
    
  case DLL_PROCESS_DETACH:
    // Perform any necessary cleanup.
    //restore
    *p1=old_p1;
    *p2=old_p2;
    *p3=old_p3;
    *p4=old_p4;
    MessageBox(NULL,"Dll即将退出","Waring!",MB_OK);
    break;

  default: 
    break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}


BOOL __stdcall My_ContinueDebugEvent(DWORD dwProcessId,
               DWORD dwThreadId,
               DWORD dwContinueStatus)
{
  MessageBox(NULL,"Start ContinueDebugEvent!","OD",MB_OK);
  return ContinueDebugEvent(dwProcessId,dwThreadId,dwContinueStatus);
}

BOOL __stdcall My_GetThreadContext(HANDLE hThread,
             LPCONTEXT lpContext)
{
//  MessageBox(NULL,"Start GetThreadContext!","OD",MB_OK);
  char buf[256]={0};
  char buf1[512]={0};

  if (ExceptionCode)
  {
    wsprintf(buf1,"ExceptionCode=%08x\nExceptionAddress=%08x\n\n",ExceptionCode,ExceptionAddress);
  }
  BOOL b=GetThreadContext(hThread,lpContext);
  wsprintf( buf,
       "EAX:%08x\nECX:%08x\nEDX:%08x\nEBX:%08x\nESP:%08x\nEBP:%08x\nESI:%08x\nEDI:%08x\n\nEIP:%08x\n\nDr0:%08x\nDr1:%08x\nDr2:%08x\nDr3:%08x\nDr6:%08x\nDr7:%08x\n\nEFLAG:%08x\n",
        lpContext->Eax,
        lpContext->Ecx,
        lpContext->Edx,
        lpContext->Ebx,
        lpContext->Esp,
        lpContext->Ebp,
        lpContext->Esi,
        lpContext->Edi,
        lpContext->Eip,
        lpContext->Dr0,
        lpContext->Dr1,
        lpContext->Dr2,
        lpContext->Dr3,
        lpContext->Dr6,
        lpContext->Dr7,
        lpContext->EFlags
        );
  strcat(buf1,buf);
  MessageBox(NULL,buf1,"GetThreadContext!",MB_OK);
  ExceptionAddress=0;
  ExceptionCode=0;
  return b;
}

BOOL __stdcall My_SetThreadContext(HANDLE hThread,
            const CONTEXT* lpContext)
{
//  MessageBox(NULL,"Start SetThreadContext!","OD",MB_OK);
  char buf[256]={0};
  wsprintf( buf,
      "EAX:%08x\nECX:%08x\nEDX:%08x\nEBX:%08x\nESP:%08x\nEBP:%08x\nESI:%08x\nEDI:%08x\n\nEIP:%08x\n\nDr0:%08x\nDr1:%08x\nDr2:%08x\nDr3:%08x\nDr6:%08x\nDr7:%08x\n\nEFLAG:%08x\n",
      lpContext->Eax,
      lpContext->Ecx,
      lpContext->Edx,
      lpContext->Ebx,
      lpContext->Esp,
      lpContext->Ebp,
      lpContext->Esi,
      lpContext->Edi,
      lpContext->Eip,
      lpContext->Dr0,
      lpContext->Dr1,
      lpContext->Dr2,
      lpContext->Dr3,
      lpContext->Dr6,
      lpContext->Dr7,
      lpContext->EFlags
        );
  MessageBox(NULL,buf,"SetThreadContext!",MB_OK);
  BOOL b=SetThreadContext(hThread,lpContext);
  return b;
}

BOOL __stdcall My_WaitForDebugEvent(
                  LPDEBUG_EVENT lpDebugEvent,  // pointer to debug event structure
                  DWORD dwMilliseconds         // milliseconds to wait for event
                  )
{
  BOOL b=WaitForDebugEvent(lpDebugEvent,dwMilliseconds);
  if(lpDebugEvent->dwDebugEventCode==EXCEPTION_DEBUG_EVENT)
  {
    ExceptionAddress=(DWORD)(lpDebugEvent->u.Exception.ExceptionRecord.ExceptionAddress);
    ExceptionCode=lpDebugEvent->u.Exception.ExceptionRecord.ExceptionCode;      
  }
  return b;
}

DWORD *GetFuncAddrIAT(char *func_name)
{
  DWORD FuncAddr=(DWORD)GetProcAddress(LoadLibrary("Kernel32.dll"),func_name);

  //Get Import Table
  DWORD *DATA_DIRECTORY_ADDR=(DWORD *)(*(DWORD *)(BaseAddr+0x3C)+0x78+BaseAddr);
  DWORD *Import_table_addr=(DWORD *)(*(DATA_DIRECTORY_ADDR+2)+BaseAddr);
  DWORD Import_Size=*(DATA_DIRECTORY_ADDR+3);

  DWORD OldProtect;  //有些OD输入表只读,害我郁闷了半天!
  VirtualProtect(Import_table_addr,Import_Size,PAGE_READWRITE,&OldProtect);

  DWORD *Find_Addr=Import_table_addr;
  while (Import_Size>0)
  {
    if (*Find_Addr==FuncAddr)
      break;
    Import_Size-=4;
    Find_Addr++;
  }
  if (!Import_Size)
    Find_Addr=0;
  return Find_Addr;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (70)
雪    币: 331
活跃值: (57)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
2
忘了附件:

又更新了一下附件:增加了很多别的DEBUG_EVENT的提示

CREATE_PROCESS_DEBUG_EVENT时,进程名通过别的方法获取了,但LOAD_DLL_DEBUG_EVENT时模块名无法获取,它们的lpImageName是NULL(或无效),用PSAPI也不行,刚刚得到这个事件时别的工具也无法察出来,OD里的模块列表应该是后来枚举出来的……不知道大家有什么高招!◎#¥%……※×
上传的附件:
2008-11-22 23:00
0
雪    币: 7318
活跃值: (3793)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
3
不错~~~
顶~~
2008-11-22 23:09
0
雪    币: 331
活跃值: (57)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
4
一开始图片没了,,,编辑了我半天……
2008-11-22 23:20
0
雪    币: 231
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qdk
5
好文要顶。。。。。
2008-11-23 00:00
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
6
顶~~
不错~~~
2008-11-23 00:59
0
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
7
强大 ,顶!!!!!!!!!!
2008-11-23 02:44
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
收藏+顶。。。。。。。。。。。。。。。
2008-11-23 09:19
0
雪    币: 290
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
用五粮液 顶 文章 真的不错
2008-11-23 09:53
0
雪    币: 10
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
文章不错,加油。
2008-11-24 13:52
0
雪    币: 331
活跃值: (57)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
11
不知道更新几次了……还是帮我想想LOAD_DLL_DEBUG_EVENT时怎么获得模块名吧,,
2008-11-24 21:50
0
雪    币: 58
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pzk
12
好文章,学习!
2008-11-24 23:53
0
雪    币: 332
活跃值: (30)
能力值: ( LV12,RANK:460 )
在线值:
发帖
回帖
粉丝
13
思路很清晰哦
2008-11-25 00:57
0
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
14
好文,学习。
2008-11-25 08:54
0
雪    币: 199
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
..支持..
2008-11-25 09:34
0
雪    币: 414
活跃值: (10)
能力值: ( LV9,RANK:460 )
在线值:
发帖
回帖
粉丝
16
好文,学习了。
2008-11-25 11:07
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
看完了,不错
2008-11-25 12:44
0
雪    币: 236
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
支持一下......
2008-11-26 10:07
0
雪    币: 134
活跃值: (157)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
支持,呵呵~~~
2008-11-26 16:51
0
雪    币: 239
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
想操练已下,HOOK函数少了,没找到程序,
2009-1-30 20:10
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
学习了  厉害
2009-2-12 16:24
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
22
最近对这些断点的理论重新整理温习了一下,再看了LZ的大作,感觉比以前的理解更清晰了许多。
2009-2-13 00:46
0
雪    币: 192
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
好文要顶。。。。。..
2009-3-2 17:18
0
雪    币: 563
活跃值: (101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
学习了!!
2009-3-2 20:57
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
不得为菜鸟们欢呼了~转论坛
2009-5-8 23:18
0
游客
登录 | 注册 方可回帖
返回
//