Implementation of GetProcAddress and GetModuleHandle
for Windows NT3.51/NT4/2000/XP/2003/Vista kernel mode,
both 32 and 64 bit platforms
Methods description
I'm astonished, so many people ask questions like "How to get address of some exported function from ntdll.dll dynamically, when we know only the name of this function ?". People, please find the answer below. These are sources of kernel-mode implementation of Win32 GetModuleHandle() and GetProcAddress(). In general, this code (except KernelGetModuleBase3()) should work not only for kernel-mode, but for user-mode too if you use ntdll.dll.
Main appliance of these functions is writing drivers with unified binary (.SYS) those work under different NT OS versions. Together with PsGetVersion() they give you a power to work wonders. Lets go.
KernelGetModuleBase()
Standard and the most legal solution is to use Nt/ZwQuerySystemInformation(SystemModuleInfo, ...). We obtain list of loaded modules, walk through it looking for required name and parse its export section. Thats all - golden key is in our pocket. The only limitation is presence of adequate NtQuerySystemInformation() implementation in ntdll.dll. NT3 has not it at all. ReactOS has dummy do-nothing implementation. Not too good.
But it has greate advantage: it works under 64-bit platforms. We should just update (thanks to Dmitri Arkhangelski, author of ultradefrag) SYSTEM_MODULE_INFORMATION structure definition.
KernelGetModuleBase3()
There is another implementation of GetModuleHandle() (thanks to Egor Yuzik). It doesn't use NtQuerySystemInformation which appeared in NT4. The implementation itself - KernelGetModuleBase3(), is universal for all Windows NT-family OS'es. The main idea is to use undocumented filed PVOID SectionHandle from DRIVER_OBJECT structure. This is actually pointer to LDR_DATA_TABLE_ENTRY describing corresponding driver. All such structures are linked in bidirectional list (see LoadOrder member in LDR_DATA_TABLE_ENTRY structure) and cover all modules loaded in memory. The root record of the list (also called PsLoadedModuleList) is located just before LDR_DATA_TABLE_ENTRY structure corresponding to NTOSKRNL.EXE.
Note: Some interesting issues were found during further testing of new code.
Issue 1
When looking for ntoskrnl.exe and hal.dll modules with KernelGetModuleBase3(), these modules always have such names (e.g. kernel is always named ntoskrnl.exe and HAL - always hal.dll). But when we use KernelGetModuleBase(), modules are named according to their real file names. For example if ntkrnlpa.exe or ntkrnlmp.exe is loaded as kernel, KernelGetModuleBase("ntoskrnl.exe") shall return NULL, while KernelGetModuleBase("ntkrnlpa.exe") - proper address. But KernelGetModuleBase("ntoskrnl.exe") works always. The same policy is applied to HAL. Rather useful feature, I should say.
Issue 2
KernelGetModuleBase3() seemed to be an ultimate solution. But in Windows prior to Win 2000 for BOOT-drivers (those are loaded by ntldr and have Start=0 in registry) PVOID SectionHandle member of DRIVER_OBJECT is always NULL. In this case KernelGetModuleBase3() doesn't work (see above why). So, you cannot use this function from your BOOT-driver. I've also found that NtUnloadDriver() checks this value to determine if the driver can be unloaded. It is assumed, that BOOT-drivers are not unloadable and the sign of BOOT-drivers is SectionHandle == NULL.
Issue 3
ReactOS source review shown, that they use SectionHandle in a different way. Thus, such approach is inapplicable there.
KernelGetModuleBaseByPtr()
I had to invent still one approach - KernelGetModuleBaseByPtr(). The idea: we build our driver so that it imports at least one function (or variable) from the module we are interested in. Let it be ntoskrnl.exe. The function is chosen to be present in all versions on Windows NT, e.g. DbgPrint(). We take its address and start looking for valid MZ/PE header at descending addresses. Very helpful fact: header is always aligned on page boundary (PAGE_SIZE=4096 for x86 family). Address of the first valid header would ModuleHandle of required module. You can use it in KernelGetProcAddress() calls. This technique shall work under all NT- and 9x-compatible OSes, in both kernel- and user-modes in 32- and 64-bit addressing modes.
Note: Do not forget, that when you write code for getting address of imported function like this:
PVOID f_ptr=DbgPrint; |
f_ptr may receive address of the call-stub, that belongs to your module:
yourmodule!DbgPrint: |
but it is also possible, that the function you chosen, really begins with such instruction. For example starting from Windows 2000
ntoskrnl!IofCallDriver: |
Plus, some antivuruses, firewalls and other useful (and not) drivers can insert at the very beginning of system functions JMP to themselves. And some other guys hook module load procedure and patch import addresses directly inside your module. I tell this to show, that there is no universal solution and you must be careful when using described mothods. And I also tell this for those people, who write such clever and tricky drivers: please, think about compatibility with other cunning ones ;).
For better reliability I would recommend to check if derived ModuleHandle is not equal to our own. If it is equal, we got stub address inside our module instead of real exported function entry point. In this case we shall extract real address from the stub. For example with SkipImportStub(). When we alredy think, that ModuleHandle is in our hands, it would be nice to check, that this module actually exports the function we have started from. If we start from address of DbgPrint and get to module which doesn't export such function, somethig goes wrong.
Note 2: Exkurs proposed better way - to import NtBuildNumber from ntoskrnl.exe. This constant is available in all versions of WinNT and we need not to check if address of NtBuildNumber is a call stub.
Limitations: along with the fact that this is a hack, significant weakness of this method is impossibility of finding in memory arbitrary module by its name.
ModuleBaseByPeb()
To draw full picture, I'll mention still one way - KernelGetModuleBaseByPeb(). It is similar to KernelGetModuleBase3(). The difference is that, LDR_DATA_TABLE_ENTRY is taken from PEB - Process Environment Block. Since PEB belongs to Win32 processes, we can use this method in appropriate execution context only (e.g. in context of Win32 or Native aplication). It shall not work in system threads.
Note: Since Windows 2003 R2 KTHREAD_HDR structure is changed This is the structure where we take PEB pointer. Look here for new definition.
MiLocateExportName
Just for education: the following function (not exported) exists since Win 2000:
PVOID |
It has same functionality as KernelGetProcAddress().
Thanks to DeastSoft for reference.
Functions and Appliance table
Function | OS | Kernel mode | 32bit User mode (Win32/native) | |||
NT | ReactOS | 9x | 32-bit | 64-bit | ||
KernelGetProcAddress() | + | + | + | + | + | + |
SkipImportStub() | + | + | + | + | - | + |
KernelGetModuleBase() | 4.0+ | - | - | + | + | + |
KernelGetModuleBase3() | 3.51+ | - | - | w2k+ 3.51,4.0 except for boot drivers | - | - |
KernelGetModuleBaseByPtr() | 3.51+ | + | + | + | - | + |
KernelGetModuleBaseByPeb() | 3.51(?) 4.0+ | ? | - | in context of user-mode thread only (e.g. IoControl handler) | - | + |
Sources
- KernelGetModuleBase() (NT 4.0+)
- SYSTEM_MODULE_INFORMATION (Win 64-bit)
- KernelGetProcAddress()
- RtlImageDirectoryEntryToData() (NT family)
- LDR_DATA_TABLE_ENTRY (NT family)
- KernelGetModuleBase3() (NT 3.51+)
- SkipImportStub()
- KernelGetModuleBaseByPtr()
- KTHREAD_HDR (NT3 - 2003)
- KTHREAD_HDR_2003_R2 (2003 R2)
- TEB
- PEB
- PEB_LDR_DATA
- KernelGetModuleBaseByPeb()
KernelGetModuleBase
NT 4.0 and higherPVOID
KernelGetModuleBase(
PCHAR pModuleName
)
{
PVOID pModuleBase = NULL;
PULONG pSystemInfoBuffer = NULL;
__try
{
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
ULONG SystemInfoBufferSize = 0;
status = ZwQuerySystemInformation(SystemModuleInfo,
&SystemInfoBufferSize,
0,
&SystemInfoBufferSize);
if (!SystemInfoBufferSize)
return NULL;
pSystemInfoBuffer = (PULONG)ExAllocatePool(NonPagedPool, SystemInfoBufferSize*2);
if (!pSystemInfoBuffer)
return NULL;
memset(pSystemInfoBuffer, 0, SystemInfoBufferSize*2);
status = ZwQuerySystemInformation(SystemModuleInfo,
pSystemInfoBuffer,
SystemInfoBufferSize*2,
&SystemInfoBufferSize);
if (NT_SUCCESS(status))
{
PSYSTEM_MODULE_ENTRY pSysModuleEntry =
((PSYSTEM_MODULE_INFORMATION)(pSystemInfoBuffer))->Module;
ULONG i;
for (i = 0; i <((PSYSTEM_MODULE_INFORMATION)(pSystemInfoBuffer))->Count; i++)
{
if (_stricmp(pSysModuleEntry[i].ModuleName +
pSysModuleEntry[i].ModuleNameOffset, pModuleName) == 0)
{
pModuleBase = pSysModuleEntry[i].ModuleBaseAddress;
break;
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
pModuleBase = NULL;
}
if(pSystemInfoBuffer) {
ExFreePool(pSystemInfoBuffer);
}
return pModuleBase;
} // end KernelGetModuleBase()
SYSTEM_MODULE_INFORMATION
// Class 11
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY
{
ULONG Unknown1;
ULONG Unknown2;
#ifdef _WIN64
ULONG Unknown3;
ULONG Unknown4;
#endif
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT NameLength;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
RtlImageDirectoryEntryToData
PVOID
RtlImageDirectoryEntryToData(
IN PVOID Base,
IN BOOLEAN MappedAsImage,
IN USHORT DirectoryEntry,
OUT PULONG Size
);
KernelGetProcAddress
PVOID
KernelGetProcAddress(
PVOID ModuleBase,
PCHAR pFunctionName
)
{
PVOID pFunctionAddress = NULL;
__try
{
#ifndef WIN9X_SUPPORT
ULONG size = 0;
PIMAGE_EXPORT_DIRECTORY exports =(PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(ModuleBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
ULONG addr = (PUCHAR)((ULONG)exports-(ULONG)ModuleBase);
#else
PIMAGE_DOS_HEADER dos =(PIMAGE_DOS_HEADER) ModuleBase;
PIMAGE_NT_HEADERS nt =(PIMAGE_NT_HEADERS)((ULONG) ModuleBase + dos->e_lfanew);
PIMAGE_DATA_DIRECTORY expdir = (PIMAGE_DATA_DIRECTORY)
(nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT);
ULONG addr = expdir->VirtualAddress;
PIMAGE_EXPORT_DIRECTORY exports =(PIMAGE_EXPORT_DIRECTORY)((ULONG) ModuleBase + addr);
#endif
PULONG functions =(PULONG)((ULONG) ModuleBase + exports->AddressOfFunctions);
PSHORT ordinals =(PSHORT)((ULONG) ModuleBase + exports->AddressOfNameOrdinals);
PULONG names =(PULONG)((ULONG) ModuleBase + exports->AddressOfNames);
ULONG max_name =exports->NumberOfNames;
ULONG max_func =exports->NumberOfFunctions;
ULONG i;
for (i = 0; i < max_name; i++)
{
ULONG ord = ordinals[i];
if(i >= max_name || ord >= max_func) {
return NULL;
}
if (functions[ord] <>= addr + size)
{
if (strcmp((PCHAR) ModuleBase + names[i], pFunctionName) == 0)
{
pFunctionAddress =(PVOID)((PCHAR) ModuleBase + functions[ord]);
break;
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
pFunctionAddress = NULL;
}
return pFunctionAddress;
} // end KernelGetProcAddress()
LDR_DATA_TABLE_ENTRY
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY LoadOrder;
LIST_ENTRY MemoryOrder;
LIST_ENTRY InitializationOrder;
PVOID ModuleBaseAddress;
PVOID EntryPoint;
ULONG ModuleSize;
UNICODE_STRING FullModuleName;
UNICODE_STRING ModuleName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY Hash;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
ULONG TimeStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
KernelGetModuleBase3
NT 3.51 and higherPLIST_ENTRY g_LoadOrderListHead = NULL;
PVOID
KernelGetModuleBase3(
PDRIVER_OBJECT DriverObject,
PCHAR pModuleName
)
{
PVOID pModuleBase = NULL;
PLIST_ENTRY Next;
PLIST_ENTRY LoadOrderListHead;
UNICODE_STRING uStr;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry0;
ULONG len;
BOOLEAN FreeUstr = FALSE;
uStr.Buffer = NULL;
__try
{
if(!g_LoadOrderListHead) {
LdrDataTableEntry0 = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection;
uStr.Length = sizeof(L"NTOSKRNL.EXE")-sizeof(WCHAR);
uStr.MaximumLength = sizeof(L"NTOSKRNL.EXE");
uStr.Buffer = L"NTOSKRNL.EXE";
Next = LdrDataTableEntry0->LoadOrder.Blink;
while ( TRUE ) {
LdrDataTableEntry = CONTAINING_RECORD( Next,
LDR_DATA_TABLE_ENTRY,
LoadOrder
);
Next = Next->Blink;
if(!LdrDataTableEntry->ModuleName.Buffer) {
return NULL;
}
if(RtlCompareUnicodeString(&LdrDataTableEntry->ModuleName, &uStr, TRUE) == 0)
{
LoadOrderListHead = Next;
break;
}
if(LdrDataTableEntry == LdrDataTableEntry0)
return NULL;
}
g_LoadOrderListHead = LoadOrderListHead;
} else {
LoadOrderListHead = g_LoadOrderListHead;
}
len = strlen(pModuleName);
if(!len)
return NULL;
len = (len+1)*sizeof(WCHAR);
uStr.MaximumLength = (USHORT)len;
uStr.Length = (USHORT)len - sizeof(WCHAR);
uStr.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, len);
FreeUstr = TRUE;
swprintf(uStr.Buffer, L"%S", pModuleName);
Next = LoadOrderListHead->Flink;
while ( Next != LoadOrderListHead ) {
LdrDataTableEntry = CONTAINING_RECORD( Next,
LDR_DATA_TABLE_ENTRY,
LoadOrder
);
if(RtlCompareUnicodeString(&LdrDataTableEntry->ModuleName, &uStr, TRUE) == 0)
{
pModuleBase = LdrDataTableEntry->ModuleBaseAddress;
break;
}
Next = Next->Flink;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
pModuleBase = NULL;
}
if(FreeUstr && uStr.Buffer) {
ExFreePool(uStr.Buffer);
}
return pModuleBase;
} // end KernelGetModuleBase3()
SkipImportStub
For entire 32-bit Windows family on x86 (e.g. ReactOS, Win9x)PVOID
SkipImportStub(
PVOID p
)
{
if(((PUCHAR)p)[0] == 0xff && ((PUCHAR)p)[1] == 0x25) {
p = (PVOID)(*(PULONG)(*(PULONG)((ULONG)p+2)));
}
return p;
} // end SkipImportStub()
KernelGetModuleBaseByPtr
For entire 32-bit Windows family on x86 (e.g. ReactOS, Win9x)PVOID
KernelGetModuleBaseByPtr(
IN PVOID ptrInSection,
IN PCHAR ptrExportedName
)
{
PUCHAR p;
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nt;
p = (PUCHAR)((ULONG)ptrInSection & ~(PAGE_SIZE-1));
for(;p;p -= PAGE_SIZE) {
__try
{
dos = (PIMAGE_DOS_HEADER)p;
if(dos->e_magic != 0x5a4d) // MZ
continue;
nt = (PIMAGE_NT_HEADERS)((ULONG)dos + dos->e_lfanew);
if((ULONG)nt >= (ULONG)ptrInSection)
continue;
if((ULONG)nt <= (ULONG)dos)
continue;
if(nt->Signature != 0x00004550) // PE
continue;
if(!ptrExportedName) {
break;
} else {
if(ptrInSection == KernelGetProcAddress(p, ptrExportedName)) {
break;
}
}
p = NULL;
break;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
return p;
} // end KernelGetModuleBaseByPtr()
PEB_LDR_DATA
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
HANDLE SsHandle;
LIST_ENTRY LoadOrder;
LIST_ENTRY MemoryOrder;
LIST_ENTRY InitializationOrder;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
PEB
typedef struct _PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
BOOLEAN SpareBool;
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PVOID FastPebLockRoutine;
PVOID FastPebUnlockRoutine;
ULONG EnvironmentUpdateCount;
PVOID KernelCallbackTable;
HANDLE EventLogSection;
PVOID EventLog;
PPEB_FREE_BLOCK FreeList;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[2]; // relates to TLS_MINIMUM_AVAILABLE
PVOID ReadOnlySharedMemoryBase;
PVOID ReadOnlySharedMemoryHeap;
PVOID *ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
// Useful information for LdrpInitialize
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
// Passed up from MmCreatePeb from Session Manager registry key
LARGE_INTEGER CriticalSectionTimeout;
ULONG HeapSegmentReserve;
ULONG HeapSegmentCommit;
ULONG HeapDeCommitTotalFreeThreshold;
ULONG HeapDeCommitFreeBlockThreshold;
// Where heap manager keeps track of all heaps created for a process
// Fields initialized by MmCreatePeb. ProcessHeaps is initialized
// to point to the first free byte after the PEB and MaximumNumberOfHeaps
// is computed from the page size used to hold the PEB, less the fixed
// size of this data structure.
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID *ProcessHeaps;
//
//
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
PVOID GdiDCAttributeList;
PVOID LoaderLock;
// Following fields filled in by MmCreatePeb from system values and/or
// image header.
ULONG OSMajorVersion;
ULONG OSMinorVersion;
ULONG OSBuildNumber;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
ULONG ImageProcessAffinityMask;
ULONG GdiHandleBuffer[GDI_HANDLE_BUFFER_SIZE];
} PEB, *PPEB;
TEB
typedef struct _TEB {
NT_TIB NtTib;
PVOID EnvironmentPointer;
CLIENT_ID ClientId;
PVOID ActiveRpcHandle;
PVOID ThreadLocalStoragePointer;
PPEB ProcessEnvironmentBlock;
ULONG LastErrorValue;
ULONG CountOfOwnedCriticalSections;
PVOID CsrClientThread;
PVOID Win32ThreadInfo; // PtiCurrent
ULONG Win32ClientInfo[WIN32_CLIENT_INFO_LENGTH]; // User32 Client Info
PVOID WOW32Reserved; // used by WOW
LCID CurrentLocale;
ULONG FpSoftwareStatusRegister;
PVOID SystemReserved1[54]; // Used by FP emulator
PVOID Spare1; // unused
NTSTATUS ExceptionCode; // for RaiseUserException
UCHAR SpareBytes1[40];
PVOID SystemReserved2[10]; // Used by user/console for temp obja
GDI_TEB_BATCH GdiTebBatch; // Gdi batching
ULONG gdiRgn;
ULONG gdiPen;
ULONG gdiBrush;
CLIENT_ID RealClientId;
HANDLE GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PVOID GdiThreadLocalInfo;
PVOID UserReserved[5]; // unused
PVOID glDispatchTable[280]; // OpenGL
ULONG glReserved1[26]; // OpenGL
PVOID glReserved2; // OpenGL
PVOID glSectionInfo; // OpenGL
PVOID glSection; // OpenGL
PVOID glTable; // OpenGL
PVOID glCurrentRC; // OpenGL
PVOID glContext; // OpenGL
ULONG LastStatusValue;
UNICODE_STRING StaticUnicodeString;
WCHAR StaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
PVOID DeallocationStack;
PVOID TlsSlots[TLS_MINIMUM_AVAILABLE];
LIST_ENTRY TlsLinks;
PVOID Vdm;
PVOID ReservedForNtRpc;
PVOID DbgSsReserved[2];
ULONG HardErrorsAreDisabled;
PVOID Instrumentation[16];
PVOID WinSockData; // WinSock
ULONG GdiBatchCount;
ULONG Spare2;
ULONG Spare3;
ULONG Spare4;
PVOID ReservedForOle;
ULONG WaitingOnLoaderLock;
} TEB;
KTHREAD_HDR, KTHREAD_HDR_2003_R2
Seems, the following is valid for OSes prior to 2003-R2.
typedef struct _KTHREAD_HDR {
// The dispatcher header and mutant listhead are faifly infrequently
// referenced, but pad the thread to a 32-byte boundary (assumption
// that pool allocation is in units of 32-bytes).
DISPATCHER_HEADER Header;
LIST_ENTRY MutantListHead;
// The following fields are referenced during trap, interrupts, or
// context switches.
//
// N.B. The Teb address and TlsArray are loaded as a quadword quantity
// on MIPS and therefore must to on a quadword boundary.
PVOID InitialStack;
PVOID StackLimit;
PVOID Teb ;
PVOID TlsArray;
PVOID KernelStack;
BOOLEAN DebugActive;
UCHAR State;
BOOLEAN Alerted[MaximumMode];
UCHAR Iopl;
UCHAR NpxState;
BOOLEAN Saturation;
SCHAR Priority;
/*
.........
*/
} KTHREAD_HDR, *PKTHREAD_HDR;
typedef struct _KTHREAD_HDR_2003_R2 {
DISPATCHER_HEADER Header;
LIST_ENTRY MutantListHead;
PVOID InitialStack;
PVOID StackLimit;
/*
Several new items here
*/
PVOID Teb ; // offset 0x74
/*
.........
*/
} KTHREAD_HDR_2003_R2, *PKTHREAD_HDR_2003_R2;
KernelGetModuleBaseByPeb
__declspec (naked)
PVOID
__stdcall
GetCurrentKThread(void)
{
_asm {
mov eax,fs:[124h]
ret
}
}
/************************/
PKTHREAD_HDR KThread;
PPEB Peb = NULL;
PPEB_LDR_DATA Ldr = NULL;
PTEB Teb;
PLIST_ENTRY InitialEntry;
PLIST_ENTRY LoadOrderListHead;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
KThread = (PKTHREAD_HDR)GetCurrentKThread();
if(!KThread)
return NULL;
if(WinVer_Id() >= WIN_VER_2003_R2) {
Teb = (PTEB)(( ((PKTHREAD_HDR_2003_R2)KThread) ->Teb);
} else {
Teb = (PTEB)(KThread->Teb);
}
if(!Teb)
return NULL;
Peb = Teb->ProcessEnvironmentBlock;
if(!Peb)
return NULL;
Ldr = Peb->Ldr;
if(!Ldr)
return NULL;
InitialEntry = Ldr->InitializationOrder.Flink;
LdrDataTableEntry = CONTAINING_RECORD( InitialEntry,
LDR_DATA_TABLE_ENTRY,
InitializationOrder
);
LoadOrderListHead = LdrDataTableEntry->LoadOrder.Blink;
/************************/
Samples
Sample 1
PVOID NtKrnlModuleHandle;
PVOID ptrNtBuildNumber;
PVOID ptrIofCallDriver;
// get address of variable inside "ntoskrnl.exe"
ptrNtBuildNumber = &NtBuildNumber;
// get base address of "ntoskrnl.exe" image
NtKrnlModuleHandle = KernelGetModuleBaseByPtr(ptrNtBuildNumber, "NtBuildNumber");
// locate exported function "IofCallDriver" inside "ntoskrnl.exe"
ptrIofCallDriver = KernelGetProcAddress(NtKrnlModuleHandle, "IofCallDriver");
Sample 2
PVOID NtKrnlModuleHandle;
PVOID ptrDbgPrint;
PVOID ptrIofCallDriver;
// get address of function inside "ntoskrnl.exe"
ptrDbgPrint = SkipImportStub(DbgPrint);
// get base address of "ntoskrnl.exe" image
NtKrnlModuleHandle = KernelGetModuleBaseByPtr(ptrDbgPrint, "DbgPrint");
// locate exported function "IofCallDriver" inside "ntoskrnl.exe"
ptrIofCallDriver = KernelGetProcAddress(NtKrnlModuleHandle, "IofCallDriver");
Sample 3
PVOID OurDriverModuleHandle;
// get base address of our driver image
OurDriverModuleHandle = KernelGetModuleBaseByPtr(DriverEntry, "DriverEntry");
Sample 4
PVOID NtKrnlModuleHandle;
PVOID ptrIofCallDriver;
// get base address of our driver image
NtKrnlModuleHandle = KernelGetModuleBase3(DriverObject, "ntoskrnl.exe");
// locate exported function "IofCallDriver" inside "ntoskrnl.exe"
ptrIofCallDriver = KernelGetProcAddress(NtKrnlModuleHandle, "IofCallDriver");
2006.08.27
reflink: http://alter.org.ua/en/docs/nt_kernel/procaddr/#methods