JoyChou 发表于 2013-4-23 19:54

Anti-Debug检测int3断点源码

本帖最后由 JoyChou 于 2013-5-9 13:10 编辑

今天看到zxcfvasd发了一篇关于int检测的CM文章
然后给大家分享下怎么实现的。

这里用VS写了一个内嵌的汇编代码
C代码:
#include <windows.h>

BOOL DetectFuncBreakpoints();

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{

    if (DetectFuncBreakpoints())
    {
      MessageBox(NULL, "检测到int3断点", "结果", MB_OK);
      return 0;
    }
    else
    {
      MessageBox(NULL, "没有检测到int3断点", "结果", MB_OK);
    }

    return 0;
}

BOOL DetectFuncBreakpoints()
{
    BOOL bFoundOD;
    bFoundOD=FALSE;
    DWORD dwAddr;
    dwAddr = (DWORD)GetProcAddress(LoadLibrary("user32.dll"),"MessageBoxA"); //将FARPROC类型转换成DWORD
    __asm
    {
            cld               ;检测代码开始
            mov   edi,dwAddr
            mov   ecx,100;100bytes
            mov   al,0CCH ;字母前面必须有0
            repne   scasb
            jnz   ODNotFound
            mov bFoundOD,1
ODNotFound:            
    }
    return bFoundOD;
}


再发一个win32汇编写的吧
;检测时,BP MessageBoxA
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
            
            .const
szKernelDlldb      'user32.dll',0
szAPIMessbox db      'MessageBoxA',0
szCaption    db      '结果',0
szFound       db      '发现API断点',0
szNotFound   db      '未发现断点',0
            .code
start:
         invoke   GetModuleHandle,addr szKernelDll
         invoke   GetProcAddress,eax,addr szAPIMessbox;API地址
                     
         cld               ;检测代码开始
         mov   edi,eax   ;API开始位置
         mov   ecx,100H;检测100字节
         mov   al, 55H
         xor   al, 99H   ;55和99异或等于0xCC
         repne   scasb   
         cmp   ecx, 0h         
         jnz      debugger_found      
                                    
       invokeMessageBox,NULL,addr szNotFound,addr szCaption,MB_OK
         jmp   exit
debugger_found: invokeMessageBox,NULL,addr szFound,addr szCaption,MB_OK
          exit: invokeExitProcess,NULL
                end start

首先我们得知道一个问题,当用OD调试的时候,我们F2或者下bp断点的时候,即是下int3断点OD载入分析:比如我们在00401000 F2下断,此时应该00401000地址应该是CC 18204000因为OD做了对int3的隐藏,我们看到的还是是68,而不是我们下断时的CC,当然这也是为了我们方便。
说这么多是为了理解00401021|.F2:AE         repne scas byte ptr es: 这句话因为当等于我们下断的时,此时数据窗口并不等于CC。这也是我调试的觉得有点困惑的地方,分享一下。
00401000 >/$68 18204000   push APISoftB.00402018                   ; /pModule = "user32.dll"
00401005|.E8 5A000000   call <jmp.&KERNEL32.GetModuleHandleA>    ; \GetModuleHandleA
0040100A|.68 23204000   push APISoftB.00402023                   ; /ProcNameOrOrdinal = "MessageBoxA"
0040100F|.50            push eax                                 ; |hModule
00401010|.E8 55000000   call <jmp.&KERNEL32.GetProcAddress>      ; \GetProcAddress
00401015|.FC            cld
00401016|.8BF8          mov edi,eax
00401018|.B9 00010000   mov ecx,0x100
0040101D|.B0 55         mov al,0x55
0040101F|.34 99         xor al,0x99
00401021|.F2:AE         repne scas byte ptr es:
000401023|.83F9 00       cmp ecx,0x0                              ;ecx不等于0表示检测到int3断点
00401026|.75 15         jnz short APISoftB.0040103D
00401028|.6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL
0040102A|.68 2F204000   push APISoftB.0040202F                   ; |Title = "结果"
0040102F|.68 40204000   push APISoftB.00402040                   ; |Text = "未发现断点"
00401034|.6A 00         push 0x0                                 ; |hOwner = NULL
00401036|.E8 1D000000   call <jmp.&USER32.MessageBoxA>         ; \MessageBoxA
0040103B|.EB 13         jmp short APISoftB.00401050
0040103D|>6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL
0040103F|.68 2F204000   push APISoftB.0040202F                   ; |Title = "结果"
00401044|.68 34204000   push APISoftB.00402034                   ; |Text = "发现API断点"
00401049|.6A 00         push 0x0                                 ; |hOwner = NULL
0040104B|.E8 08000000   call <jmp.&USER32.MessageBoxA>         ; \MessageBoxA
00401050|>6A 00         push 0x0                                 ; /ExitCode = 0
00401052\.E8 07000000   call <jmp.&KERNEL32.ExitProcess>         ; \ExitProcess

对代码段的int3检测
#include <windows.h>
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR   lpCmdLine,
                     int       nCmdShow)
{
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS32 pNtHeaders;
    PIMAGE_SECTION_HEADER pSectionHeader;
    DWORD dwBaseImage = (DWORD)GetModuleHandle(NULL); //获取当前进程的基址
   
   
    pDosHeader = (PIMAGE_DOS_HEADER)dwBaseImage;
    pNtHeaders = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeaders + sizeof(pNtHeaders->Signature) + sizeof(IMAGE_FILE_HEADER) +
    (WORD)pNtHeaders->FileHeader.SizeOfOptionalHeader);
      
    DWORD dwAddr = pSectionHeader->VirtualAddress + dwBaseImage; //获取代码段在内存中的地址
    DWORD dwCodeSize = pSectionHeader->SizeOfRawData;    //获取代码段对齐后的大小
    BOOL bFound = FALSE;
   
    __asm
    {
            cld               ;检测代码开始
            mov   edi,dwAddr
            mov   ecx,10h ;检测0x10个字节测试,原则应该是dwCodeSize大小
            mov   al,0CCH ;字母前面必须有0
            repne   scasb
            jnz   NotFound
            mov bFound,1
NotFound:            
    }
    if (bFound)
    {
      MessageBoxA(NULL, "检测到断点", "结果", 0);
    }
    else
    {
      MessageBoxA(NULL, "没有检测到断点", "结果", 0);
    }
    return 0;
   
}
最后说下原理:
先得到函数的地址,设置一个检测的字节长度(我这里设的0x100),然后就一直搜索0xCC,如果发现了就表示检测到了。反之亦然。
不过只能检测bp断点和F2(int3断点),硬件等断点是检测不到的,硬件断点可以用CONTEXT结构体里面的iDr0,iDr1,iDr2,iDr3成员检测,这里就不多说了。

跳过检测方法:
1、修改检测时的跳转
2、下 hr等强点的断点

网上很多关于int3检测的资料,所以大家想学习的善于利用好搜索功能能学到很多东西的。

混小子 发表于 2013-4-23 19:59

感谢楼主分享代码。。。

real金龟子 发表于 2013-4-23 20:07

前来膜拜。。。学习了!

JoyChou 发表于 2013-4-23 20:10

real金龟子 发表于 2013-4-23 20:07 static/image/common/back.gif
前来膜拜。。。学习了!

金龟子大大辛苦了

leeyeah93 发表于 2013-4-23 20:11

感谢楼主分享

bambooqj 发表于 2013-4-23 20:18

JoyChou 发表于 2013-4-23 20:39

bambooqj 发表于 2013-4-23 20:18 static/image/common/back.gif
前排膜拜技术贴。。。

只是混个脸熟

daiandy 发表于 2013-4-24 16:46

我有时候下硬件执行也被检测了

JoyChou 发表于 2013-4-24 18:32

daiandy 发表于 2013-4-24 16:46 static/image/common/back.gif
我有时候下硬件执行也被检测了

怎么会呢

sunflover 发表于 2013-4-26 10:55

前排支持围观,话说VMP处理一下关键位置,CC检测也相当了得。不知道硬件断点如何检测,求楼主爆料,我等菜鸟好学习
页: [1] 2
查看完整版本: Anti-Debug检测int3断点源码