获取kernel32.dll

FS寄存器

fs寄存器记录了当前活动线程的TEB结构,具体信息如下

1
2
3
4
5
6
7
8
9
10
11
12
0x000 指向SEH链指针
0x004 线程堆栈顶部
0x008 线程堆栈底部
0x00C SubSystemTib
0x010 FiberData
0x014 ArbitraryUserPointer
0x018 FS段寄存器在内存中的镜像地址
0x020 进程PID
0x024 线程ID
0x02C 指向线程局部存储指针
0x030 PEB结构地址(进程结构)
0x034 上个错误号

shellcode中常用的获取kernel32.dll方法如下 1. 通过peb(fs:[30])获取


通过fs:[30]获取

peb(fs:[30])的结构

win11环境下大部分成员都被命名为Reserved

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct _PEB {
+0x000 BYTE Reserved1[2];
+0x002 BYTE BeingDebugged;
+0x003 BYTE Reserved2[1];
+0x004 PVOID Reserved3[2];
+0x00C PPEB_LDR_DATA Ldr;
+0x010 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+0x014 PVOID Reserved4[3];
+0x020 PVOID AtlThunkSListPtr;
+0x024 PVOID Reserved5;
+0x028 ULONG Reserved6;
+0x02C PVOID Reserved7;
+0x030 ULONG Reserved8;
+0x034 ULONG AtlThunkSListPtr32;
+0x038 PVOID Reserved9[45];
+0x0EC BYTE Reserved10[96];
+0x14C PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
+0x150 BYTE Reserved11[128];
+0x1D0 PVOID Reserved12[1];
+0x1D4 ULONG SessionId;
} PEB, *PPEB;

对照windows xp sp3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
typedef struct _PEB {
+0x000 UCHAR InheritedAddressSpace;
+0x001 UCHAR ReadImageFileExecOptions;
+0x002 UCHAR BeingDebugged;
+0x003 UCHAR SpareBool;
+0x004 HANDLE Mutant;
+0x008 HINSTANCE ImageBaseAddress;
+0x00C struct _PEB_LDR_DATA *Ldr
+0x010 struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters;
+0x014 ULONG SubSystemData;
+0x018 HANDLE DefaultHeap;
+0x01C KSPIN_LOCK FastPebLock;
+0x020 ULONG FastPebLockRoutine;
+0x024 ULONG FastPebUnlockRoutine;
+0x028 ULONG EnvironmentUpdateCount;
+0x02C ULONG KernelCallbackTable;
+0x030 LARGE_INTEGER SystemReserved;
+0x038 struct _PEB_FREE_BLOCK *FreeList
+0x03C ULONG TlsExpansionCounter;
+0x040 ULONG TlsBitmap;
+0x044 LARGE_INTEGER TlsBitmapBits;
+0x04C ULONG ReadOnlySharedMemoryBase;
+0x050 ULONG ReadOnlySharedMemoryHeap;
+0x054 ULONG ReadOnlyStaticServerData;
+0x058 ULONG AnsiCodePageData;
+0x05C ULONG OemCodePageData;
+0x060 ULONG UnicodeCaseTableData;
+0x064 ULONG NumberOfProcessors;
+0x068 LARGE_INTEGER NtGlobalFlag; ER CriticalSectionTimeout;
+0x078 ULONG HeapSegmentReserve;
+0x07C ULONG HeapSegmentCommit;
+0x080 ULONG HeapDeCommitTotalFreeThreshold;
+0x084 ULONG HeapDeCommitFreeBlockThreshold;
+0x088 ULONG NumberOfHeaps;
+0x08C ULONG MaximumNumberOfHeaps;
+0x090 ULONG ProcessHeaps;
+0x094 ULONG GdiSharedHandleTable;
+0x098 ULONG ProcessStarterHelper;
+0x09C ULONG GdiDCAttributeList;
+0x0A0 KSPIN_LOCK LoaderLock;
+0x0A4 ULONG OSMajorVersion;
+0x0A8 ULONG OSMinorVersion;
+0x0AC USHORT OSBuildNumber;
+0x0AE USHORT OSCSDVersion;
+0x0B0 ULONG OSPlatformId;
+0x0B4 ULONG ImageSubsystem;
+0x0B8 ULONG ImageSubsystemMajorVersion;
+0x0BC ULONG ImageSubsystemMinorVersion;
+0x0C0 ULONG ImageProcessAffinityMask;
+0x0C4 ULONG GdiHandleBuffer[0x22];
+0x14C ULONG PostProcessInitRoutine;
+0x150 ULONG TlsExpansionBitmap;
+0x154 UCHAR TlsExpansionBitmapBits[0x80];
+0x1D4 ULONG SessionId;
+0x1d8 AppCompatFlags : _ULARGE_INTEGER
+0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x1e8 pShimData : Ptr32 Void
+0x1ec AppCompatInfo : Ptr32 Void
+0x1f0 CSDVersion : _UNICODE_STRING
+0x1f8 ActivationContextData : Ptr32 Void
+0x1fc ProcessAssemblyStorageMap :Ptr32 Void
+0x200 SystemDefaultActivationContextData : Ptr32 Void
+0x204 SystemAssemblyStorageMap : Ptr32 Void
+0x208 MinimumStackCommit : Uint4B
} PEB, *PPEB;

通过PEB+0x0C即可获得PEB_LDR_DATA结构,在PEB中较为重要的的几个成员为

1
2
3
4
5
+0x02 BeingDebugged    : UChar
+0x08 ImageBaseAddress : Ptr32 Void
+0x0C Ldr : Ptr32 _PEB_LDR_DATA
+0x18 ProcessHeap : Ptr32 Void
+0x68 NtGlobalFlag : Uint4B

PEB_LDR_DATA结构

win11环境下

1
2
3
4
5
typedef struct _PEB_LDR_DATA {
+0x00 BYTE Reserved1[8];
+0x08 PVOID Reserved2[3];
+0x14 LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
windows xp sp3下
1
2
3
4
5
6
7
8
9
10

typedef struct _PEB_LDR_DATA32
{
+0x00 ULONG Length;
+0x04 BOOLEAN Initialized;
+0x08 PVOID SsHandle;
+0x0C LIST_ENTRY InLoadOrderModuleList;
+0x14 LIST_ENTRY InMemoryOrderModuleList;
+0x1C LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA32, * PPEB_LDR_DATA32;
可以看到在win11下InInitializationOrderModuleList已被弃用,但为了保证兼容性,实际还是可以通过PEB_LDR_DATA+0x1C的方法访问InInitializationOrderModuleList

其中LIST_ENTRY是一个双向循环链表,Flink指向下一个条目,Blink指向上一个条目,指向的内容为LDR_DATA_TABLE_ENTRY结构体中相应的位置,之后详细解释

1
2
3
4
5
typedef struct _LIST_ENTRY 
{
+0x00 struct _LIST_ENTRY *Flink;
+0x04 struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY;

LDR_DATA_TABLE_ENTRY结构

win11环境下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct _LDR_DATA_TABLE_ENTRY {
+0x00 PVOID Reserved1[2];
+0x08 LIST_ENTRY InMemoryOrderLinks;
+0x10 PVOID Reserved2[2];
+0x18 PVOID DllBase;
+0x1C PVOID Reserved3[2];
+0x24 UNICODE_STRING FullDllName;
+0x2C BYTE Reserved4[8];
+0x34 PVOID Reserved5[3];
#pragma warning(push)
#pragma warning(disable: 4201) // we'll always use the Microsoft compiler
+0x40 union {
ULONG CheckSum;
PVOID Reserved6;
} DUMMYUNIONNAME;
#pragma warning(pop)
+0x48 ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

windows xp sp3下

1
2
3
4
5
6
7
8
9
10
11
12

typedef struct _LDR_DATA_TABLE_ENTRY
{
+0x00 LIST_ENTRY InLoadOrderLinks;
+0x08 LIST_ENTRY InMemoryOrderLinks;
+0x10 LIST_ENTRY InInitializationOrderLinks;
+0x18 PVOID DllBase;
+0x1C PVOID EntryPoint;
+0x20 ULONG SizeOfImage;
+0x24 UNICODE_STRING FullDllName;
+0x2C UNICODE_STRING BaseDllName;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
以windows xp sp3为例PEB_LDR_DATA32中的InLoadOrderModuleList->Flink指向的内容位置就是LDR_DATA_TABLE_ENTRY中InLoadOrderLinks的位置,InMemoryOrderLinks和InInitializationOrderLinks同理

在win11环境下 使用InLoadOrderLinks查找,模块的顺序为当前进程(xxx.exe) ->ntdll.dll -> kernel32.dll 使用InMemoryOrderLinks查找,模块的顺序为当前进程(xxx.exe) -> ntdll.dll -> kernel32.dll 使用InInitializationOrderLinks查找,模块的顺序为当前进程ntdll.dll -> kernelbase.dll -> kernel32.dll

通过代码可以验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
DWORD pebAddr = 0;
__asm {
mov eax, fs: [0x30]
mov pebAddr, eax
}
PEB* peb = (PEB*)pebAddr;
PEB_LDR_DATA* ldr = peb->Ldr;

// 获得InLoadOrderLinks的头节点
LIST_ENTRY* InLoadOrderHeader = (LIST_ENTRY*)&ldr->Reserved2[1];

// 获得InMemoryOrderLinks的头节点
LIST_ENTRY* InMemoryOrderHeader= &ldr->InMemoryOrderModuleList;

// 获得InInitializationOrderLinks的头节点
LIST_ENTRY* InInitializationOrderHeader = (LIST_ENTRY*)((DWORD)ldr + 0x1C);

cout << "-----------------------------------" << endl;
cout << "find by InLoadOrderLinks:" << endl;
cout << "-----------------------------------" << endl;
for (LIST_ENTRY* first = InLoadOrderHeader->Flink; first != InLoadOrderHeader; first = first->Flink) {
UNICODE_STRING* name = (UNICODE_STRING*)((DWORD)first + 0x24);
printf("%S \n", name->Buffer);
}

cout << endl << "-----------------------------------" << endl;
cout << "find by InMemoryOrderLinks:" << endl;
cout << "-----------------------------------" << endl;
for (LIST_ENTRY* first = InMemoryOrderHeader->Flink; first != InMemoryOrderHeader; first = first->Flink) {
UNICODE_STRING* name2 = (UNICODE_STRING*)((DWORD)first + 0x1C);
printf("%S \n", name2->Buffer);
}

cout << endl << "-----------------------------------" << endl;
cout << "find by InInitializationOrderLinks:" << endl;
cout << "-----------------------------------" << endl;
for (LIST_ENTRY* first = InInitializationOrderHeader->Flink; first != InInitializationOrderHeader; first = first->Flink) {
UNICODE_STRING* name3 = (UNICODE_STRING*)((DWORD)first + 0x14);
printf("%S \n", name3->Buffer);
}
cout << "-----------------------------------" << endl;
system("pause");

输出的结果为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-----------------------------------
find by InLoadOrderLinks:
-----------------------------------
D:\test.exe
C:\WINDOWS\SYSTEM32\ntdll.dll
C:\WINDOWS\System32\KERNEL32.DLL
C:\WINDOWS\System32\KERNELBASE.dll
C:\WINDOWS\SYSTEM32\ucrtbased.dll
C:\WINDOWS\SYSTEM32\VCRUNTIME140D.dll
C:\WINDOWS\SYSTEM32\MSVCP140D.dll

-----------------------------------
find by InMemoryOrderLinks:
-----------------------------------
D:\test.exe
C:\WINDOWS\SYSTEM32\ntdll.dll
C:\WINDOWS\System32\KERNEL32.DLL
C:\WINDOWS\System32\KERNELBASE.dll
C:\WINDOWS\SYSTEM32\ucrtbased.dll
C:\WINDOWS\SYSTEM32\VCRUNTIME140D.dll
C:\WINDOWS\SYSTEM32\MSVCP140D.dll

-----------------------------------
find by InInitializationOrderLinks:
-----------------------------------
C:\WINDOWS\SYSTEM32\ntdll.dll
C:\WINDOWS\System32\KERNELBASE.dll
C:\WINDOWS\System32\KERNEL32.DLL
C:\WINDOWS\SYSTEM32\ucrtbased.dll
C:\WINDOWS\SYSTEM32\VCRUNTIME140D.dll
C:\WINDOWS\SYSTEM32\MSVCP140D.dll
-----------------------------------
可以发现无论是用哪个Links寻找kernel32.dll都需要3次,因为任意选一个即可,这里使用InLoadOrderLinks寻找
1
2
3
4
5
6
7
8
9
10
11
__asm {
mov eax, fs: [0x30] // get peb
mov eax, dword ptr[eax + 0xC] // get PEB_LDR_DATA
mov esi, dword ptr[eax + 0xC] // get InLoadOrderModuleList
mov esi, dword ptr[esi]
lodsd // get kernel32.dll LDR_DATA_TABLE_ENTRY
lea edx, dword ptr[eax + 0x24] // get kernel32.dll name address
mov nameAddr, edx
mov eax, dword ptr[eax + 0x18] // get kernel32.dll address
mov kernel32Addr, eax
}
输出结果为
1
2
name: C:\WINDOWS\System32\KERNEL32.DLL
kernel32.dll Address is: 76760000