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;

代码下载:20095641408249.rar

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.

Last modification:November 9th, 2019 at 04:33 pm
如果觉得我的文章对你有用,请随意赞赏