View Code
1 unit Anti_Debug; 2 3 interface 4 5 uses 6 Windows, SysUtils, Classes, TlHelp32; 7 // -------------------查找-通用调试器(FD_)----------------------------------- 8 function FD_IsDebuggerPresent(): Boolean; // √ 9 function PD_PEB_BeingDebuggedFlag(): Boolean; // √ 10 function FD_PEB_NtGlobalFlags(): Boolean; // √ 11 function FD_Heap_HeapFlags(): Boolean; // √ 12 function FD_Heap_ForceFlags(): Boolean; // √ 13 function FD_HEap_Tail(): Boolean; // √x 14 function FD_CheckRemoteDebuggerPresent(): Boolean; // √ 15 function FD_NtQueryInfoProc_DbgPort(): Boolean; // √ 16 function FD_NtQueryInfoProc_DbgObjHandle(): Boolean; // √ 17 function FD_NtQueryInfoProc_DbgFlags(): Boolean; // √ 18 { function FD_NtQueryInfoProc_SysKrlDbgInfo():boolean; //× } 19 function FD_SeDebugPrivilege(csrssPid: THandle): Boolean; // √ 20 { function FD_Parent_Process();//× } 21 function FD_DebugObject_NtQueryObject(): Boolean; 22 function FD_Find_Debugger_Window(): Boolean; // √ 23 function FD_Find_Debugger_Process(): Boolean; 24 { function FD_Find_Device_Driver():boolean; //× } 25 function FD_Exception_Closehandle(): Boolean; // √ 26 function FD_Exception_Int3(): Boolean; // √ 27 { function FD_Exception_Popf():boolean; //√ } 28 function FD_OutputDebugString(): Boolean; // √ 29 { function FD_TEB_check_in_Vista():boolean;//× } 30 function FD_Check_StartupInfo(): Boolean; // √ 31 { function Parent_Process1():boolean; //× } 32 { function Exception_Instruction_count():boolean; //× } 33 function FD_INT_2d(): Boolean; // √ 34 // -----------------检测-专用调试器(FS_)------------------------------------- 35 function FS_OD_Int3_Pushfd(): Boolean; // √ 36 { function FS_SI_UnhandledExceptionFilter(): Boolean; //× } 37 { function FS_ODP_Process32NextW(): Boolean; //× } 38 { function FS_ODP_OutputDebugStringA(): Boolean; //× } 39 { function FS_ODP_OpenProcess(): Boolean; //× } 40 { function FS_ODP_CheckRemoteDebuggerPresent(): Boolean; //× } 41 { function FS_ODP_ZwSetInformationThread(): Boolean; //× } 42 43 function FS_SI_Exception_Int1(): Boolean; // √ 44 { function FS_OD_Exception_GuardPages(): Boolean; //× } 45 46 function IsInsideVMWare(): Boolean; 47 function IsRunInVPC(out ErrMsg: string): Boolean; 48 function FV_VMWare_VMX(): Boolean; 49 function FV_VPC_Exception(): Boolean; 50 { function FV_VME_RedPill():Integer;//0:none,1:vmvare;2:vpc;3:others //× } 51 // -------------检测-断点(FB_)---------------------------------------------- 52 function FB_HWBP_Exception(): Boolean; // √ 53 { function FB_SWBP_Memory_CRC():DWORD; //× } 54 { function FB_SWBP_ScanCC(BYTE * addr,int len):Boolean;//× } 55 { function FB_SWBP_CheckSum_Thread(BYTE *addr_begin,BYTE *addr_end,DWORD sumValue):Boolean;//× } 56 // --------------检测-跟踪(FT_)---------------------------------------------- 57 { //Find Single-Step or Trace 58 function FT_PushSS_PopSS():Boolean; 59 procedure FT_RDTSC(time:LongWord ); //unsigned int * time 60 function FT_GetTickCount():DWORD; 61 function FT_SharedUserData_TickCount():DWORD; 62 function FT_timeGetTime():DWORD; 63 function FT_QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount):Int64; 64 function FT_F1_IceBreakpoint():Boolean; 65 function FT_Prefetch_queue_nop1():Boolean; 66 function FT_Prefetch_queue_nop2():Boolean; 67 } 68 // -----------------检测-补丁(FP_)---------------------------------------------- 69 { function FP_Check_FileSize( Size:DWORD):Boolean; 70 function FP_Check_FileHashValue_CRC( CRCVALUE_origin:DWORD):Boolean; 71 function FP_Check_FileHashValue_MD5( MD5VALUE_origin:DWORD):Boolean; 72 } 73 // ----------------------------------------------------------------------------- 74 function TestDebug(var Mssg: AnsiString): Integer; 75 76 implementation 77 78 function TestDebug(var Mssg: AnsiString): Integer; 79 var 80 isdebugged: DWORD; 81 ts: TStringList; 82 label 83 IsDebug; 84 begin 85 ts := TStringList.Create; 86 try 87 try 88 // 反调试检测 89 isdebugged := 0; 90 if FB_HWBP_Exception then 91 begin 92 isdebugged := isdebugged + 1; 93 ts.Add('FB_HWBP_Exception'); 94 end; 95 if FS_SI_Exception_Int1 then 96 begin 97 isdebugged := isdebugged + 1; 98 ts.Add('FS_SI_Exception_Int1'); 99 end; 100 if FD_Find_Debugger_Window then 101 begin 102 isdebugged := isdebugged + 1; 103 ts.Add('FD_Find_Debugger_Window'); 104 end; 105 if FD_IsDebuggerPresent then 106 begin 107 isdebugged := isdebugged + 1; 108 ts.Add('FD_IsDebuggerPresent'); 109 end; 110 if PD_PEB_BeingDebuggedFlag then 111 begin 112 isdebugged := isdebugged + 1; 113 ts.Add('PD_PEB_BeingDebuggedFlag'); 114 end; 115 if FD_PEB_NtGlobalFlags then 116 begin 117 isdebugged := isdebugged + 1; 118 ts.Add('FD_PEB_NtGlobalFlags'); 119 end; 120 if FD_Heap_HeapFlags then 121 begin 122 isdebugged := isdebugged + 1; 123 ts.Add('FD_Heap_HeapFlags'); 124 end; 125 if FD_CheckRemoteDebuggerPresent then 126 begin 127 isdebugged := isdebugged + 1; 128 ts.Add('FD_CheckRemoteDebuggerPresent'); 129 end; 130 if FD_NtQueryInfoProc_DbgPort then 131 begin 132 isdebugged := isdebugged + 1; 133 ts.Add('FD_NtQueryInfoProc_DbgPort'); 134 end; 135 if FD_NtQueryInfoProc_DbgObjHandle then 136 begin 137 isdebugged := isdebugged + 1; 138 ts.Add('FD_NtQueryInfoProc_DbgObjHandle'); 139 end; 140 if FD_NtQueryInfoProc_DbgFlags then 141 begin 142 isdebugged := isdebugged + 1; 143 ts.Add('FD_NtQueryInfoProc_DbgFlags'); 144 end; 145 if FD_SeDebugPrivilege(916) then 146 begin 147 isdebugged := isdebugged + 1; 148 ts.Add('FD_SeDebugPrivilege'); 149 end; 150 if FD_Exception_Closehandle then 151 begin 152 isdebugged := isdebugged + 1; 153 ts.Add('FD_Exception_Closehandle'); 154 end; 155 if FD_Exception_Int3 then 156 begin 157 isdebugged := isdebugged + 1; 158 ts.Add('FD_Exception_Int3'); 159 end; 160 if FD_OutputDebugString then 161 begin 162 isdebugged := isdebugged + 1; 163 ts.Add('FD_OutputDebugString'); 164 end; 165 if FD_Check_StartupInfo then 166 begin 167 isdebugged := isdebugged + 1; 168 ts.Add('FD_Check_StartupInfo'); 169 end; 170 if FD_INT_2d then 171 begin 172 isdebugged := isdebugged + 1; 173 ts.Add('FD_INT_2d'); 174 end; 175 if FS_OD_Int3_Pushfd then 176 begin 177 isdebugged := isdebugged + 1; 178 ts.Add('FS_OD_Int3_Pushfd'); 179 end; 180 // if FD_DebugObject_NtQueryObject then begin isdebugged := isdebugged + 1; ts.Add('FD_DebugObject_NtQueryObject'); end; 181 182 IsDebug: 183 if isdebugged > 0 then 184 begin 185 Result := isdebugged; 186 Mssg := ts.Text; 187 end 188 else 189 Mssg := '正常执行!'; 190 except 191 on e: Exception do 192 Mssg := ('发生错误!' + #10#13 + e.Message); 193 end; 194 finally 195 ts.Free; 196 end; 197 end; 198 199 // 使用IsDebuggerPresent这个API来检测是否被调试 200 function FD_IsDebuggerPresent(): Boolean; 201 var 202 isDebuggerPresent: function: Boolean; 203 DllModule: THandle; 204 begin 205 DllModule := LoadLibrary('kernel32.dll'); 206 isDebuggerPresent := GetProcAddress(DllModule, 'IsDebuggerPresent'); 207 Result := isDebuggerPresent; 208 end; 209 210 // 使用查看PEB结构中标志位beingDegug来检测是否被调试 211 function PD_PEB_BeingDebuggedFlag(): Boolean; 212 begin 213 asm 214 mov @result, 0 215 mov eax, fs:[30h] // EAX = TEB.ProcessEnvironmentBlock 216 add eax, 2 217 mov eax, [eax] 218 and eax, $000000ff // AL = PEB.BeingDebugged 219 test eax, eax 220 jne @IsDebug 221 jmp @exit 222 @IsDebug: 223 mov @result, 1 224 @exit: 225 end; 226 end; 227 228 // 查看PEB结构中的NtGlobalFlags标志位来检测是否被调试 229 function FD_PEB_NtGlobalFlags(): Boolean; 230 begin 231 asm 232 mov @result, 0 233 mov eax, fs:[30h] 234 mov eax, [eax+68h] 235 and eax, $70 // NtGlobalFlags 236 test eax, eax 237 jne @IsDebug 238 jmp @exit 239 @IsDebug: 240 mov @result, 1 241 @exit: 242 end; 243 end; 244 245 // 在PEB结构中,使用HeapFlags来 246 // 检测调试器也不是非常可靠,但却很常用。 247 // 这个域由一组标志组成,正常情况下,该值应为2 248 function FD_Heap_HeapFlags(): Boolean; 249 begin 250 asm 251 mov @result, 0 252 mov eax, fs:[30h] 253 mov eax, [eax+18h] // PEB.ProcessHeap 254 mov eax, [eax+0ch] // PEB.ProcessHeap.Flags 255 cmp eax, 2 256 jne @IsDebug 257 jmp @exit 258 @IsDebug: 259 mov @result, 1 260 @exit: 261 end; 262 end; 263 264 // 检测PEB结构中的标志位ForceFlags,它也由一 265 // 组标志组成,正常情况下,该值应为0 266 function FD_Heap_ForceFlags(): Boolean; 267 begin 268 asm 269 mov @result, 0 270 mov eax, fs:[30h] 271 mov eax, [eax+18h] mov eax, [eax+10h] 272 test eax, eax 273 jne @IsDebug 274 jmp @exit 275 @IsDebug: 276 mov @result, 1 277 @exit: 278 end; 279 end; 280 281 function FD_HEap_Tail(): Boolean; 282 begin { 283 asm 284 mov @result, 0 285 //get unused_bytes 286 movzx ecx,Byte ptr[eax - 2] 287 movzx edx,word ptr[eax - 8] //size 288 sub eax,ecx 289 lea edi,[edx*8 + eax] 290 mov al,0abh 291 mov cl,8 292 repe sca** //ppansichar ? 293 je @IsDebug 294 jmp @Exit 295 @IsDebug: 296 mov @result,1 297 @exit: 298 end; } 299 end; 300 301 // 使用API:CheckRemoteDebuggerPresent 302 function FD_CheckRemoteDebuggerPresent(): Boolean; 303 var 304 Func_Addr: Pointer; 305 hModule: Cardinal; 306 pDebugBool: PBool; 307 begin 308 Result := false; 309 hModule := GetModuleHandle('kernel32.dll'); 310 if hModule = INVALID_HANDLE_VALUE then 311 exit; 312 Func_Addr := GetProcAddress(hModule, 'CheckRemoteDebuggerPresent'); 313 if (Func_Addr <> nil) then 314 begin 315 asm 316 lea eax, pDebugBool 317 push eax 318 push $ffffffff 319 call Func_addr 320 cmp dword ptr[pDebugBool], 0 321 jne @IsDebug 322 jmp @exit 323 @IsDebug: 324 mov @result, 1 325 @exit: 326 end; 327 end; 328 end; 329 330 // 使用ntdll_NtQueryInformationProcess()来查询 331 // ProcessDebugPort可以用来检测反调试 332 function FD_NtQueryInfoProc_DbgPort(): Boolean; 333 var 334 Func_Addr: Pointer; 335 hModule: Cardinal; 336 ReturnLength: PULONG; 337 dwDebugPort: PDWORD; 338 begin 339 Result := false; 340 hModule := GetModuleHandle('ntdll.dll'); 341 if hModule = INVALID_HANDLE_VALUE then 342 exit; 343 Func_Addr := GetProcAddress(hModule, 'ZwQueryInformationProcess'); 344 if (Func_Addr <> nil) then 345 begin 346 asm 347 lea eax, ReturnLength 348 push eax // ReturnLength 349 push 4 // ProcessInformationLength 350 lea eax, dwDebugPort 351 push eax // ProcessInformation 352 push 7 // ProcessInformationClass 353 push $FFFFFFFF // ProcessHandle 354 call Func_addr // NtQueryInformationProcess 355 cmp [dwDebugPort], 0 356 jne @IsDebug 357 jmp @exit 358 @IsDebug: 359 mov @result, 1 360 @exit: 361 end; 362 end; 363 end; 364 365 // 查询winXp自动创建的"debug object"的句柄 366 function FD_NtQueryInfoProc_DbgObjHandle(): Boolean; 367 var 368 Func_Addr: Pointer; 369 hModule: Cardinal; 370 ReturnLength: PULONG; 371 dwDebugPort: PDWORD; 372 begin 373 Result := false; 374 hModule := GetModuleHandle('ntdll.dll'); 375 if hModule = INVALID_HANDLE_VALUE then 376 exit; 377 Func_Addr := GetProcAddress(hModule, 'ZwQueryInformationProcess'); 378 if (Func_Addr <> nil) then 379 begin 380 asm 381 lea eax, ReturnLength 382 push eax 383 push 4 384 lea eax, dwDebugPort 385 push eax 386 push $1E 387 push $FFFFFFFF 388 call Func_addr 389 mov eax, [dwDebugPort] 390 test eax, eax 391 jnz @IsDebug 392 jmp @exit 393 @IsDebug: 394 mov @result, 1 395 @exit: 396 end; 397 end; 398 end; 399 400 // 查询winXp自动创建的"debug object", 401 // 未公开的ProcessDebugFlags类,当调试器存在时,它会返回false 402 function FD_NtQueryInfoProc_DbgFlags(): Boolean; 403 var 404 Func_Addr: Pointer; 405 hModule: Cardinal; 406 ReturnLength: PULONG; 407 dwDebugPort: PDWORD; 408 begin 409 Result := false; 410 hModule := GetModuleHandle('ntdll.dll'); 411 if hModule = INVALID_HANDLE_VALUE then 412 exit; 413 Func_Addr := GetProcAddress(hModule, 'ZwQueryInformationProcess'); 414 if (Func_Addr <> nil) then 415 begin 416 asm 417 lea eax, ReturnLength 418 push eax 419 push 4 420 lea eax, dwDebugPort 421 push eax 422 push $1F 423 push $FFFFFFFF 424 call Func_addr 425 mov eax, [dwDebugPort] 426 test eax, eax 427 jz @IsDebug 428 jmp @exit 429 @IsDebug: 430 mov @result, 1 431 @exit: 432 end; 433 end; 434 end; 435 436 // 是否获得SeDebugPrivilege 437 // 是否可以使用openprocess操作CSRSS.EXE 438 function FD_SeDebugPrivilege(csrssPid: THandle): Boolean; 439 var 440 hTmp: Cardinal; 441 begin 442 Result := false; 443 hTmp := OpenProcess(PROCESS_ALL_ACCESS, false, csrssPid); 444 if hTmp <> 0 then 445 begin 446 CloseHandle(hTmp); 447 Result := true; 448 end; 449 end; 450 451 function FD_DebugObject_NtQueryObject(): Boolean; 452 const 453 szdbgobj: array [0 .. 24] of AnsiChar = (chr($44), chr($00), chr($65), chr($00), chr($62), 454 chr($00), chr($75), chr($00), chr($67), chr($00), chr($4F), chr($00), chr($62), chr($00), 455 chr($6A), chr($00), chr($65), chr($00), chr($63), chr($00), chr($74), chr($00), chr($00), 456 chr($00), chr($00)); 457 var 458 hModule: Cardinal; 459 Func_Addr: Pointer; 460 psz: PAnsiChar; 461 begin 462 psz^ := szdbgobj[0]; 463 hModule := GetModuleHandle('ntdll.dll'); 464 if hModule = INVALID_HANDLE_VALUE then 465 exit; 466 Func_Addr := GetProcAddress(hModule, 'NtQueryObject'); 467 if Func_Addr = nil then 468 exit; 469 asm 470 xor ebx,ebx 471 push ebx 472 push esp 473 push ebx 474 push ebx 475 push 3 476 push ebx 477 Call dword ptr[Func_addr] 478 pop edi 479 push 4 480 push $1000 481 push edi 482 push ebx 483 call dword ptr[VirtualAlloc] 484 push ebx 485 push edi 486 push eax 487 push 3 488 push ebx 489 xchg esi,eax 490 call dword ptr[Func_addr] 491 lodsd 492 xchg ecx,eax 493 @label1: 494 lodsd 495 movzx edx,ax 496 lodsd 497 xchg esi,eax 498 cmp edx,$16 499 jne @lable2 500 xchg ecx,edx 501 mov edi,psz 502 repe cmpsw // repe cmp** 503 xchg ecx,edx 504 jne @lable2 505 cmp dword ptr[eax],edx 506 jne @IsDebug 507 @lable2: 508 add esi,edx 509 and esi,-4 510 lodsd 511 loop @label1 512 @IsDebug: 513 mov result, 1 514 end; 515 end; 516 517 // 查找已知的调试器的窗口来检测是否被调试 518 function FD_Find_Debugger_Window(): Boolean; 519 var 520 whWnd: DWORD; 521 begin 522 Result := true; 523 // ollydbg v1.1 524 whWnd := FindWindow('icu_dbg', nil); 525 if whWnd <> 0 then 526 exit; 527 // ollyice pe--diy 528 whWnd := FindWindow('pe--diy', nil); 529 if whWnd <> 0 then 530 exit; 531 // ollydbg ?- 532 whWnd := FindWindow('ollydbg', nil); 533 if whWnd <> 0 then 534 exit; 535 // windbg 536 whWnd := FindWindow('WinDbgFrameClass', nil); 537 if whWnd <> 0 then 538 exit; 539 // dede3.50 540 whWnd := FindWindow('TDeDeMainForm', nil); 541 if whWnd <> 0 then 542 exit; 543 // IDA5.20 544 whWnd := FindWindow('TIdaWindow', nil); 545 if whWnd <> 0 then 546 exit; 547 Result := false; 548 end; 549 550 // 进程查看,是否有 551 function FD_Find_Debugger_Process(): Boolean; 552 var 553 hSnapshort: THandle; 554 pe32: TProcessEntry32; 555 fName: AnsiString; 556 begin 557 Result := false; 558 pe32.dwSize := SizeOf(pe32); 559 hSnapshort := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); 560 if (Process32First(hSnapshort, pe32)) then 561 begin 562 while Process32Next(hSnapshort, pe32) do 563 begin 564 begin 565 fName := ExtractFileName(pe32.szExeFile); 566 fName := UpperCase(fName); 567 568 if StrComp(@fName[1], 'OLLYICE.EXE') = 0 then 569 begin 570 Result := true; 571 exit; 572 end; 573 if StrComp(@fName[1], 'IDAG.EXE') = 0 then 574 begin 575 Result := true; 576 exit; 577 end; 578 if StrComp(@fName[1], 'OLLYDBG.EXE') = 0 then 579 begin 580 Result := true; 581 exit; 582 end; 583 if StrComp(@fName[1], 'PEID.EXE') = 0 then 584 begin 585 Result := true; 586 exit; 587 end; 588 if StrComp(@fName[1], 'SOFTICE.EXE') = 0 then 589 begin 590 Result := true; 591 exit; 592 end; 593 if StrComp(@fName[1], 'LORDPE.EXE') = 0 then 594 begin 595 Result := true; 596 exit; 597 end; 598 if StrComp(@fName[1], 'IMPORTREC.EXE') = 0 then 599 begin 600 Result := true; 601 exit; 602 end; 603 if StrComp(@fName[1], 'W32DSM89.EXE') = 0 then 604 begin 605 Result := true; 606 exit; 607 end; 608 if StrComp(@fName[1], 'WINDBG.EXE') = 0 then 609 begin 610 Result := true; 611 exit; 612 end; 613 end; 614 end; 615 end; 616 end; 617 618 // 给CloseHandle()函数一个无效句柄作为输入参数 619 // 是否触发一个EXCEPTION_INVALID_HANDLE (0xc0000008)的异常 620 function FD_Exception_Closehandle(): Boolean; 621 begin 622 try 623 CloseHandle($00001234); 624 Result := false; 625 except 626 Result := true; 627 end; 628 end; 629 630 // int3 检测 631 function FD_Exception_Int3(): Boolean; 632 begin 633 asm 634 mov @result, 0 635 push offset @exception_handler // set exception handler 636 push dword ptr fs:[0h] 637 mov dword ptr fs:[0h],esp 638 xor eax,eax // reset EAX invoke int3 639 int 3h 640 pop dword ptr fs:[0h] // restore exception handler 641 add esp,4 642 test eax,eax // check the flag 643 je @IsDebug 644 jmp @exit 645 @exception_handler: 646 mov eax,dword ptr [esp+$c]// EAX = ContextRecord 647 mov dword ptr [eax+$b0],$ffffffff// set flag (ContextRecord.EAX) 648 inc dword ptr [eax+$b8]// set ContextRecord.EIP 649 xor eax,eax 650 ret 651 @IsDebug: 652 xor eax,eax 653 inc eax 654 mov esp,ebp 655 pop ebp 656 ret 657 @exit: 658 xor eax,eax 659 mov esp,ebp 660 pop ebp 661 ret 662 end; 663 end; 664 665 // 使用OutputDebugString函数来检测 666 function FD_OutputDebugString(): Boolean; 667 var 668 tmpD: DWORD; 669 begin 670 OutputDebugString(''); 671 tmpD := GetLastError; 672 if (tmpD = 0) then 673 Result := true 674 else 675 Result := false; 676 end; 677 678 // 检测STARTUPINFO结构中的值是否为0 679 function FD_Check_StartupInfo(): Boolean; 680 var 681 si: STARTUPINFO; 682 begin 683 ZeroMemory(@si, SizeOf(si)); 684 si.cb := SizeOf(si); 685 GetStartupInfo(si); 686 if (si.dwX <> 0) and (si.dwY <> 0) and (si.dwXCountChars <> 0) and (si.dwYCountChars <> 0) and 687 (si.dwFillAttribute <> 0) and (si.dwXSize <> 0) and (si.dwYSize <> 0) then 688 begin 689 Result := true 690 end 691 else 692 Result := false; 693 end; 694 695 // 使用int 2dh中断的异常检测 696 function FD_INT_2d(): Boolean; 697 begin 698 try 699 asm 700 int 2dh 701 inc eax // any opcode of singlebyte. 702 // ;or u can put some junkcode, 703 // "0xc8"..."0xc2"..."0xe8"..."0xe9" 704 mov @result, 1 705 end; 706 except 707 Result := false; 708 end; 709 end; 710 711 // 最近比较牛的反调试 712 function FS_OD_Int3_Pushfd(): Boolean; 713 begin 714 asm 715 push offset @e_handler // set exception handler 716 push dword ptr fs:[0h] 717 mov dword ptr fs:[0h],esp 718 xor eax,eax // reset EAX invoke int3 719 int 3h 720 pushfd 721 nop 722 nop 723 nop 724 nop 725 pop dword ptr fs:[0h] // restore exception handler 726 add esp,4 727 728 test eax,eax // check the flag 729 je @IsDebug 730 jmp @Exit 731 732 @e_handler: 733 push offset @e_handler1 // set exception handler 734 push dword ptr fs:[0h] 735 mov dword ptr fs:[0h],esp 736 xor eax,eax // reset EAX invoke int3 737 int 3h 738 nop 739 pop dword ptr fs:[0h] // restore exception handler 740 add esp,4 // EAX = ContextRecord 741 mov ebx,eax // dr0=>ebx 742 mov eax,dword ptr [esp+$c] // set ContextRecord.EIP 743 inc dword ptr [eax+$b8] 744 mov dword ptr [eax+$b0],ebx // dr0=>eax 745 xor eax,eax 746 ret 747 748 @e_handler1: // EAX = ContextRecord 749 mov eax,dword ptr [esp+$c] // set ContextRecord.EIP 750 inc dword ptr [eax+$b8] 751 mov ebx,dword ptr[eax+$04] 752 mov dword ptr [eax+$b0],ebx // dr0=>eax 753 xor eax,eax 754 ret 755 756 @IsDebug: 757 mov @result, 1 758 mov esp,ebp 759 pop ebp 760 ret 761 @Exit: 762 mov esp,ebp 763 pop ebp 764 ret 765 end; 766 end; 767 768 // 使用int1的异常检测来反调试 769 function FS_SI_Exception_Int1(): Boolean; 770 begin 771 asm 772 mov @result, 0 773 push offset @eh_int1 // set exception handler 774 push dword ptr fs:[0h] 775 mov dword ptr fs:[0h],esp 776 xor eax,eax // reset flag(EAX) invoke int3 777 int 1h 778 pop dword ptr fs:[0h] // restore exception handler 779 add esp,4 780 test eax, eax // check the flag 781 je @IsDebug 782 jmp @Exit 783 784 @eh_int1: 785 mov eax,[esp+$4] 786 mov ebx,dword ptr [eax] 787 mov eax,dword ptr [esp+$c] // EAX = ContextRecord 788 mov dword ptr [eax+$b0],1 // set flag (ContextRecord.EAX) 789 inc dword ptr [eax+$b8] // set ContextRecord.EIP 790 inc dword ptr [eax+$b8] // set ContextRecord.EIP 791 xor eax, eax 792 ret 793 @IsDebug: 794 mov @result, 1 795 mov esp,ebp 796 pop ebp 797 ret 798 @Exit: 799 xor eax, eax 800 mov esp,ebp 801 pop ebp 802 ret 803 end; 804 end; 805 806 function IsInsideVMWare(): Boolean; 807 var 808 r: Boolean; 809 begin 810 asm 811 push edx 812 push ecx 813 push ebx 814 815 mov eax,'VMXh' 816 mov ebx,0 // any value but MAGIC VALUE 817 mov ecx,10 // get VMWare version 818 mov edx,'VX' // port number 819 in eax,dx // read port 820 // on return EAX returns the VERSION 821 cmp ebx,'VMXh'// is it a reply from VMWare? 822 setz [r] // set return value 823 824 pop ebx 825 pop ecx 826 pop edx 827 end; 828 Result := r; 829 end; 830 831 function FV_VMWare_VMX(): Boolean; 832 begin 833 try 834 Result := IsInsideVMWare; 835 except 836 Result := false; 837 end; 838 end; 839 840 function IsRunInVPC(out ErrMsg: string): Boolean; 841 begin 842 Result := false; 843 try 844 asm 845 push ebx 846 mov ebx, 0 847 mov eax, 1 848 db 0Fh, 3Fh, 07h, 0Bh 849 test ebx, ebx 850 setz [Result] 851 pop ebx 852 end; 853 except 854 on e: Exception do 855 ErrMsg := e.Message; 856 end; 857 end; 858 859 function FV_VPC_Exception(): Boolean; 860 begin 861 asm 862 push ebp 863 mov ebp,esp 864 865 mov ecx,offset @exception_handler 866 867 push ebx 868 push ecx 869 870 push dword ptr fs:[0] 871 mov dword ptr fs:[0],esp 872 873 mov ebx,0 // flag 874 mov eax,1 // VPC function number 875 876 // _asm __emit 0Fh 877 // _asm __emit 3Fh 878 // _asm __emit 07h 879 // _asm __emit 0Bh 880 db 0Fh, 3Fh, 07h, 0Bh 881 882 mov eax,dword ptr ss:[esp] 883 mov dword ptr fs:[0],eax 884 885 add esp,8 886 test ebx,ebx 887 888 setz al 889 890 lea esp,dword ptr ss:[ebp-4] 891 mov ebx,dword ptr ss:[esp] 892 mov ebp,dword ptr ss:[esp + 4] 893 894 add esp,8 895 jmp @ret1 896 @exception_handler: 897 mov ecx,[esp + 0Ch] 898 mov dword ptr [ecx + 0A4h],-1 899 add dword ptr [ecx + 0B8h],4 900 xor eax,eax 901 ret 902 mov @result,1 // ret 903 @ret1: 904 mov @result,0 // ret 905 ret 906 end; 907 end; 908 909 // 在异常处理过程中检测硬件断点 910 function FB_HWBP_Exception(): Boolean; 911 begin 912 asm 913 push offset @exeception_handler // set exception handler 914 push dword ptr fs:[0h] 915 mov dword ptr fs:[0h],esp 916 xor eax,eax // reset EAX invoke int3 917 int 1h 918 pop dword ptr fs:[0h] // restore exception handler 919 add esp,4 // test if EAX was updated (breakpoint identified) 920 test eax,eax 921 jnz @IsDebug 922 jmp @Exit 923 924 @exeception_handler: // EAX = CONTEXT record 925 mov eax,dword ptr [esp+$c] // check if Debug Registers Context.Dr0-Dr3 is not zero 926 cmp dword ptr [eax+$04],0 927 jne @hardware_bp_found 928 cmp dword ptr [eax+$08],0 929 jne @hardware_bp_found 930 cmp dword ptr [eax+$0c],0 931 jne @hardware_bp_found 932 cmp dword ptr [eax+$10],0 933 jne @hardware_bp_found 934 jmp @exception_ret 935 @hardware_bp_found: // set Context.EAX to signal breakpoint found 936 mov dword ptr [eax+$b0],$FFFFFFFF 937 @exception_ret: // set Context.EIP upon return 938 inc dword ptr [eax+$b8] // set ContextRecord.EIP 939 inc dword ptr [eax+$b8] // set ContextRecord.EIP 940 xor eax,eax 941 ret 942 @IsDebug: 943 mov @result, 1 944 mov esp,ebp 945 pop ebp 946 ret 947 @Exit: 948 xor eax, eax 949 mov esp,ebp 950 pop ebp 951 ret 952 end; 953 end; 954 955 end.
//代码大部分来自网络