吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8115|回复: 10
收起左侧

[其他转载] delphi制作防调试程序

 关闭 [复制链接]
tianguo 发表于 2011-11-28 16:19
unit Unit1;
interface
uses
  JwaNative,  Debug,
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;
type
  TForm1 = class(TForm)
      Button1: TButton;
      Timer1: TTimer;
      Button2: TButton;
      Label1: TLabel;
      Label2: TLabel;
      Label3: TLabel;
      Label4: TLabel;
      procedure Timer1Timer(Sender: TObject);
      procedure Button2Click(Sender: TObject);
  private
      { Private declarations }
  public
      { Public declarations }
  end;
var
  Form1: TForm1;
function FD_IsDebuggerPresent(): Boolean;
  function PD_PEB_BeingDebuggedFlag(): Boolean;
  function FD_PEB_NtGlobalFlags(): Boolean;
  function FD_Heap_HeapFlags(): Boolean;
  function FD_Heap_ForceFlags(): Boolean;
  function FD_CheckRemoteDebuggerPresent(): Boolean;
  function FD_NtQueryInfoProc_DbgPort(): Boolean;
  function FD_NtQueryInfoProc_DbgObjHandle(): Boolean;
  function FD_NtQueryInfoProc_DbgFlags(): Boolean;
  function FD_SeDebugPrivilege(csrssPid: THandle): Boolean;
  function FD_Find_Debugger_Window(): Boolean;
  function FD_Exception_Closehandle(): Boolean;
  function FD_Exception_Int3(): Boolean;
  function FD_OutputDebugString(): boolean;
  function FD_Check_StartupInfo(): Boolean;
  function FD_INT_2d(): Boolean;
  function FS_OD_Int3_Pushfd(): Boolean;
  function FS_SI_Exception_Int1(): Boolean;
  function FB_HWBP_Exception(): Boolean;
implementation
{$R *.dfm}
procedure TForm1.Button2Click(Sender: TObject);
begin
  ExitProcess(0);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
  isdebugged: DWORD;
  retLen: PULONG;
  ProcessHandle: DWORD;
  tmp: PChar;
label
  IsDebug;
begin
  try
      //反调试检测
      isdebugged := 0;
      if FB_HWBP_Exception then isdebugged := isdebugged + 1;
      label4.Caption := IntToStr(isdebugged);
      if FS_SI_Exception_Int1 then isdebugged := isdebugged + 1;
      label4.Caption := IntToStr(isdebugged);
      if FD_Find_Debugger_Window then isdebugged := isdebugged + 1;
      if FD_IsDebuggerPresent then isdebugged := isdebugged + 1;
      if PD_PEB_BeingDebuggedFlag then isdebugged := isdebugged + 1;
      if FD_PEB_NtGlobalFlags then isdebugged := isdebugged + 1;
      if FD_Heap_HeapFlags then isdebugged := isdebugged + 1;
      if FD_CheckRemoteDebuggerPresent then isdebugged := isdebugged + 1;
      if FD_NtQueryInfoProc_DbgPort then isdebugged := isdebugged + 1;
      if FD_NtQueryInfoProc_DbgObjHandle then isdebugged := isdebugged + 1;
      if FD_NtQueryInfoProc_DbgFlags then isdebugged := isdebugged + 1;
      if FD_SeDebugPrivilege(916) then isdebugged := isdebugged + 1;
      if FD_Exception_Closehandle then isdebugged := isdebugged + 1;
      if FD_Exception_Int3 then isdebugged := isdebugged + 1;
      if FD_OutputDebugString then isdebugged := isdebugged + 1;
      if FD_Check_StartupInfo then isdebugged := isdebugged + 1;
      if FD_INT_2d then isdebugged := isdebugged + 1;
      if FS_OD_Int3_Pushfd then isdebugged := isdebugged + 1;

IsDebug:
      if isdebugged > 0 then
        tmp := pchar('存在调试器!(共有' + inttostr(isdebugged) + '种方法检测出调试器)')
      else
        tmp := '正常执行!';
      Label1.Caption := tmp;
  except
      on e: Exception do
      debug.DebugPrint('发生错误!' + #10#13 + e.Message);
  end;
end;

//使用IsDebuggerPresent这个API来检测是否被调试
function FD_IsDebuggerPresent(): Boolean;
begin
  if IsDebuggerPresent then
      Result := True
  else
      Result := False;
end;
//使用查看PEB结构中标志位beingDegug来检测是否被调试
function PD_PEB_BeingDebuggedFlag(): Boolean;
begin
  asm
      mov @result, 0
      mov eax, fs:[30h]  //EAX = TEB.ProcessEnvironmentBlock
      add eax, 2
      mov eax, [eax]
      and eax, $000000ff //AL = PEB.BeingDebugged
      test eax, eax
      jne @IsDebug
      jmp @exit
  @IsDebug:
      mov @result, 1
  @exit:
  end;
end;
//查看PEB结构中的NtGlobalFlags标志位来检测是否被调试
function FD_PEB_NtGlobalFlags(): Boolean;
begin
  asm
      mov @result, 0
      mov eax, fs:[30h]
      mov eax, [eax+68h]
      and eax, $70      //NtGlobalFlags
      test eax, eax
      jne @IsDebug
      jmp @exit
  @IsDebug:
      mov @result, 1
  @exit:
  end;
end;
//在PEB结构中,使用HeapFlags来
//检测调试器也不是非常可靠,但却很常用。
//这个域由一组标志组成,正常情况下,该值应为2
function FD_Heap_HeapFlags(): Boolean;
begin
  asm
      mov @result, 0
      mov eax, fs:[30h]
      mov eax, [eax+18h] //PEB.ProcessHeap
      mov eax, [eax+0ch] //PEB.ProcessHeap.Flags
      cmp eax, 2
      jne @IsDebug
      jmp @exit
  @IsDebug:
      mov @result, 1
  @exit:
  end;
end;
//检测PEB结构中的标志位ForceFlags,它也由一
//组标志组成,正常情况下,该值应为0
function FD_Heap_ForceFlags(): Boolean;
begin
  asm
      mov @result, 0
      mov eax, fs:[30h]
      mov eax, [eax+18h]       mov eax, [eax+10h]
      test eax, eax
      jne @IsDebug
      jmp @exit
  @IsDebug:
      mov @result, 1
  @exit:
  end;
end;
//使用API:CheckRemoteDebuggerPresent
function FD_CheckRemoteDebuggerPresent(): Boolean;
var
  Func_Addr: Pointer;
  hModule: Cardinal;
  pDebugBool: PBool;
begin
  result := false;
  hModule := GetModuleHandle('kernel32.dll');
  if hModule = INVALID_HANDLE_VALUE then exit;
  Func_addr := GetProcAddress(hModule, 'CheckRemoteDebuggerPresent');
  if (Func_addr <> nil) then begin
      asm
        lea eax, pDebugBool
        push eax
        push $ffffffff
        call Func_addr
        cmp dword ptr[pDebugBool], 0
        jne @IsDebug
        jmp @exit
      @IsDebug:
        mov @result, 1
      @exit:
      end;
  end;
end;
//使用ntdll_NtQueryInformationProcess()来查询
//ProcessDebugPort可以用来检测反调试
function FD_NtQueryInfoProc_DbgPort(): Boolean;
var
  Func_Addr: Pointer;
  hModule: Cardinal;
  ReturnLength: PULONG;
  dwDebugPort: PDWORD;
begin
  result := false;
  hModule := GetModuleHandle('ntdll.dll');
  if hModule = INVALID_HANDLE_VALUE then exit;
  Func_addr := GetProcAddress(hModule, 'ZwQueryInformationProcess');
  if (Func_addr <> nil) then begin
      asm
        lea eax, ReturnLength
        push eax                    //ReturnLength
        push 4                      //ProcessInformationLength
        lea eax, dwDebugPort
        push eax                    //ProcessInformation
        push 7                      //ProcessInformationClass
        push $FFFFFFFF              //ProcessHandle
        call Func_addr              //NtQueryInformationProcess
        cmp [dwDebugPort], 0
        jne @IsDebug
        jmp @exit
      @IsDebug:
        mov @result, 1
      @exit:
      end;
  end;
end;
//查询winXp自动创建的"debug object"的句柄
function FD_NtQueryInfoProc_DbgObjHandle(): Boolean;
var
  Func_Addr: Pointer;
  hModule: Cardinal;
  ReturnLength: PULONG;
  dwDebugPort: PDWORD;
begin
  result := false;
  hModule := GetModuleHandle('ntdll.dll');
  if hModule = INVALID_HANDLE_VALUE then exit;
  Func_addr := GetProcAddress(hModule, 'ZwQueryInformationProcess');
  if (Func_addr <> nil) then begin
      asm
        lea eax, ReturnLength
        push eax
        push 4
        lea eax, dwDebugPort
        push eax
        push $1E
        push $FFFFFFFF
        call Func_addr
        mov eax, [dwDebugPort]
        test eax, eax
        jnz @IsDebug
        jmp @exit
      @IsDebug:
        mov @result, 1
      @exit:
      end;
  end;
end;
//查询winXp自动创建的"debug object",
//未公开的ProcessDebugFlags类,当调试器存在时,它会返回false
function FD_NtQueryInfoProc_DbgFlags(): Boolean;
var
  Func_Addr: Pointer;
  hModule: Cardinal;
  ReturnLength: PULONG;
  dwDebugPort: PDWORD;
begin
  result := false;
  hModule := GetModuleHandle('ntdll.dll');
  if hModule = INVALID_HANDLE_VALUE then exit;
  Func_addr := GetProcAddress(hModule, 'ZwQueryInformationProcess');
  if (Func_addr <> nil) then begin
      asm
        lea eax, ReturnLength
        push eax
        push 4
        lea eax, dwDebugPort
        push eax
        push $1F
        push $FFFFFFFF
        call Func_addr
        mov eax, [dwDebugPort]
        test eax, eax
        jz @IsDebug
        jmp @exit
      @IsDebug:
        mov @result, 1
      @exit:
      end;
  end;
end;
//是否获得SeDebugPrivilege
//是否可以使用openprocess操作CSRSS.EXE
function FD_SeDebugPrivilege(csrssPid: THandle): Boolean;
var
  hTmp: Cardinal;
begin
  result := False;
  hTmp := OpenProcess(PROCESS_ALL_ACCESS,false,csrssPid);
  if hTmp <> 0 then begin
      CloseHandle (hTmp);
      result := true;
  end;
end;
//查找已知的调试器的窗口来检测是否被调试
function FD_Find_Debugger_Window(): Boolean;
var
  whWnd: DWORD;
begin
  result := True;
  //OllyDbg v1.1
  whWnd := FindWindow('icu_dbg', nil);
  if whWnd <> 0 then Exit;
  //ollyice pe--diy
  whWnd := FindWindow('pe--diy', nil);
  if whWnd <> 0 then Exit;
  //ollydbg ?-
  whWnd := FindWindow('ollydbg', nil);
  if whWnd <> 0 then Exit;
  //windbg
  whWnd := FindWindow('WinDbgFrameClass', nil);
  if whWnd <> 0 then Exit;
  //dede3.50
  whWnd := FindWindow('TDeDeMainForm', nil);
  if whWnd <> 0 then Exit;
  //IDA5.20
  whWnd := FindWindow('TIdaWindow', nil);
  if whWnd <> 0 then Exit;
  result := False;
end;
//给CloseHandle()函数一个无效句柄作为输入参数
//是否触发一个EXCEPTION_INVALID_HANDLE (0xc0000008)的异常
function FD_Exception_Closehandle(): Boolean;
begin
  try
      CloseHandle($00001234);
      result := False;
  except
      Result := True;
  end;
end;
//int3 检测
function FD_Exception_Int3(): Boolean;
begin
      asm
        mov @result, 0
        push offset @exception_handler //set exception handler
        push dword ptr fs:[0h]
        mov dword ptr fs:[0h],esp
        xor eax,eax       //reset EAX invoke int3
        int 3h
        pop dword ptr fs:[0h] //restore exception handler
        add esp,4
        test eax,eax // check the flag
        je @IsDebug
        jmp @exit
      @exception_handler:
        mov eax,dword ptr [esp+$c]//EAX = ContextRecord
        mov dword ptr [eax+$b0],$ffffffff//set flag (ContextRecord.EAX)
        inc dword ptr [eax+$b8]//set ContextRecord.EIP
        xor eax,eax
        ret
      @IsDebug:
        xor eax,eax
        inc eax
        mov esp,ebp
        pop ebp
        ret
      @exit:
        xor eax,eax
        mov esp,ebp
        pop ebp
        ret
      end;
end;
//使用OutputDebugString函数来检测
function FD_OutputDebugString(): boolean;
var
  tmpD: DWORD;
begin
  OutputDebugString('');
  tmpD := GetLastError;
  if(tmpD = 0) then
      result := true
  else
      Result := false;
end;
//检测STARTUPINFO结构中的值是否为0
function FD_Check_StartupInfo(): Boolean;
var
  si: STARTUPINFO;
begin
  ZeroMemory(@si, sizeof(si));
  si.cb := sizeof(si);
  GetStartupInfo(si);
  if (si.dwX <> 0) and (si.dwY <> 0)
      and (si.dwXCountChars <> 0)
      and (si.dwYCountChars <> 0)
      and (si.dwFillAttribute <> 0)
      and (si.dwXSize <> 0)
      and (si.dwYSize <> 0) then begin
      result := true
  end else
      result := false;
end;
//使用int 2dh中断的异常检测
function FD_INT_2d(): Boolean;
begin
  try
      asm
        int 2dh
        inc eax //any opcode of singlebyte.
                //;or u can put some junkcode,
                //"0xc8"..."0xc2"..."0xe8"..."0xe9"
        mov @result, 1
      end;
  except
      Result := false;
  end;
end;
//最近比较牛的反调试
function FS_OD_Int3_Pushfd(): Boolean;
begin
  asm
      push offset @e_handler //set exception handler
      push dword ptr fs:[0h]
      mov dword ptr fs:[0h],esp
      xor eax,eax //reset EAX invoke int3
      int 3h
      pushfd
      nop
      nop
      nop
      nop
      pop dword ptr fs:[0h]  //restore exception handler
      add esp,4
      test eax,eax  //check the flag
      je @IsDebug
      jmp @Exit
@e_handler:
      push offset @e_handler1  //set exception handler
      push dword ptr fs:[0h]
      mov dword ptr fs:[0h],esp
      xor eax,eax  //reset EAX invoke int3
      int 3h
      nop
      pop dword ptr fs:[0h]  //restore exception handler
      add esp,4      //EAX = ContextRecord
      mov ebx,eax  //dr0=>ebx
      mov eax,dword ptr [esp+$c]     //set ContextRecord.EIP
      inc dword ptr [eax+$b8]
      mov dword ptr [eax+$b0],ebx  //dr0=>eax
      xor eax,eax
      ret
@e_handler1:        //EAX = ContextRecord
      mov eax,dword ptr [esp+$c]     //set ContextRecord.EIP
      inc dword ptr [eax+$b8]
      mov ebx,dword ptr[eax+$04]
      mov dword ptr [eax+$b0],ebx  //dr0=>eax
      xor eax,eax
      ret
@IsDebug:
      mov @result, 1
      mov esp,ebp
      pop ebp
      ret
  @Exit:
      mov esp,ebp
      pop ebp
      ret
  end;
end;
//使用int1的异常检测来反调试
function FS_SI_Exception_Int1(): Boolean;
begin
  asm
      mov @result, 0
      push offset @eh_int1 //set exception handler
      push dword ptr fs:[0h]
      mov dword ptr fs:[0h],esp
      xor eax,eax  //reset flag(EAX) invoke int3
      int 1h
      pop dword ptr fs:[0h] //restore exception handler
      add esp,4
      test eax, eax  // check the flag
      je @IsDebug
      jmp @Exit
@eh_int1:
      mov eax,[esp+$4]
      mov ebx,dword ptr [eax]
      mov eax,dword ptr [esp+$c] //EAX = ContextRecord
      mov dword ptr [eax+$b0],1 //set flag (ContextRecord.EAX)
      inc dword ptr [eax+$b8] //set ContextRecord.EIP
      inc dword ptr [eax+$b8] //set ContextRecord.EIP
      xor eax, eax
      ret
  @IsDebug:
      mov @result, 1
      mov esp,ebp
      pop ebp
      ret
  @Exit:
      xor eax, eax
      mov esp,ebp
      pop ebp
      ret
  end;
end;
//在异常处理过程中检测硬件断点
function FB_HWBP_Exception(): Boolean;
begin
  asm
      push offset @exeception_handler //set exception handler
      push dword ptr fs:[0h]
      mov dword ptr fs:[0h],esp
      xor eax,eax  //reset EAX invoke int3
      int 1h
      pop dword ptr fs:[0h]  //restore exception handler
      add esp,4  //test if EAX was updated (breakpoint identified)
      test eax,eax
      jnz @IsDebug
      jmp @Exit
@exeception_handler:       //EAX = CONTEXT record
      mov eax,dword ptr [esp+$c]  //check if Debug Registers Context.Dr0-Dr3 is not zero
      cmp dword ptr [eax+$04],0
      jne @hardware_bp_found
      cmp dword ptr [eax+$08],0
      jne @hardware_bp_found
      cmp dword ptr [eax+$0c],0
      jne @hardware_bp_found
      cmp dword ptr [eax+$10],0
      jne @hardware_bp_found
      jmp @exception_ret
  @hardware_bp_found: //set Context.EAX to signal breakpoint found
      mov dword ptr [eax+$b0],$FFFFFFFF
  @exception_ret:       //set Context.EIP upon return
      inc dword ptr [eax+$b8] //set ContextRecord.EIP
      inc dword ptr [eax+$b8] //set ContextRecord.EIP
      xor eax,eax
      ret
  @IsDebug:
      mov @result, 1
      mov esp,ebp
      pop ebp
      ret
  @Exit:
      xor eax, eax
      mov esp,ebp
      pop ebp
      ret
  end;
end;
end.

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| tianguo 发表于 2011-11-28 16:20
自己顶下



gvbcn 发表于 2011-11-28 16:28
pwzh88 发表于 2011-11-28 17:04
头像被屏蔽
zhang63 发表于 2011-11-28 17:43
提示: 作者被禁止或删除 内容自动屏蔽
pzaitp 发表于 2011-11-28 18:16
肯定是违规的。
daxiong328 发表于 2011-11-28 18:40
简单的复制粘贴...两个帖子了
shfdljz 发表于 2011-11-30 01:00
楼主很一定很厉害
这几天像学习Delphi7 我把你的代码贴到Delphi7 有错误提示,一定需要改什么,请说下好吗
lxj520dyn 发表于 2011-11-30 10:31
这是嘛这是嘛。。。。楼主
我是小白   看不明白啊
demondk 发表于 2012-1-31 20:51
本帖最后由 demondk 于 2012-1-31 21:03 编辑

少了两个类哦
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-9-21 15:33

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表