The operating system allocates a structure for every running process that can always be found at
fs:[0x30] from within the process.The PEB structure holds information about the process's heaps,binary image information and ,most importantly,three linked lists regarding loaded modules that have been mapped into process space.The linked lists themseleves differ in purpose from showing the order in which the modules were loaded to the order in which the modules were initialized.The initialization order linked list is of most interest as the order in which
kernel32.dll is initialized is always constant as the second module to be initialized.By walking the list to the second entry,one can deterministically extract the base address for kernel32.dll.
Declarations for PEB:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
typedef struct _PEB
{
2
BOOLEAN InheritedAddressSpace;
3
BOOLEAN ReadImageFileExecOptions;
4
BOOLEAN BeingDebugged;
5
BOOLEAN Spare;
6
HANDLE Mutant;
7
PVOID ImageBaseAddress;
8
PPEB_LDR_DATA LoaderData;
9
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
10
PVOID SubSystemData;
11
PVOID ProcessHeap;
12
PVOID FastPebLock;
13
PPEBLOCKROUTINE FastPebLockRoutine;
14
PPEBLOCKROUTINE FastPebUnlockRoutine;
15
ULONG EnvironmentUpdateCount;
16
PVOID *KernelCallbackTable;
17
PVOID EventLogSection;
18
PVOID EventLog;
19
PPEB_FREE_BLOCK FreeList;
20
ULONG TlsExpansionCounter;
21
PVOID TlsBitmap;
22
ULONG TlsBitmapBits[0x2];
23
PVOID ReadOnlySharedMemoryBase;
24
PVOID ReadOnlySharedMemoryHeap;
25
PVOID *ReadOnlyStaticServerData;
26
PVOID AnsiCodePageData;
27
PVOID OemCodePageData;
28
PVOID UnicodeCaseTableData;
29
ULONG NumberOfProcessors;
30
ULONG NtGlobalFlag;
31
BYTE Spare2[0x4];
32
LARGE_INTEGER CriticalSectionTimeout;
33
ULONG HeapSegmentReserve;
34
ULONG HeapSegmentCommit;
35
ULONG HeapDeCommitTotalFreeThreshold;
36
ULONG HeapDeCommitFreeBlockThreshold;
37
ULONG NumberOfHeaps;
38
ULONG MaximumNumberOfHeaps;
39
PVOID **ProcessHeaps;
40
PVOID GdiSharedHandleTable;
41
PVOID ProcessStarterHelper;
42
PVOID GdiDCAttributeList;
43
PVOID LoaderLock;
44
ULONG OSMajorVersion;
45
ULONG OSMinorVersion;
46
ULONG OSBuildNumber;
47
ULONG OSPlatformId;
48
ULONG ImageSubSystem;
49
ULONG ImageSubSystemMajorVersion;
50
ULONG ImageSubSystemMinorVersion;
51
ULONG GdiHandleBuffer[0x22];
52
ULONG PostProcessInitRoutine;
53
ULONG TlsExpansionBitmap;
54
BYTE TlsExpansionBitmapBits[0x80];
55
ULONG SessionId;
56
} PEB, *PPEB; The LoaderData member of PEB structure is of type PEB_LDR_DATA,as you can see,it's at the 0x0c offset from the head of PEB,and it is defined as below:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
typedef struct _PEB_LDR_DATA
{
2
ULONG Length;
3
BOOLEAN Initialized;
4
PVOID SsHandle;
5
LIST_ENTRY InLoadOrderModuleList;
6
LIST_ENTRY InMemoryOrderModuleList;
7
LIST_ENTRY InInitializationOrderModuleList;
8
} PEB_LDR_DATA, *PPEB_LDR_DATA;
9![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
Declaration for LIST_ENTRY:
1
typedef struct _LIST_ENTRY
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
3
struct _LIST_ENTRY *Flink;
4
struct _LIST_ENTRY *Blink;
5
} LIST_ENTRY, *PLIST_ENTRY; All the modules loaded by the process is cascaded by a list member InInitializationOrderModuleList,and "Kernel32.dll" is always the second item.
The element type of InInitializationOrderModuleList is defined like this:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
typedef struct _LDR_MODULE
{
2
LIST_ENTRY InLoadOrderModuleList;
3
LIST_ENTRY InMemoryOrderModuleList;
4
LIST_ENTRY InInitializationOrderModuleList;
5
PVOID BaseAddress;
6
PVOID EntryPoint;
7
ULONG SizeOfImage;
8
UNICODE_STRING FullDllName;
9
UNICODE_STRING BaseDllName;
10
ULONG Flags;
11
SHORT LoadCount;
12
SHORT TlsIndex;
13
LIST_ENTRY HashTableEntry;
14
ULONG TimeDateStamp;
15
} LDR_MODULE, *PLDR_MODULE; So,to get the base address of "kernel32.dll",you can try this:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
1
FIND_KERNEL32:
2
PUSH ESI;Preserve the ESI register
3
XOR EAX,EAX;Zero the EAX register
4
MOV EAX,FS:[EAX+0X30];Store the address of PEB in EAX
5
TEST EAX,EAX;Bitwidth compare eax with itself
6
JS FIND_KERNEL32_9X;If SF is 1 then it is operating on Windows 9x system,other wise it's running on NT.
7
MOV EAX,[EAX+0X0C];Extract the pointer to Load data structure.
8
MOV ESI,[EAX+0X1C];Extract the first entry in the initialization module list.
9
LODSD;Grab the next entry in the list which points to kernel32.dll
10
MOV EAX,[EAX+0X08];Grab the module base address and store in EAX
11
JMP FIND_KERNEL32_FINISHED;Jump the the end as kernel32.dll has been done.
12
FIND_KERNEL32_9X:
13
MOV EAX,[EAX+0X34];Stores the pointer at offset 0x34 in EAX
14
LEA EAX,[EAX+0X7C];Load the effective address at EAX plus 0x7c to keep us in signed byte range in order to avoid nulls.
15
MOV EAX,[EAX+0X3C];Extract the base address of kernel32.dll
16
FIND_KERNEL32_FINISHED:
17
POP ESI;Restore ESI register
18
RET;Return the caller