相关文章推荐
体贴的小马驹  ·  es 字段权重排序 ...·  4 月前    · 
坏坏的丝瓜  ·  ajax post传参数 ajax ...·  6 月前    · 
失望的作业本  ·  javascript - A ...·  1 年前    · 

+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