- How long you been coding/hacking?
- 5 years
Undocumented Windows API Functions & Structures
You will need to access and use many undocumented Windows API functions and structures in the course of your hacking career. In the Windows SDK there is a file called winternl.h which has many structures which are important to us, but many of them have "Reserved" member variables that Microsoft doesn't want us to know about and doesn't want us to use but everyone uses them regardless, especially antiviruses and other low level software. Using the winternl.h versions will not allow you complete access to everything you may need.
People have reversed these structured and defined them for us.
Undocumented NT Internals Website
In this part of your learning the best resource for browsing and getting to know them is undocumented.ntinternals.net because they are nicely organized and displayed.
x64dbg ntdll header file
When it comes to including these structures and function prototypes in your project I recommend using the x64dbg ntdll.h header file as it is the most recently updated and x64dbg is actively developed by a large group of people.
ReactOS
ReactOS can be regarded as a Windows clone, it can load PE files just like Windows so there source code is super helpful for learning about the internal workings of Windows. While we're talking about the Windows Loader, this function specifically is a great resource: CreateProcessInternal
Another cool site:
Vergilius Project
winternl.h
winternl.h contains many of these items but they have member variables labeled "reserved" which is not helpful. For some things the wintern.h header is fine but as you start to do more advanced stuff you will probably want to avoid using it. Mixing and matching winternl.h and the x64dbg header for instance will cause you a headache. My solution to this problem is I prefixed all the x64dbg structures with _RFW_ so they don't interfere with any Windows definitions, you may want to do the same.
Most Important undocumented items for game hacking
The most important "undocumented" items for game hacking which you will want to learn about are:
The reason they are important is because one of the first things you will want to do is to parse the linked list of loaded modules in the Peb->Ldr to either hide your module or to find hidden modules. The TIB contains a pointer to the TEB, the TEB contains a pointer to the PEB and the PEB contains a pointer to the PEB_LDR_DATA linked list.
To introduce you to the topic of undocumented nt internals we will show you how to play with the Ldr
_THREAD_BASIC_INFORMATION
Important because it contains a pointer to the TEB
Thread Environment Block
Lots of juicy stuff here, most importantly it contains a pointer to the PEB
Process Environment Block
Every running process has a PEB, it's a structure that resides in usermode. This structure underlies the functionality of many Windows API functions. For instance it contains the BeingDebugged bool, when you call IsDebuggerPresent it is actually just checking this flag. It contains the ImageBaseAddress which is the memory address of the main .exe.
The PEB looks like this, taken from the x64dbg header file:
PEB_LDR_DATA
Most importantly the PEB contains a pointer to the Ldr, defined as _PPEB_LDR_DATA. All the other information provided here was to get you to the Ldr. The Ldr contains linked lists starting with InLoadOrderModuleList which contains all the modules loaded in memory for the process. This is what is used on the backend for ToolHelp32Snapshot etc...
If you have to hide a module to bypass anticheat or something like that, hooking all the functions which wrap this structure isn't always enough. You will find yourself having to parse this list and modify it.
The Ldr looks like this:
NTQueryInformationProcess
NtQueryInformationProcess is a "undocumented" Windows API function, this is your entry point to grabbing the PEB which will enable you to parse it. Using this function is a good entrypoint to learning about Windows internals. Use the PROCESS_BASIC_INFORMATION argument and you can get an address to the PEB.
Get the PEB using NtQueryInformationProcess() Externally
Get the PEB Internally
Much easier internally, you read the fs segment register offset 0x30/0x60 that gives you address of the PEB depending if you're on x86 or x64.
Parsing the PEB_LDR_DATA linked list
Once you've gotten the PEB you can access the Ldr. Here is a function which takes a module name, such as "client.dll" and returns you the Ldr and a wrapper which grabs the base address.
You can see how I use this function to pattern scan modules internally without using ToolHelp32Snapshot Guide - External & Internal Pattern Scanning Guide
There are several other similar functions here
https://guidedhacking.com/threads/internal-safe-getmodulehandlew-getprocaddress.13565/
How to Hide Module from PEB Ldr
Source Code - How to Hide Module from PEB
Here is a function from Broihon which does something similar but it uses NtQueryInformationProcess, MemoryBasicInformation & section data
What if you need more advanced, 100% guranteed up to date structures?
@iPower shared a tip which is important you can easily dump these structures by:
- Using the dt command - WinDbg
- Opening ntoskrnl.exe in IDA Pro, loading the symbols (you can ask IDA to download them or use PDBDownloader and manually open the pdbs) and going to View -> Open subviews -> Local types
- PDBDownloader + pdbex
Conclusion
Now you have a basic understanding of the undocumented nt internals, you've gained some hands on experience parsing the Ldr module list and should you need to use any of these functions or structures you will be ready to do so in the future.
Learn about SysCalls from @timb3r
Tutorial - Understanding Windows SysCalls - SysCall Dumper
At this point in your research you may also want to read this thread
Guide - PE File Format & Windows PE Loader
Discuss - Collection of undocumented windows functions from ntdll
Guide - Hidden structure definitions in UxTheme.dll
Geoff Chappell, Software Analyst
Vergilius Project
You will need to access and use many undocumented Windows API functions and structures in the course of your hacking career. In the Windows SDK there is a file called winternl.h which has many structures which are important to us, but many of them have "Reserved" member variables that Microsoft doesn't want us to know about and doesn't want us to use but everyone uses them regardless, especially antiviruses and other low level software. Using the winternl.h versions will not allow you complete access to everything you may need.
People have reversed these structured and defined them for us.
Undocumented NT Internals Website
In this part of your learning the best resource for browsing and getting to know them is undocumented.ntinternals.net because they are nicely organized and displayed.
x64dbg ntdll header file
When it comes to including these structures and function prototypes in your project I recommend using the x64dbg ntdll.h header file as it is the most recently updated and x64dbg is actively developed by a large group of people.
ReactOS
ReactOS can be regarded as a Windows clone, it can load PE files just like Windows so there source code is super helpful for learning about the internal workings of Windows. While we're talking about the Windows Loader, this function specifically is a great resource: CreateProcessInternal
Another cool site:
Vergilius Project
winternl.h
winternl.h contains many of these items but they have member variables labeled "reserved" which is not helpful. For some things the wintern.h header is fine but as you start to do more advanced stuff you will probably want to avoid using it. Mixing and matching winternl.h and the x64dbg header for instance will cause you a headache. My solution to this problem is I prefixed all the x64dbg structures with _RFW_ so they don't interfere with any Windows definitions, you may want to do the same.
Most Important undocumented items for game hacking
The most important "undocumented" items for game hacking which you will want to learn about are:
The reason they are important is because one of the first things you will want to do is to parse the linked list of loaded modules in the Peb->Ldr to either hide your module or to find hidden modules. The TIB contains a pointer to the TEB, the TEB contains a pointer to the PEB and the PEB contains a pointer to the PEB_LDR_DATA linked list.
To introduce you to the topic of undocumented nt internals we will show you how to play with the Ldr
_THREAD_BASIC_INFORMATION
Important because it contains a pointer to the TEB
C++:
typedef struct _THREAD_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
PVOID TebBaseAddress;
CLIENT_ID ClientId;
ULONG_PTR AffinityMask;
KPRIORITY Priority;
LONG BasePriority;
} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
Lots of juicy stuff here, most importantly it contains a pointer to the PEB
C++:
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;
ULONG User32Reserved[26];
ULONG UserReserved[5];
PVOID WOW32Reserved;
LCID CurrentLocale;
ULONG FpSoftwareStatusRegister;
PVOID ReservedForDebuggerInstrumentation[16];
#ifdef _WIN64
PVOID SystemReserved1[30];
#else
PVOID SystemReserved1[26];
#endif
CHAR PlaceholderCompatibilityMode;
CHAR PlaceholderReserved[11];
ULONG ProxiedProcessId;
ACTIVATION_CONTEXT_STACK ActivationStack;
UCHAR WorkingOnBehalfTicket[8];
NTSTATUS ExceptionCode;
PACTIVATION_CONTEXT_STACK ActivationContextStackPointer;
ULONG_PTR InstrumentationCallbackSp;
ULONG_PTR InstrumentationCallbackPreviousPc;
ULONG_PTR InstrumentationCallbackPreviousSp;
#ifdef _WIN64
ULONG TxFsContext;
#endif
BOOLEAN InstrumentationCallbackDisabled;
#ifndef _WIN64
UCHAR SpareBytes[23];
ULONG TxFsContext;
#endif
GDI_TEB_BATCH GdiTebBatch;
CLIENT_ID RealClientId;
HANDLE GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PVOID GdiThreadLocalInfo;
ULONG_PTR Win32ClientInfo[62];
PVOID glDispatchTable[233];
ULONG_PTR glReserved1[29];
PVOID glReserved2;
PVOID glSectionInfo;
PVOID glSection;
PVOID glTable;
PVOID glCurrentRC;
PVOID glContext;
NTSTATUS LastStatusValue;
UNICODE_STRING StaticUnicodeString;
WCHAR StaticUnicodeBuffer[261];
PVOID DeallocationStack;
PVOID TlsSlots[64];
LIST_ENTRY TlsLinks;
PVOID Vdm;
PVOID ReservedForNtRpc;
PVOID DbgSsReserved[2];
ULONG HardErrorMode;
#ifdef _WIN64
PVOID Instrumentation[11];
#else
PVOID Instrumentation[9];
#endif
GUID ActivityId;
PVOID SubProcessTag;
PVOID PerflibData;
PVOID EtwTraceData;
PVOID WinSockData;
ULONG GdiBatchCount;
union
{
PROCESSOR_NUMBER CurrentIdealProcessor;
ULONG IdealProcessorValue;
struct
{
UCHAR ReservedPad0;
UCHAR ReservedPad1;
UCHAR ReservedPad2;
UCHAR IdealProcessor;
} s1;
} u1;
ULONG GuaranteedStackBytes;
PVOID ReservedForPerf;
PVOID ReservedForOle;
ULONG WaitingOnLoaderLock;
PVOID SavedPriorityState;
ULONG_PTR ReservedForCodeCoverage;
PVOID ThreadPoolData;
PVOID* TlsExpansionSlots;
#ifdef _WIN64
PVOID DeallocationBStore;
PVOID BStoreLimit;
#endif
ULONG MuiGeneration;
ULONG IsImpersonating;
PVOID NlsCache;
PVOID pShimData;
USHORT HeapVirtualAffinity;
USHORT LowFragHeapDataSlot;
HANDLE CurrentTransactionHandle;
PTEB_ACTIVE_FRAME ActiveFrame;
PVOID FlsData;
PVOID PreferredLanguages;
PVOID UserPrefLanguages;
PVOID MergedPrefLanguages;
ULONG MuiImpersonation;
union
{
USHORT CrossTebFlags;
USHORT SpareCrossTebBits : 16;
} u2;
union
{
USHORT SameTebFlags;
struct
{
USHORT SafeThunkCall : 1;
USHORT InDebugPrint : 1;
USHORT HasFiberData : 1;
USHORT SkipThreadAttach : 1;
USHORT WerInShipAssertCode : 1;
USHORT RanProcessInit : 1;
USHORT ClonedThread : 1;
USHORT SuppressDebugMsg : 1;
USHORT DisableUserStackWalk : 1;
USHORT RtlExceptionAttached : 1;
USHORT InitialThread : 1;
USHORT SessionAware : 1;
USHORT LoadOwner : 1;
USHORT LoaderWorker : 1;
USHORT SkipLoaderInit : 1;
USHORT SpareSameTebBits : 1;
} s2;
} u3;
PVOID TxnScopeEnterCallback;
PVOID TxnScopeExitCallback;
PVOID TxnScopeContext;
ULONG LockCount;
LONG WowTebOffset;
PVOID ResourceRetValue;
PVOID ReservedForWdf;
ULONGLONG ReservedForCrt;
GUID EffectiveContainerId;
Process Environment Block
Every running process has a PEB, it's a structure that resides in usermode. This structure underlies the functionality of many Windows API functions. For instance it contains the BeingDebugged bool, when you call IsDebuggerPresent it is actually just checking this flag. It contains the ImageBaseAddress which is the memory address of the main .exe.
The PEB looks like this, taken from the x64dbg header file:
C++:
typedef struct _PEB
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser32Forwarders : 1;
BOOLEAN IsPackagedProcess : 1;
BOOLEAN IsAppContainer : 1;
BOOLEAN IsProtectedProcessLight : 1;
BOOLEAN IsLongPathAwareProcess : 1;
} s1;
} u1;
HANDLE Mutant;
PVOID ImageBaseAddress;
_PPEB_LDR_DATA Ldr;
_PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PVOID AtlThunkSListPtr;
PVOID IFEOKey;
union
{
ULONG CrossProcessFlags;
struct
{
ULONG ProcessInJob : 1;
ULONG ProcessInitializing : 1;
ULONG ProcessUsingVEH : 1;
ULONG ProcessUsingVCH : 1;
ULONG ProcessUsingFTH : 1;
ULONG ProcessPreviouslyThrottled : 1;
ULONG ProcessCurrentlyThrottled : 1;
ULONG ReservedBits0 : 25;
} s2;
} u2;
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
} u3;
ULONG SystemReserved[1];
ULONG AtlThunkSListPtr32;
PVOID ApiSetMap;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[2];
PVOID ReadOnlySharedMemoryBase;
PVOID SharedData; // HotpatchInformation
PVOID* ReadOnlyStaticServerData;
PVOID AnsiCodePageData; // PCPTABLEINFO
PVOID OemCodePageData; // PCPTABLEINFO
PVOID UnicodeCaseTableData; // PNLSTABLEINFO
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
LARGE_INTEGER CriticalSectionTimeout;
SIZE_T HeapSegmentReserve;
SIZE_T HeapSegmentCommit;
SIZE_T HeapDeCommitTotalFreeThreshold;
SIZE_T HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID* ProcessHeaps; // PHEAP
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
ULONG GdiDCAttributeList;
PRTL_CRITICAL_SECTION LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
USHORT OSBuildNumber;
USHORT OSCSDVersion;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
ULONG_PTR ActiveProcessAffinityMask;
GDI_HANDLE_BUFFER GdiHandleBuffer;
PVOID PostProcessInitRoutine;
PVOID TlsExpansionBitmap;
ULONG TlsExpansionBitmapBits[32];
ULONG SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
PVOID pShimData;
PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA
_UNICODE_STRING CSDVersion;
PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA
PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA
PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
SIZE_T MinimumStackCommit;
PVOID* FlsCallback;
LIST_ENTRY FlsListHead;
PVOID FlsBitmap;
ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)];
ULONG FlsHighIndex;
PVOID WerRegistrationData;
PVOID WerShipAssertPtr;
PVOID pUnused; // pContextData
PVOID pImageHeaderHash;
union
{
ULONG TracingFlags;
struct
{
ULONG HeapTracingEnabled : 1;
ULONG CritSecTracingEnabled : 1;
ULONG LibLoaderTracingEnabled : 1;
ULONG SpareTracingBits : 29;
} s3;
} u4;
ULONGLONG CsrServerReadOnlySharedMemoryBase;
PVOID TppWorkerpListLock;
LIST_ENTRY TppWorkerpList;
PVOID WaitOnAddressHashTable[128];
PVOID TelemetryCoverageHeader; // REDSTONE3
ULONG CloudFileFlags;
}
Most importantly the PEB contains a pointer to the Ldr, defined as _PPEB_LDR_DATA. All the other information provided here was to get you to the Ldr. The Ldr contains linked lists starting with InLoadOrderModuleList which contains all the modules loaded in memory for the process. This is what is used on the backend for ToolHelp32Snapshot etc...
If you have to hide a module to bypass anticheat or something like that, hooking all the functions which wrap this structure isn't always enough. You will find yourself having to parse this list and modify it.
The Ldr looks like this:
C++:
typedef struct _RFW_PEB_LDR_DATA
{
ULONG Length;
BOOLEAN Initialized;
HANDLE SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
BOOLEAN ShutdownInProgress;
HANDLE ShutdownThreadId;
} *RFW_PPEB_LDR_DATA;
NtQueryInformationProcess is a "undocumented" Windows API function, this is your entry point to grabbing the PEB which will enable you to parse it. Using this function is a good entrypoint to learning about Windows internals. Use the PROCESS_BASIC_INFORMATION argument and you can get an address to the PEB.
C++:
typedef struct _PROCESS_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
PPEB PebBaseAddress;
ULONG_PTR AffinityMask;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
C++:
typedef NTSTATUS(__stdcall* tNtQueryInformationProcess)
(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
tNtQueryInformationProcess NtQueryInfoProc = nullptr;
bool ImportNTQueryInfo()
{
NtQueryInfoProc = (tNtQueryInformationProcess)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationProcess");
if (NtQueryInfoProc == nullptr)
{
return false;
}
else return true;
}
PEB GetPEB()
{
PROCESS_BASIC_INFORMATION pbi;
PEB peb = { 0 };
if (!NtQueryInfoProc) ImportNTQueryInfo();
if (NtQueryInfoProc)
{
NTSTATUS status = NtQueryInfoProc(handle, ProcessBasicInformation, &pbi, sizeof(pbi), 0);
if (NT_SUCCESS(status))
{
ReadProcessMemory(handle, pbi.PebBaseAddress, &peb, sizeof(peb), 0);
}
}
return peb;
}
Much easier internally, you read the fs segment register offset 0x30/0x60 that gives you address of the PEB depending if you're on x86 or x64.
C++:
__readfsdword(0x30); //x86
__readgsqword(0x60); //x64
Parsing the PEB_LDR_DATA linked list
Once you've gotten the PEB you can access the Ldr. Here is a function which takes a module name, such as "client.dll" and returns you the Ldr and a wrapper which grabs the base address.
C++:
PEB* GetPEBInternal()
{
#ifdef _WIN64
PEB* peb = (PEB*)__readgsqword(0x60);
#else
PEB* peb = (PEB*)__readfsdword(0x30);
#endif
return peb;
}
LDR_DATA_TABLE_ENTRY* GetLDREntryInternal(const wchar_t* modName)
{
LDR_DATA_TABLE_ENTRY* modEntry = nullptr;
PEB* peb = GetPEBInternal();
LIST_ENTRY head = peb->Ldr->InMemoryOrderModuleList;
LIST_ENTRY curr = head;
for (auto curr = head; curr.Flink != &peb->Ldr->InMemoryOrderModuleList; curr = *curr.Flink)
{
LDR_DATA_TABLE_ENTRY* mod = (LDR_DATA_TABLE_ENTRY*)CONTAINING_RECORD(curr.Flink, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (mod->BaseDllName.Buffer)
{
if (_wcsicmp(modName, mod->BaseDllName.Buffer) == 0)
{
modEntry = mod;
break;
}
}
}
return modEntry;
}
char* GetModuleBaseAddressInternalPEB(const wchar_t* modName)
{
LDR_DATA_TABLE_ENTRY* modEntry = GetLDREntryInternal(modName);
return (char*)modEntry->DllBase;
}
There are several other similar functions here
https://guidedhacking.com/threads/internal-safe-getmodulehandlew-getprocaddress.13565/
How to Hide Module from PEB Ldr
Source Code - How to Hide Module from PEB
Here is a function from Broihon which does something similar but it uses NtQueryInformationProcess, MemoryBasicInformation & section data
C++:
UINT EnumModulesNTQVM(HANDLE hTargetProcess)
{
MEMORY_BASIC_INFORMATION MBI{ 0 };
SECTION_INFO section_info[2] = { 0, 0 };
section_info[0].MaxLen = sizeof(SECTION_INFO::pData);
section_info[0].szData = reinterpret_cast<wchar_t*>(section_info[0].pData);
section_info[1].MaxLen = sizeof(SECTION_INFO::pData);
section_info[1].szData = reinterpret_cast<wchar_t*>(section_info[1].pData);
UINT ret{ 0 };
while (NT_SUCCESS(NT::NtQueryVirtualMemory(hTargetProcess, MBI.BaseAddress, MEMORYINFOCLASS::MemoryBasicInformation, &MBI, sizeof(MBI), nullptr)))
{
if (MBI.State & MEM_COMMIT)
{
if (NT_SUCCESS(NT::NtQueryVirtualMemory(hTargetProcess, MBI.BaseAddress, MEMORYINFOCLASS::MemoryMappedFilenameInformation, §ion_info[0], sizeof(SECTION_INFO), nullptr)))
{
void * CurrentModuleBase = MBI.BaseAddress;
DWORD CurrentModuleSize = 0;
NT::NtQueryVirtualMemory(hTargetProcess, MBI.BaseAddress, MEMORYINFOCLASS::MemoryMappedFilenameInformation, §ion_info[1], sizeof(SECTION_INFO), nullptr);
while (!wcscmp(section_info[0].szData, section_info[1].szData))
{
MBI.BaseAddress = reinterpret_cast<BYTE*>(MBI.BaseAddress) + MBI.RegionSize;
CurrentModuleSize += MBI.RegionSize;
NT::NtQueryVirtualMemory(hTargetProcess, MBI.BaseAddress, MEMORYINFOCLASS::MemoryBasicInformation, &MBI, sizeof(MBI), nullptr);
if (NT_FAIL(NT::NtQueryVirtualMemory(hTargetProcess, MBI.BaseAddress, MEMORYINFOCLASS::MemoryMappedFilenameInformation, §ion_info[1], sizeof(SECTION_INFO), nullptr)))
{
break;
}
}
printf("%ls\n\t%p\n\t%08X\n\n", section_info[0].szData, CurrentModuleBase, CurrentModuleSize);
}
else
{
MBI.BaseAddress = reinterpret_cast<BYTE*>(MBI.BaseAddress) + MBI.RegionSize;
}
}
else
{
MBI.BaseAddress = reinterpret_cast<BYTE*>(MBI.BaseAddress) + MBI.RegionSize;
}
}
return ret;
}
@iPower shared a tip which is important you can easily dump these structures by:
- Using the dt command - WinDbg
- Opening ntoskrnl.exe in IDA Pro, loading the symbols (you can ask IDA to download them or use PDBDownloader and manually open the pdbs) and going to View -> Open subviews -> Local types
- PDBDownloader + pdbex
Conclusion
Now you have a basic understanding of the undocumented nt internals, you've gained some hands on experience parsing the Ldr module list and should you need to use any of these functions or structures you will be ready to do so in the future.
Learn about SysCalls from @timb3r
Tutorial - Understanding Windows SysCalls - SysCall Dumper
At this point in your research you may also want to read this thread
Guide - PE File Format & Windows PE Loader
Discuss - Collection of undocumented windows functions from ntdll
Guide - Hidden structure definitions in UxTheme.dll
Geoff Chappell, Software Analyst
Vergilius Project
Last edited: