755 lines
24 KiB
C
755 lines
24 KiB
C
/*
|
|
* Copyright 2020-2022 David Xanatos, xanasoft.com
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Win32 Services
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#define NOGDI
|
|
#include "dll.h"
|
|
#include "debug.h"
|
|
|
|
#include "common\pattern.h"
|
|
#include "common\arm64_asm.h"
|
|
#include "core/drv/api_defs.h"
|
|
#include "core/low/lowdata.h"
|
|
|
|
#ifndef _WIN64
|
|
#include "common\dllimport.h"
|
|
|
|
NTSTATUS SbieApi_ProtectVirtualMemory(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, ULONG flNewProtect, ULONG* lpflOldProtect);
|
|
NTSTATUS SbieApi_ReadVirtualMemory(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, ULONG64* lpNumberOfBytesRead);
|
|
NTSTATUS SbieApi_WriteVirtualMemory(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, ULONG64* lpNumberOfBytesWritten);
|
|
NTSTATUS SbieApi_FlushInstructionCache(HANDLE hProcess, DWORD64 lpBaseAddress, SIZE_T nSize);
|
|
NTSTATUS SbieApi_QueryVirtualMemory(HANDLE hProcess, DWORD64 BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength);
|
|
|
|
BOOLEAN Win32_HookWin32WoW64();
|
|
#endif
|
|
|
|
#ifdef _M_ARM64EC
|
|
ULONG Hook_GetSysCallFunc(ULONG* aCode, void** pHandleStubHijack);
|
|
ULONG* SbieDll_FindFirstSysCallFunc(ULONG* aCode, void** pHandleStubHijack);
|
|
void* SbieDll_GetEcExitThunk(void* HandleStubHijack);
|
|
#endif
|
|
|
|
ULONG SbieDll_GetSysCallOffset(const ULONG *SyscallPtr, ULONG syscall_index);
|
|
|
|
extern SBIELOW_DATA* SbieApi_data;
|
|
#define SBIELOW_CALL(x) ((P_##x)&data->x##_code)
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Win32_HookWin32SysCalls
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOLEAN Win32_HookWin32SysCalls(HMODULE win32u_base)
|
|
{
|
|
UCHAR *SystemServiceAsm;
|
|
ULONG *SyscallPtr;
|
|
ULONG SyscallNum;
|
|
void *RegionBase;
|
|
SIZE_T RegionSize;
|
|
ULONG OldProtect;
|
|
|
|
SBIELOW_DATA* data = SbieApi_data;
|
|
SystemServiceAsm = (UCHAR*)data->pSystemService;
|
|
|
|
UCHAR* syscall_data = (UCHAR *)HeapAlloc(GetProcessHeap(), 0, 16384); // enough room for over 2000 syscalls
|
|
if (!syscall_data)
|
|
return FALSE;
|
|
|
|
if (!NT_SUCCESS(SbieApi_Call(API_QUERY_SYSCALLS, 2, (ULONG_PTR)syscall_data, 1))) {
|
|
HeapFree(GetProcessHeap(), 0, syscall_data);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// our syscall data area describes the ZwXxx functions in ntdll,
|
|
// overwrite each export to jump to our assembly SystemService
|
|
// see also core/drv/syscall.c and core/svc/DriverInjectAssist.cpp
|
|
//
|
|
|
|
SyscallPtr = (ULONG *)(syscall_data
|
|
+ sizeof(ULONG)); // size of buffer
|
|
|
|
#ifdef _M_ARM64EC
|
|
|
|
ULONG* aCode = SbieDll_FindFirstSysCallFunc((ULONG*)win32u_base, NULL);
|
|
if (aCode == NULL) {
|
|
HeapFree(GetProcessHeap(), 0, syscall_data);
|
|
return FALSE;
|
|
}
|
|
|
|
for (ULONG pos = 0; pos < 128; aCode++, pos += 4) {
|
|
|
|
SyscallNum = Hook_GetSysCallFunc(aCode, NULL);
|
|
if (SyscallNum == -1)
|
|
continue;
|
|
|
|
if (SbieDll_GetSysCallOffset(SyscallPtr, SyscallNum)) {
|
|
|
|
RegionBase = aCode;
|
|
|
|
RegionSize = 16;
|
|
|
|
SBIELOW_CALL(NtProtectVirtualMemory)(
|
|
NtCurrentProcess(), &RegionBase, &RegionSize,
|
|
PAGE_EXECUTE_READWRITE, &OldProtect);
|
|
|
|
MOV mov;
|
|
mov.OP = 0xD2800011; // mov x17, #0xFFFF
|
|
mov.imm16 = (USHORT)SyscallNum;
|
|
*aCode++ = mov.OP;
|
|
*aCode++ = 0x18000048; // ldr w8, 8
|
|
*aCode++ = 0xD61F0100; // br x8
|
|
*(ULONG*)aCode = (ULONG)(ULONG_PTR)SystemServiceAsm;
|
|
|
|
SBIELOW_CALL(NtFlushInstructionCache)(
|
|
NtCurrentProcess(), RegionBase, (ULONG)RegionSize);
|
|
|
|
SBIELOW_CALL(NtProtectVirtualMemory)(
|
|
NtCurrentProcess(), &RegionBase, &RegionSize,
|
|
OldProtect, &OldProtect);
|
|
|
|
}
|
|
|
|
//if (aCode[13] != 0 || aCode[14] != 0 || aCode[15] != 0 || aCode[16] != 0)
|
|
// break;
|
|
//aCode += (13 + 3 + 3 + 1);
|
|
aCode += 16;
|
|
pos = 0; // reset
|
|
}
|
|
|
|
#else
|
|
|
|
while (SyscallPtr[0] || SyscallPtr[1]) {
|
|
|
|
//
|
|
// the ULONG at SyscallPtr[1] gives the offset of the ZwXxx export
|
|
// from the base address of ntdll
|
|
//
|
|
|
|
UCHAR* ZwXxxPtr = (UCHAR *)((ULONG_PTR)SyscallPtr[1] + (UCHAR*)win32u_base);
|
|
|
|
//
|
|
// make the syscall address writable
|
|
//
|
|
RegionBase = ZwXxxPtr;
|
|
|
|
#ifdef _M_ARM64
|
|
RegionSize = 16;
|
|
#elif _WIN64
|
|
RegionSize = 14;
|
|
#else ! _WIN64
|
|
RegionSize = 10;
|
|
#endif _WIN64
|
|
|
|
//
|
|
// SyscallPtr[0] specifies the syscall number in the low 24 bits.
|
|
// on 32-bit Windows, also specifies the parameter count (in bytes)
|
|
// in the high 8 bits. this is used by SystemServiceAsm
|
|
//
|
|
// overwrite the ZwXxx export to call our SystemServiceAsm,
|
|
// and then restore the original page protection
|
|
//
|
|
|
|
SBIELOW_CALL(NtProtectVirtualMemory)(
|
|
NtCurrentProcess(), &RegionBase, &RegionSize,
|
|
PAGE_EXECUTE_READWRITE, &OldProtect);
|
|
|
|
SyscallNum = SyscallPtr[0];
|
|
|
|
#ifdef _M_ARM64
|
|
|
|
ULONG* aCode = (ULONG*)ZwXxxPtr;
|
|
|
|
MOV mov;
|
|
mov.OP = 0xD2800011; // mov x17, #0xFFFF
|
|
mov.imm16 = (USHORT)SyscallNum;
|
|
*aCode++ = mov.OP;
|
|
*aCode++ = 0x18000048; // ldr w8, 8
|
|
*aCode++ = 0xD61F0100; // br x8
|
|
*(ULONG*)aCode = (ULONG)(ULONG_PTR)SystemServiceAsm;
|
|
|
|
|
|
SBIELOW_CALL(NtFlushInstructionCache)(
|
|
NtCurrentProcess(), RegionBase, (ULONG)RegionSize);
|
|
|
|
#elif _WIN64
|
|
|
|
ZwXxxPtr[0] = 0x49; // mov r10, SyscallNumber
|
|
ZwXxxPtr[1] = 0xC7;
|
|
ZwXxxPtr[2] = 0xC2;
|
|
*(ULONG *)&ZwXxxPtr[3] = SyscallNum;
|
|
if (!data->flags.long_diff) {
|
|
|
|
if (data->flags.is_win10) {
|
|
ZwXxxPtr[7] = 0x48; // jmp SystemServiceAsm
|
|
ZwXxxPtr[8] = 0xE9;
|
|
*(ULONG *)&ZwXxxPtr[9] = (ULONG)(ULONG_PTR)(SystemServiceAsm - (ZwXxxPtr + 13));
|
|
}
|
|
else {
|
|
ZwXxxPtr[7] = 0xe9; // jmp SystemServiceAsm
|
|
*(ULONG *)&ZwXxxPtr[8] = (ULONG)(ULONG_PTR)(SystemServiceAsm - (ZwXxxPtr + 12));
|
|
}
|
|
}
|
|
else {
|
|
|
|
ZwXxxPtr[7] = 0xB8; // mov eax, SystemServiceAsm
|
|
*(ULONG *)&ZwXxxPtr[8] = (ULONG)(ULONG_PTR)SystemServiceAsm;
|
|
*(USHORT *)&ZwXxxPtr[12] = 0xE0FF; // jmp rax
|
|
}
|
|
|
|
#else ! _WIN64
|
|
|
|
ZwXxxPtr[0] = 0xB8; // mov eax, SyscallNumber, with param count in the highest byte
|
|
*(ULONG *)&ZwXxxPtr[1] = SyscallNum;
|
|
ZwXxxPtr[5] = 0xE9; // jmp SystemServiceAsm
|
|
*(ULONG *)&ZwXxxPtr[6] =
|
|
(ULONG)(ULONG_PTR)(SystemServiceAsm - (ZwXxxPtr + 10));
|
|
|
|
#endif _WIN64
|
|
|
|
SBIELOW_CALL(NtProtectVirtualMemory)(
|
|
NtCurrentProcess(), &RegionBase, &RegionSize,
|
|
OldProtect, &OldProtect);
|
|
|
|
SyscallPtr += 2;
|
|
}
|
|
|
|
#endif
|
|
|
|
HeapFree(GetProcessHeap(), 0, syscall_data);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Win32_Init
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOLEAN Win32_Init(HMODULE hmodule)
|
|
{
|
|
Dll_Win32u = hmodule;
|
|
|
|
// In Windows 10 all Win32k.sys calls are located in win32u.dll
|
|
if (Dll_OsBuild < 10041 || (Dll_ProcessFlags & SBIE_FLAG_WIN32K_HOOKABLE) == 0 || !SbieApi_QueryConfBool(NULL, L"EnableWin32kHooks", TRUE))
|
|
return TRUE; // just return on older builds, or not enabled
|
|
|
|
if (Dll_CompartmentMode || SbieApi_data->flags.bNoSysHooks)
|
|
return TRUE; // no syscall hooking in comaprtment mode
|
|
|
|
//
|
|
// chrome needs for a working GPU acceleration the GdiDdDDI* win32k syscalls to have the right user token
|
|
// this however with some other software causes issues, presumably as then other syscalls would need to have the same token
|
|
//
|
|
|
|
BOOLEAN useByDefualt = (Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME);
|
|
if (SbieDll_GetSettingsForName_bool(NULL, Dll_ImageName, L"UseWin32kHooks", useByDefualt)) {
|
|
|
|
// disable Electron Workaround when we are ready to hook the required win32k syscalls
|
|
extern BOOL Dll_ElectronWorkaround;
|
|
Dll_ElectronWorkaround = FALSE;
|
|
|
|
#ifndef _WIN64
|
|
if (Dll_IsWow64)
|
|
Win32_HookWin32WoW64(); // WoW64 hooks
|
|
else
|
|
#endif
|
|
Win32_HookWin32SysCalls(hmodule); // Native x86/x64 hooks
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#ifndef _WIN64
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Win32_GetSysCallNumberWoW64
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
ULONG Win32_GetSysCallNumberWoW64(DWORD64 pos, UCHAR* dll_data)
|
|
{
|
|
// 4C 8B D1 - r10,rcx
|
|
if (!(dll_data[pos + 0] == 0x4c && dll_data[pos + 1] == 0x8b && dll_data[pos + 2] == 0xd1))
|
|
return 0;
|
|
|
|
// B8 XX XX XX XX - mov eax,0xXXXX
|
|
if (!(dll_data[pos + 3] == 0xb8))
|
|
return 0;
|
|
ULONG syscall_index = *(ULONG*)&dll_data[pos + 4];
|
|
|
|
// F6 04 25 08 03 FE 7F 01 - test BYTE PTR ds:0x7ffe0308,0x1
|
|
//
|
|
|
|
// 75 03 - jne 0x15 (label_1)
|
|
if (!(dll_data[pos + 16] == 0x75 && dll_data[pos + 17] == 0x03))
|
|
return 0;
|
|
|
|
// 0F 05 - syscall
|
|
if (!(dll_data[pos + 18] == 0x0f && dll_data[pos + 19] == 0x05))
|
|
return 0;
|
|
// C3 - ret
|
|
if (!(dll_data[pos + 20] == 0xc3))
|
|
return 0;
|
|
|
|
// label_1:
|
|
// CD 2E - int 0x2e
|
|
if (!(dll_data[pos + 21] == 0xcd && dll_data[pos + 22] == 0x2e))
|
|
return 0;
|
|
// C3 - ret
|
|
if (!(dll_data[pos + 23] == 0xc3))
|
|
return 0;
|
|
|
|
//
|
|
|
|
return syscall_index;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Win32_GetSysCallNumberArm64
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX ULONG Win32_GetSysCallNumberArm64(ULONG* aCode)
|
|
{
|
|
// 0: e10000d4 svc #0x1000
|
|
SVC svc;
|
|
svc.OP = aCode[0];
|
|
if (!IS_SVC(svc) || svc.imm16 < 0x1000) // win32 syscalls are >= 0x1000
|
|
return -1;
|
|
|
|
// 1: c0035fd6 ret
|
|
if (aCode[1] != 0xd65f03c0)
|
|
return -1;
|
|
|
|
return svc.imm16;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Win32_HookWin32WoW64
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOLEAN Win32_HookWin32WoW64()
|
|
{
|
|
BOOLEAN ok = FALSE;
|
|
UCHAR* dll_data = NULL;
|
|
UCHAR* syscall_data = NULL;
|
|
|
|
//
|
|
// first set up the 64 bit capable NtQueryVirtualMemory64 for FindDllBase64
|
|
//
|
|
|
|
extern void* NtQueryVirtualMemory64;
|
|
if (!NtQueryVirtualMemory64)
|
|
NtQueryVirtualMemory64 = SbieApi_QueryVirtualMemory;
|
|
|
|
//
|
|
// get the 64-bit address of the wow64win.dll
|
|
//
|
|
|
|
DWORD64 BaseAddress = FindDllBase64(NtCurrentProcess(), L"wow64win.dll");
|
|
|
|
SIZE_T SizeOfImage = 0x00100000; // 1 MB should be more than enough
|
|
if (!BaseAddress) {
|
|
SbieApi_Log(2303, L"win32k, wow64win.dll base not found");
|
|
return FALSE;
|
|
}
|
|
|
|
dll_data = (UCHAR *)HeapAlloc(GetProcessHeap(), 0, (SIZE_T)SizeOfImage);
|
|
if (!dll_data) {
|
|
SbieApi_Log(2303, L"win32k, alloc failed (1)");
|
|
goto finish;
|
|
}
|
|
|
|
ULONG64 SizeRead;
|
|
if (!NT_SUCCESS(SbieApi_ReadVirtualMemory(NtCurrentProcess(), (PVOID64)BaseAddress, dll_data, SizeOfImage, &SizeRead))) {
|
|
SbieApi_Log(2303, L"win32k, wow64win.dll read failed");
|
|
goto finish;
|
|
}
|
|
|
|
DWORD64 SystemServiceAsm;
|
|
ULONG* SyscallPtr;
|
|
ULONG SyscallNum;
|
|
DWORD64 RegionBase;
|
|
SIZE_T RegionSize;
|
|
ULONG OldProtect;
|
|
|
|
SBIELOW_DATA* data = SbieApi_data;
|
|
SystemServiceAsm = data->pSystemService;
|
|
|
|
syscall_data = (UCHAR*)HeapAlloc(GetProcessHeap(), 0, 16384); // enough room for over 2000 syscalls
|
|
if (!syscall_data) {
|
|
SbieApi_Log(2303, L"win32k, alloc failed (2)");
|
|
goto finish;
|
|
}
|
|
|
|
if (!NT_SUCCESS(SbieApi_Call(API_QUERY_SYSCALLS, 2, (ULONG_PTR)syscall_data, 1))) {
|
|
SbieApi_Log(2303, L"win32k, syscall query failed");
|
|
goto finish;
|
|
}
|
|
|
|
SyscallPtr = (ULONG*)(syscall_data + sizeof(ULONG)); // size of buffer
|
|
|
|
if (Dll_IsXtAjit) { // x86 on arm64
|
|
|
|
UCHAR* ZwXxxPtr;
|
|
|
|
ULONG* aCode = (ULONG*)dll_data;
|
|
|
|
for (ULONG64 pos = 0; pos < SizeRead; aCode++, pos += 4) {
|
|
if (Win32_GetSysCallNumberArm64(aCode) != -1)
|
|
break;
|
|
}
|
|
|
|
if ((DWORD64)aCode >= (DWORD64)dll_data + SizeRead) {
|
|
SbieApi_Log(2303, L"win32k, get first syscall wrapper failed");
|
|
goto finish;
|
|
}
|
|
|
|
for (ULONG pos = 0; pos < 128; aCode++, pos += 4) {
|
|
|
|
ULONG SyscallNum = Win32_GetSysCallNumberArm64(aCode);
|
|
if (SyscallNum == -1)
|
|
continue;
|
|
|
|
if (SbieDll_GetSysCallOffset(SyscallPtr, SyscallNum)) {
|
|
|
|
DWORD64 offset = (DWORD64)aCode - (DWORD64)dll_data;
|
|
|
|
RegionBase = BaseAddress + offset;
|
|
RegionSize = 16;
|
|
|
|
//
|
|
// prepare call to call our SystemServiceAsm
|
|
//
|
|
|
|
ZwXxxPtr = aCode;
|
|
|
|
MOV mov;
|
|
mov.OP = 0xD2800011; // mov x17, #0xFFFF
|
|
mov.imm16 = (USHORT)SyscallNum;
|
|
*aCode++ = mov.OP;
|
|
*aCode++ = 0x18000048; // ldr w8, 8
|
|
*aCode++ = 0xD61F0100; // br x8
|
|
*(ULONG*)aCode = (ULONG)(ULONG_PTR)SystemServiceAsm;
|
|
|
|
//
|
|
// overwrite the ZwXxx export to call our SystemServiceAsm,
|
|
// and then restore the original page protection
|
|
//
|
|
|
|
if (!NT_SUCCESS(SbieApi_ProtectVirtualMemory(NtCurrentProcess(), RegionBase, RegionSize, PAGE_EXECUTE_READWRITE, &OldProtect))) {
|
|
SbieApi_Log(2303, L"win32k %d (1)", SyscallNum);
|
|
goto finish;
|
|
}
|
|
|
|
if (!NT_SUCCESS(SbieApi_WriteVirtualMemory(NtCurrentProcess(), RegionBase, ZwXxxPtr, RegionSize, &SizeRead))) {
|
|
SbieApi_Log(2303, L"win32k %d (2)", SyscallNum);
|
|
goto finish;
|
|
}
|
|
|
|
if (!NT_SUCCESS(SbieApi_FlushInstructionCache(NtCurrentProcess(), RegionBase, RegionSize))) {
|
|
SbieApi_Log(2303, L"win32k %d (3)", SyscallNum);
|
|
goto finish;
|
|
}
|
|
|
|
if (!NT_SUCCESS(SbieApi_ProtectVirtualMemory(NtCurrentProcess(), RegionBase, RegionSize, OldProtect, &OldProtect))) {
|
|
SbieApi_Log(2303, L"win32k %d (4)", SyscallNum);
|
|
goto finish;
|
|
}
|
|
|
|
}
|
|
|
|
//if (aCode[2] != 0 || aCode[3] != 0)
|
|
// break;
|
|
aCode += 4;
|
|
pos = 0; // reset
|
|
}
|
|
|
|
}
|
|
else { // x86 on x64
|
|
|
|
UCHAR ZwXxxPtr[16];
|
|
|
|
DWORD64 FuncTable = 0;
|
|
|
|
for (DWORD64 pos = 0; pos < SizeRead - 0x20; pos++) {
|
|
if (Win32_GetSysCallNumberWoW64(pos, dll_data) != 0) {
|
|
FuncTable = pos;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FuncTable == 0) {
|
|
SbieApi_Log(2303, L"win32k, wow64win.dll sys call table not found");
|
|
goto finish;
|
|
}
|
|
|
|
for (DWORD64 pos = FuncTable; pos < SizeRead - 0x20; )
|
|
{
|
|
SyscallNum = Win32_GetSysCallNumberWoW64(pos, dll_data);
|
|
if (SyscallNum)
|
|
{
|
|
if (SbieDll_GetSysCallOffset(SyscallPtr, SyscallNum))
|
|
{
|
|
RegionBase = BaseAddress + pos;
|
|
RegionSize = 14;
|
|
|
|
//
|
|
// prepare call to call our SystemServiceAsm
|
|
//
|
|
|
|
ZwXxxPtr[0] = 0x49; // mov r10, SyscallNumber
|
|
ZwXxxPtr[1] = 0xC7;
|
|
ZwXxxPtr[2] = 0xC2;
|
|
*(ULONG*)&ZwXxxPtr[3] = SyscallNum;
|
|
if (!data->flags.long_diff) {
|
|
|
|
if (data->flags.is_win10) {
|
|
ZwXxxPtr[7] = 0x48; // jmp SystemServiceAsm
|
|
ZwXxxPtr[8] = 0xE9;
|
|
*(ULONG*)&ZwXxxPtr[9] = (ULONG)(ULONG_PTR)(SystemServiceAsm - (RegionBase + 13));
|
|
}
|
|
else {
|
|
ZwXxxPtr[7] = 0xe9; // jmp SystemServiceAsm
|
|
*(ULONG*)&ZwXxxPtr[8] = (ULONG)(ULONG_PTR)(SystemServiceAsm - (RegionBase + 12));
|
|
}
|
|
}
|
|
else {
|
|
|
|
ZwXxxPtr[7] = 0xB8; // mov eax, SystemServiceAsm
|
|
*(ULONG*)&ZwXxxPtr[8] = (ULONG)(ULONG_PTR)SystemServiceAsm;
|
|
*(USHORT*)&ZwXxxPtr[12] = 0xE0FF; // jmp rax
|
|
}
|
|
|
|
//
|
|
// overwrite the ZwXxx export to call our SystemServiceAsm,
|
|
// and then restore the original page protection
|
|
//
|
|
|
|
if (!NT_SUCCESS(SbieApi_ProtectVirtualMemory(NtCurrentProcess(), RegionBase, RegionSize, PAGE_EXECUTE_READWRITE, &OldProtect))) {
|
|
SbieApi_Log(2303, L"win32k %d (1)", SyscallNum);
|
|
goto finish;
|
|
}
|
|
|
|
if (!NT_SUCCESS(SbieApi_WriteVirtualMemory(NtCurrentProcess(), RegionBase, ZwXxxPtr, RegionSize, &SizeRead))) {
|
|
SbieApi_Log(2303, L"win32k %d (2)", SyscallNum);
|
|
goto finish;
|
|
}
|
|
|
|
if (!NT_SUCCESS(SbieApi_ProtectVirtualMemory(NtCurrentProcess(), RegionBase, RegionSize, OldProtect, &OldProtect))) {
|
|
SbieApi_Log(2303, L"win32k %d (3)", SyscallNum);
|
|
goto finish;
|
|
}
|
|
}
|
|
|
|
pos += 0x20;
|
|
}
|
|
else if (*((ULONG*)&dll_data[pos]) == 0xCCCCCCCC) { // int 3; int 3; int 3; int 3;
|
|
ok = TRUE;
|
|
break; // end of sys call function table
|
|
}
|
|
else
|
|
pos++;
|
|
}
|
|
|
|
}
|
|
|
|
finish:
|
|
|
|
if(syscall_data)
|
|
HeapFree(GetProcessHeap(), 0, syscall_data);
|
|
|
|
if(dll_data)
|
|
HeapFree(GetProcessHeap(), 0, dll_data);
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
//
|
|
// Win32_HookWin32WoW64 needs to be able to read and write the 64-bit portion of the address space
|
|
// therefore we issue direct syscalls using 64 bit arguments to our driver's syscall interface
|
|
// The driver accepts function names and optionally returns the corresponding syscall index for later direct use
|
|
// This replaces the use of heaven's gate (wow64ext), as it is unavailable when running in emulation on arm64
|
|
//
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SbieApi_ProtectVirtualMemory
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS SbieApi_ProtectVirtualMemory(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, ULONG flNewProtect, ULONG* lpflOldProtect)
|
|
{
|
|
ULONG64 BaseAddress = lpAddress;
|
|
ULONG64 NumberOfBytesToProtect = dwSize;
|
|
|
|
static SHORT syscall_index = 0xFFF;
|
|
|
|
ULONG64 stack[17];
|
|
stack[0] = hProcess;
|
|
stack[1] = &BaseAddress;
|
|
stack[2] = &NumberOfBytesToProtect;
|
|
stack[3] = flNewProtect;
|
|
stack[4] = lpflOldProtect;
|
|
|
|
__declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
|
|
memset(parms, 0, sizeof(parms));
|
|
parms[0] = API_INVOKE_SYSCALL;
|
|
parms[1] = (ULONG64)(ULONG_PTR)syscall_index;
|
|
parms[2] = (ULONG64)(ULONG_PTR)stack; // pointer to system service arguments on stack
|
|
parms[3] = (ULONG64)(ULONG_PTR)"ProtectVirtualMemory";
|
|
parms[4] = (ULONG64)(ULONG_PTR)&syscall_index;
|
|
|
|
NTSTATUS status = SbieApi_Ioctl(parms);
|
|
return status;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SbieApi_ReadVirtualMemory
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS SbieApi_ReadVirtualMemory(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, ULONG64 *lpNumberOfBytesRead)
|
|
{
|
|
static SHORT syscall_index = 0xFFF;
|
|
|
|
ULONG64 stack[17];
|
|
stack[0] = hProcess;
|
|
stack[1] = lpBaseAddress;
|
|
stack[2] = lpBuffer;
|
|
stack[3] = nSize;
|
|
stack[4] = lpNumberOfBytesRead;
|
|
|
|
__declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
|
|
memset(parms, 0, sizeof(parms));
|
|
parms[0] = API_INVOKE_SYSCALL;
|
|
parms[1] = (ULONG64)(ULONG_PTR)syscall_index;
|
|
parms[2] = (ULONG64)(ULONG_PTR)stack; // pointer to system service arguments on stack
|
|
parms[3] = (ULONG64)(ULONG_PTR)"ReadVirtualMemory";
|
|
parms[4] = (ULONG64)(ULONG_PTR)&syscall_index;
|
|
|
|
NTSTATUS status = SbieApi_Ioctl(parms);
|
|
if (status == STATUS_PARTIAL_COPY)
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SbieApi_WriteVirtualMemory
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS SbieApi_WriteVirtualMemory(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, ULONG64 *lpNumberOfBytesWritten)
|
|
{
|
|
static SHORT syscall_index = 0xFFF;
|
|
|
|
ULONG64 stack[17];
|
|
stack[0] = hProcess;
|
|
stack[1] = lpBaseAddress;
|
|
stack[2] = lpBuffer;
|
|
stack[3] = nSize;
|
|
stack[4] = lpNumberOfBytesWritten;
|
|
|
|
__declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
|
|
memset(parms, 0, sizeof(parms));
|
|
parms[0] = API_INVOKE_SYSCALL;
|
|
parms[1] = (ULONG64)(ULONG_PTR)syscall_index;
|
|
parms[2] = (ULONG64)(ULONG_PTR)stack; // pointer to system service arguments on stack
|
|
parms[3] = (ULONG64)(ULONG_PTR)"WriteVirtualMemory";
|
|
parms[4] = (ULONG64)(ULONG_PTR)&syscall_index;
|
|
|
|
NTSTATUS status = SbieApi_Ioctl(parms);
|
|
return status;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SbieApi_FlushInstructionCache
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS SbieApi_FlushInstructionCache(HANDLE hProcess, DWORD64 lpBaseAddress, SIZE_T nSize)
|
|
{
|
|
static SHORT syscall_index = 0xFFF;
|
|
|
|
ULONG64 stack[17];
|
|
stack[0] = hProcess;
|
|
stack[1] = lpBaseAddress;
|
|
stack[2] = nSize;
|
|
|
|
__declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
|
|
memset(parms, 0, sizeof(parms));
|
|
parms[0] = API_INVOKE_SYSCALL;
|
|
parms[1] = (ULONG64)(ULONG_PTR)syscall_index;
|
|
parms[2] = (ULONG64)(ULONG_PTR)stack; // pointer to system service arguments on stack
|
|
parms[3] = (ULONG64)(ULONG_PTR)"FlushInstructionCache";
|
|
parms[4] = (ULONG64)(ULONG_PTR)&syscall_index;
|
|
|
|
NTSTATUS status = SbieApi_Ioctl(parms);
|
|
return status;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SbieApi_QueryVirtualMemory
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS SbieApi_QueryVirtualMemory(HANDLE hProcess, DWORD64 BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength)
|
|
{
|
|
DWORD64 ReturnLength64 = 0;
|
|
|
|
static SHORT syscall_index = 0xFFF;
|
|
|
|
ULONG64 stack[17];
|
|
stack[0] = hProcess;
|
|
stack[1] = BaseAddress;
|
|
stack[2] = MemoryInformationClass;
|
|
stack[3] = MemoryInformation;
|
|
stack[4] = MemoryInformationLength;
|
|
stack[5] = &ReturnLength64;
|
|
|
|
__declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
|
|
memset(parms, 0, sizeof(parms));
|
|
parms[0] = API_INVOKE_SYSCALL;
|
|
parms[1] = (ULONG64)(ULONG_PTR)syscall_index;
|
|
parms[2] = (ULONG64)(ULONG_PTR)stack; // pointer to system service arguments on stack
|
|
parms[3] = (ULONG64)(ULONG_PTR)"QueryVirtualMemory";
|
|
parms[4] = (ULONG64)(ULONG_PTR)&syscall_index;
|
|
|
|
NTSTATUS status = SbieApi_Ioctl(parms);
|
|
|
|
if(ReturnLength) *ReturnLength = (SIZE_T)ReturnLength64;
|
|
|
|
return status;
|
|
}
|
|
|
|
#endif
|