Video Tutorial NtQueryInformationProcess - How to loop through Peb Ldr Module List

Hexui Undetected CSGO Cheats PUBG Accounts

Rake

I'm not your friend
Administrator
Jan 21, 2014
13,021
79,068
2,468
Game Name
N/A
Anticheat
N/A
How long you been coding/hacking?
5 years
Coding Language
C++
What you need
Visual Studio
You may be familiar with ToolHelp32Snapshot for getting a list of loaded modules in a target process. There are 3 methods in total, ToolHelp32Snapshot, Peb LDR module linked list and EnumModules.

The Windows API (WinAPI) is Microsoft's core set of application programming interfaces (APIs) available in the Microsoft Windows operating systems. Almost all Windows programs interact with WinAPI. Despite a lot of the APIs and the structures they use being officially documented, there is a portion of them that is not. These APIs have been studied, reversed and documented non-officially.

In this video, you will learn how to get the base address of modules based on information acquired from the PEB, in addition to how to get the PEB externally or internally. In the beginning, the undocumented structs need to be grabbed. These structs may be found on NTinternals, x64dbg ntdll header file or Vergilius project. Then, NtQueryInformationProcess is used to get the PEB. To do so, call NtQueryInformationProcess to get a PROCESS_BASIC_INFORMATION struct which contains an address of the PEB and use ReadProcessMemory to read the PEB of the process. Getting the PEB internally is easier since the address of the PEB can be grabbed from the segment registers.


After having the address to the PEB, the modules list will be scanned to get the base address of the required module. To do so, the modules list is grabbed from the loader (which exists in the PEB) and then looped through, checking the names of the modules, to the determine if the modules is found. One important note to keep in mind is that three versions of the modules exist in the loader (with different order), and if you need to hide your module from anti-cheat then you have to remove it from all three to be sure that the anti-cheat is not searching a version of the list other than the one you removed the module from.

After finishing this video, you will have knowledge about some undocumented WinAPI functions and structs as well as how to get the base address of a module by parsing data from the PEB. With this video you will learn how to use NtQueryInformationProcess to parse the PEB Ldr module linked list. You can use this method as an alternative to using ToolHelp32Snapshot

You can find the NtQueryInformationProcess function exported by ntdll.dll and call the function. This will give you a PROCESS_BASIC_INFORMATION structure which contains the PEB address. The PEB contains the Ldr, the Ldr contains the linked list full of modules. The modules are defined as LDR_DATA_TABLE_ENTRY and contain many useful variables such as dll name, address and size.

C++:
typedef NTSTATUS(__stdcall* tNtQueryInformationProcess)
(
    HANDLE ProcessHandle,
    PROCESSINFOCLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength
    );
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;
This tutorial will teach you how to use undocumented windows structures, of which there are many. Using NtQueryInformationProcess and PROCESS_BASIC_INFORMATION is an alternative to using toolhelp32snapshot.

Sample of the code:
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;
}
Resources
 

Attachments

You can download 0 Attachments
Last edited:
Community Mods