OD內存斷點初步分析

內存斷點原理:

       內存斷點原理,通過將內存斷點所在內存頁的屬性修改爲內存斷點屬性(non-access or non-writable),程序執行時,對目標內存頁中所有數據的訪問或寫,都會拋出異常,OD通過截獲此異常,然後對比,存儲在某一內存的內存斷點信息表的地址,判斷是否匹配內存斷點地址範圍,匹配則中斷程序執行,否則,繼續執行。

IDA靜態分析:

本例利用IDA和OD動靜結合,分析OD內存斷點基本流程,以及內存斷點存儲在哪兒段內存地址。

首先將OD丟進IDA中,在程序函數列表中搜索breakpoint字符串,如圖:


我們僅分析內存斷點,通過function name 可知:_setmembreakpoint是我們需要分析的函數。跳到該函數分析,入口點部分截圖:



可知,該函數有3個參數,通過F5(hexray),其反編譯僞代碼:

signed int __cdecl Setmembreakpoint(__int16 a1, unsigned int a2, int a3)
{
  _DWORD *v3; // eax@3
  signed int result; // eax@5

  if ( !dword_4D8138 && VersionInformation.dwPlatformId != 2 )
  {
    v3 = Findmemory(a2);
    if ( a2 < 0x80000000 )     //判斷內存斷點地址是否在用戶內存中(0x800000~0xffffffff屬於系統內核內存區域)
    {
      if ( v3 && *((_BYTE *)v3 + 11) & 1 )   //判斷內存斷點是否在資源內存區域
      {
        if ( MessageBoxA(
               hWnd,
               "You are going to set memory breakpoint on resource. This breakpoint, when hit within system DLL, may freeze Windows or cause system crash. Do you really want to set this breakpoint?",
               "Memory breakpoint on resource",
               0x14u) != 6 )
          return -1;
      }
      else
      {
        if ( v3 && *((_BYTE *)v3 + 11) & 4 )    //判斷內存斷點地址是否在堆棧內存區域
        {
          MessageBoxA(
            hWnd,
            "You are going to set memory breakpoint on stack. This doesn't work on Win95-based operating systems.",
            "Memory breakpoint on stack",
            0x10u);
          return -1;
        }
      }
    }
    else
    {
      if ( MessageBoxA(
             hWnd,
             "You are going to set memory breakpoint in system area. This breakpoint may freeze Windows or cause system crash. Do you really want to set this breakpoint?",
             "Memory breakpoint in system area",
             0x14u) != 6 )
        return -1;
    }
  }
  if ( sub_418E24() )
  {
    result = -1;
  }
  else
  {
    dword_4D813C = a2;
    dword_4D8140 = a3;
    dword_4D8144 = a2 & 0xFFFFF000;
    dword_4D8148 = (a3 + a2 + 4095) & 0xFFFFF000;
    dword_4D8138 = (HIBYTE(a1) & 0x10) != 0;
    dword_4D8D5C = 1;
    if ( a1 & 3 && a3 )
    {
      if ( (a1 & 3) == 2 )
        dword_4D814C = 32;
      else
        dword_4D814C = 1;
      if ( dword_4D5A5C == 3 )
        sub_419034();
      result = 0;
    }
    else
    {
      result = 0;
    }
  }
  return result;
}

OD調試OD動態分析:

我們通過OD來調試OD,分析setmembreakpoint函數的流程。

將OD丟進OD中,並在setmembreakpoint入口地址下斷點(F2),並運行被調試的OD。然後在被調試的OD程序中加載調試一個任意程序,並在某一地址下內存訪問斷點,如圖(被調試的od程序中,在紅線0x401377處下了內存斷點):


下完該內存斷點,調試程序OD立即捕獲,並中斷在setmembreakpoint的入口地址,然後我們通過單步,查看該函數的三個參數分別是神馬:


發現esi中的值即我們在被調試程序中所下的內存斷點地址,edi爲內存斷點的字節長度(0x401377處指令爲6bytes)。ebx值其實是內存斷點的屬性(訪問:0x00000003,寫:0x00000002),這裏我們之前下的是內存訪問斷點,所以ebx:0x00000003。

繼續單步執行,在0x4192fb處跳轉到0x41938d。先不管這裏爲什麼會調轉。繼續單步,發現之後的彙編操作將我們所下的內存斷點信息存儲到了某段內存中,如圖:


當前eax=0x401377,即我們的內存斷點地址。

分析彙編:

004193A2  |.  A3 3C814D00   mov     dword ptr [4D813C], eax   //將內存斷點地址存儲到0x4d813c處       
004193A7  |.  8BC8          mov     ecx, eax      //ecx=eax=0x401377 內存斷點地址
004193A9  |.  03C2          add     eax, edx      //edx爲內存斷點字節長度,這裏是取內存斷點結束地址,本例中,eax=0x401377+6=0x40137d
004193AB  |.  81E1 00F0FFFF and     ecx, FFFFF000   //相當於去該內存地址所在的內存頁起始地址   ecx=0x401000
004193B1  |.  05 FF0F0000   add     eax, 0FFF      //將內存斷點結束地址加上了一個內存頁大小
004193B6  |.  8915 40814D00 mov     dword ptr [4D8140], edx  //將內存斷點長度存儲到0x4d8140
004193BC  |.  25 00F0FFFF   and     eax, FFFFF000   //取該內存地址所在的內存頁地址
004193C1  |.  890D 44814D00 mov     dword ptr [4D8144], ecx   //將內存斷點坐在內存也的起始地址存儲到0x4d8144處
004193C7  |.  F6C7 10       test    bh, 10    //設置zf屬性,執行後,zf=1
004193CA  |.  A3 48814D00   mov     dword ptr [4D8148], eax   //本例中eax=402000
004193CF  |.  0F95C0        setne   al      //if zf=1 then al=0, if zf=0 then al=1
004193D2  |.  83E0 01       and     eax, 1        //之後 eax=0x00000000
004193D5  |.  83E3 03       and     ebx, 3        //ebx之前存儲的是內存斷點屬性(訪問or 寫)
004193D8  |.  A3 38814D00   mov     dword ptr [4D8138], eax    //存儲這個不知道有何用途
004193DD  |.  C705 5C8D4D00>mov     dword ptr [4D8D5C], 1  
004193E7  |.  85DB          test    ebx, ebx
004193E9  |.  74 04         je      short 004193EF
004193EB  |.  85FF          test    edi, edi       //edi存的是內存斷點字節長度
004193ED  |.  75 04         jnz     short 004193F3   //跳轉成功
004193EF  |>  33C0          xor     eax, eax
004193F1  |.  EB 2B         jmp     short 0041941E
004193F3  |>  83FB 02       cmp     ebx, 2           //ebx與2 比較,判斷是否是內存寫屬性
004193F6  |.  75 0C         jnz     short 00419404     //不是則跳轉到0x419404(訪問屬性)
004193F8  |.  C705 4C814D00>mov     dword ptr [4D814C], 20   //內存寫屬性,則將0x20存儲在0x4d814c
00419402  |.  EB 0A         jmp     short 0041940E
00419404  |>  C705 4C814D00>mov     dword ptr [4D814C], 1    //內存訪問屬性,將0x01存儲在0x4d814c
0041940E  |>  833D 5C5A4D00>cmp     dword ptr [4D5A5C], 3
00419415  |.  75 05         jnz     short 0041941C
00419417  |.  E8 18FCFFFF   call    00419034
0041941C  |>  33C0          xor     eax, eax
0041941E  |>  5F            pop     edi
0041941F  |.  5E            pop     esi
00419420  |.  5B            pop     ebx
00419421  |.  5D            pop     ebp
00419422  \.  C3            retn

通過對上面的彙編代碼的分析,我們基本上可以定位內存斷點信息的存儲地址:0x4d8138~0x4d814f ,本例如圖:


0x4d8138~0x40813b:0x00000000 未知

0x4d813c~0x4d813f: 0x00401377 內存斷點起始地址

0x4d8140~0x4d8143: 0x00000006 內存斷點長度

0x4d8144~0x4d8147: 0x00401000 內存斷點地址所在的內存頁起始地址

0x4d8148~0x4d814b: 0x00402000 內存斷點尾部地址+內存也大小地址後,所在的內存頁起始地址(這裏有所疑問,爲什麼要加上0xfff,而不是直接取內存斷點尾部地址所在的內存頁起始地址,本例中,應該也是0x401000)。

0x4d814c~0x4d814f:0x00000001 內存斷點屬性(訪問:0x00000001,寫:0x00000020,與ebx區分開)

對該段內存的賦值其實在初始化一個結構體,該結構體存儲內存斷點相關信息:

Typedef struct membrakpointinfo

Dword unrecognized;//0x4d8138~0x40813b 未知

Dwordmemaddr;   //0x4d813c~0x4d813f 內存斷點起始地址

Dword size;        //0x4d8140~0x4d8143:0x00000006 內存斷點長度

Dword base1;      //0x4d8144~0x4d8147內存斷點地址所在的內存頁起始地址

Dword base2;     //0x4d8148~0x4d814b:0x00402000 內存斷點尾部地址+內存也大小地址後,所在的內存頁起始地址

Dword memtype;  //0x4d814c~0x4d814f 內存斷點屬性

}

參考文章:http://bbs.pediy.com/showthread.php?t=65221

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