delphi 反调试代码汇总

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.

//代码大部分来自网络

原文地址:https://www.cnblogs.com/xspace/p/2882443.html