Delphi 19种反调试检测法
//使用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;
Delphi 19种反调试检测法的更多相关文章
- 编译Android内核 For nexus 5 以及绕过Android的反调试
本文博客链接:http://blog.csdn.net/qq1084283172/article/details/54880488 前面的博客中已经记录了Nexus 5手机的Android 4.4.4 ...
- Windows 32位-调试与反调试
1.加载调试符号链接文件并放入d:/symbols目录下. 0:000> .sympath srv*d:\symbols*http://msdl.microsoft.com/download/s ...
- C/C++ 程序反调试的方法
C/C++ 要实现程序反调试有多种方法,BeingDebugged,NtGlobalFlag,ProcessHeap,CheckRemoteDebuggerPresent,STARTUPINFO,Is ...
- 一种绕过PTRACE反调试的办法
Linux 系统gdb等调试器,都是通过ptrace系统调用实现.Android加固中,ptrace自身防止调试器附加是一种常用的反调试手段. 调试时一般需要手工在ptrace处下断点,通过修改ptr ...
- JavaScript反调试技巧
一.函数重定义 这是一种最基本也是最常用的代码反调试技术了.在JavaScript中,我们可以对用于收集信息的函数进行重定义.比如说,console.log()函数可以用来收集函数和变量等信息,并将其 ...
- WIN10 X64下通过TLS实现反调试
目录(?)[-] TLS技术简介 1 TLS回调函数 2 TLS的数据结构 具体实现及原理 1 VS2015 X64 release下的demo 2 回调函数的具体实现 21 使用IsDebugger ...
- Windows 反调试技术——OpenProcess 权限过滤 - ObRegisterCallback
转载: https://blog.xpnsec.com/anti-debug-openprocess/ 看雪翻译:https://bbs.pediy.com/thread-223857.htm 本周我 ...
- 解决Android加固多进程ptrace反调试的思路整理
本文博客链接:http://blog.csdn.net/qq1084283172/article/details/53613481 一.Android多进程反调试的原理代码 当ptrace附加目标进程 ...
- 基于TLS的反调试技术
TLS(Thread Local Storage 线程局部存储) 一个进程中的每个线程在访问同一个线程局部存储时,访问到的都是独立的绑定于该线程的数据块.在PEB(进程环境块)中TLS存储槽共64个( ...
随机推荐
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介【转】
转自:http://www.cnblogs.com/shoemaker/p/linux_graphics02.html 1. Framebuffer Framebuffer驱动提供基本的显示,fram ...
- google closure 笔记-SOY template
一 使用js模板 closure template 目前支持Java和js.但是模板语法的设计不依赖于任何现成的语言,所以理论上可以支持任何语言,只是暂时只有java编译器. 使用js模板:编写模板文 ...
- 【linux】环境变量
参考链接: http://www.cnblogs.com/growup/archive/2011/07/02/2096142.html https://zhidao.baidu.com/questio ...
- protected
protected 继承访问权限 在同一包中可以访问protected成员. 继承状态可以访问protected成员 在不同包中非继承不可以访问protected成员.
- Java第三阶段学习(八:网络通信协议、UDP与TCP协议)
一.网络通信协议 1.概念: 通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传 ...
- sklearn GMM模型介绍
参考 SKlearn 库 EM 算法混合高斯模型参数说明及代码实现 和 sklearn.mixture.GaussianMixture 以前的推导内容: GMM 与 EM 算法 记录下 ...
- 工作流调度器azkaban2.5.0的安装和使用
为什么需要工作流调度系统 一个完整的数据分析系统通常都是由大量任务单元组成: shell脚本程序,java程序,mapreduce程序.hive脚本等 各任务单元之间存在时间先后及前后依赖关系 为了很 ...
- linux学习笔记-10.解压与压缩
1.gzip压缩 gzip a.txt 2.解压 gunzip a.txt.gzgzip -d a.txt.gz 3.bzip2压缩 bzip2 a 4.解压 bunzip2 a.bz2bzip2 - ...
- url后面添加参数,注意&?的添加方式
// 添加参数&key=value 直接输出url function insertParam(key, value) { key = encodeURI(key); value = encod ...
- mac那些事儿
OS是苹果公司开发的电脑操作系统,MAC是苹果公司开发的笔记本.台式机.IOS是苹果公司开发的移动操作系统,iPhone是苹果公司研发的智能手机系列,搭载IOS操作系统. 一.mac系统快捷键 回到桌 ...