From 4f656a898a348949e8216846e1284e7d138c11ae Mon Sep 17 00:00:00 2001 From: DavidXanatos Date: Sat, 25 Jun 2022 17:56:35 +0200 Subject: [PATCH] 1.2.0 --- Sandboxie/common/dllimport.c | 461 ++++++++++++++++ Sandboxie/common/dllimport.h | 39 ++ Sandboxie/common/hook_util.c | 146 +++++ Sandboxie/common/wow64ext/CMemPtr.h | 56 -- Sandboxie/common/wow64ext/internal.h | 73 --- Sandboxie/common/wow64ext/wow64ext.cpp | 600 --------------------- Sandboxie/common/wow64ext/wow64ext.h | 377 ------------- Sandboxie/core/dll/SboxDll.vcxproj | 9 +- Sandboxie/core/dll/SboxDll.vcxproj.filters | 21 +- Sandboxie/core/dll/Win32.c | 486 +++++++++++------ Sandboxie/core/dll/dllhook.c | 123 +---- Sandboxie/core/drv/syscall.c | 23 + Sandboxie/core/low/init.c | 107 +--- 13 files changed, 1021 insertions(+), 1500 deletions(-) create mode 100644 Sandboxie/common/dllimport.c create mode 100644 Sandboxie/common/dllimport.h create mode 100644 Sandboxie/common/hook_util.c delete mode 100644 Sandboxie/common/wow64ext/CMemPtr.h delete mode 100644 Sandboxie/common/wow64ext/internal.h delete mode 100644 Sandboxie/common/wow64ext/wow64ext.cpp delete mode 100644 Sandboxie/common/wow64ext/wow64ext.h diff --git a/Sandboxie/common/dllimport.c b/Sandboxie/common/dllimport.c new file mode 100644 index 00000000..6895ed86 --- /dev/null +++ b/Sandboxie/common/dllimport.c @@ -0,0 +1,461 @@ +/* + * Copyright 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 . + */ + +#define WIN32_NO_STATUS +#include +#include "win32_ntddk.h" + +// ntimage.h + +typedef struct _IMAGE_CHPE_METADATA_X86 { + ULONG Version; + ULONG CHPECodeAddressRangeOffset; + ULONG CHPECodeAddressRangeCount; + ULONG WowA64ExceptionHandlerFunctionPointer; + ULONG WowA64DispatchCallFunctionPointer; + ULONG WowA64DispatchIndirectCallFunctionPointer; + ULONG WowA64DispatchIndirectCallCfgFunctionPointer; + ULONG WowA64DispatchRetFunctionPointer; + ULONG WowA64DispatchRetLeafFunctionPointer; + ULONG WowA64DispatchJumpFunctionPointer; + ULONG CompilerIATPointer; // Present if Version >= 2 + ULONG WowA64RdtscFunctionPointer; // Present if Version >= 3 +} IMAGE_CHPE_METADATA_X86, * PIMAGE_CHPE_METADATA_X86; + +typedef struct _IMAGE_CHPE_RANGE_ENTRY { + union { + ULONG StartOffset; + struct { + ULONG NativeCode : 1; + ULONG AddressBits : 31; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + + ULONG Length; +} IMAGE_CHPE_RANGE_ENTRY, * PIMAGE_CHPE_RANGE_ENTRY; + +typedef struct _IMAGE_ARM64EC_METADATA { + ULONG Version; + ULONG CodeMap; + ULONG CodeMapCount; + ULONG CodeRangesToEntryPoints; + ULONG RedirectionMetadata; + ULONG tbd__os_arm64x_dispatch_call_no_redirect; + ULONG tbd__os_arm64x_dispatch_ret; + ULONG tbd__os_arm64x_dispatch_call; + ULONG tbd__os_arm64x_dispatch_icall; + ULONG tbd__os_arm64x_dispatch_icall_cfg; + ULONG AlternateEntryPoint; + ULONG AuxiliaryIAT; + ULONG CodeRangesToEntryPointsCount; + ULONG RedirectionMetadataCount; + ULONG GetX64InformationFunctionPointer; + ULONG SetX64InformationFunctionPointer; + ULONG ExtraRFETable; + ULONG ExtraRFETableSize; + ULONG __os_arm64x_dispatch_fptr; + ULONG AuxiliaryIATCopy; +} IMAGE_ARM64EC_METADATA; + +typedef struct _IMAGE_ARM64EC_REDIRECTION_ENTRY { + ULONG Source; + ULONG Destination; +} IMAGE_ARM64EC_REDIRECTION_ENTRY; + +// + +typedef NTSTATUS(__stdcall* P_NtQueryVirtualMemory64)( + IN HANDLE ProcessHandle, + IN DWORD64 BaseAddress, + IN MEMORY_INFORMATION_CLASS MemoryInformationClass, + OUT PVOID MemoryInformation, + IN SIZE_T MemoryInformationLength, + OUT PSIZE_T ReturnLength OPTIONAL); + +typedef NTSTATUS(__stdcall* P_NtReadVirtualMemory64)( + IN HANDLE ProcessHandle, + IN DWORD64 BaseAddress, + OUT PVOID Buffer, + IN SIZE_T BufferSize, + OUT PSIZE_T NumberOfBytesRead OPTIONAL); + +#ifdef _WIN64 +P_NtQueryVirtualMemory64 NtQueryVirtualMemory64 = (P_NtQueryVirtualMemory64)NtQueryVirtualMemory; +P_NtReadVirtualMemory64 NtReadVirtualMemory64 = (P_NtReadVirtualMemory64)NtReadVirtualMemory; +#else +P_NtQueryVirtualMemory64 NtQueryVirtualMemory64 = NULL; +P_NtReadVirtualMemory64 NtReadVirtualMemory64 = NULL; +#endif + +DWORD64 FindDllBase64(HANDLE hProcess, const WCHAR* dll) +{ + char buffer[512]; + ULONG len = wcslen(dll); + + if (!NtQueryVirtualMemory64) + return -1; + + for (DWORD64 baseAddress = 0;;) + { + MEMORY_BASIC_INFORMATION64 basicInfo; + if (!NT_SUCCESS(NtQueryVirtualMemory64(hProcess, baseAddress, MemoryBasicInformation, &basicInfo, sizeof(MEMORY_BASIC_INFORMATION64), NULL))) + break; + + baseAddress = baseAddress + basicInfo.RegionSize; + if (NT_SUCCESS(NtQueryVirtualMemory64(hProcess, basicInfo.AllocationBase, MemoryMappedFilenameInformation, buffer, sizeof(buffer), NULL))) + { + UNICODE_STRING64* FullImageName = (UNICODE_STRING*)buffer; + if (FullImageName->Length > len * sizeof(WCHAR)) { + + WCHAR* path = (WCHAR*)((DWORD64)FullImageName->Buffer + FullImageName->Length - len * sizeof(WCHAR)); + if (_wcsicmp(path, dll) == 0) { + + return (DWORD64)basicInfo.AllocationBase; + } + } + } + } + + return 0; +} + +BYTE* MapRemoteDll(HANDLE hProcess, DWORD64 DllBase) +{ + DWORD64 MaxSize = 0; + + if (!NtQueryVirtualMemory64 || !NtReadVirtualMemory64) + return (BYTE*)-1; + + for (DWORD64 baseAddress = 0;;) + { + MEMORY_BASIC_INFORMATION64 basicInfo; + if (!NT_SUCCESS(NtQueryVirtualMemory64(hProcess, baseAddress, MemoryBasicInformation, &basicInfo, sizeof(MEMORY_BASIC_INFORMATION64), NULL))) + break; + + baseAddress = baseAddress + basicInfo.RegionSize; + if (basicInfo.AllocationBase == DllBase) + { + DWORD64 CurrentSize = (basicInfo.BaseAddress + basicInfo.RegionSize) - basicInfo.AllocationBase; + if (MaxSize < CurrentSize) + MaxSize = CurrentSize; + } + } + + if (MaxSize == 0) + return NULL; + + BYTE* buffer = HeapAlloc(GetProcessHeap(), 0, (SIZE_T)MaxSize); + if (!buffer) + return NULL; + + BYTE* ptr = buffer; + for (DWORD64 pos = DllBase; pos < (DllBase + MaxSize); pos += 0x1000) + { + NtReadVirtualMemory64(hProcess, pos, ptr, 0x1000, NULL); + ptr += 0x1000; + } + + return buffer; +} + +IMAGE_SECTION_HEADER* FindImageSection(DWORD rva, PIMAGE_NT_HEADERS32 pNTHeader) +{ + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader); + for (ULONG i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++) { + DWORD size = section->Misc.VirtualSize; + if (size == 0) + size = section->SizeOfRawData; + if ((rva >= section->VirtualAddress) && (rva < (section->VirtualAddress + size))) + return section; + } + return NULL; +} + +DWORD64 FindImagePosition(DWORD rva, void* pNTHeader, DWORD64 imageBase) +{ + if (imageBase != 0) // live image + return imageBase + rva; + // file on disk + IMAGE_SECTION_HEADER* pSectionHdr = FindImageSection(rva, pNTHeader); + if (!pSectionHdr) + return 0; + DWORD delta = pSectionHdr->VirtualAddress - pSectionHdr->PointerToRawData; + //return imageBase + rva - delta; + return rva - delta; +} + +DWORD64 FindDllExport2(P_NtReadVirtualMemory64 ReadDll, HANDLE hProcess, DWORD64 DllBase, IMAGE_DATA_DIRECTORY *dir0, const char* ProcName, void* pNTHeader) +{ + NTSTATUS status; + BYTE* buffer; + DWORD64 proc = 0; + + DWORD64 dir0Address = FindImagePosition(dir0->VirtualAddress, pNTHeader, DllBase); + + buffer = HeapAlloc(GetProcessHeap(), 0, dir0->Size); + status = ReadDll(hProcess, dir0Address, buffer, dir0->Size, NULL); + + IMAGE_EXPORT_DIRECTORY* exports = buffer; + + ULONG* names = (ULONG*)((DWORD64)buffer + exports->AddressOfNames - dir0->VirtualAddress); + USHORT* ordinals = (USHORT*)((DWORD64)buffer + exports->AddressOfNameOrdinals - dir0->VirtualAddress); + ULONG* functions = (ULONG*)((DWORD64)buffer + exports->AddressOfFunctions - dir0->VirtualAddress); + + for (ULONG i = 0; i < exports->NumberOfNames; ++i) { + + //BYTE* name = (BYTE*)DllBase + names[i]; + char* name = (char*)((DWORD64)exports + names[i] - dir0->VirtualAddress); + + if(strcmp(name, ProcName) == 0) + { + if (ordinals[i] < exports->NumberOfFunctions) { + + proc = DllBase + functions[ordinals[i]]; + + // Note: if this is an arm32 image the real address has a 0x01 appended to indicate it uses the thumb instruction set + //if (((PIMAGE_NT_HEADERS32)pNTHeader)->FileHeader.Machine == IMAGE_FILE_MACHINE_ARMNT) + // proc &= ~1; + + break; + } + } + } + + if (proc && proc >= dir0Address && proc < dir0Address + dir0->Size) { + + // + // if the export points inside the export table, then it is a + // forwarder entry. we don't handle these, because none of the + // exports we need is a forwarder entry. if this changes, we + // might have to scan LDR tables to find the target dll + // + + proc = 0; + } + + HeapFree(GetProcessHeap(), 0, buffer); + + return proc; +} + +DWORD64 ResolveWoWRedirection64(P_NtReadVirtualMemory64 ReadDll, HANDLE hProcess, DWORD64 DllBase, DWORD64 proc, DWORD64 CHPEMetadataPointer, void* pNTHeader) +{ + NTSTATUS status; + + IMAGE_ARM64EC_METADATA MetaData; + status = ReadDll(hProcess, CHPEMetadataPointer, &MetaData, sizeof(MetaData), NULL); + + ULONG size = MetaData.RedirectionMetadataCount * sizeof(IMAGE_ARM64EC_REDIRECTION_ENTRY); + BYTE* buffer = HeapAlloc(GetProcessHeap(), 0, size); + status = ReadDll(hProcess, FindImagePosition(MetaData.RedirectionMetadata, pNTHeader, DllBase), buffer, size, NULL); + IMAGE_ARM64EC_REDIRECTION_ENTRY* RedirectionMetadata = buffer; + + for (ULONG i = 0; i < MetaData.RedirectionMetadataCount; i++) { + if ((proc - DllBase) == RedirectionMetadata[i].Source) { + proc = DllBase + RedirectionMetadata[i].Destination; + break; + } + } + + HeapFree(GetProcessHeap(), 0, buffer); + + return proc; +} + +DWORD64 FindDllExport_impl(P_NtReadVirtualMemory64 ReadDll, HANDLE hProcess, DWORD64 DllBase, const char* ProcName) +{ + NTSTATUS status; + DWORD64 proc = 0; + + IMAGE_DOS_HEADER* dos_hdr; + IMAGE_NT_HEADERS* nt_hdrs; + + BYTE Buffer[0x10000]; + BYTE Buffer2[0x10000]; + + status = ReadDll(hProcess, DllBase, Buffer, sizeof(Buffer), NULL); + + BOOLEAN resolve_ec = ProcName[0] == '#'; + if (resolve_ec) + ProcName++; + + BOOLEAN resolve_exp = memcmp(ProcName, "EXP+", 4) == 0; + if (resolve_exp) + ProcName += 4; + + dos_hdr = Buffer; + + if (dos_hdr->e_magic != 'MZ' && dos_hdr->e_magic != 'ZM') + return 0; + nt_hdrs = (IMAGE_NT_HEADERS*)((BYTE*)dos_hdr + dos_hdr->e_lfanew); + if (nt_hdrs->Signature != IMAGE_NT_SIGNATURE) // 'PE\0\0' + return 0; + + if (nt_hdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + + IMAGE_NT_HEADERS32* nt_hdrs_32 = (IMAGE_NT_HEADERS32*)nt_hdrs; + IMAGE_OPTIONAL_HEADER32* opt_hdr_32 = &nt_hdrs_32->OptionalHeader; + + if (opt_hdr_32->NumberOfRvaAndSizes) { + + IMAGE_DATA_DIRECTORY* dir0 = &opt_hdr_32->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + proc = FindDllExport2(ReadDll, hProcess, DllBase, dir0, ProcName, nt_hdrs_32); + } + } + + else if (nt_hdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + + IMAGE_NT_HEADERS64* nt_hdrs_64 = (IMAGE_NT_HEADERS64*)nt_hdrs; + IMAGE_OPTIONAL_HEADER64* opt_hdr_64 = &nt_hdrs_64->OptionalHeader; + + if (opt_hdr_64->NumberOfRvaAndSizes) { + + IMAGE_LOAD_CONFIG_DIRECTORY64 LoadConfig; + + IMAGE_DATA_DIRECTORY* dir10 = &opt_hdr_64->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]; + if (resolve_ec && dir10->VirtualAddress && dir10->Size >= FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, CHPEMetadataPointer) + sizeof(ULONGLONG)) { + + status = ReadDll(hProcess, FindImagePosition(dir10->VirtualAddress, nt_hdrs_64, DllBase), &LoadConfig, min(sizeof(LoadConfig), dir10->Size), NULL); + } + + typedef struct _DYN_RELOC_TABLE { + ULONG Unknown1; + ULONG Unknown2; + ULONG Unknown3; + ULONG Unknown4; + ULONG TableSize; + UCHAR Entries[]; + } DYN_RELOC_TABLE; + + DYN_RELOC_TABLE* DynamicValueRelocTable = NULL; + + if (DllBase == 0 && (resolve_ec || resolve_exp)) { // only for images on disk, on linve images we take the actuallly used export directory + + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(nt_hdrs); + nt_hdrs->FileHeader.NumberOfSections; + + section += (LoadConfig.DynamicValueRelocTableSection - 1); + + DWORD64 pos = FindImagePosition(section->VirtualAddress, nt_hdrs_64, DllBase); + status = ReadDll(hProcess, pos, Buffer2, min(sizeof(Buffer2), section->Misc.VirtualSize), NULL); + + DynamicValueRelocTable = (DYN_RELOC_TABLE*)(Buffer2 + LoadConfig.DynamicValueRelocTableOffset); + + + for (UCHAR* TablePtr = DynamicValueRelocTable->Entries; TablePtr < DynamicValueRelocTable->Entries + DynamicValueRelocTable->TableSize; ) { + + struct { + ULONG Offset; + ULONG Size; + } *Section = TablePtr; + TablePtr += 8; + Section->Size -= 8; + + for (UCHAR* EntryPtr = TablePtr; TablePtr < EntryPtr + Section->Size; ) { + + struct { + USHORT + RVA : 12, + Unknown : 1, + Size : 3; + } *Entry = TablePtr; + TablePtr += 2; + + ULONGLONG Value = 0; + memcpy(&Value, TablePtr, Entry->Size); + TablePtr += Entry->Size; + + ULONG RVA = Section->Offset + Entry->RVA; + + // Apply the value relocs to our header buffer + if (RVA < sizeof(Buffer)) { + + //DbgPrintf("%08x -> %08x\n", RVA, (ULONG)Value); + memcpy(Buffer + RVA, &Value, Entry->Size); + } + } + } + } + + IMAGE_DATA_DIRECTORY* dir0 = &opt_hdr_64->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + + proc = FindDllExport2(ReadDll, hProcess, DllBase, dir0, ProcName, nt_hdrs_64); + + if(resolve_ec && LoadConfig.CHPEMetadataPointer) { + if (DllBase == 0) // file on disk + LoadConfig.CHPEMetadataPointer = FindImagePosition((DWORD)(LoadConfig.CHPEMetadataPointer - opt_hdr_64->ImageBase), nt_hdrs_64, DllBase); + proc = ResolveWoWRedirection64(ReadDll, hProcess, DllBase, proc, LoadConfig.CHPEMetadataPointer, nt_hdrs_64); + } + } + } + + return proc; +} + +NTSTATUS __stdcall ReadLocalMemory( + _In_ HANDLE Unused, + _In_opt_ DWORD64 BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T pNumberOfBytesRead) +{ + memcpy(Buffer, (void*)BaseAddress, BufferSize); + if (pNumberOfBytesRead) *pNumberOfBytesRead = BufferSize; + return 0; +} + +DWORD64 FindDllExport(DWORD64 DllBase, const char* ProcName) +{ + return FindDllExport_impl(ReadLocalMemory, NULL, DllBase, ProcName); +} + +DWORD64 FindRemoteDllExport(HANDLE hProcess, DWORD64 DllBase, const char* ProcName) +{ + if (NtReadVirtualMemory64 == NULL) + return -1; + + return FindDllExport_impl(NtReadVirtualMemory64, hProcess, DllBase, ProcName); +} + +NTSTATUS __stdcall ReadDllFile( + _In_ HANDLE FileHandle, + _In_opt_ DWORD64 BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T pNumberOfBytesRead) +{ + LARGE_INTEGER pos; + pos.QuadPart = BaseAddress; + SetFilePointerEx(FileHandle, pos, NULL, FILE_BEGIN); + DWORD NumberOfBytesRead; + BOOL ret = ReadFile(FileHandle, Buffer, (DWORD)BufferSize, &NumberOfBytesRead, NULL); + if (pNumberOfBytesRead) *pNumberOfBytesRead = NumberOfBytesRead; + return ret ? 0 : 0xC0000001L; +} + +DWORD64 FindDllExportFromFile(const WCHAR* dll, const char* ProcName) +{ + DWORD64 proc; + HANDLE hFile = CreateFileW(dll, GENERIC_READ, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return 0; + + proc = FindDllExport_impl(ReadDllFile, hFile, 0, ProcName); + + CloseHandle(hFile); + return proc; +} diff --git a/Sandboxie/common/dllimport.h b/Sandboxie/common/dllimport.h new file mode 100644 index 00000000..b399710c --- /dev/null +++ b/Sandboxie/common/dllimport.h @@ -0,0 +1,39 @@ +/* + * Copyright 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 . + */ + + +#ifndef DLLIMPORT_H +#define DLLIMPORT_H +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +DWORD64 FindDllBase64(HANDLE hProcess, const WCHAR* dll); +BYTE* MapRemoteDll(HANDLE hProcess, DWORD64 DllBase); +DWORD64 FindDllExport(DWORD64 DllBase, const char* ProcName); +DWORD64 FindRemoteDllExport(HANDLE hProcess, DWORD64 DllBase, const char* ProcName); +DWORD64 FindDllExportFromFile(const WCHAR* dll, const char* ProcName); + +#ifdef __cplusplus +} +#endif + +#endif /* DLLIMPORT_H */ diff --git a/Sandboxie/common/hook_util.c b/Sandboxie/common/hook_util.c new file mode 100644 index 00000000..40fc2c2a --- /dev/null +++ b/Sandboxie/common/hook_util.c @@ -0,0 +1,146 @@ +/* + * Copyright 2004-2020 Sandboxie Holdings, LLC + * 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 . + */ + +//--------------------------------------------------------------------------- +// Variouse generic hooking helpers +//--------------------------------------------------------------------------- + + + + +//--------------------------------------------------------------------------- +// Hook_CheckChromeHook +//--------------------------------------------------------------------------- + + +#ifdef _WIN64 +#define MAX_FUNC_SIZE 0x76 +ULONGLONG * findChromeTarget(unsigned char* addr) +{ + int i = 0; + ULONGLONG target; + ULONGLONG * ChromeTarget = NULL; + if (!addr) return NULL; + + //Look for mov rcx,[target 4 byte offset] or in some cases mov rax,[target 4 byte offset] + //So far the offset has been positive between 0xa00000 and 0xb00000 bytes; + //This may change in a future version of chrome + for (i = 0; i < MAX_FUNC_SIZE; i++) { + + // some chromium 90+ derivatives replace the function with a return 1 stub + // mov eax,1 + // ret + // int 3 + if (addr[i] == 0xB8 && addr[i + 5] == 0xC3 && addr[i + 6] == 0xCC) + return NULL; + + if ((*(USHORT *)&addr[i] == 0x8b48)) { + + //Look for mov rcx,[target 4 byte offset] or in some cases mov rax,[target 4 byte offset] + if ((addr[i + 2] == 0x0d || addr[i + 2] == 0x05)) { + LONG delta; + target = (ULONG_PTR)(addr + i + 7); + delta = *(LONG *)&addr[i + 3]; + + //check if offset is close to the expected value (is positive and less than 0x100000 as of chrome 64) + // if (delta > 0 && delta < 0x100000 ) { //may need to check delta in a future version of chrome + target += delta; + ChromeTarget = *(ULONGLONG **)target; + + // special case when compiled using mingw toolchain + // mov rcx,qword ptr [rax+offset] or mov rcx,qword ptr [rcx+offset] + if ((*(USHORT *)&addr[i + 7] == 0x8B48)) + { + if (addr[i + 9] == 0x48 || addr[i + 9] == 0x49) + delta = addr[i + 10]; + else if (addr[i + 9] == 0x88 || addr[i + 9] == 0x89) + delta = *(ULONG*)&addr[i + 10]; + else + break; + target = (ULONGLONG)ChromeTarget + delta; + ChromeTarget = *(ULONGLONG **)target; + } + + // } + break; + } + } + } + + return ChromeTarget; +} +#endif + +_FX void* Hook_CheckChromeHook(void *SourceFunc) +{ + if (!SourceFunc) + return NULL; +#ifdef _WIN64 + UCHAR *func = (UCHAR *)SourceFunc; + ULONGLONG *chrome64Target = NULL; + + if (func[0] == 0x50 && //push rax + func[1] == 0x48 && //mov rax,? + func[2] == 0xb8) { + ULONGLONG *longlongs = *(ULONGLONG **)&func[3]; + chrome64Target = findChromeTarget((unsigned char *)longlongs); + } + // Chrome 49+ 64bit hook + // mov rax, + // jmp rax + else if (func[0] == 0x48 && //mov rax, + func[1] == 0xb8 && + *(USHORT *)&func[10] == 0xe0ff) /* jmp rax */ { + ULONGLONG *longlongs = *(ULONGLONG **)&func[2]; + chrome64Target = findChromeTarget((unsigned char *)longlongs); + } + if (chrome64Target) { + SourceFunc = chrome64Target; + } + /*sboxie 64bit jtable hook signature */ + /* // use this to hook jtable location (useful for debugging) + //else if(func[0] == 0x51 && func[1] == 0x48 && func[2] == 0xb8 ) { + else if(func[0] == 0x90 && func[1] == 0x48 && func[2] == 0xb8 ) { + long long addr; + addr = (ULONG_PTR) *(ULONGLONG **)&func[3] ; + SourceFunc = (void *) addr; + } + */ +#else + UCHAR *func = (UCHAR *)SourceFunc; + if (func[0] == 0xB8 && // mov eax,? + func[5] == 0xBA && // mov edx,? + *(USHORT *)&func[10] == 0xE2FF) // jmp edx + { + ULONG i = 0; + ULONG *longs = *(ULONG **)&func[6]; + + for (i = 0; i < 20; i++, longs++) + { + if (longs[0] == 0x5208EC83 && longs[1] == 0x0C24548B && + longs[2] == 0x08245489 && longs[3] == 0x0C2444C7 && + longs[5] == 0x042444C7) + { + SourceFunc = (void *)longs[4]; + break; + } + } + } +#endif ! _WIN64 + return SourceFunc; +} \ No newline at end of file diff --git a/Sandboxie/common/wow64ext/CMemPtr.h b/Sandboxie/common/wow64ext/CMemPtr.h deleted file mode 100644 index 01502b59..00000000 --- a/Sandboxie/common/wow64ext/CMemPtr.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * - * WOW64Ext Library - * - * Copyright (c) 2014 ReWolf - * http://blog.rewolf.pl/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - */ -#pragma once - -class CMemPtr -{ -private: - void** m_ptr; - bool watchActive; - -public: - CMemPtr(void** ptr) : m_ptr(ptr), watchActive(true) {} - - ~CMemPtr() - { - if (*m_ptr && watchActive) - { - HeapFree(GetProcessHeap(), 0, *m_ptr); - *m_ptr = 0; - } - } - - static void* Alloc(size_t size) { - return HeapAlloc(GetProcessHeap(), 0, size); - } - - void disableWatch() { watchActive = false; } -}; - -#define NEW(size) \ - CMemPtr::Alloc(size) - -#define WATCH(ptr) \ - CMemPtr watch_##ptr((void**)&ptr) - -#define DISABLE_WATCH(ptr) \ - watch_##ptr.disableWatch() diff --git a/Sandboxie/common/wow64ext/internal.h b/Sandboxie/common/wow64ext/internal.h deleted file mode 100644 index b439881a..00000000 --- a/Sandboxie/common/wow64ext/internal.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * - * WOW64Ext Library - * - * Copyright (c) 2014 ReWolf - * http://blog.rewolf.pl/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - */ -#pragma once - -#define EMIT(a) __asm __emit (a) - -#define X64_Start_with_CS(_cs) \ - { \ - EMIT(0x6A) EMIT(_cs) /* push _cs */ \ - EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \ - EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(5) /* add dword [esp], 5 */ \ - EMIT(0xCB) /* retf */ \ - } - -#define X64_End_with_CS(_cs) \ - { \ - EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \ - EMIT(0xC7) EMIT(0x44) EMIT(0x24) EMIT(4) EMIT(_cs) EMIT(0) EMIT(0) EMIT(0) /* mov dword [rsp + 4], _cs */ \ - EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(0xD) /* add dword [rsp], 0xD */ \ - EMIT(0xCB) /* retf */ \ - } - -#define X64_Start() X64_Start_with_CS(0x33) -#define X64_End() X64_End_with_CS(0x23) - -#define _RAX 0 -#define _RCX 1 -#define _RDX 2 -#define _RBX 3 -#define _RSP 4 -#define _RBP 5 -#define _RSI 6 -#define _RDI 7 -#define _R8 8 -#define _R9 9 -#define _R10 10 -#define _R11 11 -#define _R12 12 -#define _R13 13 -#define _R14 14 -#define _R15 15 - -#define X64_Push(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x50 | ((r) & 7)) -#define X64_Pop(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x58 | ((r) & 7)) - -#define REX_W EMIT(0x48) __asm - -//to fool M$ inline asm compiler I'm using 2 DWORDs instead of DWORD64 -//use of DWORD64 will generate wrong 'pop word ptr[]' and it will break stack -union reg64 -{ - DWORD64 v; - DWORD dw[2]; -}; diff --git a/Sandboxie/common/wow64ext/wow64ext.cpp b/Sandboxie/common/wow64ext/wow64ext.cpp deleted file mode 100644 index 91cbd0c7..00000000 --- a/Sandboxie/common/wow64ext/wow64ext.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/** - * - * WOW64Ext Library - * - * Copyright (c) 2014 ReWolf - * http://blog.rewolf.pl/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - */ - -#include -#include "internal.h" -#include "wow64ext.h" - -#if defined _MSC_VER && !defined _CRT_USE_BUILTIN_OFFSETOF - #ifdef __cplusplus - #define offsetof(s,m) ((::size_t)&reinterpret_cast((((s*)0)->m))) - #else - #define offsetof(s,m) ((size_t)&(((s*)0)->m)) - #endif -#else - #define offsetof(s,m) __builtin_offsetof(s,m) -#endif - -//HANDLE g_heap; -BOOL g_isWow64 = TRUE; - -#include "CMemPtr.h" - -/*int _wcsicmp(const wchar_t *string1, const wchar_t *string2) -{ - wchar_t c1; - wchar_t c2; - int i = 0; - do - { - c1 = string1[i]; - if (c1 >= 'A' && c1 <= 'Z') - c1 += 0x20; - - c2 = string2[i]; - if (c2 >= 'A' && c2 <= 'Z') - c2 += 0x20; - - i++; - } while (c1 && c1 == c2); - return c1 - c2; -}*/ - -/*BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (DLL_PROCESS_ATTACH == fdwReason) - { - IsWow64Process(GetCurrentProcess(), &g_isWow64); - g_heap = GetProcessHeap(); - } - return TRUE; -}*/ - -#pragma warning(push) -#pragma warning(disable : 4409) -extern "C" DWORD64 __cdecl X64Call(DWORD64 func, int argC, ...) -{ - if (!g_isWow64) - return 0; - - va_list args; - va_start(args, argC); - reg64 _rcx = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 }; - reg64 _rdx = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 }; - reg64 _r8 = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 }; - reg64 _r9 = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 }; - reg64 _rax = { 0 }; - - reg64 restArgs = { (DWORD64)&va_arg(args, DWORD64) }; - - // conversion to QWORD for easier use in inline assembly -#ifdef _M_IX86 - reg64 _argC = { (DWORD64)argC }; - DWORD back_esp = 0; - WORD back_fs = 0; - __asm - { - ;// reset FS segment, to properly handle RFG - mov back_fs, fs - mov eax, 0x2B - mov fs, ax - - ;// keep original esp in back_esp variable - mov back_esp, esp - - ;// align esp to 0x10, without aligned stack some syscalls may return errors ! - ;// (actually, for syscalls it is sufficient to align to 8, but SSE opcodes - ;// requires 0x10 alignment), it will be further adjusted according to the - ;// number of arguments above 4 - and esp, 0xFFFFFFF0 - - X64_Start(); - - ;// below code is compiled as x86 inline asm, but it is executed as x64 code - ;// that's why it need sometimes REX_W() macro, right column contains detailed - ;// transcription how it will be interpreted by CPU - - ;// fill first four arguments - REX_W mov ecx, _rcx.dw[0] ;// mov rcx, qword ptr [_rcx] - REX_W mov edx, _rdx.dw[0] ;// mov rdx, qword ptr [_rdx] - push _r8.v ;// push qword ptr [_r8] - X64_Pop(_R8); ;// pop r8 - push _r9.v ;// push qword ptr [_r9] - X64_Pop(_R9); ;// pop r9 - ;// - REX_W mov eax, _argC.dw[0] ;// mov rax, qword ptr [_argC] - ;// - ;// final stack adjustment, according to the ;// - ;// number of arguments above 4 ;// - test al, 1 ;// test al, 1 - jnz _no_adjust ;// jnz _no_adjust - sub esp, 8 ;// sub rsp, 8 -_no_adjust: ;// - ;// - push edi ;// push rdi - REX_W mov edi, restArgs.dw[0] ;// mov rdi, qword ptr [restArgs] - ;// - ;// put rest of arguments on the stack ;// - REX_W test eax, eax ;// test rax, rax - jz _ls_e ;// je _ls_e - REX_W lea edi, dword ptr [edi + 8*eax - 8] ;// lea rdi, [rdi + rax*8 - 8] - ;// -_ls: ;// - REX_W test eax, eax ;// test rax, rax - jz _ls_e ;// je _ls_e - push dword ptr [edi] ;// push qword ptr [rdi] - REX_W sub edi, 8 ;// sub rdi, 8 - REX_W sub eax, 1 ;// sub rax, 1 - jmp _ls ;// jmp _ls -_ls_e: ;// - ;// - ;// create stack space for spilling registers ;// - REX_W sub esp, 0x20 ;// sub rsp, 20h - ;// - call func ;// call qword ptr [func] - ;// - ;// cleanup stack ;// - REX_W mov ecx, _argC.dw[0] ;// mov rcx, qword ptr [_argC] - REX_W lea esp, dword ptr [esp + 8*ecx + 0x20] ;// lea rsp, [rsp + rcx*8 + 20h] - ;// - pop edi ;// pop rdi - ;// - // set return value ;// - REX_W mov _rax.dw[0], eax ;// mov qword ptr [_rax], rax - - X64_End(); - - mov ax, ds - mov ss, ax - mov esp, back_esp - - ;// restore FS segment - mov ax, back_fs - mov fs, ax - } -#endif // _M_IX86 - - return _rax.v; -} -#pragma warning(pop) - -void getMem64(void* dstMem, DWORD64 srcMem, size_t sz) -{ - if ((nullptr == dstMem) || (0 == srcMem) || (0 == sz)) - return; - - reg64 _src = { srcMem }; -#ifdef _M_IX86 - __asm - { - X64_Start(); - - ;// below code is compiled as x86 inline asm, but it is executed as x64 code - ;// that's why it need sometimes REX_W() macro, right column contains detailed - ;// transcription how it will be interpreted by CPU - - push edi ;// push rdi - push esi ;// push rsi - ;// - mov edi, dstMem ;// mov edi, dword ptr [dstMem] ; high part of RDI is zeroed - REX_W mov esi, _src.dw[0] ;// mov rsi, qword ptr [_src] - mov ecx, sz ;// mov ecx, dword ptr [sz] ; high part of RCX is zeroed - ;// - mov eax, ecx ;// mov eax, ecx - and eax, 3 ;// and eax, 3 - shr ecx, 2 ;// shr ecx, 2 - ;// - rep movsd ;// rep movs dword ptr [rdi], dword ptr [rsi] - ;// - test eax, eax ;// test eax, eax - je _move_0 ;// je _move_0 - cmp eax, 1 ;// cmp eax, 1 - je _move_1 ;// je _move_1 - ;// - movsw ;// movs word ptr [rdi], word ptr [rsi] - cmp eax, 2 ;// cmp eax, 2 - je _move_0 ;// je _move_0 - ;// -_move_1: ;// - movsb ;// movs byte ptr [rdi], byte ptr [rsi] - ;// -_move_0: ;// - pop esi ;// pop rsi - pop edi ;// pop rdi - - X64_End(); - } -#endif -} - -bool cmpMem64(const void* dstMem, DWORD64 srcMem, size_t sz) -{ - if ((nullptr == dstMem) || (0 == srcMem) || (0 == sz)) - return false; - - bool result = false; - reg64 _src = { srcMem }; -#ifdef _M_IX86 - __asm - { - X64_Start(); - - ;// below code is compiled as x86 inline asm, but it is executed as x64 code - ;// that's why it need sometimes REX_W() macro, right column contains detailed - ;// transcription how it will be interpreted by CPU - - push edi ;// push rdi - push esi ;// push rsi - ;// - mov edi, dstMem ;// mov edi, dword ptr [dstMem] ; high part of RDI is zeroed - REX_W mov esi, _src.dw[0] ;// mov rsi, qword ptr [_src] - mov ecx, sz ;// mov ecx, dword ptr [sz] ; high part of RCX is zeroed - ;// - mov eax, ecx ;// mov eax, ecx - and eax, 3 ;// and eax, 3 - shr ecx, 2 ;// shr ecx, 2 - ;// - repe cmpsd ;// repe cmps dword ptr [rsi], dword ptr [rdi] - jnz _ret_false ;// jnz _ret_false - ;// - test eax, eax ;// test eax, eax - je _move_0 ;// je _move_0 - cmp eax, 1 ;// cmp eax, 1 - je _move_1 ;// je _move_1 - ;// - cmpsw ;// cmps word ptr [rsi], word ptr [rdi] - jnz _ret_false ;// jnz _ret_false - cmp eax, 2 ;// cmp eax, 2 - je _move_0 ;// je _move_0 - ;// -_move_1: ;// - cmpsb ;// cmps byte ptr [rsi], byte ptr [rdi] - jnz _ret_false ;// jnz _ret_false - ;// -_move_0: ;// - mov result, 1 ;// mov byte ptr [result], 1 - ;// -_ret_false: ;// - pop esi ;// pop rsi - pop edi ;// pop rdi - - X64_End(); - } -#endif - return result; -} - -DWORD64 getTEB64() -{ - reg64 reg; - reg.v = 0; -#ifdef _M_IX86 - X64_Start(); - // R12 register should always contain pointer to TEB64 in WoW64 processes - X64_Push(_R12); - // below pop will pop QWORD from stack, as we're in x64 mode now - __asm pop reg.dw[0] - X64_End(); -#endif - return reg.v; -} - -extern "C" DWORD64 __cdecl GetModuleHandle64(const wchar_t* lpModuleName) -{ - if (!g_isWow64) - return 0; - - TEB64 teb64; - getMem64(&teb64, getTEB64(), sizeof(TEB64)); - - PEB64 peb64; - getMem64(&peb64, teb64.ProcessEnvironmentBlock, sizeof(PEB64)); - PEB_LDR_DATA64 ldr; - getMem64(&ldr, peb64.Ldr, sizeof(PEB_LDR_DATA64)); - - DWORD64 LastEntry = peb64.Ldr + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList); - LDR_DATA_TABLE_ENTRY64 head; - head.InLoadOrderLinks.Flink = ldr.InLoadOrderModuleList.Flink; - do - { - getMem64(&head, head.InLoadOrderLinks.Flink, sizeof(LDR_DATA_TABLE_ENTRY64)); - - wchar_t* tempBuf = (wchar_t*)NEW(head.BaseDllName.MaximumLength); - if (nullptr == tempBuf) - return 0; - WATCH(tempBuf); - getMem64(tempBuf, head.BaseDllName.Buffer, head.BaseDllName.MaximumLength); - - if (0 == _wcsicmp(lpModuleName, tempBuf)) - return head.DllBase; - } - while (head.InLoadOrderLinks.Flink != LastEntry); - - return 0; -} - -DWORD64 __cdecl getNTDLL64() -{ - static DWORD64 ntdll64 = 0; - if (0 != ntdll64) - return ntdll64; - - ntdll64 = GetModuleHandle64(L"ntdll.dll"); - return ntdll64; -} - -DWORD64 getLdrGetProcedureAddress() -{ - DWORD64 modBase = getNTDLL64(); - if (0 == modBase) - return 0; - - IMAGE_DOS_HEADER idh; - getMem64(&idh, modBase, sizeof(idh)); - - IMAGE_NT_HEADERS64 inh; - getMem64(&inh, modBase + idh.e_lfanew, sizeof(IMAGE_NT_HEADERS64)); - - IMAGE_DATA_DIRECTORY& idd = inh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - - if (0 == idd.VirtualAddress) - return 0; - - IMAGE_EXPORT_DIRECTORY ied; - getMem64(&ied, modBase + idd.VirtualAddress, sizeof(ied)); - - DWORD* rvaTable = (DWORD*)NEW(sizeof(DWORD)*ied.NumberOfFunctions); - if (nullptr == rvaTable) - return 0; - WATCH(rvaTable); - getMem64(rvaTable, modBase + ied.AddressOfFunctions, sizeof(DWORD)*ied.NumberOfFunctions); - - WORD* ordTable = (WORD*)NEW(sizeof(WORD)*ied.NumberOfFunctions); - if (nullptr == ordTable) - return 0; - WATCH(ordTable); - getMem64(ordTable, modBase + ied.AddressOfNameOrdinals, sizeof(WORD)*ied.NumberOfFunctions); - - DWORD* nameTable = (DWORD*)NEW(sizeof(DWORD)*ied.NumberOfNames); - if (nullptr == nameTable) - return 0; - WATCH(nameTable); - getMem64(nameTable, modBase + ied.AddressOfNames, sizeof(DWORD)*ied.NumberOfNames); - - // lazy search, there is no need to use binsearch for just one function - for (DWORD i = 0; i < ied.NumberOfFunctions; i++) - { - if (!cmpMem64("LdrGetProcedureAddress", modBase + nameTable[i], sizeof("LdrGetProcedureAddress"))) - continue; - else - return modBase + rvaTable[ordTable[i]]; - } - return 0; -} - -extern "C" VOID __cdecl SetLastErrorFromX64Call(DWORD64 status) -{ - typedef ULONG (WINAPI *RtlNtStatusToDosError_t)(LONG Status); - typedef ULONG (WINAPI *RtlSetLastWin32Error_t)(LONG Status); - - static RtlNtStatusToDosError_t RtlNtStatusToDosError = nullptr; - static RtlSetLastWin32Error_t RtlSetLastWin32Error = nullptr; - - if ((nullptr == RtlNtStatusToDosError) || (nullptr == RtlSetLastWin32Error)) - { - HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); - RtlNtStatusToDosError = (RtlNtStatusToDosError_t)GetProcAddress(ntdll, "RtlNtStatusToDosError"); - RtlSetLastWin32Error = (RtlSetLastWin32Error_t)GetProcAddress(ntdll, "RtlSetLastWin32Error"); - } - - if ((nullptr != RtlNtStatusToDosError) && (nullptr != RtlSetLastWin32Error)) - { - RtlSetLastWin32Error(RtlNtStatusToDosError((DWORD)status)); - } -} - -extern "C" DWORD64 __cdecl GetProcAddress64(DWORD64 hModule, const char* funcName) -{ - static DWORD64 _LdrGetProcedureAddress = 0; - if (0 == _LdrGetProcedureAddress) - { - _LdrGetProcedureAddress = getLdrGetProcedureAddress(); - if (0 == _LdrGetProcedureAddress) - return 0; - } - - _UNICODE_STRING_T fName = { 0 }; - fName.Buffer = (DWORD64)funcName; - fName.Length = (WORD)strlen(funcName); - fName.MaximumLength = fName.Length + 1; - DWORD64 funcRet = 0; - X64Call(_LdrGetProcedureAddress, 4, (DWORD64)hModule, (DWORD64)&fName, (DWORD64)0, (DWORD64)&funcRet); - return funcRet; -} - -extern "C" SIZE_T __cdecl VirtualQueryEx64(HANDLE hProcess, DWORD64 lpAddress, MEMORY_BASIC_INFORMATION64* lpBuffer, SIZE_T dwLength) -{ - static DWORD64 ntqvm = 0; - if (0 == ntqvm) - { - ntqvm = GetProcAddress64(getNTDLL64(), "NtQueryVirtualMemory"); - if (0 == ntqvm) - return 0; - } - DWORD64 ret = 0; - DWORD64 status = X64Call(ntqvm, 6, (DWORD64)hProcess, lpAddress, (DWORD64)0, (DWORD64)lpBuffer, (DWORD64)dwLength, (DWORD64)&ret); - if (STATUS_SUCCESS != status) - SetLastErrorFromX64Call(status); - return (SIZE_T)ret; -} - -extern "C" DWORD64 __cdecl VirtualAllocEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) -{ - static DWORD64 ntavm = 0; - if (0 == ntavm) - { - ntavm = GetProcAddress64(getNTDLL64(), "NtAllocateVirtualMemory"); - if (0 == ntavm) - return 0; - } - - DWORD64 tmpAddr = lpAddress; - DWORD64 tmpSize = dwSize; - DWORD64 ret = X64Call(ntavm, 6, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)0, (DWORD64)&tmpSize, (DWORD64)flAllocationType, (DWORD64)flProtect); - if (STATUS_SUCCESS != ret) - { - SetLastErrorFromX64Call(ret); - return FALSE; - } - else - return tmpAddr; -} - -extern "C" BOOL __cdecl VirtualFreeEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD dwFreeType) -{ - static DWORD64 ntfvm = 0; - if (0 == ntfvm) - { - ntfvm = GetProcAddress64(getNTDLL64(), "NtFreeVirtualMemory"); - if (0 == ntfvm) - return 0; - } - - DWORD64 tmpAddr = lpAddress; - DWORD64 tmpSize = dwSize; - DWORD64 ret = X64Call(ntfvm, 4, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)dwFreeType); - if (STATUS_SUCCESS != ret) - { - SetLastErrorFromX64Call(ret); - return FALSE; - } - else - return TRUE; -} - -extern "C" BOOL __cdecl VirtualProtectEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD* lpflOldProtect) -{ - static DWORD64 ntpvm = 0; - if (0 == ntpvm) - { - ntpvm = GetProcAddress64(getNTDLL64(), "NtProtectVirtualMemory"); - if (0 == ntpvm) - return 0; - } - - DWORD64 tmpAddr = lpAddress; - DWORD64 tmpSize = dwSize; - DWORD64 ret = X64Call(ntpvm, 5, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)flNewProtect, (DWORD64)lpflOldProtect); - if (STATUS_SUCCESS != ret) - { - SetLastErrorFromX64Call(ret); - return FALSE; - } - else - return TRUE; -} - -extern "C" BOOL __cdecl ReadProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead) -{ - static DWORD64 nrvm = 0; - if (0 == nrvm) - { - nrvm = GetProcAddress64(getNTDLL64(), "NtReadVirtualMemory"); - if (0 == nrvm) - return 0; - } - DWORD64 numOfBytes = lpNumberOfBytesRead ? *lpNumberOfBytesRead : 0; - DWORD64 ret = X64Call(nrvm, 5, (DWORD64)hProcess, lpBaseAddress, (DWORD64)lpBuffer, (DWORD64)nSize, (DWORD64)&numOfBytes); - if (STATUS_SUCCESS != ret && ret != 0x8000000DL) // STATUS_PARTIAL_COPY - { - SetLastErrorFromX64Call(ret); - return FALSE; - } - else - { - if (lpNumberOfBytesRead) - *lpNumberOfBytesRead = (SIZE_T)numOfBytes; - return TRUE; - } -} - -extern "C" BOOL __cdecl WriteProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten) -{ - static DWORD64 nrvm = 0; - if (0 == nrvm) - { - nrvm = GetProcAddress64(getNTDLL64(), "NtWriteVirtualMemory"); - if (0 == nrvm) - return 0; - } - DWORD64 numOfBytes = lpNumberOfBytesWritten ? *lpNumberOfBytesWritten : 0; - DWORD64 ret = X64Call(nrvm, 5, (DWORD64)hProcess, lpBaseAddress, (DWORD64)lpBuffer, (DWORD64)nSize, (DWORD64)&numOfBytes); - if (STATUS_SUCCESS != ret) - { - SetLastErrorFromX64Call(ret); - return FALSE; - } - else - { - if (lpNumberOfBytesWritten) - *lpNumberOfBytesWritten = (SIZE_T)numOfBytes; - return TRUE; - } -} - -extern "C" BOOL __cdecl GetThreadContext64(HANDLE hThread, _CONTEXT64_2* lpContext) -{ - static DWORD64 gtc = 0; - if (0 == gtc) - { - gtc = GetProcAddress64(getNTDLL64(), "NtGetContextThread"); - if (0 == gtc) - return 0; - } - DWORD64 ret = X64Call(gtc, 2, (DWORD64)hThread, (DWORD64)lpContext); - if(STATUS_SUCCESS != ret) - { - SetLastErrorFromX64Call(ret); - return FALSE; - } - else - return TRUE; -} - -extern "C" BOOL __cdecl SetThreadContext64(HANDLE hThread, _CONTEXT64_2* lpContext) -{ - static DWORD64 stc = 0; - if (0 == stc) - { - stc = GetProcAddress64(getNTDLL64(), "NtSetContextThread"); - if (0 == stc) - return 0; - } - DWORD64 ret = X64Call(stc, 2, (DWORD64)hThread, (DWORD64)lpContext); - if (STATUS_SUCCESS != ret) - { - SetLastErrorFromX64Call(ret); - return FALSE; - } - else - return TRUE; -} diff --git a/Sandboxie/common/wow64ext/wow64ext.h b/Sandboxie/common/wow64ext/wow64ext.h deleted file mode 100644 index c0fd0b33..00000000 --- a/Sandboxie/common/wow64ext/wow64ext.h +++ /dev/null @@ -1,377 +0,0 @@ -/** - * - * WOW64Ext Library - * - * Copyright (c) 2014 ReWolf - * http://blog.rewolf.pl/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - */ -#pragma once - -#include - -#ifndef STATUS_SUCCESS -# define STATUS_SUCCESS 0 -#endif - -#pragma warning(disable : 4201) -#pragma pack(push) -#pragma pack(1) -template -struct _LIST_ENTRY_T -{ - T Flink; - T Blink; -}; - -template -struct _UNICODE_STRING_T -{ - union - { - struct - { - WORD Length; - WORD MaximumLength; - }; - T dummy; - }; - T Buffer; -}; - -template -struct _NT_TIB_T -{ - T ExceptionList; - T StackBase; - T StackLimit; - T SubSystemTib; - T FiberData; - T ArbitraryUserPointer; - T Self; -}; - -template -struct _CLIENT_ID_T -{ - T UniqueProcess; - T UniqueThread; -}; - -template -struct _TEB_T_ -{ - _NT_TIB_T NtTib; - T EnvironmentPointer; - _CLIENT_ID_T ClientId; - T ActiveRpcHandle; - T ThreadLocalStoragePointer; - T ProcessEnvironmentBlock; - DWORD LastErrorValue; - DWORD CountOfOwnedCriticalSections; - T CsrClientThread; - T Win32ThreadInfo; - DWORD User32Reserved[26]; - //rest of the structure is not defined for now, as it is not needed -}; - -template -struct _LDR_DATA_TABLE_ENTRY_T -{ - _LIST_ENTRY_T InLoadOrderLinks; - _LIST_ENTRY_T InMemoryOrderLinks; - _LIST_ENTRY_T InInitializationOrderLinks; - T DllBase; - T EntryPoint; - union - { - DWORD SizeOfImage; - T dummy01; - }; - _UNICODE_STRING_T FullDllName; - _UNICODE_STRING_T BaseDllName; - DWORD Flags; - WORD LoadCount; - WORD TlsIndex; - union - { - _LIST_ENTRY_T HashLinks; - struct - { - T SectionPointer; - T CheckSum; - }; - }; - union - { - T LoadedImports; - DWORD TimeDateStamp; - }; - T EntryPointActivationContext; - T PatchInformation; - _LIST_ENTRY_T ForwarderLinks; - _LIST_ENTRY_T ServiceTagLinks; - _LIST_ENTRY_T StaticLinks; - T ContextInformation; - T OriginalBase; - _LARGE_INTEGER LoadTime; -}; - -template -struct _PEB_LDR_DATA_T -{ - DWORD Length; - DWORD Initialized; - T SsHandle; - _LIST_ENTRY_T InLoadOrderModuleList; - _LIST_ENTRY_T InMemoryOrderModuleList; - _LIST_ENTRY_T InInitializationOrderModuleList; - T EntryInProgress; - DWORD ShutdownInProgress; - T ShutdownThreadId; - -}; - -template -struct _PEB_T -{ - union - { - struct - { - BYTE InheritedAddressSpace; - BYTE ReadImageFileExecOptions; - BYTE BeingDebugged; - BYTE BitField; - }; - T dummy01; - }; - T Mutant; - T ImageBaseAddress; - T Ldr; - T ProcessParameters; - T SubSystemData; - T ProcessHeap; - T FastPebLock; - T AtlThunkSListPtr; - T IFEOKey; - T CrossProcessFlags; - T UserSharedInfoPtr; - DWORD SystemReserved; - DWORD AtlThunkSListPtr32; - T ApiSetMap; - T TlsExpansionCounter; - T TlsBitmap; - DWORD TlsBitmapBits[2]; - T ReadOnlySharedMemoryBase; - T HotpatchInformation; - T ReadOnlyStaticServerData; - T AnsiCodePageData; - T OemCodePageData; - T UnicodeCaseTableData; - DWORD NumberOfProcessors; - union - { - DWORD NtGlobalFlag; - NGF dummy02; - }; - LARGE_INTEGER CriticalSectionTimeout; - T HeapSegmentReserve; - T HeapSegmentCommit; - T HeapDeCommitTotalFreeThreshold; - T HeapDeCommitFreeBlockThreshold; - DWORD NumberOfHeaps; - DWORD MaximumNumberOfHeaps; - T ProcessHeaps; - T GdiSharedHandleTable; - T ProcessStarterHelper; - T GdiDCAttributeList; - T LoaderLock; - DWORD OSMajorVersion; - DWORD OSMinorVersion; - WORD OSBuildNumber; - WORD OSCSDVersion; - DWORD OSPlatformId; - DWORD ImageSubsystem; - DWORD ImageSubsystemMajorVersion; - T ImageSubsystemMinorVersion; - T ActiveProcessAffinityMask; - T GdiHandleBuffer[A]; - T PostProcessInitRoutine; - T TlsExpansionBitmap; - DWORD TlsExpansionBitmapBits[32]; - T SessionId; - ULARGE_INTEGER AppCompatFlags; - ULARGE_INTEGER AppCompatFlagsUser; - T pShimData; - T AppCompatInfo; - _UNICODE_STRING_T CSDVersion; - T ActivationContextData; - T ProcessAssemblyStorageMap; - T SystemDefaultActivationContextData; - T SystemAssemblyStorageMap; - T MinimumStackCommit; - T FlsCallback; - _LIST_ENTRY_T FlsListHead; - T FlsBitmap; - DWORD FlsBitmapBits[4]; - T FlsHighIndex; - T WerRegistrationData; - T WerShipAssertPtr; - T pContextData; - T pImageHeaderHash; - T TracingFlags; -}; - -typedef _LDR_DATA_TABLE_ENTRY_T LDR_DATA_TABLE_ENTRY32; -typedef _LDR_DATA_TABLE_ENTRY_T LDR_DATA_TABLE_ENTRY64; - -typedef _TEB_T_ TEB32; -typedef _TEB_T_ TEB64; - -typedef _PEB_LDR_DATA_T PEB_LDR_DATA32; -typedef _PEB_LDR_DATA_T PEB_LDR_DATA64; - -typedef _PEB_T PEB32; -typedef _PEB_T PEB64; - -struct _XSAVE_FORMAT64 -{ - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - _M128A FloatRegisters[8]; - _M128A XmmRegisters[16]; - BYTE Reserved4[96]; -}; - -struct _CONTEXT64_2 -{ - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - _XSAVE_FORMAT64 FltSave; - _M128A Header[2]; - _M128A Legacy[8]; - _M128A Xmm0; - _M128A Xmm1; - _M128A Xmm2; - _M128A Xmm3; - _M128A Xmm4; - _M128A Xmm5; - _M128A Xmm6; - _M128A Xmm7; - _M128A Xmm8; - _M128A Xmm9; - _M128A Xmm10; - _M128A Xmm11; - _M128A Xmm12; - _M128A Xmm13; - _M128A Xmm14; - _M128A Xmm15; - _M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; -}; -#pragma warning(default : 4201) - -// Below defines for .ContextFlags field are taken from WinNT.h -#ifndef CONTEXT_AMD64 -#define CONTEXT_AMD64 0x100000 -#endif - -#define CONTEXT64_CONTROL (CONTEXT_AMD64 | 0x1L) -#define CONTEXT64_INTEGER (CONTEXT_AMD64 | 0x2L) -#define CONTEXT64_SEGMENTS (CONTEXT_AMD64 | 0x4L) -#define CONTEXT64_FLOATING_POINT (CONTEXT_AMD64 | 0x8L) -#define CONTEXT64_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L) -#define CONTEXT64_FULL (CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_FLOATING_POINT) -#define CONTEXT64_ALL (CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_SEGMENTS | CONTEXT64_FLOATING_POINT | CONTEXT64_DEBUG_REGISTERS) -#define CONTEXT64_XSTATE (CONTEXT_AMD64 | 0x20L) - -#pragma pack(pop) - -#ifdef WOW64EXT_EXPORTS -# define SPEC dllexport -#else -# define SPEC dllimport -#endif - -extern "C" -{ - DWORD64 __cdecl X64Call(DWORD64 func, int argC, ...); - DWORD64 __cdecl GetModuleHandle64(const wchar_t* lpModuleName); - DWORD64 __cdecl getNTDLL64(); - DWORD64 __cdecl GetProcAddress64(DWORD64 hModule, const char* funcName); - SIZE_T __cdecl VirtualQueryEx64(HANDLE hProcess, DWORD64 lpAddress, MEMORY_BASIC_INFORMATION64* lpBuffer, SIZE_T dwLength); - DWORD64 __cdecl VirtualAllocEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - BOOL __cdecl VirtualFreeEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD dwFreeType); - BOOL __cdecl VirtualProtectEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD* lpflOldProtect); - BOOL __cdecl ReadProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead); - BOOL __cdecl WriteProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten); - BOOL __cdecl GetThreadContext64(HANDLE hThread, _CONTEXT64_2* lpContext); - BOOL __cdecl SetThreadContext64(HANDLE hThread, _CONTEXT64_2* lpContext); - VOID __cdecl SetLastErrorFromX64Call(DWORD64 status); -} diff --git a/Sandboxie/core/dll/SboxDll.vcxproj b/Sandboxie/core/dll/SboxDll.vcxproj index 35eeb21f..8cd16d08 100644 --- a/Sandboxie/core/dll/SboxDll.vcxproj +++ b/Sandboxie/core/dll/SboxDll.vcxproj @@ -174,6 +174,7 @@ + true true @@ -221,10 +222,6 @@ true true - - true - true - false false @@ -433,6 +430,7 @@ + @@ -445,9 +443,6 @@ - - - diff --git a/Sandboxie/core/dll/SboxDll.vcxproj.filters b/Sandboxie/core/dll/SboxDll.vcxproj.filters index 2ee992e2..8548231c 100644 --- a/Sandboxie/core/dll/SboxDll.vcxproj.filters +++ b/Sandboxie/core/dll/SboxDll.vcxproj.filters @@ -204,9 +204,6 @@ pst - - common\wow64ext - debug @@ -235,6 +232,9 @@ file + + common + @@ -305,15 +305,6 @@ common - - common\wow64ext - - - common\wow64ext - - - common\wow64ext - common @@ -332,6 +323,9 @@ obj + + common + @@ -387,9 +381,6 @@ {bbd6a003-d74d-405a-bd10-e2fea62301f9} - - {c6a9654a-9f55-43ca-9cd1-7571bb879288} - {db0f9820-8908-4325-96f9-69c82fa9e268} diff --git a/Sandboxie/core/dll/Win32.c b/Sandboxie/core/dll/Win32.c index c336a8ae..e1b626be 100644 --- a/Sandboxie/core/dll/Win32.c +++ b/Sandboxie/core/dll/Win32.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 David Xanatos, xanasoft.com + * 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 @@ -28,18 +28,33 @@ #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 + + +ULONG SbieDll_GetSysCallOffset(const ULONG *SyscallPtr, ULONG syscall_index); + extern SBIELOW_DATA* SbieApi_data; #define SBIELOW_CALL(x) ((P_##x)&data->x##_code) //--------------------------------------------------------------------------- -// SbieDll_HookWin32SysCalls +// Win32_HookWin32SysCalls //--------------------------------------------------------------------------- -_FX BOOLEAN SbieDll_HookWin32SysCalls(HMODULE win32u_base) +_FX BOOLEAN Win32_HookWin32SysCalls(HMODULE win32u_base) { - UCHAR *SystemServiceAsm, *ZwXxxPtr; + UCHAR *SystemServiceAsm; ULONG *SyscallPtr; ULONG SyscallNum; void *RegionBase; @@ -75,7 +90,7 @@ _FX BOOLEAN SbieDll_HookWin32SysCalls(HMODULE win32u_base) // from the base address of ntdll // - ZwXxxPtr = (UCHAR *)((ULONG_PTR)SyscallPtr[1] + (UCHAR*)win32u_base); + UCHAR* ZwXxxPtr = (UCHAR *)((ULONG_PTR)SyscallPtr[1] + (UCHAR*)win32u_base); // // make the syscall address writable @@ -151,11 +166,51 @@ _FX BOOLEAN SbieDll_HookWin32SysCalls(HMODULE win32u_base) //--------------------------------------------------------------------------- -// Win32_WoW64_GetSysCallNumber +// Win32_Init //--------------------------------------------------------------------------- + +_FX BOOLEAN Win32_Init(HMODULE 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 -ULONG Win32_WoW64_GetSysCallNumber(DWORD64 pos, UCHAR* dll_data) + 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)) @@ -195,100 +250,59 @@ ULONG Win32_WoW64_GetSysCallNumber(DWORD64 pos, UCHAR* dll_data) //--------------------------------------------------------------------------- -// SbieDll_HasSysCallHook +// Win32_HookWin32WoW64 //--------------------------------------------------------------------------- -_FX BOOLEAN SbieDll_HasSysCallHook(UCHAR* syscall_data, ULONG syscall_index) -{ - ULONG *SyscallPtr; - ULONG SyscallNum; - - SyscallPtr = (ULONG *)(syscall_data + sizeof(ULONG)); // size of buffer - - while (SyscallPtr[0] || SyscallPtr[1]) { - - SyscallNum = SyscallPtr[0]; - - SyscallNum &= 0xFFFF; // clear the not needed param count - - if (SyscallNum == syscall_index) - return TRUE; - - SyscallPtr += 2; - } - - return FALSE; -} - - -//--------------------------------------------------------------------------- -// SbieDll_HookWin32WoW64 -//--------------------------------------------------------------------------- - -//#include "../../common/wow64ext/wow64ext.h" -DWORD64 __cdecl X64Call(DWORD64 func, int argC, ...); -DWORD64 __cdecl GetModuleHandle64(const wchar_t* lpModuleName); -BOOL __cdecl VirtualProtectEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD* lpflOldProtect); -BOOL __cdecl ReadProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead); -BOOL __cdecl WriteProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten); - -_FX BOOLEAN SbieDll_HookWin32WoW64() +_FX BOOLEAN Win32_HookWin32WoW64() { BOOLEAN ok = FALSE; UCHAR* dll_data = NULL; UCHAR* syscall_data = NULL; - DWORD64 BaseAddress = GetModuleHandle64(L"wow64win.dll"); + // + // 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; } - HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); - if (hProcess == INVALID_HANDLE_VALUE) { - SbieApi_Log(2303, L"win32k, can't open process"); - return FALSE; - } - dll_data = (UCHAR *)HeapAlloc(GetProcessHeap(), 0, (SIZE_T)SizeOfImage); if (!dll_data) { SbieApi_Log(2303, L"win32k, alloc failed (1)"); goto finish; } - SIZE_T SizeRead; - if (!ReadProcessMemory64(hProcess, (PVOID64)BaseAddress, dll_data, SizeOfImage, &SizeRead)) { + 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 FuncTable = 0; - - for (DWORD64 pos = 0; pos < SizeRead-0x20; pos++) { - if (Win32_WoW64_GetSysCallNumber(pos, dll_data) != 0){ - FuncTable = pos; - break; - } - } - - if (FuncTable == 0) { - SbieApi_Log(2303, L"win32k, wow64win.dll sys call table not found"); - goto finish; - } - DWORD64 SystemServiceAsm; - UCHAR ZwXxxPtr[16]; + 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 + 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; @@ -299,74 +313,92 @@ _FX BOOLEAN SbieDll_HookWin32WoW64() goto finish; } - for (DWORD64 pos = FuncTable; pos < SizeRead - 0x20; ) - { - SyscallNum = Win32_WoW64_GetSysCallNumber(pos, dll_data); - if (SyscallNum) + SyscallPtr = (ULONG*)(syscall_data + sizeof(ULONG)); // size of buffer + + + 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; ) { - if(SbieDll_HasSysCallHook(syscall_data, SyscallNum)) + SyscallNum = Win32_GetSysCallNumberWoW64(pos, dll_data); + if (SyscallNum) { - RegionBase = BaseAddress + pos; - RegionSize = 14; - - // - // prepare call to call our SystemServiceAsm - // + if (SbieDll_GetSysCallOffset(SyscallPtr, SyscallNum)) + { + RegionBase = BaseAddress + pos; + RegionSize = 14; - ZwXxxPtr[0] = 0x49; // mov r10, SyscallNumber - ZwXxxPtr[1] = 0xC7; - ZwXxxPtr[2] = 0xC2; - *(ULONG *)&ZwXxxPtr[3] = SyscallNum; - if (!data->flags.long_diff) { + // + // prepare call to call our SystemServiceAsm + // - if (data->flags.is_win10) { - ZwXxxPtr[7] = 0x48; // jmp SystemServiceAsm - ZwXxxPtr[8] = 0xE9; - *(ULONG *)&ZwXxxPtr[9] = (ULONG)(ULONG_PTR)(SystemServiceAsm - (RegionBase + 13)); + 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] = 0xe9; // jmp SystemServiceAsm - *(ULONG *)&ZwXxxPtr[8] = (ULONG)(ULONG_PTR)(SystemServiceAsm - (RegionBase + 12)); + + 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; } } - 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 (!VirtualProtectEx64(hProcess, RegionBase, RegionSize, PAGE_EXECUTE_READWRITE, &OldProtect)) { - SbieApi_Log(2303, L"win32k %d (1)", SyscallNum); - goto finish; - } - - if (!WriteProcessMemory64(hProcess, RegionBase, ZwXxxPtr, RegionSize, &SizeRead)) { - SbieApi_Log(2303, L"win32k %d (2)", SyscallNum); - goto finish; - } - - if (!VirtualProtectEx64(hProcess, RegionBase, RegionSize, OldProtect, &OldProtect)) { - SbieApi_Log(2303, L"win32k %d (3)", SyscallNum); - goto finish; - } + pos += 0x20; } - - 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++; } - 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: @@ -376,46 +408,194 @@ finish: if(dll_data) HeapFree(GetProcessHeap(), 0, dll_data); - CloseHandle(hProcess); - return ok; } -#endif + + +// +// Win32_HookWin32WoW64 needs to be able to read and write the 64-bit portion of the address space +// ther for we issue direct syscalls using 64 bit arguments to our driver's syscall interface +// The driver accepts function names and optionaly returns the curesponding syscall index for later direct use +// This replaces the use of heaven's gate (wow64ext) as its unavailable when running in emulation on arm64 +// + //--------------------------------------------------------------------------- -// Win32_Init +// SbieApi_ProtectVirtualMemory //--------------------------------------------------------------------------- -_FX BOOLEAN Win32_Init(HMODULE hmodule) +NTSTATUS SbieApi_ProtectVirtualMemory(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, ULONG flNewProtect, ULONG* lpflOldProtect) { - // 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 + ULONG64 BaseAddress = lpAddress; + ULONG64 NumberOfBytesToProtect = dwSize; - if (Dll_CompartmentMode || SbieApi_data->flags.bNoSysHooks) - return TRUE; // no syscall hooking in comaprtment mode + static SHORT syscall_index = 0xFFF; - // - // 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 - // + ULONG64 stack[17]; + stack[0] = hProcess; + stack[1] = &BaseAddress; + stack[2] = &NumberOfBytesToProtect; + stack[3] = flNewProtect; + stack[4] = lpflOldProtect; - BOOLEAN useByDefualt = (Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME); - if (SbieDll_GetSettingsForName_bool(NULL, Dll_ImageName, L"UseWin32kHooks", useByDefualt)) { + __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; - // disable Electron Workaround when we are ready to hook the required win32k syscalls - extern BOOL Dll_ElectronWorkaround; - Dll_ElectronWorkaround = FALSE; + 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; +} -#ifndef _WIN64 - if (Dll_IsWow64) - SbieDll_HookWin32WoW64(); // WoW64 hooks - else #endif - SbieDll_HookWin32SysCalls(hmodule); // Native x86/x64 hooks + + +//--------------------------------------------------------------------------- +// SbieDll_GetSysCallOffset +//--------------------------------------------------------------------------- + + +_FX ULONG SbieDll_GetSysCallOffset(const ULONG *SyscallPtr, ULONG syscall_index) +{ + ULONG SyscallNum; + + while (SyscallPtr[0] || SyscallPtr[1]) { + + SyscallNum = SyscallPtr[0]; + + SyscallNum &= 0xFFFF; // clear the not needed param count + + if (SyscallNum == syscall_index) + return SyscallPtr[1]; + + SyscallPtr += 2; } - return TRUE; - -} \ No newline at end of file + return 0; +} diff --git a/Sandboxie/core/dll/dllhook.c b/Sandboxie/core/dll/dllhook.c index a36e1d32..c9dd1e25 100644 --- a/Sandboxie/core/dll/dllhook.c +++ b/Sandboxie/core/dll/dllhook.c @@ -26,6 +26,7 @@ #include "hook.h" #include "common/pool.h" #include "common/pattern.h" +#include "common/hook_util.c" //#include @@ -35,8 +36,6 @@ //--------------------------------------------------------------------------- -static void *SbieDll_Hook_CheckChromeHook(void *SourceFunc); - ULONG_PTR DLL_FindWow64Target(ULONG_PTR address); BOOLEAN SbieDll_FuncSkipHook(const char* func); @@ -162,7 +161,7 @@ _FX void *SbieDll_Hook( // Chrome sandbox support // - SourceFunc = SbieDll_Hook_CheckChromeHook(SourceFunc); + SourceFunc = Hook_CheckChromeHook(SourceFunc); // // if the source function begins with relative jump EB xx, it means @@ -197,7 +196,7 @@ _FX void *SbieDll_Hook( #else ! WIN_64 - func = SbieDll_Hook_CheckChromeHook((void *)target); + func = Hook_CheckChromeHook((void *)target); if (func != (void *)target) { SourceFunc = func; goto skip_e9_rewrite; @@ -654,122 +653,6 @@ _FX void SbieDll_UnHookModule(HMODULE module) } -//--------------------------------------------------------------------------- -// SbieDll_Hook_CheckChromeHook -//--------------------------------------------------------------------------- -#ifdef _WIN64 -#define MAX_FUNC_SIZE 0x76 -//Note any change to this function requires the same modification to the function in LowLevel: see init.c (findChromeTarget) -ULONGLONG * SbieDll_findChromeTarget(unsigned char* addr) -{ - int i = 0; - ULONGLONG target; - ULONGLONG * ChromeTarget = NULL; - if (!addr) return NULL; - //Look for mov rcx,[target 4 byte offset] or in some cases mov rax,[target 4 byte offset] - //So far the offset has been positive between 0xa00000 and 0xb00000 bytes; - //This may change in a future version of chrome - for (i = 0; i < MAX_FUNC_SIZE; i++) { - // some chromium 90+ derivatives replace the function with a return 1 stub - // mov eax,1 - // ret - // int 3 - if (addr[i] == 0xB8 && addr[i + 5] == 0xC3 && addr[i + 6] == 0xCC) - return NULL; - if ((*(USHORT *)&addr[i] == 0x8b48)) { - //Look for mov rcx,[target 4 byte offset] or in some cases mov rax,[target 4 byte offset] - if ((addr[i + 2] == 0x0d || addr[i + 2] == 0x05)) { - LONG delta; - target = (ULONG_PTR)(addr + i + 7); - delta = *(LONG *)&addr[i + 3]; - //check if offset is close to the expected value (is positive and less than 0x100000 as of chrome 64) - // if (delta > 0 && delta < 0x100000 ) { //may need to check delta in a future version of chrome - target += delta; - ChromeTarget = *(ULONGLONG **)target; - - // special case when compiled using mingw toolchain - // mov rcx,qword ptr [rax+offset] or mov rcx,qword ptr [rcx+offset] - if ((*(USHORT *)&addr[i + 7] == 0x8B48)) - { - if (addr[i + 9] == 0x48 || addr[i + 9] == 0x49) - delta = addr[i + 10]; - else if (addr[i + 9] == 0x88 || addr[i + 9] == 0x89) - delta = *(ULONG*)&addr[i + 10]; - else - break; - target = (ULONGLONG)ChromeTarget + delta; - ChromeTarget = *(ULONGLONG **)target; - } - - //} - break; - } - } - } - - return ChromeTarget; -} -#endif - -_FX void *SbieDll_Hook_CheckChromeHook(void *SourceFunc) -{ - if (!SourceFunc) - return NULL; - UCHAR *func = (UCHAR *)SourceFunc; -#ifndef _WIN64 - if (func[0] == 0xB8 && // mov eax,? - func[5] == 0xBA && // mov edx,? - *(USHORT *)&func[10] == 0xE2FF) // jmp edx - { - ULONG i = 0; - ULONG *longs = *(ULONG **)&func[6]; - - for (i = 0; i < 20; i++, longs++) - { - if (longs[0] == 0x5208EC83 && longs[1] == 0x0C24548B && - longs[2] == 0x08245489 && longs[3] == 0x0C2444C7 && - longs[5] == 0x042444C7) - { - SourceFunc = (void *)longs[4]; - break; - } - } - } -#else if - ULONGLONG *chrome64Target = NULL; - - if (func[0] == 0x50 && //push rax - func[1] == 0x48 && //mov rax,? - func[2] == 0xb8) { - ULONGLONG *longlongs = *(ULONGLONG **)&func[3]; - chrome64Target = SbieDll_findChromeTarget((unsigned char *)longlongs); - } - // Chrome 49+ 64bit hook - // mov rax, - // jmp rax - else if (func[0] == 0x48 && //mov rax, - func[1] == 0xb8 && - *(USHORT *)&func[10] == 0xe0ff) /* jmp rax */ { - ULONGLONG *longlongs = *(ULONGLONG **)&func[2]; - chrome64Target = SbieDll_findChromeTarget((unsigned char *)longlongs); - } - if (chrome64Target) { - SourceFunc = chrome64Target; - } - /*sboxie 64bit jtable hook signature */ - /* // use this to hook jtable location (useful for debugging) - //else if(func[0] == 0x51 && func[1] == 0x48 && func[2] == 0xb8 ) { - else if(func[0] == 0x90 && func[1] == 0x48 && func[2] == 0xb8 ) { - long long addr; - addr = (ULONG_PTR) *(ULONGLONG **)&func[3] ; - SourceFunc = (void *) addr; - } - */ -#endif ! _WIN64 - return SourceFunc; -} - - //--------------------------------------------------------------------------- // SbieDll_FuncSkipHook //--------------------------------------------------------------------------- diff --git a/Sandboxie/core/drv/syscall.c b/Sandboxie/core/drv/syscall.c index 584b6954..78f91485 100644 --- a/Sandboxie/core/drv/syscall.c +++ b/Sandboxie/core/drv/syscall.c @@ -594,6 +594,27 @@ _FX NTSTATUS Syscall_Api_Invoke(PROCESS *proc, ULONG64 *parms) //DbgPrint("[syscall] request for service %d / %08X\n", syscall_index, syscall_index); + // + // use direct syscalls to access 64 bit memory from a wow process + // instead of using heaven's gate / wow64ext + // + + if (syscall_index == 0xFFF && parms[3] != 0) { + __try { + + entry = Syscall_GetByName((UCHAR*)parms[3]); + + if(parms[4]) // return found index to the caller to be re used later + *(USHORT*)parms[4] = entry->syscall_index; + + } __except (EXCEPTION_EXECUTE_HANDLER) { + entry = NULL; + } + } + else + + // + if (Syscall_Table && (syscall_index <= Syscall_MaxIndex)) entry = Syscall_Table[syscall_index]; else @@ -933,6 +954,8 @@ _FX BOOLEAN Syscall_QuerySystemInfo_SupportProcmonStack( // In Win10, case 0xb9 triggers WbCreateWarbirdProcess/WbDispatchOperation/WbSetTrapFrame // and PspSetContextThreadInternal (Warbird operation?) to deliver a apc call in the current // thread in user mode. Warbird needs the real thread context. + // https://github.com/xpn/warbird_exploit + // this exploit only works on x86 windows but can still crash a x64 one // It seems only NtQuerySystemInfomation is doing this. // Call Syscall_Set3 in Syscall_Init if we see a different syscall does this in the future. diff --git a/Sandboxie/core/low/init.c b/Sandboxie/core/low/init.c index 62480732..6f342c73 100644 --- a/Sandboxie/core/low/init.c +++ b/Sandboxie/core/low/init.c @@ -29,7 +29,7 @@ typedef long NTSTATUS; #include "common/defines.h" #include "core/drv/api_defs.h" #include "lowdata.h" - +#include "common/hook_util.c" //--------------------------------------------------------------------------- // Defines @@ -197,106 +197,9 @@ _FX void WaitForDebugger(SBIELOW_DATA *data) //--------------------------------------------------------------------------- -// InitSyscalls +// PrepSyscalls //--------------------------------------------------------------------------- -#ifdef _WIN64 - -#define MAX_FUNC_SIZE 0x76 - -//Note any change to this function requires the same modification to the same function in sbiedll: see dllhook.c (findChromeTarget) -ULONGLONG * findChromeTarget(unsigned char* addr) -{ - int i = 0; - ULONGLONG target; - ULONG_PTR * ChromeTarget = NULL; - if (!addr) return NULL; - //Look for mov rcx,[target 4 byte offset] or in some cases mov rax,[target 4 byte offset] - //So far the offset has been positive between 0xa00000 and 0xb00000 bytes; - //This may change in a future version of chrome - for (i = 0; i < MAX_FUNC_SIZE; i++) { - if ((*(USHORT *)&addr[i] == 0x8b48)) { - //Look for mov rcx,[target 4 byte offset] or in some cases mov rax,[target 4 byte offset] - if ((addr[i + 2] == 0x0d || addr[i + 2] == 0x05)) { - LONG delta; - target = (ULONG_PTR)(addr + i + 7); - delta = *(LONG *)&addr[i + 3]; - //check if offset is close to the expected value (is positive and less than 0x100000 as of chrome 64) - // if (delta > 0 && delta < 0x100000 ) { //may need to check delta in a future version of chrome - target += delta; - ChromeTarget = *(ULONGLONG **)target; - - // special case when compiled using mingw toolchain - // mov rcx,qword ptr [rax+offset] or mov rcx,qword ptr [rcx+offset] - if ((*(USHORT *)&addr[i + 7] == 0x8B48)) - { - if (addr[i + 9] == 0x48 || addr[i + 9] == 0x49) - delta = addr[i + 10]; - else if (addr[i + 9] == 0x88 || addr[i + 9] == 0x89) - delta = *(ULONG*)&addr[i + 10]; - else - break; - target = (ULONGLONG)ChromeTarget + delta; - ChromeTarget = *(ULONGLONG **)target; - } - - // } - break; - } - } - } - return ChromeTarget; -} -#endif - -void *Hook_CheckChromeHook(void *SourceFunc) -{ - if (!SourceFunc) - return NULL; - UCHAR *ZwXxxPtr = (UCHAR *)SourceFunc; -#ifndef _WIN64 //if not _WIN64 - if (ZwXxxPtr[0] == 0xB8 && // mov eax,? - ZwXxxPtr[5] == 0xBA && // mov edx,? - *(USHORT *)&ZwXxxPtr[10] == 0xE2FF) // jmp edx - { - ULONG i = 0; - - ULONG *longs = *(ULONG **)&ZwXxxPtr[6]; - for (i = 0; i < 20; i++, longs++) - { - if (longs[0] == 0x5208EC83 && longs[1] == 0x0C24548B && - longs[2] == 0x08245489 && longs[3] == 0x0C2444C7 && - longs[5] == 0x042444C7) - { - ZwXxxPtr = (UCHAR *)longs[4]; - break; - } - } - } -#else // _WIN64 - ULONGLONG *chrome64Target = NULL; - - if (ZwXxxPtr[0] == 0x50 && //push rax - ZwXxxPtr[1] == 0x48 && //mov rax,? - ZwXxxPtr[2] == 0xb8) { - ULONGLONG* longlongs = *(ULONGLONG**)&ZwXxxPtr[3]; - chrome64Target = findChromeTarget((unsigned char*)longlongs); - } - // Chrome 49+ 64bit hook - // mov rax, - // jmp rax - else if (ZwXxxPtr[0] == 0x48 && //mov rax, - ZwXxxPtr[1] == 0xb8 && - *(USHORT*)&ZwXxxPtr[10] == 0xe0ff)/* jmp rax */ { - ULONGLONG* longlongs = *(ULONGLONG**)&ZwXxxPtr[2]; - chrome64Target = findChromeTarget((unsigned char*)longlongs); - } - if (chrome64Target != NULL) { - ZwXxxPtr = (UCHAR *)chrome64Target; - } -#endif - return ZwXxxPtr; -} _FX void PrepSyscalls(SBIELOW_DATA *data, void * SystemService) { @@ -334,6 +237,12 @@ _FX void PrepSyscalls(SBIELOW_DATA *data, void * SystemService) data->pSystemService = (ULONG64)SystemServiceAsm; } + +//--------------------------------------------------------------------------- +// InitSyscalls +//--------------------------------------------------------------------------- + + _FX void InitSyscalls(SBIELOW_DATA *data, void * SystemService) { UCHAR *SystemServiceAsm, *ZwXxxPtr;