特点:一般在调试开始时阻拦调试者,调试只需要找到原因后就可以一次性突破
PEB
?
BeginDebug
: 调试标志位// 通过检查 PEB.BeingDebuged 字段判断是否被调试
// 可以在目标程序运行之前修改对应的字段为 0 进行反反调试
bool CheckBeingDebugged()
{
__asm
{
; 获取到 PEB 的内容
mov eax, fs:[0x30]
; 获取 PEB 内偏移为 2 大小为 1 字节的字段
movzx eax, byte ptr[eax + 2]
}
}
int main()
{
if (CheckBeingDebugged())
printf("当前处于[被]调试状态\n");
else
printf("当前处于[非]调试状态\n");
system("pause");
return 0;
}
// 使用 IsDebuggerPresent 原理同样是判断 PEB.BeingDebuged
// 通过 HOOK 函数和修改对应字段的方式可以进行反调试
int main()
{
if (IsDebuggerPresent())
printf("当前处于[被]调试状态\n");
else
printf("当前处于[非]调试状态\n");
system("pause");
return 0;
}
Ldr
内存状态Heap
(Flags
, Force Flags
): 堆状态NtGlobalFlag
: 内核全局标记
PEB.NtGlobalFlag
判断是否被调试,当处于被调试状态时PEB.NtGlobalFlag
保存的是 0x70
,可以通过修改标志反反调试bool CheckNtGlobalFlag()
{
__asm
{
; 获取到 PEB, 保存在 FS :[0x30]
mov eax, fs : [0x30]
;获取到 NtGlobalFlag 字段的内容
mov eax, [eax + 0x68]
}
}
int main()
{
if (CheckNtGlobalFlag())
printf("当前处于[被]调试状态\n");
else
printf("当前处于[非]调试状态\n");
system("pause");
return 0;
}
TEB
StaticUnicodeString
:静态缓冲区使用原始 API
NtQuerySystemInformationProcess()
ProcessDebugPort(0x07)
: 获取调试端口ProcessDebugObjectHandle(0x1E)
: 获取调试句柄ProcessDebugFlag(0x1F)
: 获取调试标记NtQuerySystemInformation()
:
SystemKernelDeBuggerInformation(0x23)
:获取系统调试状态 (双机)NtQueryObject()
: 遍历系统内核攻击调试器
NtSetInformationThread()
ThreadHideFormDebugger(0x11)
打开进程检查
SetDebugPrivilege
?? 检查进程是否具有调试权限利用TLS
回调函数
使用普通API
Explorer.exe
,也就是资源管理器,如果判断不是,就可能被调试,提供参考。bool CheckParentProcess()
{
struct PROCESS_BASIC_INFORMATION {
ULONG ExitStatus; // 进程返回码
PPEB PebBaseAddress; // PEB 地址
ULONG AffinityMask; // CPU 亲和性掩码
LONG BasePriority; // 基本优先级
ULONG UniqueProcessId; // 本进程PID
ULONG InheritedFromUniqueProcessId; // 父进程PID
}stcProcInfo;
// 查询到目标进程的对应信息,主要是 父进程 ID
NtQueryInformationProcess(
GetCurrentProcess(),
ProcessBasicInformation,
&stcProcInfo,
sizeof(stcProcInfo),
NULL);
// 查询资源管理器对应的 PID
DWORD ExplorerPID = 0;
DWORD CurrentPID = stcProcInfo.InheritedFromUniqueProcessId;
GetWindowThreadProcessId(FindWindow(L"Progman", NULL), &ExplorerPID);
// 比对两个 PID 的值,相同就OK,不同就可能被调试
return ExplorerPID == CurrentPID ? false : true;
}
int main()
{
if (CheckParentProcess())
printf("当前处于[被]调试状态\n");
else
printf("当前处于[非]调试状态\n");
system("pause");
return 0;
}
int main()
{
if (FindWindow(NULL, L"OllyDbg"))
printf("存在调试器\n");
else
printf("没检测到调试器\n");
return 0;
}
EPROCESS
结构体中相关的字段,因为不能在 R3
修改 R0
的数据,所以只能 HOOK
bool CheckProcessDebugPort()
{
int nDebugPort = 0;
NtQueryInformationProcess(
GetCurrentProcess(), // 目标进程句柄
ProcessDebugPort, // 查询信息类型(7)
&nDebugPort, // 输出查询信息
sizeof(nDebugPort), // 查询类型大小
NULL); // 实际返回数据大小
// 如果返回的是 -1 ,那么就被调试了
return nDebugPort == 0xFFFFFFFF ? true : false;
}
int main()
{
if (CheckProcessDebugPort())
printf("当前处于[被]调试状态\n");
else
printf("当前处于[非]调试状态\n");
system("pause");
return 0;
}
SEH
SetUnhandleedExceptionFilter()
OllyDbg
插件编写通常以DLL
的方式存在的,但是后缀名可能会有变化
所有的插件都应该被保护到具体的路径中
原文:https://www.cnblogs.com/TJTO/p/11374003.html