Created
November 4, 2018 02:40
-
-
Save wbenny/41b2bf4256f28d61bcc336f10650b3d2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////////////////////////////////////////////////////// | |
// General definitions. | |
//////////////////////////////////////////////////////////////////////////////// | |
// | |
// Context flags. | |
// winnt.h (Windows SDK) | |
// | |
#define CONTEXT_i386 0x00010000L | |
#define CONTEXT_AMD64 0x00100000L | |
#define CONTEXT_ARM 0x00200000L | |
#define CONTEXT_ARM64 0x00400000L | |
// | |
// Machine type. | |
// winnt.h (Windows SDK) | |
// | |
#define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001 // Useful for indicating we want to interact with the host and not a WoW guest. | |
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386. | |
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian | |
#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian | |
#define IMAGE_FILE_MACHINE_CHPE_X86 0x3A64 // Hybrid PE (defined in ntimage.h (WDK)) | |
//////////////////////////////////////////////////////////////////////////////// | |
// ntoskrnl.exe | |
//////////////////////////////////////////////////////////////////////////////// | |
typedef struct _PS_NTDLL_EXPORT_ITEM { | |
PCSTR RoutineName; | |
PVOID RoutineAddress; | |
} PS_NTDLL_EXPORT_ITEM, *PPS_NTDLL_EXPORT_ITEM; | |
PS_NTDLL_EXPORT_ITEM NtdllExports[] = { | |
// | |
// 19 exports on x64 | |
// 14 exports on ARM64 | |
// | |
}; | |
PVOID PsWowX86SharedInformation[Wow64SharedPageEntriesCount]; | |
PS_NTDLL_EXPORT_ITEM NtdllWowX86Exports[] = { | |
{ "LdrInitializeThunk", | |
&PsWowX86SharedInformation[SharedNtdll32LdrInitializeThunk] }, | |
{ "KiUserExceptionDispatcher", | |
&PsWowX86SharedInformation[SharedNtdll32KiUserExceptionDispatcher] }, | |
{ "KiUserApcDispatcher", | |
&PsWowX86SharedInformation[SharedNtdll32KiUserApcDispatcher] }, | |
{ "KiUserCallbackDispatcher", | |
&PsWowX86SharedInformation[SharedNtdll32KiUserCallbackDispatcher] }, | |
{ "RtlUserThreadStart", | |
&PsWowX86SharedInformation[SharedNtdll32RtlUserThreadStart] }, | |
{ "RtlpQueryProcessDebugInformationRemote", | |
&PsWowX86SharedInformation[SharedNtdll32pQueryProcessDebugInformationRemote] }, | |
{ "LdrSystemDllInitBlock", | |
&PsWowX86SharedInformation[SharedNtdll32LdrSystemDllInitBlock] }, | |
{ "RtlpFreezeTimeBias", | |
&PsWowX86SharedInformation[SharedNtdll32RtlpFreezeTimeBias] }, | |
}; | |
#ifdef _M_ARM64 | |
PVOID PsWowArm32SharedInformation[Wow64SharedPageEntriesCount]; | |
PS_NTDLL_EXPORT_ITEM NtdllWowArm32Exports[] = { | |
// | |
// ... | |
// | |
}; | |
PVOID PsWowAmd64SharedInformation[Wow64SharedPageEntriesCount]; | |
PS_NTDLL_EXPORT_ITEM NtdllWowAmd64Exports[] = { | |
// | |
// ... | |
// | |
}; | |
PVOID PsWowChpeX86SharedInformation[Wow64SharedPageEntriesCount]; | |
PS_NTDLL_EXPORT_ITEM NtdllWowChpeX86Exports[] = { | |
// | |
// ... | |
// | |
}; | |
#endif // _M_ARM64 | |
// | |
// ... | |
// | |
typedef struct _PS_NTDLL_EXPORT_INFORMATION { | |
PPS_NTDLL_EXPORT_ITEM NtdllExports; | |
SIZE_T Count; | |
} PS_NTDLL_EXPORT_INFORMATION, *PPS_NTDLL_EXPORT_INFORMATION; | |
// | |
// RTL_NUMBER_OF(NtdllExportInformation) | |
// == 6 | |
// == (SYSTEM_DLL_TYPE)PsSystemDllTotalTypes | |
// | |
PS_NTDLL_EXPORT_INFORMATION NtdllExportInformation[PsSystemDllTotalTypes] = { | |
{ NtdllExports, RTL_NUMBER_OF(NtdllExports) }, | |
{ NtdllWowX86Exports, RTL_NUMBER_OF(NtdllWowX86Exports) }, | |
#ifdef _M_ARM64 | |
{ NtdllWowArm32Exports, RTL_NUMBER_OF(NtdllWowArm32Exports) }, | |
{ NtdllWowAmd64Exports, RTL_NUMBER_OF(NtdllWowAmd64Exports) }, | |
{ NtdllWowChpeX86Exports, RTL_NUMBER_OF(NtdllWowChpeX86Exports) }, | |
#endif // _M_ARM64 | |
// | |
// { NULL, 0 } for the rest... | |
// | |
}; | |
typedef struct _PS_SYSTEM_DLL_INFO { | |
// | |
// Flags. | |
// Initialized statically. | |
// | |
USHORT Flags; | |
// | |
// Machine type of this WoW64 NTDLL. | |
// Initialized statically. | |
// Examples: | |
// - IMAGE_FILE_MACHINE_I386 | |
// - IMAGE_FILE_MACHINE_ARMNT | |
// | |
USHORT MachineType; | |
// | |
// Unused, always 0. | |
// | |
ULONG Reserved1; | |
// | |
// Path to the WoW64 NTDLL. | |
// Initialized statically. | |
// Examples: | |
// - "\\SystemRoot\\SysWOW64\\ntdll.dll" | |
// - "\\SystemRoot\\SysArm32\\ntdll.dll" | |
// | |
UNICODE_STRING Ntdll32Path; | |
// | |
// Image base of the DLL. | |
// Initialized at runtime by PspMapSystemDll. | |
// Equivalent of: | |
// RtlImageNtHeader(BaseAddress)-> | |
// OptionalHeader.ImageBase; | |
// | |
PVOID ImageBase; | |
// | |
// Contains DLL name (such as "ntdll.dll" or | |
// "ntdll32.dll") before runtime initialization. | |
// Initialized at runtime by MmMapViewOfSectionEx, | |
// called from PspMapSystemDll. | |
// | |
union { | |
PVOID BaseAddress; | |
PWCHAR DllName; | |
}; | |
// | |
// Unused, always 0. | |
// | |
PVOID Reserved2; | |
// | |
// Section relocation information. | |
// | |
PVOID SectionRelocationInformation; | |
// | |
// Unused, always 0. | |
// | |
PVOID Reserved3; | |
} PS_SYSTEM_DLL_INFO, *PPS_SYSTEM_DLL_INFO; | |
typedef struct _PS_SYSTEM_DLL { | |
// | |
// _SECTION* object of the DLL. | |
// Initialized at runtime by PspLocateSystemDll. | |
// | |
union { | |
EX_FAST_REF SectionObjectFastRef; | |
PVOID SectionObject; | |
}; | |
// | |
// Push lock. | |
// | |
EX_PUSH_LOCK PushLock; | |
// | |
// System DLL information. | |
// This part is returned by PsQuerySystemDllInfo. | |
// | |
PS_SYSTEM_DLL_INFO SystemDllInfo; | |
} PS_SYSTEM_DLL, *PPS_SYSTEM_DLL; | |
//////////////////////////////////////////////////////////////////////////////// | |
// ntdll.dll | |
//////////////////////////////////////////////////////////////////////////////// | |
ULONG | |
RtlpArchContextFlagFromMachine( | |
_In_ USHORT MachineType | |
) | |
/*++ | |
Routine description: | |
This routine translates architecture-specific CONTEXT | |
flag to the machine type. | |
Arguments: | |
MachineType - One of IMAGE_FILE_MACHINE_* values. | |
Return Value: | |
Context flag. | |
Note: | |
RtlpArchContextFlagFromMachine can be found only in | |
ntoskrnl.exe symbols, but from ntdll.dll disassembly | |
it is obvious that this function is present there | |
as well (probably __forceinline'd, or used as a macro). | |
--*/ | |
{ | |
switch (MachineType) | |
{ | |
case IMAGE_FILE_MACHINE_I386: | |
return CONTEXT_i386; | |
case IMAGE_FILE_MACHINE_AMD64: | |
return CONTEXT_AMD64; | |
case IMAGE_FILE_MACHINE_ARMNT: | |
return CONTEXT_ARM; | |
case IMAGE_FILE_MACHINE_ARM64: | |
return CONTEXT_ARM64; | |
default: | |
return 0; | |
} | |
} | |
ULONG | |
RtlpGetLegacyContextLength( | |
_In_ ULONG ArchContextFlag, | |
_Out_opt_ PULONG SizeOfContext, | |
_Out_opt_ PULONG AlignOfContext | |
) | |
/*++ | |
Routine description: | |
This routine determines size and alignment of the architecture- | |
-specific CONTEXT structure. | |
Arguments: | |
ArchContextFlag - Architecture-specific CONTEXT flag. | |
SizeOfContext - Receives sizeof(CONTEXT). | |
AlignOfContext - Receives __alignof(CONTEXT). | |
Return Value: | |
Alignment of the CONTEXT structure. | |
Note: | |
You can find corresponding DECLSPEC_ALIGN specifiers | |
for each CONTEXT structure in the winnt.h (Windows SDK). | |
By WOW64_CONTEXT_* here is meant an original CONTEXT | |
structure for the specific architecture (as CONTEXT | |
structures for other architectures are not available, | |
because it is selected during compile-time). | |
--*/ | |
{ | |
ULONG SizeOf = 0; | |
ULONG AlignOf = 0; | |
switch (ArchContextFlag) | |
{ | |
case CONTEXT_i386: | |
SizeOf = sizeof(WOW64_CONTEXT_i386); | |
AlignOf = __alignof(WOW64_CONTEXT_i386); // 4 | |
break; | |
case CONTEXT_AMD64: | |
SizeOf = sizeof(WOW64_CONTEXT_AMD64); | |
AlignOf = __alignof(WOW64_CONTEXT_AMD64); // 16 | |
break; | |
case CONTEXT_ARM: | |
SizeOf = sizeof(WOW64_CONTEXT_ARM); | |
AlignOf = __alignof(WOW64_CONTEXT_ARM); // 8 | |
break; | |
case CONTEXT_ARM64: | |
SizeOf = sizeof(WOW64_CONTEXT_ARM64); | |
AlignOf = __alignof(WOW64_CONTEXT_ARM64); // 16 | |
break; | |
} | |
if (SizeOfContext) { | |
*SizeOfContext = SizeOf; | |
} | |
if (AlignOfContext) { | |
*AlignOfContext = AlignOf; | |
} | |
return AlignOf; | |
} | |
PULONG | |
RtlpGetContextFlagsLocation( | |
_In_ PCONTEXT_UNION Context, | |
_In_ ULONG ArchContextFlag | |
) | |
/*++ | |
Routine description: | |
This routine returns pointer to the the "ContextFlags" | |
member of the CONTEXT structure. | |
Arguments: | |
Context - Architecture-specific CONTEXT structure. | |
ArchContextFlag - Architecture-specific CONTEXT flag. | |
Return Value: | |
Pointer to the the "ContextFlags" member. | |
--*/ | |
{ | |
// | |
// ContextFlags is always the first member of the | |
// CONTEXT struct - except for AMD64. | |
// | |
switch (ArchContextFlag) | |
{ | |
case CONTEXT_i386: | |
return &Context->X86.ContextFlags; // Context + 0x00 | |
case CONTEXT_AMD64: | |
return &Context->X64.ContextFlags; // Context + 0x30 | |
case CONTEXT_ARM: | |
return &Context->ARM.ContextFlags; // Context + 0x00 | |
case CONTEXT_ARM64: | |
return &Context->ARM64.ContextFlags; // Context + 0x00 | |
default: | |
// | |
// Assume first member (Context + 0x00). | |
// | |
return (PULONG)Context; | |
} | |
} | |
// | |
// Architecture-specific WoW64 structure, | |
// holding the machine type and context | |
// structure. | |
// | |
#define WOW64_CPURESERVED_FLAG_RESET_STATE 1 | |
typedef struct _WOW64_CPURESERVED { | |
USHORT Flags; | |
USHORT MachineType; | |
// | |
// CONTEXT has different alignment for | |
// each architecture and its location | |
// is determined at runtime (see | |
// RtlWow64GetCpuAreaInfo below). | |
// | |
// CONTEXT Context; | |
// CONTEXT_EX ContextEx; | |
// | |
} WOW64_CPURESERVED, *PWOW64_CPURESERVED; | |
typedef struct _WOW64_CPU_AREA_INFO { | |
PCONTEXT_UNION Context; | |
PCONTEXT_EX ContextEx; | |
PVOID ContextFlagsLocation; | |
PWOW64_CPURESERVED CpuReserved; | |
ULONG ContextFlag; | |
USHORT MachineType; | |
} WOW64_CPU_AREA_INFO, *PWOW64_CPU_AREA_INFO; | |
NTSTATUS | |
RtlWow64GetCpuAreaInfo( | |
_In_ PWOW64_CPURESERVED CpuReserved, | |
_In_ ULONG Reserved, | |
_Out_ PWOW64_CPU_AREA_INFO CpuAreaInfo | |
) | |
/*++ | |
Routine description: | |
This routine returns architecture- and WoW64-specific | |
information based on the CPU-reserved region. It is | |
used mainly for fetching MachineType and the pointer | |
to the architecture-specific CONTEXT structure (which | |
is part of the WOW64_CPURESERVED structure). Because | |
the CONTEXT structure has different size and alignment | |
for each architecture, the pointer must be obtained | |
dynamically. | |
Arguments: | |
CpuReserved - WoW64 CPU-reserved region, usually located | |
at NtCurrentTeb()->TlsSlots[/* 1 */ WOW64_TLS_CPURESERVED] | |
Reserved - Unused. All callers set this argument to 0. | |
CpuAreaInfo - Receives the CPU-area information. | |
Return Value: | |
STATUS_SUCCESS - on success | |
STATUS_INVALID_PARAMETER - if CpuReserved contains invalid MachineType | |
--*/ | |
{ | |
ULONG ContextFlag; | |
ULONG SizeOfContext; | |
ULONG AlignOfContext; | |
// | |
// In the ntdll.dll, this call is probably inlined, because | |
// RtlpArchContextFlagFromMachine symbol is not present there. | |
// | |
ContextFlag = RtlpArchContextFlagFromMachine(CpuReserved->MachineType); | |
if (!ContextFlag) { | |
return STATUS_INVALID_PARAMETER; | |
} | |
RtlpGetLegacyContextLength(ContextFlag, &SizeOfContext, &AlignOfContext); | |
// | |
// CpuAreaInfo->Context = &CpuReserved->Context; | |
// CpuAreaInfo->ContextEx = &CpuReserved->ContextEx; | |
// | |
CpuAreaInfo->Context = ALIGN_UP_POINTER_BY( | |
(PUCHAR)CpuArea + sizeof(WOW64_CPU_AREA), | |
AlignOfContext | |
); | |
CpuAreaInfo->ContextEx = ALIGN_UP_POINTER_BY( | |
(PUCHAR)Context + SizeOfContext + sizeof(CONTEXT_EX), | |
sizeof(PVOID) | |
); | |
CpuAreaInfo->ContextFlagsLocation = ContextFlagsLocation; | |
CpuAreaInfo->CpuArea = CpuArea; | |
CpuAreaInfo->ContextFlag = ContextFlag; | |
CpuAreaInfo->MachineType = CpuReserved->MachineType; | |
return STATUS_SUCCESS; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
// wow64.dll | |
//////////////////////////////////////////////////////////////////////////////// | |
// | |
// WOW64INFO, based on: | |
// wow64t.h (WRK: https://github.com/mic101/windows/blob/master/WRK-v1.2/public/internal/base/inc/wow64t.h#L269) | |
// | |
#define WOW64_CPUFLAGS_MSFT64 0x00000001 | |
#define WOW64_CPUFLAGS_SOFTWARE 0x00000002 | |
typedef struct _WOW64INFO { | |
ULONG NativeSystemPageSize; | |
ULONG CpuFlags; | |
ULONG Wow64ExecuteFlags; | |
ULONG Unknown1; | |
USHORT NativeMachineType; | |
USHORT EmulatedMachineType; | |
} WOW64INFO, *PWOW64INFO; | |
// | |
// Thread Local Storage (TLS) support. TLS slots are statically allocated. | |
// wow64tls.h (WRK: https://github.com/mic101/windows/blob/master/WRK-v1.2/public/internal/base/inc/wow64tls.h#L23) | |
// Note: Not all fields probably matches their names on Windows 10. | |
// | |
#define WOW64_TLS_STACKPTR64 0 // contains 64-bit stack ptr when simulating 32-bit code | |
#define WOW64_TLS_CPURESERVED 1 // per-thread data for the CPU simulator | |
#define WOW64_TLS_INCPUSIMULATION 2 // Set when inside the CPU | |
#define WOW64_TLS_TEMPLIST 3 // List of memory allocated in thunk call. | |
#define WOW64_TLS_EXCEPTIONADDR 4 // 32-bit exception address (used during exception unwinds) | |
#define WOW64_TLS_USERCALLBACKDATA 5 // Used by win32k callbacks | |
#define WOW64_TLS_EXTENDED_FLOAT 6 // Used in ia64 to pass in floating point | |
#define WOW64_TLS_APCLIST 7 // List of outstanding usermode APCs | |
#define WOW64_TLS_FILESYSREDIR 8 // Used to enable/disable the filesystem redirector | |
#define WOW64_TLS_LASTWOWCALL 9 // Pointer to the last wow call struct (Used when wowhistory is enabled) | |
#define WOW64_TLS_WOW64INFO 10 // Wow64Info address (structure shared between 32-bit and 64-bit code inside Wow64). | |
#define WOW64_TLS_INITIAL_TEB32 11 // A pointer to the 32-bit initial TEB | |
#define WOW64_TLS_PERFDATA 12 // A pointer to temporary timestamps used in perf measurement | |
#define WOW64_TLS_DEBUGGER_COMM 13 // Communicate with 32bit debugger for event notification | |
#define WOW64_TLS_INVALID_STARTUP_CONTEXT 14 // Used by IA64 to indicate an invalid startup context. After startup, it stores a pointer to the context. | |
#define WOW64_TLS_SLIST_FAULT 15 // Used to retry RtlpInterlockedPopEntrySList faults | |
#define WOW64_TLS_UNWIND_NATIVE_STACK 16 // Forces an unwind of the native 64-bit stack after an APC | |
#define WOW64_TLS_APC_WRAPPER 17 // Holds the Wow64 APC jacket routine | |
#define WOW64_TLS_IN_SUSPEND_THREAD 18 // Indicates the current thread is in the middle of NtSuspendThread. Used by software CPUs. | |
#define WOW64_TLS_MAX_NUMBER 19 // Maximum number of TLS slot entries to allocate | |
typedef struct _WOW64_ERROR_CASE { | |
ULONG Case; | |
NTSTATUS TransformedStatus; | |
} WOW64_ERROR_CASE, *PWOW64_ERROR_CASE; | |
typedef struct _WOW64_SERVICE_TABLE_DESCRIPTOR { | |
// | |
// struct _KSERVICE_TABLE_DESCRIPTOR { | |
// | |
// // | |
// // Pointer to a system call table (array of function pointers). | |
// // | |
// | |
// PULONG_PTR Base; | |
// | |
// // | |
// // Pointer to a system call count table. | |
// // This field has been set only on checked (debug) builds, | |
// // where the Count (with the corresponding system call index) | |
// // has been incremented with each system call. | |
// // On non-checked builds it is set to NULL. | |
// // | |
// | |
// PULONG Count; | |
// | |
// // | |
// // Maximum number of items in the system call table. | |
// // In ntoskrnl.exe it corresponds with the actual number | |
// // of system calls. In wow64.dll it is set to 4096. | |
// // | |
// | |
// ULONG Limit; | |
// | |
// // | |
// // Pointer to a system call argument table. | |
// // The elements in this table actually contain how many | |
// // bytes on the stack are assigned to the function parameters | |
// // for a particular system call. | |
// // On 32-bit systems, if you divide this number by 4, you'll | |
// // get the the number of arguments that the system call expects. | |
// // | |
// | |
// PUCHAR Number; | |
// }; | |
// | |
KSERVICE_TABLE_DESCRIPTOR Descriptor; | |
// | |
// Extended fields of the WoW64 servie table: | |
// Wow64HandleSystemServiceError | |
// | |
WOW64_ERROR_CASE ErrorCaseDefault; | |
PWOW64_ERROR_CASE ErrorCase; | |
} WOW64_SERVICE_TABLE_DESCRIPTOR, *PWOW64_SERVICE_TABLE_DESCRIPTOR; | |
#define WOW64_NTDLL_SERVICE_INDEX 0 | |
#define WOW64_WIN32U_SERVICE_INDEX 1 | |
#define WOW64_KERNEL32_SERVICE_INDEX 2 | |
#define WOW64_USER32_SERVICE_INDEX 3 | |
#define WOW64_SERVICE_TABLE_MAX 4 | |
WOW64_SERVICE_TABLE_DESCRIPTOR ServiceTables[WOW64_SERVICE_TABLE_MAX]; | |
typedef struct _WOW64_LOG_SERVICE | |
{ | |
PVOID Reserved; | |
PULONG Arguments; | |
ULONG ServiceTable; | |
ULONG ServiceNumber; | |
NTSTATUS Status; | |
BOOLEAN PostCall; | |
} WOW64_LOG_SERVICE, *PWOW64_LOG_SERVICE; | |
NTSTATUS | |
Wow64HandleSystemServiceError( | |
_In_ NTSTATUS ExceptionStatus, | |
_In_ PWOW64_LOG_SERVICE LogService | |
) | |
/*++ | |
Routine description: | |
This routine transforms exception from native system | |
call to WoW64-compatible NTSTATUS. | |
Arguments: | |
ExceptionStatus - NTSTATUS raised from executing system call. | |
LogService - Information about the WoW64 system call. | |
Return Value: | |
Transformed NTSTATUS. | |
--*/ | |
{ | |
PWOW64_SERVICE_TABLE_DESCRIPTOR ServiceTable; | |
PWOW64_ERROR_CASE ErrorCaseTable; | |
ULONG ErrorCase; | |
NTSTATUS TransformedStatus; | |
ErrorCaseTable = ServiceTables[LogService->ServiceTable].ErrorCase; | |
if (!ErrorCaseTable) | |
{ | |
ErrorCaseTable = &ServiceTables[LogService->ServiceTable].ErrorCaseDefault; | |
} | |
ErrorCase = ErrorCaseTable[LogService->ServiceNumber].ErrorCase; | |
TransformedStatus = ErrorCaseTable[LogService->ServiceNumber].TransformedStatus; | |
switch (ErrorCase) | |
{ | |
case 0: | |
return ExceptionStatus; | |
case 1: | |
NtCurrentTeb()->LastErrorValue = RtlNtStatusToDosError(ExceptionStatus); | |
return ExceptionStatus; | |
case 2: | |
return TransformedStatus; | |
case 3: | |
NtCurrentTeb()->LastErrorValue = RtlNtStatusToDosError(ExceptionStatus); | |
return TransformedStatus; | |
default: | |
return STATUS_INVALID_PARAMETER; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment