一 原理和概述
找kernel32基地址的方法一般有三种:暴力搜索法、异常处理链表搜索法、PEB法。
暴力搜索法是最早的动态查找kernel32基地址的方法。它的原理是: 几乎所有的win32可执行文件(pe格
式文件)运行的时候都加载kernel32.dll,可执行文件进入入口点执行后esp中存放的一般是
Kernel32.DLL 中的某个地址,沿着这个地址向上查找就可以找到kernel32的基地址。
那么如何知道找到的地址是kernel32的基地址?
因为kernel32.dll也是标准的pe结构文件,pe结构文件的开始是IMAGE_DOS_HEADER结构,
IMAGE_DOS_HEADER结构的第一个字段是e_magic,它的值为’MZ’用于证明这是DOS兼容的
文件类型,所以如果我们找到的地址所指向的字符串为’MZ’,那么我们可以确信这是kernel32的基地址
所谓异常处理链表就是系统提供的处理异常的机制,当系统遇到一个不知道如何处理的异常时就会查找异
常处理链表,找到对应的异常处理程序,把保存的处理程序地址赋给eip,并执行处理程序,避免系统崩
溃,异常处理链表的最后一项
是默认异常处理函数UnhandledExceptionFilter,因为UnhandledExceptionFilter在kernel32中,所以从
UNhandledExceptionFilter地址向上搜索即可找到kernel32的基地址
PEB法
在NT内核系统中fs寄存器指向TEB结构,TEB+0x30处指向PEB结构,PEB+0x0c处指向PEB_LDR_DATA结构,
PEB_LDR_DATA+0x1c处存放一些动态链接库地址,第一个指向ntdl.dll,第二个就是kernel32.dll的基地址了
此方法是通过TEB获得PEB结构地址,然后再获得PEB_LDR_DATA结构地址,然后遍历模块列表,查找kernel32.dll模块的基地址。
TEB是线程环境块(Thread Environment Block)结构, 我们的fs段选择子所对应的段指向TEB,也就是fs:[0]指向TEB.那么TEB的ProcessEnvironmentBlock结构成员指
向我们的PEB进程环境块结构(Process Environment Block),然后通过PEB结构来获得PEB_LDR_DATA。 接下来我们通过windbg来查看下相关结构。
看下TEB结构,通过windbg的dt命令。
lkd> 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
可以看到TEB结构的0x30偏移处存储的我们的PEB结构的地址
二 PEB和TEB结构
1 TEB结构
//
// Thread Environment Block (TEB)
//
typedef struct _TEB
{
NT_TIB Tib; /* 00h */
PVOID EnvironmentPointer; /* 1Ch */
CLIENT_ID Cid; /* 20h */
PVOID ActiveRpcHandle; /* 28h */
PVOID ThreadLocalStoragePointer; /* 2Ch */
struct _PEB *ProcessEnvironmentBlock; /* 30h */
ULONG LastErrorValue; /* 34h */
ULONG CountOfOwnedCriticalSections; /* 38h */
PVOID CsrClientThread; /* 3Ch */
struct _W32THREAD* Win32ThreadInfo; /* 40h */
ULONG User32Reserved[0x1A]; /* 44h */
ULONG UserReserved[5]; /* ACh */
PVOID WOW32Reserved; /* C0h */
LCID CurrentLocale; /* C4h */
ULONG FpSoftwareStatusRegister; /* C8h */
PVOID SystemReserved1[0x36]; /* CCh */
LONG ExceptionCode; /* 1A4h */
struct _ACTIVATION_CONTEXT_STACK *ActivationContextStackPointer; /* 1A8h */
UCHAR SpareBytes1[0x28]; /* 1ACh */
GDI_TEB_BATCH GdiTebBatch; /* 1D4h */
CLIENT_ID RealClientId; /* 6B4h */
PVOID GdiCachedProcessHandle; /* 6BCh */
ULONG GdiClientPID; /* 6C0h */
ULONG GdiClientTID; /* 6C4h */
PVOID GdiThreadLocalInfo; /* 6C8h */
ULONG Win32ClientInfo[62]; /* 6CCh */
PVOID glDispatchTable[0xE9]; /* 7C4h */
ULONG glReserved1[0x1D]; /* B68h */
PVOID glReserved2; /* BDCh */
PVOID glSectionInfo; /* BE0h */
PVOID glSection; /* BE4h */
PVOID glTable; /* BE8h */
PVOID glCurrentRC; /* BECh */
PVOID glContext; /* BF0h */
NTSTATUS LastStatusValue; /* BF4h */
UNICODE_STRING StaticUnicodeString; /* BF8h */
WCHAR StaticUnicodeBuffer[0x105]; /* C00h */
PVOID DeallocationStack; /* E0Ch */
PVOID TlsSlots[0x40]; /* E10h */
LIST_ENTRY TlsLinks; /* F10h */
PVOID Vdm; /* F18h */
PVOID ReservedForNtRpc; /* F1Ch */
PVOID DbgSsReserved[0x2]; /* F20h */
ULONG HardErrorDisabled; /* F28h */
PVOID Instrumentation[14]; /* F2Ch */
PVOID SubProcessTag; /* F64h */
PVOID EtwTraceData; /* F68h */
PVOID WinSockData; /* F6Ch */
ULONG GdiBatchCount; /* F70h */
BOOLEAN InDbgPrint; /* F74h */
BOOLEAN FreeStackOnTermination; /* F75h */
BOOLEAN HasFiberData; /* F76h */
UCHAR IdealProcessor; /* F77h */
ULONG GuaranteedStackBytes; /* F78h */
PVOID ReservedForPerf; /* F7Ch */
PVOID ReservedForOle; /* F80h */
ULONG WaitingOnLoaderLock; /* F84h */
ULONG SparePointer1; /* F88h */
ULONG SoftPatchPtr1; /* F8Ch */
ULONG SoftPatchPtr2; /* F90h */
PVOID *TlsExpansionSlots; /* F94h */
ULONG ImpersionationLocale; /* F98h */
ULONG IsImpersonating; /* F9Ch */
PVOID NlsCache; /* FA0h */
PVOID pShimData; /* FA4h */
ULONG HeapVirualAffinity; /* FA8h */
PVOID CurrentTransactionHandle; /* FACh */
PTEB_ACTIVE_FRAME ActiveFrame; /* FB0h */
PVOID FlsData; /* FB4h */
UCHAR SafeThunkCall; /* FB8h */
UCHAR BooleanSpare[3]; /* FB9h */
} TEB, *PTEB;
2 PEB结构
typedef struct _PEB
{
UCHAR InheritedAddressSpace; // 00h
UCHAR ReadImageFileExecOptions; // 01h
UCHAR BeingDebugged; // 02h
UCHAR Spare; // 03h
PVOID Mutant; // 04h
PVOID ImageBaseAddress; // 08h
PPEB_LDR_DATA Ldr; // 0Ch
PRTL_USER_PROCESS_PARAMETERS ProcessParameters; // 10h
PVOID SubSystemData; // 14h
PVOID ProcessHeap; // 18h
PVOID FastPebLock; // 1Ch
PPEBLOCKROUTINE FastPebLockRoutine; // 20h
PPEBLOCKROUTINE FastPebUnlockRoutine; // 24h
ULONG EnvironmentUpdateCount; // 28h
PVOID* KernelCallbackTable; // 2Ch
PVOID EventLogSection; // 30h
PVOID EventLog; // 34h
PPEB_FREE_BLOCK FreeList; // 38h
ULONG TlsExpansionCounter; // 3Ch
PVOID TlsBitmap; // 40h
ULONG TlsBitmapBits[0x2]; // 44h
PVOID ReadOnlySharedMemoryBase; // 4Ch
PVOID ReadOnlySharedMemoryHeap; // 50h
PVOID* ReadOnlyStaticServerData; // 54h
PVOID AnsiCodePageData; // 58h
PVOID OemCodePageData; // 5Ch
PVOID UnicodeCaseTableData; // 60h
ULONG NumberOfProcessors; // 64h
ULONG NtGlobalFlag; // 68h
UCHAR Spare2[0x4]; // 6Ch
LARGE_INTEGER CriticalSectionTimeout; // 70h
ULONG HeapSegmentReserve; // 78h
ULONG HeapSegmentCommit; // 7Ch
ULONG HeapDeCommitTotalFreeThreshold; // 80h
ULONG HeapDeCommitFreeBlockThreshold; // 84h
ULONG NumberOfHeaps; // 88h
ULONG MaximumNumberOfHeaps; // 8Ch
PVOID** ProcessHeaps; // 90h
PVOID GdiSharedHandleTable; // 94h
PVOID ProcessStarterHelper; // 98h
PVOID GdiDCAttributeList; // 9Ch
PVOID LoaderLock; // A0h
ULONG OSMajorVersion; // A4h
ULONG OSMinorVersion; // A8h
ULONG OSBuildNumber; // ACh
ULONG OSPlatformId; // B0h
ULONG ImageSubSystem; // B4h
ULONG ImageSubSystemMajorVersion; // B8h
ULONG ImageSubSystemMinorVersion; // C0h
ULONG GdiHandleBuffer[0x22]; // C4h
PVOID ProcessWindowStation; // ???
} PEB, *PPEB;
原理:在NT内核系统中fs寄存器指向TEB结构,TEB+0x30处指向PEB结构,PEB+0x0c处指向PEB_LDR_DATA结构,
PEB_LDR_DATA+0x1c处存放一些动态链接库地址,第一个指向ntdl.dll,第二个就是kernel32.dll的基地址了
三 暴力搜索法代码
1 程序1
#include "stdafx.h"
#include <stdio.h>
int main()
{
_asm { jmp Start }
int ieax;
_asm{
Start:
GetKernelBase: ;查找 kernel地址
mov eax,7c800000h ;因为有非法访问我直接把我本机的kerne32.dll地址(7c800000h)
给eax 就可以了
Compare:
cmp eax,80000000h
jl SearchFinal
cmp word ptr[eax],'ZM'
je FindedKernelBase
add eax,010000h
jmp Compare
}
FindedKernelBase:
{
_asm{ mov ieax,eax}
printf("kernel addr offset %x \n",ieax);
return 0;
}
SearchFinal :
{ //;查找结束
printf("find kernel faild \n ");
return 0;
}
return 0;
}
2 程序2,汇编代码
;**********获得image of kernel32.dll的基址*****************GetKBase:
mov edi , [esp+04h]
and edi , 0FFFF0000h
.while TRUE
.if WORD ptr [edi] == IMAGE_DOS_SIGNATURE ;判断是否是MZ
mov esi, edi
add esi, DWORD ptr [esi+03Ch] ;esi指向PE标志
.if DWORD ptr [esi] ==IMAGE_NT_SIGNATURE;是否有PE标志
.break;如果有跳出循环
.endif
.endif
sub edi, 010000h
.if edi < MIN_KERNEL_SEARCH_BASE ;win9x
mov edi, 0bff70000h ;0bff7000h=9x"base
.break
.endif
.endw
mov hKernel32[ebx],edi;把找到的KERNEL32。DLL的基地址保存起来
ret
四 异常处理链表搜索法代码
1 程序1
这个方法适用于XP, win7上获得是ntdll.dll的地址。
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwKrnlAddr = 0;
__asm
{
mov edx, fs:[0] // 获得EXCEPTION_REGISTRATION结构地址
Next:
inc dword ptr [edx] // 将prev+1,如果是-1为0
jz Krnl
dec dword ptr [edx] // 不为-1,还原
mov edx, [edx] // 获得prev指向的地址
jmp Next
Krnl:
dec dword ptr [edx] // 恢复
mov edx, [edx + 4] // 获得handle指向的地址
Looop:
cmp word ptr [edx], 'ZM'
jz IsPe
dec edx
xor dx, dx
jmp Looop
IsPe:
mov eax, dword ptr [edx + 3ch]
cmp word ptr [edx + eax], 'EP'
jnz Next
mov dwKrnlAddr, edx
}
_tprintf(TEXT("Kernel32.dll address: %x\r\n"), dwKrnlAddr);
_tprintf(TEXT("GetModuleHandle Kernel32.dll address: %x\r\n"),
GetModuleHandle(TEXT("kernel32.dll")));
return 0;
}
五 PEB法代码
1 程序1
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwKrnlAddr = 0;
__asm
{
mov edx, fs:[30h] // 取得PEB
mov edx, [edx + 0ch] // PEB_LDR_DATA
mov edx, [edx + 1ch] // 获得InInitializationOrderModuleList.Flink指向的地址,也即指向第一个LDR_MODULE
mov edx, [edx] // 因为edx当前为InInitializationOrderModuleList
// 而它的第一成员Flink又指向下一个LDR_MODULE, 所以直接读取就是下一个
mov edx, [edx + 8h]
mov dwKrnlAddr, edx
}
_tprintf(TEXT("Kernel32.dll address: %x\r\n"), dwKrnlAddr);
_tprintf(TEXT("GetModuleHandle Kernel32.dll address: %x\r\n"),
GetModuleHandle(TEXT("kernel32.dll")));
return 0;
}