+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged
: UChar
+0x003 BitField : UChar
+0x003 ImageUsesLargePages : Pos 0, 1 Bit
+0x003 IsProtectedProcess : Pos 1, 1 Bit
+0x003 IsLegacyProcess : Pos 2, 1 Bit
+0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit
+0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit
+0x003 SpareBits : Pos 5, 3 Bits
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
......
PEB(进程环境块)结构体存储在TEB(线程环境块)中,
TEB
结构如下
kd> dt _teb
nt!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32 Void
+0x040 Win32ThreadInfo : Ptr32 Void
+0x044 User32Reserved : [26] Uint4B
+0x0ac UserReserved : [5] Uint4B
+0x0c0 WOW32Reserved : Ptr32 Void
......
其中
_NT_TIB结构如下
kd> dt _NT_TIB
nt!_NT_TIB
+0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x004 StackBase : Ptr32 Void
+0x008 StackLimit : Ptr32 Void
+0x00c SubSystemTib : Ptr32 Void
+0x010 FiberData : Ptr32 Void
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32 Void
+0x018 Self : Ptr32 _NT_TIB
......
其中
+0x018 Self 是一个指向TIB的指针.同时也是TEB结构体的首地址
FS段寄存器中 地址FS:0指向当前线程TEB。
当我们需要
TEB地址时,可以利用 mov eax, fs:[0x18]得到。且从上文可知在TEB偏移0x30处得到PEB地址。
固可以通过
fs:[30h}获得当前进程的PEB。
BOOL
IsDebuggerPresentPEB()
#if
defined
(ENV64BIT)
PPEB pPeb = (PPEB)__readgsqword(0x60);
#elif
defined
(
ENV32BIT
)
PPEB
pPeb = (
PPEB
)__readfsdword(0x30);
#endif
if
(pPeb->BeingDebugged == 1)
return
TRUE
;
return
FALSE
;
内联汇编版本
BOOL
MY
IsDebuggerPresent()
__asm{
mov eax, fs:[0x30]
movz eax, byte ptr [eax+]
2.
__readgsqword(0x60)
得到指向
PEB64
的指针,
__readfsdword(0x30)
得到指向
PEB
32
的指针,
pPeb->BeingDebugged .
3.
CheckRemoteDebuggerPresent(GetCurrentProcess(), &bIsDbgPresent)
4.
BOOL HeapFlags()
,
64
位下,得到指向
PEB
的地址加上
0x30
的偏移得到
pProcessHeap
,由于
pHeapFlags
在不同版本的操作系统中位置不一,需要
IsWindowsVistaOrGreater()
判断大概版本,高于
VISTA
的版本
pProcessHeap
解星号加上
0x70
的偏移得到
pHeapFlags
,低于高于
VISTA
的版本
pProcessHeap
解星号加上
0x14
的偏移得到
pHeapFlags
32
位下,得到指向
PEB
的地址加上
0x18
的偏移得到
pProcessHeap
,由于
pHeapFlags
在不同版本的操作系统中位置不一,需要
IsWindowsVistaOrGreater()
判断大概版本,高于
VISTA
的版本
pProcessHeap
解星号加上
0x40
的偏移得到
pHeapFlags
,低于
VISTA
的版本
pProcessHeap
解星号加上
0x0C
的偏移得到
pHeapFlags
。判断
*pHeapFlags > 2
是否为真
5.
__readgsqword(0x30)
得到
TEB64
指针
.*(DWORD64*)(_teb64 + 0x60)
得到
PEB64
结构体,
PEB64
取偏移
0xBC
得到
NTGlobalFlag
。
__readfsdword(0x18)
得到
TEB32
指针
.*(DWORD64*)(_teb32 + 0x30)
得到
PEB32
结构体,
PEB32
取偏移
0x68
得到
NTGlobalFlag
假如是
wow64
下的
__readfsdword(0x18)
得到
TEB64
指针
.*(DWORD64*)(_teb64 + 0x60)
得到
PEB64
结构体,
PEB64
取偏移
0xBC
得到
NTGlobalFlag
当进程被调试时,
NTGlobalFlag
会被置为
FLG_HEAP_ENABLE_TAIL_CHECK (0x10), FLG_HEAP_ENABLE_FREE_CHECK(0x20),
和
FLG_HEAP_VALIDATE_PARAMETERS(0x40)
即
0x70
6.
BOOL HeapForceFlags()
,
64
位下,得到指向
PEB
的地址加上
0x30
的偏移得到
pProcessHeap
,由于
pHeapForceFlags
在不同版本的操作系统中位置不一,需要
IsWindowsVistaOrGreater()
判断大概版本,高于
VISTA
的版本
pProcessHeap
解星号加上
0x74
的偏移得到
pHeapFlags
,低于高于
VISTA
的版本
pProcessHeap
解星号加上
0x18
的偏移得到
pHeapFlags
32
位下,得到指向
PEB
的地址加上
0x18
的偏移得到
pProcessHeap
,由于
pHeapForceFlags
在不同版本的操作系统中位置不一,需要
IsWindowsVistaOrGreater()
判断大概版本,高于
VISTA
的版本
pProcessHeap
解星号加上
0x44
的偏移得到
pHeapForceFlags
,低于
VISTA
的版本
pProcessHeap
解星号加上
0x10
的偏移得到
pHeapFlags
。判断
*pHeapFlags > 2
是否为真
7.
通过
LoadLibrary
得到
ntdll
的句柄
hNtdll
,通过
GetProcAddress
从
ntdll
模块中得到
NtQueryInformationProcess const int ProcessDbgPort = 7;
NtQueryInfoProcess(GetCurrentProcess(),
ProcessDbgPort,
&IsRemotePresent,
dProcessInformationLength,
NULL)
当
IsRemotePresent
不等于
0
时 进程被调试
8.
通过
LoadLibrary
得到
ntdll
的句柄
hNtdll
,通过
GetProcAddress
从
ntdll
模块中得到
NtQueryInformationProcess const int ProcessDebugFlags = 0x1f;
NtQueryInfoProcess(GetCurrentProcess(),
ProcessDebugFlags,
&NoDebugInherit,
sizeof(DWORD),
NULL);NoDebugInherit
精确等于
0
时,被调试
9.
通过
LoadLibrary
得到
ntdll
的句柄
hNtdll
,通过
GetProcAddress
从
ntdll
模块中得到
NtQueryInformationProcess const int ProcessDebugObjectHandle = 0x1e;
NtQueryInfoProcess(GetCurrentProcess(), ProcessDebugObjectHandle, &hDebugObject, dProcessInformationLength, NULL);hDebugObject
不为空
10.
通过
GetProcAddress
从
ntdll
模块中得到
NtSetInformationThread
将
ThreadInformationClass
设置为
0x11(ThreadHideFromDebugger)
,用于隐藏调试器中的线程,调用之后调试器与该线程不再关联
NtSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);
当函数成功时,被调试
11.
CloseHandle_InvalideHandle()
当进程被调试时,调用
CloseHandle
并传入无效句柄,会得到一个
STATUS_INVALID_HANDLE
的异常,函数返回
TRUE
。
__try
{
NtClose_((HANDLE)0x99999999);}__except (EXCEPTION_EXECUTE_HANDLER) {return TRUE;}
12.
UnhandledExcepFilterTest ()
设置一个
SetUnhandledExceptionFilter
。然后利用
RaiseException
提出一个异常交给异常处理机制
由于没有设置相应的异常处理程序
当进程被调试时,会通知进程的调试器,而不会调用
UnhandledExceptionFilter
13.
OutputDebugStringAPI
(),
只在
XP
或
2000
中适用。
OutputDebugString()
用于输出字符串给调试器显示。若
GetLastError
被置为
Val
,说明调试器与进程关联。
14.
HardwareBreakpoints()
,初始化
PCONTEXT ctx
,将
ctx->ContextFlags = CONTEXT_DEBUG_REGISTERS
。通过
GetThreadContext(GetCurrentThread(), ctx)
得到寄存器信息,
硬件断点,用
Dr0-Dr7
七个寄存器控制。
Dr1-Dr3
存放了断点地址,
若有一个寄存器存放了断点地址说明
被调试
15.
SoftwareBreakpoints()
,
NOTE this check might not work on x64 because of alignment 0xCC bytes
.
软件断点
INT 3
在
32
位下被编译成
0xCC
,
建立两个函数
A B
,在
B
中调用
A
。计算
A B
地址之间的偏移,将
A
强制类型转换成
PUCHAR
型放置在变量
v1
中,
两个函数地址之间的偏移
为长度
以字节为单位查询是否存在
0xCC
16.
Interrupt_0x2d()
,
利
AddVectoredExceptionHandler()注册一个定向的情况处理
,
__int2d()是一个用asm写的函数,利用指令
int 2dh
测试进程是否被调试,当进程没有关联调试器,会返回一个异常
,
进入我们设置的定向情况处理。无需手动
将
Rip或Eip++
17.
Interrupt_3()
,
利
AddVectoredExceptionHandler()
注册一个定向的情况处理
,
__debugbreak() Microsoft
专用将在代码中引起断点,并在其中提示用户运行调试程序。当进程没有关联调试器,会返回一个异常,当情况为异常断点时需要我们手动将
Rip
或
Eip++
18.
MemoryBreakpoints_PageGuard
(),
动态分配大小为
SystemInfo.dwPageSize
的一块内存,并将
0xC3
(
ret
)
写入内存中,最后将这块内存
VirtualProtect
属性置为
PAGE_EXECUTE_READWRITE | PAGE_GUARD
(
可读写,页面保护
)。
以函数的形式调用这块内存的首地址,观察是否抛出异常。
线程试图访问具备
PAGE_GUARD
属性的内存。该内存可以被访问,但同时
EXCEPTION_GUARD_PAGE
异常会被抛出
,
此时进程没有被调试。
、
19.
CanOpenCsrss()
,
当进程被调试且被提权到
administrator时,该进程可以打开Csrss进程
20.
NtYieldExecutionAPI()
21.
NtQueryObject_ObjectTypeInformation
()
22.
NtQueryObject_ObjectAllTypesInformation
()
23.
SetHandleInformatiom_ProtectedHandle
(),
创建了一个互斥体对象,利用
SetHandleInformation将我们互斥体对象句柄标志改为HANDLE_FLAG_PROTECT_FROM_CLOSE,最后关闭句柄
,
会抛出异常
HANDLE_FLAG_PROTECT_FROM_CLOSE