Skip to content

Instantly share code, notes, and snippets.

@hasherezade
Last active January 31, 2024 11:56
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save hasherezade/87158b926e33418f5d3b0a0026d0ccc2 to your computer and use it in GitHub Desktop.
Save hasherezade/87158b926e33418f5d3b0a0026d0ccc2 to your computer and use it in GitHub Desktop.
Get PEB64 from a WOW64 process
#include <Windows.h>
#include <iostream>
#include "ntdll_undoc.h"
PPEB get_default_peb()
{
#if defined(_WIN64)
return (PPEB)__readgsqword(0x60);
#else
return (PPEB)__readfsdword(0x30);
#endif
}
PPEB64 get_peb64(HANDLE hProcess, OUT PROCESS_BASIC_INFORMATION_WOW64 &pbi64)
{
if (NtWow64QueryInformationProcess64 == nullptr) {
return nullptr;
}
//reset structure:
memset(&pbi64,0, sizeof(PROCESS_BASIC_INFORMATION_WOW64));
ULONG outLength = 0;
NTSTATUS status = NtWow64QueryInformationProcess64(
hProcess,
ProcessBasicInformation,
&pbi64,
sizeof(PROCESS_BASIC_INFORMATION_WOW64),
&outLength
);
if (status != STATUS_SUCCESS) {
return nullptr;
}
return (PPEB64) pbi64.PebBaseAddress;
}
int main()
{
BOOL isWow64 = FALSE;
IsWow64Process(GetCurrentProcess(), &isWow64);
std::cout << "IsWow64" << " : " << isWow64 << std::endl;
if (init_ntdll_func(isWow64) == false) {
printf("Cannot load functions!\n");
return -1;
}
PPEB myPeb = get_default_peb();
std::cout << "PEB: \t" ;
std::cout << std::hex << myPeb << std::endl;
PPEB64 pebWow64 = nullptr;
if (isWow64) {
PROCESS_BASIC_INFORMATION_WOW64 pbi64 = { 0 };
pebWow64 = get_peb64(GetCurrentProcess(), pbi64);
if (pebWow64 == nullptr) {
std::cerr << "Fetching PEB64 failed!" << std::endl;
return -1;
}
std::cout << "PEB64:\t" ;
std::cout << std::hex << pebWow64 << std::endl;
}
std::cout << "ImageBaseAddress from PEB: \t" << std::hex << myPeb->ImageBaseAddress << std::endl;
if (pebWow64 != nullptr) {
std::cout << "ImageBaseAddress from PEB64: \t" << std::hex << pebWow64->ImageBaseAddress << std::endl;
}
system("pause");
return 0;
}
#include "ntdll_undoc.h"
NTSTATUS (NTAPI *RtlCreateProcessParametersEx)(
_Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters,
_In_ PUNICODE_STRING ImagePathName,
_In_opt_ PUNICODE_STRING DllPath,
_In_opt_ PUNICODE_STRING CurrentDirectory,
_In_opt_ PUNICODE_STRING CommandLine,
_In_opt_ PVOID Environment,
_In_opt_ PUNICODE_STRING WindowTitle,
_In_opt_ PUNICODE_STRING DesktopInfo,
_In_opt_ PUNICODE_STRING ShellInfo,
_In_opt_ PUNICODE_STRING RuntimeData,
_In_ ULONG Flags // pass RTL_USER_PROC_PARAMS_NORMALIZED to keep parameters normalized
) = nullptr;
NTSTATUS (NTAPI *NtWow64ReadVirtualMemory64)(
IN HANDLE ProcessHandle,
IN PVOID64 BaseAddress,
OUT PVOID Buffer,
IN ULONG64 Size,
OUT PULONG64 NumberOfBytesRead
) = nullptr;
NTSTATUS (NTAPI *NtWow64QueryInformationProcess64) (
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
) = nullptr;
bool init_wow64_func(HMODULE lib)
{
if (lib == nullptr) {
return false;
}
FARPROC proc = GetProcAddress(lib, "NtWow64ReadVirtualMemory64");
if (proc == nullptr) {
return false;
}
NtWow64ReadVirtualMemory64 = (NTSTATUS (NTAPI *)(
HANDLE,
PVOID64,
PVOID,
ULONG64,
PULONG64
)) proc;
proc = GetProcAddress(lib, "NtWow64QueryInformationProcess64");
if (proc == nullptr) {
return false;
}
NtWow64QueryInformationProcess64 = (NTSTATUS (NTAPI *)(
HANDLE,
PROCESSINFOCLASS,
PVOID,
ULONG,
PULONG
)) proc;
return true;
}
bool init_ntdll_func(BOOL isWow64)
{
HMODULE lib = LoadLibraryA("ntdll.dll");
if (lib == nullptr) {
return false;
}
FARPROC proc = GetProcAddress(lib, "RtlCreateProcessParametersEx");
if (proc == nullptr) {
return false;
}
RtlCreateProcessParametersEx = (NTSTATUS (NTAPI *)(
PRTL_USER_PROCESS_PARAMETERS*,
PUNICODE_STRING,
PUNICODE_STRING,
PUNICODE_STRING,
PUNICODE_STRING,
PVOID,
PUNICODE_STRING,
PUNICODE_STRING,
PUNICODE_STRING,
PUNICODE_STRING,
ULONG
)) proc;
if (isWow64) {
if (!init_wow64_func(lib)) {
return false;
}
}
return true;
}
#pragma once
#include <Windows.h>
#include "ntddk.h"
#include "ntdll_types.h"
//Structures:
typedef struct _PROCESS_BASIC_INFORMATION_WOW64
{
NTSTATUS ExitStatus;
ULONG64 PebBaseAddress;
ULONG64 AffinityMask;
KPRIORITY BasePriority;
ULONG64 UniqueProcessId;
ULONG64 InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION_WOW64, *PPROCESS_BASIC_INFORMATION_WOW64;
typedef struct _UNICODE_STRING_WOW64 {
USHORT Length;
USHORT MaximumLength;
PVOID64 Buffer;
} UNICODE_STRING_WOW64;
// PEB 64:
typedef struct _PEB64 {
BYTE Reserved[16];
PVOID64 ImageBaseAddress;
PVOID64 LdrData;
PVOID64 ProcessParameters;
} PEB64, *PPEB64;
typedef struct _CURDIR64
{
UNICODE_STRING_WOW64 DosPath;
HANDLE Handle;
} CURDIR64, *PCURDIR64;
typedef struct _RTL_USER_PROCESS_PARAMETERS64
{
ULONG MaximumLength; // Should be set before call RtlCreateProcessParameters
ULONG Length; // Length of valid structure
ULONG Flags; // Currently only PPF_NORMALIZED (1) is known:
// - Means that structure is normalized by call RtlNormalizeProcessParameters
ULONG DebugFlags;
PVOID64 ConsoleHandle; // HWND to console window associated with process (if any).
ULONG ConsoleFlags;
DWORD64 StandardInput;
DWORD64 StandardOutput;
DWORD64 StandardError;
CURDIR64 CurrentDirectory; // Specified in DOS-like symbolic link path, ex: "C:/WinNT/SYSTEM32"
UNICODE_STRING_WOW64 DllPath; // DOS-like paths separated by ';' where system should search for DLL files.
UNICODE_STRING_WOW64 ImagePathName; // Full path in DOS-like format to process'es file image.
UNICODE_STRING_WOW64 CommandLine; // Command line
PVOID64 Environment; // Pointer to environment block (see RtlCreateEnvironment)
ULONG StartingX;
ULONG StartingY;
ULONG CountX;
ULONG CountY;
ULONG CountCharsX;
ULONG CountCharsY;
ULONG FillAttribute; // Fill attribute for console window
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING_WOW64 WindowTitle;
UNICODE_STRING_WOW64 DesktopInfo; // Name of WindowStation and Desktop objects, where process is assigned
UNICODE_STRING_WOW64 ShellInfo;
UNICODE_STRING_WOW64 RuntimeData;
RTL_DRIVE_LETTER_CURDIR CurrentDirectores[0x20];
ULONG EnvironmentSize;
} RTL_USER_PROCESS_PARAMETERS64, *PRTL_USER_PROCESS_PARAMETERS64;
//Functions:
extern NTSTATUS (NTAPI *RtlCreateProcessParametersEx)(
_Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters,
_In_ PUNICODE_STRING ImagePathName,
_In_opt_ PUNICODE_STRING DllPath,
_In_opt_ PUNICODE_STRING CurrentDirectory,
_In_opt_ PUNICODE_STRING CommandLine,
_In_opt_ PVOID Environment,
_In_opt_ PUNICODE_STRING WindowTitle,
_In_opt_ PUNICODE_STRING DesktopInfo,
_In_opt_ PUNICODE_STRING ShellInfo,
_In_opt_ PUNICODE_STRING RuntimeData,
_In_ ULONG Flags // pass RTL_USER_PROC_PARAMS_NORMALIZED to keep parameters normalized
);
//for 32bit process on 64bit system:
extern NTSTATUS (NTAPI *NtWow64ReadVirtualMemory64)(
IN HANDLE ProcessHandle,
IN PVOID64 BaseAddress,
OUT PVOID Buffer,
IN ULONG64 Size,
OUT PULONG64 NumberOfBytesRead
);
extern NTSTATUS (NTAPI *NtWow64QueryInformationProcess64) (
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
// Initialization function:
bool init_ntdll_func(BOOL isWow64);
@peta909
Copy link

peta909 commented Nov 16, 2020

hi there,
Thank you for sharing your code.
Just a slight error I think for main.cpp line 17,18

if (NtWow64QueryInformationProcess64 == nullptr) { return false;

it should be
if (NtWow64QueryInformationProcess64 == nullptr) { return nullptr;

@hasherezade
Copy link
Author

@peta909 - indeed, thank you for noticing! fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment