1.2.0
This commit is contained in:
parent
4bf2228856
commit
4f656a898a
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windows.h>
|
||||
#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;
|
||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DLLIMPORT_H
|
||||
#define DLLIMPORT_H
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#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 */
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// 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, <target>
|
||||
// jmp rax
|
||||
else if (func[0] == 0x48 && //mov rax,<target>
|
||||
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;
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#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()
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#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];
|
||||
};
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Windows.h>
|
||||
#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<char const volatile&>((((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<DWORD64> 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;
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef STATUS_SUCCESS
|
||||
# define STATUS_SUCCESS 0
|
||||
#endif
|
||||
|
||||
#pragma warning(disable : 4201)
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
template <class T>
|
||||
struct _LIST_ENTRY_T
|
||||
{
|
||||
T Flink;
|
||||
T Blink;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct _UNICODE_STRING_T
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
WORD Length;
|
||||
WORD MaximumLength;
|
||||
};
|
||||
T dummy;
|
||||
};
|
||||
T Buffer;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct _NT_TIB_T
|
||||
{
|
||||
T ExceptionList;
|
||||
T StackBase;
|
||||
T StackLimit;
|
||||
T SubSystemTib;
|
||||
T FiberData;
|
||||
T ArbitraryUserPointer;
|
||||
T Self;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct _CLIENT_ID_T
|
||||
{
|
||||
T UniqueProcess;
|
||||
T UniqueThread;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct _TEB_T_
|
||||
{
|
||||
_NT_TIB_T<T> NtTib;
|
||||
T EnvironmentPointer;
|
||||
_CLIENT_ID_T<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 <class T>
|
||||
struct _LDR_DATA_TABLE_ENTRY_T
|
||||
{
|
||||
_LIST_ENTRY_T<T> InLoadOrderLinks;
|
||||
_LIST_ENTRY_T<T> InMemoryOrderLinks;
|
||||
_LIST_ENTRY_T<T> InInitializationOrderLinks;
|
||||
T DllBase;
|
||||
T EntryPoint;
|
||||
union
|
||||
{
|
||||
DWORD SizeOfImage;
|
||||
T dummy01;
|
||||
};
|
||||
_UNICODE_STRING_T<T> FullDllName;
|
||||
_UNICODE_STRING_T<T> BaseDllName;
|
||||
DWORD Flags;
|
||||
WORD LoadCount;
|
||||
WORD TlsIndex;
|
||||
union
|
||||
{
|
||||
_LIST_ENTRY_T<T> HashLinks;
|
||||
struct
|
||||
{
|
||||
T SectionPointer;
|
||||
T CheckSum;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
T LoadedImports;
|
||||
DWORD TimeDateStamp;
|
||||
};
|
||||
T EntryPointActivationContext;
|
||||
T PatchInformation;
|
||||
_LIST_ENTRY_T<T> ForwarderLinks;
|
||||
_LIST_ENTRY_T<T> ServiceTagLinks;
|
||||
_LIST_ENTRY_T<T> StaticLinks;
|
||||
T ContextInformation;
|
||||
T OriginalBase;
|
||||
_LARGE_INTEGER LoadTime;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct _PEB_LDR_DATA_T
|
||||
{
|
||||
DWORD Length;
|
||||
DWORD Initialized;
|
||||
T SsHandle;
|
||||
_LIST_ENTRY_T<T> InLoadOrderModuleList;
|
||||
_LIST_ENTRY_T<T> InMemoryOrderModuleList;
|
||||
_LIST_ENTRY_T<T> InInitializationOrderModuleList;
|
||||
T EntryInProgress;
|
||||
DWORD ShutdownInProgress;
|
||||
T ShutdownThreadId;
|
||||
|
||||
};
|
||||
|
||||
template <class T, class NGF, int A>
|
||||
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<T> CSDVersion;
|
||||
T ActivationContextData;
|
||||
T ProcessAssemblyStorageMap;
|
||||
T SystemDefaultActivationContextData;
|
||||
T SystemAssemblyStorageMap;
|
||||
T MinimumStackCommit;
|
||||
T FlsCallback;
|
||||
_LIST_ENTRY_T<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<DWORD> LDR_DATA_TABLE_ENTRY32;
|
||||
typedef _LDR_DATA_TABLE_ENTRY_T<DWORD64> LDR_DATA_TABLE_ENTRY64;
|
||||
|
||||
typedef _TEB_T_<DWORD> TEB32;
|
||||
typedef _TEB_T_<DWORD64> TEB64;
|
||||
|
||||
typedef _PEB_LDR_DATA_T<DWORD> PEB_LDR_DATA32;
|
||||
typedef _PEB_LDR_DATA_T<DWORD64> PEB_LDR_DATA64;
|
||||
|
||||
typedef _PEB_T<DWORD, DWORD64, 34> PEB32;
|
||||
typedef _PEB_T<DWORD64, DWORD, 30> 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);
|
||||
}
|
|
@ -174,6 +174,7 @@
|
|||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\common\dllimport.c" />
|
||||
<ClCompile Include="..\..\common\map.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
|
||||
|
@ -221,10 +222,6 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\wow64ext\wow64ext.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="advapi.c">
|
||||
<ShowIncludes Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">false</ShowIncludes>
|
||||
<ShowIncludes Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">false</ShowIncludes>
|
||||
|
@ -433,6 +430,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\apps\com\common.h" />
|
||||
<ClInclude Include="..\..\common\dllimport.h" />
|
||||
<ClInclude Include="..\..\common\map.h" />
|
||||
<ClInclude Include="..\..\common\my_version.h" />
|
||||
<ClInclude Include="..\..\common\ntproto.h" />
|
||||
|
@ -445,9 +443,6 @@
|
|||
<ClInclude Include="..\..\common\rbtree.h" />
|
||||
<ClInclude Include="..\..\common\stream.h" />
|
||||
<ClInclude Include="..\..\common\win32_ntddk.h" />
|
||||
<ClInclude Include="..\..\common\wow64ext\CMemPtr.h" />
|
||||
<ClInclude Include="..\..\common\wow64ext\internal.h" />
|
||||
<ClInclude Include="..\..\common\wow64ext\wow64ext.h" />
|
||||
<ClInclude Include="advapi.h" />
|
||||
<ClInclude Include="debug.h" />
|
||||
<ClInclude Include="dll.h" />
|
||||
|
|
|
@ -204,9 +204,6 @@
|
|||
<ClCompile Include="cred.c">
|
||||
<Filter>pst</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\wow64ext\wow64ext.cpp">
|
||||
<Filter>common\wow64ext</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="debug.c">
|
||||
<Filter>debug</Filter>
|
||||
</ClCompile>
|
||||
|
@ -235,6 +232,9 @@
|
|||
<ClCompile Include="file_snapshots.c">
|
||||
<Filter>file</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\dllimport.c">
|
||||
<Filter>common</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="advapi.h" />
|
||||
|
@ -305,15 +305,6 @@
|
|||
<ClInclude Include="..\..\common\win32_ntddk.h">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\wow64ext\CMemPtr.h">
|
||||
<Filter>common\wow64ext</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\wow64ext\internal.h">
|
||||
<Filter>common\wow64ext</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\wow64ext\wow64ext.h">
|
||||
<Filter>common\wow64ext</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\my_version.h">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
|
@ -332,6 +323,9 @@
|
|||
<ClInclude Include="handle.h">
|
||||
<Filter>obj</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\dllimport.h">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="resource.rc" />
|
||||
|
@ -387,9 +381,6 @@
|
|||
<Filter Include="net">
|
||||
<UniqueIdentifier>{bbd6a003-d74d-405a-bd10-e2fea62301f9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="common\wow64ext">
|
||||
<UniqueIdentifier>{c6a9654a-9f55-43ca-9cd1-7571bb879288}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="debug">
|
||||
<UniqueIdentifier>{db0f9820-8908-4325-96f9-69c82fa9e268}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "hook.h"
|
||||
#include "common/pool.h"
|
||||
#include "common/pattern.h"
|
||||
#include "common/hook_util.c"
|
||||
|
||||
//#include <stdio.h>
|
||||
|
||||
|
@ -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, <target>
|
||||
// jmp rax
|
||||
else if (func[0] == 0x48 && //mov rax,<target>
|
||||
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
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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, <target>
|
||||
// jmp rax
|
||||
else if (ZwXxxPtr[0] == 0x48 && //mov rax,<target>
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue