Skip to content

Instantly share code, notes, and snippets.

@wizardy0ga
Created June 18, 2024 03:08
Show Gist options
  • Save wizardy0ga/cf8d469ea09515dc33eaf869d0fd8c03 to your computer and use it in GitHub Desktop.
Save wizardy0ga/cf8d469ea09515dc33eaf869d0fd8c03 to your computer and use it in GitHub Desktop.
Dynamically parsing ntdll from the local process using the process environment block & supporting structures
/*
Author:
wizardy0ga
Date:
June 2024
Arch:
x64
Compiler:
MSVC
Description:
Recursively parse modules loaded in the local process via the process environment block.
Note:
I was looking for ways to dynamically parse ntdll from the local process. The function SW3_PopulateSyscallList() in syswhispers3
syscalls.c file does this so i used it as a template. I noticed that Reserved members where used and got curious.
I resolved the undefined structure members and came up with this. It works by parsing the 'InLoadOrderModuleList' & 'InLoadOrderLinks'
members within the PEB_LDR_DATA & LDR_DATA_TABLE_ENTRY structures respectively. String comparison is used here, no hashing on this one.
Reference:
https://ntdoc.m417z.com/
https://github.com/klezVirus/SysWhispers3/blob/31cfc93c9466b52ae79d60925b0b5e0a1f653b88/example-output/Syscalls.c#L142
https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
*/
#include <windows.h>
#include "stdio.h"
/* structs resourced from https://ntdoc.m417z.com/ */
typedef struct _PEB_LDR_DATA
{
ULONG Length;
BOOLEAN Initialized;
HANDLE SsHandle;
LIST_ENTRY InLoadOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef BOOLEAN(NTAPI* PLDR_INIT_ROUTINE)(
_In_ PVOID DllHandle,
_In_ ULONG Reason,
_In_opt_ PVOID Context
);
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PLDR_INIT_ROUTINE EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
/* Borrowed from MSDN */
typedef struct _PEB
{
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
} PEB, * PPEB;
int main() {
WCHAR NtDll[MAX_PATH] = { 0 };
int StringSize = 0;
/* Get a pointer to the peb and initialize a dll entry */
PPEB pPeb = (PPEB)__readgsqword(0x60);
PLDR_DATA_TABLE_ENTRY pEntry = NULL;
/* Loop through each dll in the 'InLoadOrderModuleList' list. */
for (
pEntry = (PLDR_DATA_TABLE_ENTRY)pPeb->Ldr->InLoadOrderModuleList.Flink;
pEntry->DllBase != NULL;
pEntry = (PLDR_DATA_TABLE_ENTRY)pEntry->InLoadOrderLinks.Flink
) {
/* Check buffer size*/
StringSize = lstrlen(pEntry->BaseDllName.Buffer);
if ( StringSize < sizeof(NtDll)) {
/* Convert dll name to lower case */
int i = 0;
for (; i < StringSize; i++) {
NtDll[i] = towlower(pEntry->BaseDllName.Buffer[i]);
}
NtDll[i++] = '\0';
if (lstrcmpW(NtDll, L"ntdll.dll") == 0) {
printf("Found %S base address in memory at 0x%p\n", pEntry->BaseDllName.Buffer, pEntry->DllBase);
}
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment