以下基于一个简单的x64位程序,在Windows 10 x64上调试
TEB的结构
dt _teb
+0x000 NtTib : _NT_TIB
+0x038 EnvironmentPointer : Ptr64 Void
+0x040 ClientId : _CLIENT_ID
+0x050 ActiveRpcHandle : Ptr64 Void
+0x058 ThreadLocalStoragePointer : Ptr64 Void
+0x060 ProcessEnvironmentBlock : Ptr64 _PEB
+0x068 LastErrorValue : Uint4B
+0x06c CountOfOwnedCriticalSections : Uint4B
+0x070 CsrClientThread : Ptr64 Void
+0x078 Win32ThreadInfo : Ptr64 Void
+0x080 User32Reserved : [26] Uint4B
+0x0e8 UserReserved : [5] Uint4B
+0x100 WOW32Reserved : Ptr64 Void
+0x108 CurrentLocale : Uint4B
+0x10c FpSoftwareStatusRegister : Uint4B
+0x110 ReservedForDebuggerInstrumentation : [16] Ptr64 Void
+0x190 SystemReserved1 : [32] Ptr64 Void
+0x290 _ActivationStack : _ACTIVATION_CONTEXT_STACK
+0x2b8 WorkingOnBehalfTicket : [8] UChar
+0x2c0 ExceptionCode : Int4B
+0x2c4 Padding0 : [4] UChar
+0x2c8 ActivationContextStackPointer : Ptr64 _ACTIVATION_CONTEXT_STACK
+0x2d0 InstrumentationCallbackSp : Uint8B
+0x2d8 InstrumentationCallbackPreviousPc : Uint8B
+0x2e0 InstrumentationCallbackPreviousSp : Uint8B
+0x2e8 TxFsContext : Uint4B
+0x2ec InstrumentationCallbackDisabled : UChar
+0x2ed Padding1 : [3] UChar
+0x2f0 GdiTebBatch : _GDI_TEB_BATCH
+0x7d8 RealClientId : _CLIENT_ID
+0x7e8 GdiCachedProcessHandle : Ptr64 Void
+0x7f0 GdiClientPID : Uint4B
+0x7f4 GdiClientTID : Uint4B
+0x7f8 GdiThreadLocalInfo : Ptr64 Void
+0x800 Win32ClientInfo : [62] Uint8B
+0x9f0 glDispatchTable : [233] Ptr64 Void
+0x1138 glReserved1 : [29] Uint8B
+0x1220 glReserved2 : Ptr64 Void
+0x1228 glSectionInfo : Ptr64 Void
+0x1230 glSection : Ptr64 Void
+0x1238 glTable : Ptr64 Void
+0x1240 glCurrentRC : Ptr64 Void
+0x1248 glContext : Ptr64 Void
+0x1250 LastStatusValue : Uint4B
+0x1254 Padding2 : [4] UChar
+0x1258 StaticUnicodeString : _UNICODE_STRING
+0x1268 StaticUnicodeBuffer : [261] Wchar
+0x1472 Padding3 : [6] UChar
+0x1478 DeallocationStack : Ptr64 Void
+0x1480 TlsSlots : [64] Ptr64 Void
+0x1680 TlsLinks : _LIST_ENTRY
+0x1690 Vdm : Ptr64 Void
+0x1698 ReservedForNtRpc : Ptr64 Void
+0x16a0 DbgSsReserved : [2] Ptr64 Void
+0x16b0 HardErrorMode : Uint4B
+0x16b4 Padding4 : [4] UChar
+0x16b8 Instrumentation : [11] Ptr64 Void
+0x1710 ActivityId : _GUID
+0x1720 SubProcessTag : Ptr64 Void
+0x1728 PerflibData : Ptr64 Void
+0x1730 EtwTraceData : Ptr64 Void
+0x1738 WinSockData : Ptr64 Void
+0x1740 GdiBatchCount : Uint4B
+0x1744 CurrentIdealProcessor : _PROCESSOR_NUMBER
+0x1744 IdealProcessorValue : Uint4B
+0x1744 ReservedPad0 : UChar
+0x1745 ReservedPad1 : UChar
+0x1746 ReservedPad2 : UChar
+0x1747 IdealProcessor : UChar
+0x1748 GuaranteedStackBytes : Uint4B
+0x174c Padding5 : [4] UChar
+0x1750 ReservedForPerf : Ptr64 Void
+0x1758 ReservedForOle : Ptr64 Void
+0x1760 WaitingOnLoaderLock : Uint4B
+0x1764 Padding6 : [4] UChar
+0x1768 SavedPriorityState : Ptr64 Void
+0x1770 ReservedForCodeCoverage : Uint8B
+0x1778 ThreadPoolData : Ptr64 Void
+0x1780 TlsExpansionSlots : Ptr64 Ptr64 Void
+0x1788 DeallocationBStore : Ptr64 Void
+0x1790 BStoreLimit : Ptr64 Void
+0x1798 MuiGeneration : Uint4B
+0x179c IsImpersonating : Uint4B
+0x17a0 NlsCache : Ptr64 Void
+0x17a8 pShimData : Ptr64 Void
+0x17b0 HeapVirtualAffinity : Uint2B
+0x17b2 LowFragHeapDataSlot : Uint2B
+0x17b4 Padding7 : [4] UChar
+0x17b8 CurrentTransactionHandle : Ptr64 Void
+0x17c0 ActiveFrame : Ptr64 _TEB_ACTIVE_FRAME
+0x17c8 FlsData : Ptr64 Void
+0x17d0 PreferredLanguages : Ptr64 Void
+0x17d8 UserPrefLanguages : Ptr64 Void
+0x17e0 MergedPrefLanguages : Ptr64 Void
+0x17e8 MuiImpersonation : Uint4B
+0x17ec CrossTebFlags : Uint2B
+0x17ec SpareCrossTebBits : Pos 0, 16 Bits
+0x17ee SameTebFlags : Uint2B
+0x17ee SafeThunkCall : Pos 0, 1 Bit
+0x17ee InDebugPrint : Pos 1, 1 Bit
+0x17ee HasFiberData : Pos 2, 1 Bit
+0x17ee SkipThreadAttach : Pos 3, 1 Bit
+0x17ee WerInShipAssertCode : Pos 4, 1 Bit
+0x17ee RanProcessInit : Pos 5, 1 Bit
+0x17ee ClonedThread : Pos 6, 1 Bit
+0x17ee SuppressDebugMsg : Pos 7, 1 Bit
+0x17ee DisableUserStackWalk : Pos 8, 1 Bit
+0x17ee RtlExceptionAttached : Pos 9, 1 Bit
+0x17ee InitialThread : Pos 10, 1 Bit
+0x17ee SessionAware : Pos 11, 1 Bit
+0x17ee LoadOwner : Pos 12, 1 Bit
+0x17ee LoaderWorker : Pos 13, 1 Bit
+0x17ee SkipLoaderInit : Pos 14, 1 Bit
+0x17ee SpareSameTebBits : Pos 15, 1 Bit
+0x17f0 TxnScopeEnterCallback : Ptr64 Void
+0x17f8 TxnScopeExitCallback : Ptr64 Void
+0x1800 TxnScopeContext : Ptr64 Void
+0x1808 LockCount : Uint4B
+0x180c WowTebOffset : Int4B
+0x1810 ResourceRetValue : Ptr64 Void
+0x1818 ReservedForWdf : Ptr64 Void
+0x1820 ReservedForCrt : Uint8B
+0x1828 EffectiveContainerId : _GUID
_NT_TIB 结构
需要注意的是,_NT_TIB
在x64
上,结构是_NT_TIB64
,长度是0x38
,这与x86
上有区别。_NT_TIB32
长度是0x1c
dt _NT_TIB
+0x000 ExceptionList : Ptr64 _EXCEPTION_REGISTRATION_RECORD
+0x008 StackBase : Ptr64 Void
+0x010 StackLimit : Ptr64 Void
+0x018 SubSystemTib : Ptr64 Void
+0x020 FiberData : Ptr64 Void
+0x020 Version : Uint4B
+0x028 ArbitraryUserPointer : Ptr64 Void
+0x030 Self : Ptr64 _NT_TIB
!peb
调试器用户经常会需要查看在启动调试目标时使用了哪些命令行参数,这个信息是保存在PEB中的,可以通过!peb来获取,这个命令将解析PEB并给出完整的命令行,所有已加载DLL的位置,以及环境变量等.
!peb
PEB at 000000cc4b84d000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: Yes
ImageBaseAddress: 00007ff6317b0000
Ldr 00007ffabf1db340
Ldr.Initialized: Yes
Ldr.InInitializationOrderModuleList: 0000026568643260 . 0000026568643960
Ldr.InLoadOrderModuleList: 0000026568643410 . 0000026568647650
Ldr.InMemoryOrderModuleList: 0000026568643420 . 0000026568647660
Base TimeStamp Module
7ff6317b0000 593f8d46 Jun 13 14:59:18 2017 D:\Desktop\x64.exe
7ffabf080000 b79b6ddb Aug 13 07:18:51 2067 C:\WINDOWS\SYSTEM32\ntdll.dll
7ffabd1a0000 f5fa43df Oct 10 10:41:35 2100 C:\WINDOWS\System32\KERNEL32.DLL
7ffabc100000 a0527b0c Mar 27 19:33:32 2055 C:\WINDOWS\System32\KERNELBASE.dll
7ffabd7e0000 d66f509b Jan 02 10:42:35 2084 C:\WINDOWS\System32\USER32.dll
7ffabb5a0000 d9592a17 Jul 21 04:29:11 2085 C:\WINDOWS\System32\win32u.dll
7ffabd2c0000 efcc154c Jun 27 07:57:00 2097 C:\WINDOWS\System32\GDI32.dll
7ffabbe10000 2e4a909f Aug 12 04:57:03 1994 C:\WINDOWS\System32\gdi32full.dll
7ffabbcc0000 d867caf3 Jan 19 02:26:59 2085 C:\WINDOWS\System32\msvcp_win.dll
7ffabc000000 5ba8b66e Sep 24 18:03:26 2018 C:\WINDOWS\System32\ucrtbase.dll
7ffaa5d60000 589abd8e Feb 08 14:41:18 2017 C:\WINDOWS\SYSTEM32\VCRUNTIME140.dll
SubSystemData: 0000000000000000
ProcessHeap: 0000026568640000
ProcessParameters: 00000265686429b0
CurrentDirectory: 'C:\Program Files (x86)\Windows Kits\10\Debuggers\'
WindowTitle: 'D:\Desktop\x64.exe'
ImageFile: 'D:\Desktop\x64.exe'
CommandLine: 'D:\Desktop\x64.exe'
DllPath: '< Name not readable >'
Environment: 0000026568641100
=::=::\
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\Administrator\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
...
以下略
手工分析PEB结构
dt _PEB @$peb
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
+0x002 BeingDebugged : 0x1 ''
+0x003 BitField : 0x4 ''
+0x003 ImageUsesLargePages : 0y0
+0x003 IsProtectedProcess : 0y0
+0x003 IsImageDynamicallyRelocated : 0y1
+0x003 SkipPatchingUser32Forwarders : 0y0
+0x003 IsPackagedProcess : 0y0
+0x003 IsAppContainer : 0y0
+0x003 IsProtectedProcessLight : 0y0
+0x003 IsLongPathAwareProcess : 0y0
+0x004 Padding0 : [4] ""
+0x008 Mutant : 0xffffffff`ffffffff Void
+0x010 ImageBaseAddress : 0x00007ff6`317b0000 Void
+0x018 Ldr : 0x00007ffa`bf1db340 _PEB_LDR_DATA
+0x020 ProcessParameters : 0x00000265`686429b0 _RTL_USER_PROCESS_PARAMETERS
+0x028 SubSystemData : (null)
+0x030 ProcessHeap : 0x00000265`68640000 Void
+0x038 FastPebLock : 0x00007ffa`bf1dae60 _RTL_CRITICAL_SECTION
+0x040 AtlThunkSListPtr : (null)
+0x048 IFEOKey : (null)
...
以下略
分析ldr
上例中找到LDR
的地址是:+0x018 Ldr : 0x00007ffa`bf1db340 _PEB_LDR_DATA
dt 0x00007ffa`bf1db340 _PEB_LDR_DATA
+0x000 Length : 0x58
+0x004 Initialized : 0x1 ''
+0x008 SsHandle : (null)
+0x010 InLoadOrderModuleList : _LIST_ENTRY [ 0x00000265`68643410 - 0x00000265`68647650 ]
+0x020 InMemoryOrderModuleList : _LIST_ENTRY [ 0x00000265`68643420 - 0x00000265`68647660 ]
+0x030 InInitializationOrderModuleList : _LIST_ENTRY [ 0x00000265`68643260 - 0x00000265`68643960 ]
+0x040 EntryInProgress : (null)
+0x048 ShutdownInProgress : 0 ''
+0x050 ShutdownThreadId : (null)
对比!peb中列表的地址内容
可以看到是一样的
Ldr.InInitializationOrderModuleList: 0000026568643260 . 0000026568643960
Ldr.InLoadOrderModuleList: 0000026568643410 . 0000026568647650
Ldr.InMemoryOrderModuleList: 0000026568643420 . 0000026568647660
+0x010 InLoadOrderModuleList : _LIST_ENTRY [ 0x00000265`68643410 - 0x00000265`68647650 ]
+0x020 InMemoryOrderModuleList : _LIST_ENTRY [ 0x00000265`68643420 - 0x00000265`68647660 ]
+0x030 InInitializationOrderModuleList : _LIST_ENTRY [ 0x00000265`68643260 - 0x00000265`68643960 ]
这三个列表分别是
LIST_ENTRY InLoadOrderModuleList; //按加载顺序
LIST_ENTRY InMemoryOrderModuleList; //按内存顺序
LIST_ENTRY InInitializationOrderModuleList;//按初始化顺序
查找InLoadOrderModuleList的链表
上面得知:InLoadOrderModuleList
的相对于Ldr
偏移是0x10
dt 0x00007ffa`bf1db340+0x10 _LIST_ENTRY
ntdll!_LIST_ENTRY
[ 0x00000265`68643410 - 0x00000265`68647650 ]
+0x000 Flink : 0x00000265`68643410 _LIST_ENTRY [ 0x00000265`68643240 - 0x00007ffa`bf1db350 ]
+0x008 Blink : 0x00000265`68647650 _LIST_ENTRY [ 0x00007ffa`bf1db350 - 0x00000265`68646620 ]
按MSDN解释是:Each item in the list is a pointer to an LDR_DATA_TABLE_ENTRY structure,双向循环链表吧,从一个方向开始,不停的循环,就回到初始位了,就相当于遍历了一次
LDR_DATA_TABLE_ENTRY结构
比如上例中Flink
的指向0x00000265`68643410
,这个结构是LDR_DATA_TABLE_ENTRY
dt 0x00000265`68643410 _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x00000265`68643240 - 0x00007ffa`bf1db350 ]
+0x010 InMemoryOrderLinks : _LIST_ENTRY [ 0x00000265`68643250 - 0x00007ffa`bf1db360 ]
+0x020 InInitializationOrderLinks : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
+0x030 DllBase : 0x00007ff6`317b0000 Void
+0x038 EntryPoint : 0x00007ff6`317b1608 Void
+0x040 SizeOfImage : 0x20000
+0x048 FullDllName : _UNICODE_STRING "D:\Desktop\x64.exe"
+0x058 BaseDllName : _UNICODE_STRING "x64.exe"
...
以下略
可以看到第一个是D:\Desktop\x64.exe
,符合上文!peb
加载对象
上文+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x00000265`68643240 - 0x00007ffa`bf1db350 ]
我们找到了第二个0x00000265`68643240
dt 0x00000265`68643240 _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x00000265`68643940 - 0x00000265`68643410 ]
+0x010 InMemoryOrderLinks : _LIST_ENTRY [ 0x00000265`68643950 - 0x00000265`68643420 ]
+0x020 InInitializationOrderLinks : _LIST_ENTRY [ 0x00000265`68643f40 - 0x00007ffa`bf1db370 ]
+0x030 DllBase : 0x00007ffa`bf080000 Void
+0x038 EntryPoint : (null)
+0x040 SizeOfImage : 0x1db000
+0x048 FullDllName : _UNICODE_STRING "C:\WINDOWS\SYSTEM32\ntdll.dll"
+0x058 BaseDllName : _UNICODE_STRING "ntdll.dll"
...
以下略
符合上文!peb
中第二个加载对象
启动进程的参数
我们注意到PEB 0x20
处的偏移+0x020 ProcessParameters : 0x00000265`686429b0 _RTL_USER_PROCESS_PARAMETERS
dt 0x00000265`686429b0 _RTL_USER_PROCESS_PARAMETERS
ntdll!_RTL_USER_PROCESS_PARAMETERS
+0x000 MaximumLength : 0x6e8
+0x004 Length : 0x6e8
+0x008 Flags : 0x2001
+0x00c DebugFlags : 0
+0x010 ConsoleHandle : (null)
+0x018 ConsoleFlags : 0
+0x020 StandardInput : (null)
+0x028 StandardOutput : (null)
+0x030 StandardError : (null)
+0x038 CurrentDirectory : _CURDIR
+0x050 DllPath : _UNICODE_STRING ""
+0x060 ImagePathName : _UNICODE_STRING "D:\Desktop\x64.exe"
+0x070 CommandLine : _UNICODE_STRING "D:\Desktop\x64.exe"
+0x080 Environment : 0x00000265`68641100 Void
+0x088 StartingX : 0
+0x08c StartingY : 0
+0x090 CountX : 0
+0x094 CountY : 0
+0x098 CountCharsX : 0
+0x09c CountCharsY : 0
+0x0a0 FillAttribute : 0
+0x0a4 WindowFlags : 0
+0x0a8 ShowWindowFlags : 0
+0x0b0 WindowTitle : _UNICODE_STRING "D:\Desktop\x64.exe"
+0x0c0 DesktopInfo : _UNICODE_STRING "WinSta0\Default"
+0x0d0 ShellInfo : _UNICODE_STRING ""
+0x0e0 RuntimeData : _UNICODE_STRING ""
+0x0f0 CurrentDirectores : [32] _RTL_DRIVE_LETTER_CURDIR
+0x3f0 EnvironmentSize : 0x1874
+0x3f8 EnvironmentVersion : 3
+0x400 PackageDependencyData : (null)
+0x408 ProcessGroupId : 0x288
+0x40c LoaderThreads : 0
没有用参数启动 :see_no_evil:
基于以上实现,遍历当前进程所有加载的模块
以下程序基于x64的结构
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
int main()
{
void *pebAddr = *((void **)( ( BYTE* )NtCurrentTeb()+ 0x60)); // TEB->ProcessEnvironmentBlock也就是PEB
void *ldrAddr = *(( void ** )(( BYTE* )pebAddr + 0x18)); // PEB->Ldr
void *fLink = *(( void ** )(( BYTE* )ldrAddr + 0x20)); // PEB->Ldr->InLoadOrderLinks->FLink
void *p = fLink;
void *baseAddr = NULL;
void *dllName = NULL;
void *fullDllName = NULL;
void *entryPoint = NULL;
void *imageOfSize = NULL;
void *isDebuged = *(( void ** )(( BYTE* )pebAddr + 0x02));
_tprintf(_T("当前程序%s被调试\n", ((WORD)isDebuged) & 0x1 ? _T("正在") : _T("没有")));
_tprintf(_T("\n--------------------------按加载顺序遍历双向循环链表----------------------------\n\n"));
_tprintf(_T("\tPEB ADDRESS = \t0x%08X\n"), pebAddr);
_tprintf(_T("\tLDR ADDRESS = \t0x%08X\n"), ldrAddr);
_tprintf(_T("----------------------------------------------------\n"));
do
{
baseAddr = *(( void ** )(( BYTE* )p + 0x30));
dllName = *(( void ** )(( BYTE* )p + 0x58));
fullDllName = *(( void ** )(( BYTE* )p + 0x48));
entryPoint = *(( void ** )(( BYTE* )p + 0x38));
imageOfSize = *(( void ** )(( BYTE* )p + 0x40));
_tprintf(_T("\tModuleName:%s\n"), dllName);
_tprintf(_T("\t\tBase Address:0x%08X\n"), baseAddr);
_tprintf(_T"\t\tFull Module Name:%s\n", fullDllName);
_tprintf(_T("\t\tentryPoint:0x%08X\n"), entryPoint);
_tprintf(_T("\t\timageOfSize:0x%08X\n"), imageOfSize);
p = *( void ** )p; // p->InLoadOrderLinks->FLink
} while (p! = fLink);
return (0);
}