#include <cstdio> | |||||
#include <ntdll.h> | |||||
#include <cstdint> | |||||
#include "structs.h" | |||||
#include "wow64ext.h" | |||||
#include "misc.h" | |||||
#include "syscall64.h" | |||||
#include "get_syscall64_ids.h" | |||||
/** | |||||
\file | |||||
*/ | |||||
/** | |||||
\brief All functions doing direct syscalls are saved with a hash of their name | |||||
and the accompying syscall ID in the table (API_TO_INDEX*) ID_table. | |||||
To get the ID for a given hash the table can be searched. | |||||
(To speed up the search the table is sorted and a binary search is used) | |||||
*/ | |||||
struct API_TO_INDEX | |||||
{ | |||||
DWORD hash; | |||||
DWORD id; | |||||
} *ID_table = NULL; | |||||
DWORD ID_table_count = 0; //!< Count of entries in ID_table | |||||
/** | |||||
\brief Parses the ID out of a x64 function. | |||||
\return Returns the ID or INVALID_SYSCALL_ID on err | |||||
*/ | |||||
static DWORD get_syscall_id(LPBYTE function) | |||||
{ | |||||
if(!function) | |||||
return INVALID_SYSCALL_ID; | |||||
/* | |||||
00000000`77b61800 4c8bd1 mov r10,rcx | |||||
00000000`77b61803 b852000000 mov eax,52h | |||||
00000000`77b61808 0f05 syscall | |||||
On Windows 10 it's: | |||||
0:000> u NtOpenFile | |||||
ntdll!NtOpenFile: | |||||
00007ffe`62bf6720 4c8bd1 mov r10,rcx | |||||
00007ffe`62bf6723 b833000000 mov eax,33h | |||||
00007ffe`62bf6728 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1 | |||||
00007ffe`62bf6730 7503 jne ntdll!NtOpenFile+0x15 (00007ffe`62bf6735) | |||||
00007ffe`62bf6732 0f05 syscall | |||||
00007ffe`62bf6734 c3 ret | |||||
00007ffe`62bf6735 cd2e int 2Eh | |||||
00007ffe`62bf6737 c3 ret | |||||
*/ | |||||
const unsigned char MOV_R10_RCX_OPCODE[] = {0x4c, 0x8b, 0xd1}; | |||||
if(memcmp(function, MOV_R10_RCX_OPCODE, sizeof(MOV_R10_RCX_OPCODE))) | |||||
return INVALID_SYSCALL_ID; | |||||
const unsigned char SYSCALL_OPCODE[] = {0x0f, 0x05}; | |||||
const size_t SYSCALL_OFFSET_OLD = 8, | |||||
SYSCALL_OFFSET_10 = 0x12; | |||||
uint8_t* old = function + SYSCALL_OFFSET_OLD; | |||||
uint8_t* win10 = function + SYSCALL_OFFSET_10; | |||||
if (memcmp(old, SYSCALL_OPCODE, sizeof(SYSCALL_OPCODE)) && | |||||
memcmp(win10, SYSCALL_OPCODE, sizeof(SYSCALL_OPCODE))) | |||||
{ | |||||
return INVALID_SYSCALL_ID; | |||||
} | |||||
const unsigned char MOV_EAX_OPCODE = 0xB8; | |||||
const size_t MOV_EAX_ID_OFFSET = 3; | |||||
if(MOV_EAX_OPCODE != *(function + MOV_EAX_ID_OFFSET)) | |||||
return INVALID_SYSCALL_ID; | |||||
return *(PDWORD)(function + MOV_EAX_ID_OFFSET + 1); | |||||
} | |||||
/** | |||||
\brief Parses the given image to get the ID or just count them. | |||||
\return Number of entries found / populated | |||||
\param imageBase Image base of the DLL the info will be taken from | |||||
\param ids The struct the info is put into. If NULL - won't be touched | |||||
*/ | |||||
static DWORD get_syscall_ids(LPVOID imageBase, API_TO_INDEX* ids) | |||||
{ | |||||
if(!imageBase) | |||||
return 0; | |||||
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)imageBase; | |||||
// not a valid DOS header | |||||
if(IMAGE_DOS_SIGNATURE != dos->e_magic) | |||||
return 0; | |||||
PIMAGE_NT_HEADERS64 nt = (PIMAGE_NT_HEADERS64)((LPBYTE)imageBase + dos->e_lfanew); | |||||
// not a valid PE or not the correct architecture | |||||
if(IMAGE_NT_SIGNATURE != nt->Signature || IMAGE_FILE_MACHINE_AMD64 != nt->FileHeader.Machine) | |||||
{ | |||||
return 0; | |||||
} | |||||
// No exports? | |||||
if(!nt->OptionalHeader.DataDirectory->Size) | |||||
return 0; | |||||
DWORD count = 0; //! Number of functions who do direct syscalls | |||||
IMAGE_EXPORT_DIRECTORY *exportDir = (IMAGE_EXPORT_DIRECTORY *)((LPBYTE)imageBase + nt->OptionalHeader.DataDirectory->VirtualAddress); | |||||
PDWORD nameRef = (DWORD *)((LPBYTE)imageBase + exportDir->AddressOfNames); | |||||
WORD* ordinal = (WORD *)((LPBYTE)imageBase + exportDir->AddressOfNameOrdinals); | |||||
DWORD* addressOfFunctions = (DWORD*)((LPBYTE)imageBase + exportDir->AddressOfFunctions); | |||||
printf("Total functions: %d\n", exportDir->NumberOfNames); | |||||
for(DWORD i = 0; i < exportDir->NumberOfNames; i++, nameRef++) | |||||
{ | |||||
const char* name = (const char*)((LPBYTE)imageBase + (*nameRef)); | |||||
LPBYTE address = (LPBYTE)imageBase + addressOfFunctions[ordinal[i]]; | |||||
DWORD id = get_syscall_id(address); | |||||
if(INVALID_SYSCALL_ID == id) | |||||
continue; | |||||
// Put it into the table | |||||
if(ids) | |||||
{ | |||||
ids[count].hash = hash(name); | |||||
ids[count].id = id; | |||||
} | |||||
// Print info | |||||
else | |||||
{ | |||||
printf("%s (%X) = %X\n", name, hash(name), id); | |||||
} | |||||
count++; | |||||
} | |||||
return count; | |||||
} | |||||
/** | |||||
\brief (Bubble)Sorts the ID_table so it can be searched via binary search | |||||
*/ | |||||
static void sort_ID_table() | |||||
{ | |||||
DWORD n = ID_table_count; | |||||
bool swapped = false; | |||||
do | |||||
{ | |||||
for(unsigned int i = 0; i < n - 1; ++i) | |||||
{ | |||||
if(ID_table[i].hash > ID_table[i + 1].hash) | |||||
{ | |||||
API_TO_INDEX tmp = {ID_table[i].hash, ID_table[i].id}; | |||||
ID_table[i].hash = ID_table[i + 1].hash; | |||||
ID_table[i].id = ID_table[i + 1].id; | |||||
ID_table[i + 1].hash = tmp.hash; | |||||
ID_table[i + 1].id = tmp.id; | |||||
swapped = true; | |||||
} | |||||
} | |||||
n = n - 1; | |||||
} while(swapped == true && n); | |||||
} | |||||
/** | |||||
\brief Gets the path to the x64 ntdll in native format | |||||
\param path Output buffer | |||||
*/ | |||||
static void get_ntdll_path(wchar_t* path) | |||||
{ | |||||
wchar_t systemDirectory[MAX_PATH]; | |||||
if(!path) | |||||
return; | |||||
GetSystemDirectory(systemDirectory, _countof(systemDirectory)); | |||||
wsprintfW(path, L"\\??\\%s\\ntdll.dll", systemDirectory); | |||||
} | |||||
/** | |||||
*/ | |||||
static BOOL read_ntdll(LPBYTE& content, DWORD& size) | |||||
{ | |||||
wchar_t ntdllPath[MAX_PATH]; //! Path in the native format | |||||
get_ntdll_path(ntdllPath); | |||||
printf("%ls\n", ntdllPath); | |||||
_UNICODE_STRING_T<DWORD64> filename = {lstrlenW(ntdllPath) * sizeof(WCHAR), MAX_PATH * sizeof(WCHAR), (DWORD64)ntdllPath}; | |||||
_OBJECT_ATTRIBUTES_T<DWORD64> obja = {sizeof(_OBJECT_ATTRIBUTES_T<DWORD64>), NULL, (DWORD64)&filename, OBJ_CASE_INSENSITIVE, NULL, NULL}; | |||||
_IO_STATUS_BLOCK_T<DWORD64> iostatusblock = {0}; | |||||
_HANDLE_T<DWORD64> fileHandle = {(DWORD64)INVALID_HANDLE_VALUE}; | |||||
NTSTATUS stat = DO_SYSCALL(get_basic_syscall_ID(NTOPENFILE), &fileHandle, | |||||
FILE_READ_DATA | SYNCHRONIZE, &obja, &iostatusblock, FILE_SHARE_READ, | |||||
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); | |||||
if(STATUS_SUCCESS != stat) | |||||
{ | |||||
printf("NTSTATUS: %X\tHandle: %llX\n", stat, fileHandle.h); | |||||
return FALSE; | |||||
} | |||||
printf("Handle: %llX\n", fileHandle.h); | |||||
if(!(size = GetFileSize((HANDLE)fileHandle.h, NULL))) | |||||
{ | |||||
DO_SYSCALL(get_basic_syscall_ID(NTCLOSE), fileHandle.h); | |||||
return FALSE; | |||||
} | |||||
printf("Size of ntdll: %dkb\n", size / 1024); | |||||
/* As no code is actually executed in the new ntdll - but only | |||||
a few bytes are read from it - rw is enough */ | |||||
if(!(content = (LPBYTE)VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, | |||||
PAGE_READWRITE))) | |||||
{ | |||||
DO_SYSCALL(get_basic_syscall_ID(NTCLOSE), fileHandle.h); | |||||
return FALSE; | |||||
} | |||||
printf("content %p\n", content); | |||||
printf("ios ptr %X", &iostatusblock); | |||||
LARGE_INTEGER offset = {0}; | |||||
stat = DO_SYSCALL(get_basic_syscall_ID(NTREADFILE), | |||||
(HANDLE)fileHandle.h, | |||||
NULL, // event | |||||
NULL, // ApcRoutine | |||||
NULL, // ApcContext | |||||
&iostatusblock, | |||||
content, | |||||
size, | |||||
&offset, | |||||
NULL); // key | |||||
if(STATUS_SUCCESS != stat) | |||||
{ | |||||
VirtualFree(content, 0, MEM_RELEASE); | |||||
content = NULL; | |||||
DO_SYSCALL(get_basic_syscall_ID(NTCLOSE), fileHandle.h); | |||||
printf("Reading failed: %X\t%X != %X\n", stat, size, offset.LowPart); | |||||
return FALSE; | |||||
} | |||||
printf("ios: %X\toffset: %X\n", iostatusblock.Status, offset.LowPart); | |||||
DO_SYSCALL(get_basic_syscall_ID(NTCLOSE), fileHandle.h); | |||||
return TRUE; | |||||
} | |||||
/** | |||||
\brief (Partly) maps the image. | |||||
This does NOT fix relocations, imports, TLS, sets section protections yadda yadda. | |||||
As this image is only used to parse out the IDs that is no problem. | |||||
\param content Raw data of the file to be mapped | |||||
\param mappedImage The finished image | |||||
*/ | |||||
static BOOL map_PE(LPBYTE content, LPBYTE* mappedImage) | |||||
{ | |||||
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)content; | |||||
if(IMAGE_DOS_SIGNATURE != dos->e_magic) | |||||
{ | |||||
printf("Not a valid DOS header: %s\n", content); | |||||
return FALSE; | |||||
} | |||||
PIMAGE_NT_HEADERS64 nt = (PIMAGE_NT_HEADERS64)(content + dos->e_lfanew); | |||||
if(IMAGE_NT_SIGNATURE != nt->Signature) | |||||
{ | |||||
printf("Not a valid PE header\n"); | |||||
return FALSE; | |||||
} | |||||
/* Must be mapped properly (Actually almost - | |||||
only the code section would be needed) so the IDs can be be | |||||
parsed properly */ | |||||
if(!(*mappedImage = (LPBYTE)VirtualAlloc(NULL, nt->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, | |||||
PAGE_READWRITE))) | |||||
{ | |||||
printf("Can't alloc\n"); | |||||
return FALSE; | |||||
} | |||||
printf("Let's map that shit @ %p. %X sections. %X imageSize\n", *mappedImage, | |||||
nt->FileHeader.NumberOfSections, nt->OptionalHeader.SizeOfImage); | |||||
// Copy up to the first section (Size of optional header + delta optional header to start of image) | |||||
memcpy(*mappedImage, content, nt->FileHeader.SizeOfOptionalHeader + ((LPBYTE)&nt->OptionalHeader - (LPBYTE)content)); | |||||
// Copy sections | |||||
#define IMAGE_FIRST_SECTION64( ntheader ) ((PIMAGE_SECTION_HEADER) \ | |||||
((ULONG_PTR)(ntheader)+\ | |||||
FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader) + \ | |||||
((ntheader))->FileHeader.SizeOfOptionalHeader \ | |||||
)) | |||||
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION64(nt); | |||||
for(unsigned int i = 0; i < nt->FileHeader.NumberOfSections; i++) | |||||
{ | |||||
printf("Copy %Xbytes @ RVA %X From %X\n", pish->SizeOfRawData, pish->VirtualAddress, pish->PointerToRawData); | |||||
memcpy((*mappedImage + pish->VirtualAddress), (content + pish->PointerToRawData), | |||||
pish->SizeOfRawData); | |||||
pish++; | |||||
} | |||||
return TRUE; | |||||
} | |||||
/** | |||||
\brief Initalize the ID_table. | |||||
*/ | |||||
BOOL initalize_ID_table() | |||||
{ | |||||
LPBYTE ntdll = NULL, imageBase = NULL; | |||||
DWORD ntdllSize = 0; | |||||
if(!read_ntdll(ntdll, ntdllSize)) | |||||
return FALSE; | |||||
if(!map_PE(ntdll, &imageBase)) | |||||
return FALSE; | |||||
ID_table_count = get_syscall_ids(imageBase, NULL); | |||||
printf("%i functions who do direct syscalls\n", ID_table_count); | |||||
if(!ID_table_count) | |||||
return FALSE; | |||||
if(!(ID_table = (API_TO_INDEX*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ID_table_count * sizeof(API_TO_INDEX)))) | |||||
return FALSE; | |||||
if(!get_syscall_ids(imageBase, ID_table)) | |||||
return FALSE; | |||||
VirtualFree(ntdll, 0, MEM_RELEASE); | |||||
VirtualFree(imageBase, 0, MEM_RELEASE); | |||||
sort_ID_table(); | |||||
return TRUE; | |||||
} | |||||
/** | |||||
\brief Has a few hardcoded IDs and returns the correct one for the current OS | |||||
Which IDs exactly are hardcoded can be seen in the enum. | |||||
Table made mostly with data from: | |||||
x86: http://j00ru.vexillium.org/ntapi/ | |||||
WOW64: http://j00ru.vexillium.org/ntapi_64/ | |||||
\fixme >=Win8 Support? | |||||
*/ | |||||
DWORD get_basic_syscall_ID(SYSCALL_IDS func) | |||||
{ | |||||
_KUSER_SHARED_DATA* _kuser_s_d = GET_KUSER_SHARED_DATA(); | |||||
ULONG majorVersion = _kuser_s_d->NtMajorVersion; | |||||
ULONG minorVersion = _kuser_s_d->NtMinorVersion; | |||||
NT_PRODUCT_TYPE productType = _kuser_s_d->NtProductType; | |||||
_PEB* p = (_PEB*)__readfsdword(0x30); | |||||
ULONG buildID = p->NtBuildNumber; | |||||
switch(majorVersion) | |||||
{ | |||||
case 5: | |||||
// XP | |||||
if(1 == minorVersion || | |||||
(2 == minorVersion && VER_NT_WORKSTATION == productType)) | |||||
{ | |||||
if(NTOPENFILE == func) | |||||
return 0x30; | |||||
else if(NTCREATEFILE == func) | |||||
return 0x52; | |||||
else if(NTREADFILE == func) | |||||
return 0x03; | |||||
else if(NTCLOSE == func) | |||||
return 0x0C; | |||||
} | |||||
// Server 2003 | |||||
else | |||||
{ | |||||
printf("SRV03 unsupported\n"); // fixme | |||||
if(NTOPENFILE == func) | |||||
return 0x7a; | |||||
else if(NTCREATEFILE == func) | |||||
return 0x26; | |||||
else if(NTREADFILE == func) | |||||
return 0xbf; | |||||
else if(NTCLOSE == func) | |||||
return 0x1b; | |||||
} | |||||
break; | |||||
case 6: | |||||
switch(minorVersion) | |||||
{ | |||||
// Vista SP0-2 & Server 2008 | |||||
case 0: | |||||
printf("Vista unsupported\n"); // fixme | |||||
if(NTOPENFILE == func) | |||||
return 0xba; | |||||
else if(NTCREATEFILE == func) | |||||
return 0x3c; | |||||
else if(NTREADFILE == func) | |||||
return 0x102; | |||||
else if(NTCLOSE == func) | |||||
return 0x30; | |||||
break; | |||||
// Win7 | |||||
case 1: | |||||
if(NTOPENFILE == func) | |||||
return 0x30; | |||||
else if(NTCREATEFILE == func) | |||||
return 0x52; | |||||
else if(NTREADFILE == func) | |||||
return 0x03; | |||||
else if(NTCLOSE == func) | |||||
return 0x0C; | |||||
// Win 8 | |||||
case 2: | |||||
printf("Win8 unsupported\n"); // fixme | |||||
if(NTOPENFILE == func) | |||||
return 0xe7; | |||||
else if(NTCREATEFILE == func) | |||||
return 0x15f; | |||||
else if(NTREADFILE == func) | |||||
return 0x86; | |||||
else if(NTCLOSE == func) | |||||
return 0x0171; | |||||
break; | |||||
} | |||||
break; | |||||
// Win 10 | |||||
case 10: | |||||
if (NTOPENFILE == func) | |||||
return 0x0033; | |||||
else if (NTCREATEFILE == func) | |||||
return 0x55; | |||||
else if (NTREADFILE == func) | |||||
return 0x06; | |||||
else if (NTCLOSE == func) | |||||
return 0x0f; | |||||
} | |||||
return INVALID_SYSCALL_ID; | |||||
} | |||||
DWORD get_syscall_ID(DWORD func) | |||||
{ | |||||
DWORD left = 0, right = ID_table_count; | |||||
while(left != right) | |||||
{ | |||||
DWORD middle = (left + right) / 2; | |||||
if(func == ID_table[middle].hash) | |||||
return ID_table[middle].id; | |||||
if(func > ID_table[middle].hash) | |||||
left = middle + 1; | |||||
else | |||||
right = middle - 1; | |||||
} | |||||
if(func == ID_table[left].hash) | |||||
{ | |||||
return ID_table[left].id; | |||||
} | |||||
return INVALID_SYSCALL_ID; | |||||
} | |||||
VOID destroy_ID_table() | |||||
{ | |||||
HeapFree(GetProcessHeap(), 0, ID_table); | |||||
} | |||||
#if 0 | |||||
BOOL test_id_table() | |||||
{ | |||||
LPVOID imageBase = GetModuleHandle(TEXT("ntdll.dll")); | |||||
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)imageBase; | |||||
// not a valid DOS header | |||||
if(IMAGE_DOS_SIGNATURE != dos->e_magic) | |||||
return FALSE; | |||||
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((LPBYTE)imageBase + dos->e_lfanew); | |||||
// not a valid PE or not the correct architecture | |||||
if(IMAGE_NT_SIGNATURE != nt->Signature || IMAGE_FILE_MACHINE_I386 != nt->FileHeader.Machine) | |||||
{ | |||||
return FALSE; | |||||
} | |||||
// No exports? | |||||
if(!nt->OptionalHeader.DataDirectory->Size) | |||||
return FALSE; | |||||
IMAGE_EXPORT_DIRECTORY *exportDir = (IMAGE_EXPORT_DIRECTORY *)((LPBYTE)imageBase + nt->OptionalHeader.DataDirectory->VirtualAddress); | |||||
PDWORD nameRef = (DWORD *)((LPBYTE)imageBase + exportDir->AddressOfNames); | |||||
WORD* ordinal = (WORD *)((LPBYTE)imageBase + exportDir->AddressOfNameOrdinals); | |||||
DWORD* addressOfFunctions = (DWORD*)((LPBYTE)imageBase + exportDir->AddressOfFunctions); | |||||
for(DWORD i = 0; i < exportDir->NumberOfNames; i++, nameRef++) | |||||
{ | |||||
const char* name = (const char*)((LPBYTE)imageBase + (*nameRef)); | |||||
LPBYTE address = (LPBYTE)imageBase + addressOfFunctions[ordinal[i]]; | |||||
DWORD id = get_syscall_id(address); | |||||
if(INVALID_SYSCALL_ID == id) | |||||
continue; | |||||
// At address is a function doing direct syscalls - check if can be found | |||||
if(INVALID_SYSCALL_ID == get_syscall_ID(hash(name))) | |||||
{ | |||||
printf("%s not found", name); | |||||
return FALSE; | |||||
} | |||||
} | |||||
return TRUE; | |||||
} | |||||
#endif |
#ifndef GET_SYSCALL64_IDS_H | |||||
#define GET_SYSCALL64_IDS_H | |||||
/** | |||||
\file | |||||
*/ | |||||
/** | |||||
\brief Definition of the hashs of APIs and the error value INVALID_SYSCALL_ID | |||||
*/ | |||||
enum SYSCALL_IDS | |||||
{ | |||||
// Files | |||||
NTOPENFILE = 0xC29C5019, //! Supported by get_basic_syscall_ID | |||||
NTCREATEFILE = 0x15A5ECDB, //! Supported by get_basic_syscall_ID | |||||
NTREADFILE = 0x2E979AE3, //! Supported by get_basic_syscall_ID | |||||
NTCLOSE = 0x8B8E133D, //! Supported by get_basic_syscall_ID | |||||
NTWRITEFILE = 0xD69326B2, | |||||
// Mutexes | |||||
NTCREATEMUTANT = 0x280632B4, | |||||
NTOPENMUTANT = 0xEC225D72, | |||||
NTRELEASEMUTANT = 0x29567961, | |||||
// Registry | |||||
NTOPENKEY = 0x4BB73E02, | |||||
NTQUERYVALUEKEY = 0xB4C18A83, | |||||
// Process | |||||
NTQUERYSYSTEMINFORMATION = 0xEE4F73A8, | |||||
INVALID_SYSCALL_ID = 0xFFFFFFFF, //! Used to signify errors | |||||
}; | |||||
/** | |||||
\brief Gets the basic ID for the hash given. | |||||
This function does not dependent on the ID table but instead has | |||||
hardcoded definitions for a FEW Apis (these are marked in the | |||||
SYSCALL_IDS enum) | |||||
\param func The hash of the API that the ID is searched for | |||||
\return Returns the ID or INVALID_SYSCALL_ID | |||||
\sa get_syscall_ID() | |||||
*/ | |||||
DWORD get_basic_syscall_ID(SYSCALL_IDS func); | |||||
/** | |||||
\brief Initalizes the ID table. | |||||
\return If FALSE no direct syscalls can be made. | |||||
\sa free_ID_table() | |||||
*/ | |||||
BOOL initalize_ID_table(); | |||||
/** | |||||
\brief Frees the ID table. After this is done | |||||
no direct syscalls can be made anymore | |||||
\sa initalize_ID_table() | |||||
*/ | |||||
VOID destroy_ID_table(); | |||||
/** | |||||
\brief Gets the ID for the hash given. | |||||
\pre This function does dependent on the ID table so make sure | |||||
to initalize_ID_table() first. | |||||
\param func The hash of the API that the ID is searched for | |||||
\return Returns the ID or INVALID_SYSCALL_ID | |||||
\sa initalize_ID_table() | |||||
*/ | |||||
DWORD get_syscall_ID(DWORD func); | |||||
#endif // GET_SYSCALL64_IDS_H | |||||
/* | |||||
there was a call to openfile that failed with STATUS_DATATYPE_MISALIGNMENT | |||||
*/ | |||||
#include <cstdio> | |||||
#include <iostream> | |||||
#include <stddef.h> | |||||
#include <malloc.h> | |||||
#include <Windows.h> | |||||
#include <shlobj.h> | |||||
#include <Shlwapi.h> | |||||
#include <ntdll.h> | |||||
#include "structs.h" | |||||
#include "wow64ext.h" | |||||
#include "misc.h" | |||||
#include "syscall64.h" | |||||
#include "get_syscall64_ids.h" | |||||
BOOL file_test(); | |||||
void WINAPI RtlInitUnicodeString(unsigned char* target, PCWSTR source); | |||||
#define PRINTF_PP(string, ...) printf(string, NARG(__VA_ARGS__), __VA_ARGS__) | |||||
int main() | |||||
{ | |||||
print_os_info(); | |||||
if(!initalize_ID_table()) | |||||
return 0; | |||||
file_test(); | |||||
} | |||||
#include <cstdio> | |||||
#include <ntdll.h> | |||||
#include "structs.h" | |||||
#include "misc.h" | |||||
BOOL is_WOW64() | |||||
{ | |||||
return NULL != __readfsdword(0xC0); | |||||
} | |||||
VOID print_os_info() | |||||
{ | |||||
_KUSER_SHARED_DATA* _kuser_s_d = GET_KUSER_SHARED_DATA(); | |||||
ULONG majorVersion = _kuser_s_d->NtMajorVersion; | |||||
ULONG minorVersion = _kuser_s_d->NtMinorVersion; | |||||
NT_PRODUCT_TYPE productType = _kuser_s_d->NtProductType; | |||||
_PEB* p = (_PEB*)__readfsdword(0x30); | |||||
ULONG buildID = p->NtBuildNumber; | |||||
printf("Running on %i.%i %i %X (x%s)\n", majorVersion, minorVersion, buildID, productType, (is_WOW64() ? "64" : "86")); | |||||
} | |||||
DWORD hash(const char* str) | |||||
{ | |||||
return hash((const unsigned char*)str, strlen(str)); | |||||
} | |||||
DWORD hash(const unsigned char* buf, const size_t sz) | |||||
{ | |||||
unsigned int hash = 5381; | |||||
for(unsigned int i = 0; i < sz; i++) | |||||
hash = ((hash << 5) + hash) + (unsigned int)buf[i]; | |||||
return hash; | |||||
} | |||||
BOOL is_executable(LPVOID addr) | |||||
{ | |||||
MEMORY_BASIC_INFORMATION mbi = {0}; | |||||
if(!VirtualQuery(addr, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) | |||||
{ | |||||
return FALSE; | |||||
} | |||||
return (mbi.Protect & PAGE_EXECUTE); | |||||
} | |||||
BOOL is_Win8() | |||||
{ | |||||
KUSER_SHARED_DATA* _kuser_s_d = GET_KUSER_SHARED_DATA(); | |||||
ULONG majorVersion = _kuser_s_d->NtMajorVersion; | |||||
ULONG minorVersion = _kuser_s_d->NtMinorVersion; | |||||
return 6 == majorVersion && 2 == minorVersion; | |||||
} |
#ifndef MISC_H | |||||
#define MISC_H | |||||
/** | |||||
\brief Checks if the page at addr is executable | |||||
*/ | |||||
BOOL is_executable(LPVOID addr); | |||||
/** | |||||
\brief Checks if the process is running on WOW64 by examing Heaven's Gate | |||||
*/ | |||||
BOOL is_WOW64(); | |||||
/** | |||||
\brief Computes the djb2 hash of the input string | |||||
\param str The data to be hashed | |||||
\return The value. | |||||
*/ | |||||
DWORD hash(const char* str); | |||||
/** | |||||
\brief Computes the djb2 hash of the input | |||||
\param buf The data to be hashed | |||||
\param sz The size of the data | |||||
\return The value. | |||||
*/ | |||||
DWORD hash(const unsigned char* buf, const size_t sz); | |||||
/** | |||||
\brief Prints a small summarization of the current OS | |||||
*/ | |||||
VOID print_os_info(); | |||||
BOOL is_Win8(); | |||||
#define GET_KUSER_SHARED_DATA() ((_KUSER_SHARED_DATA*)0x7FFE0000) | |||||
#endif |
#ifndef STRUCTS_INCLUDE_HEADER | |||||
#define STRUCTS_INCLUDE_HEADER | |||||
typedef struct _KSYSTEM_TIME { | |||||
UINT32 LowPart; | |||||
INT32 High1Time; | |||||
INT32 High2Time; | |||||
} KSYSTEM_TIME, *PKSYSTEM_TIME; | |||||
typedef enum _NT_PRODUCT_TYPE | |||||
{ | |||||
NtProductWinNt = 1, | |||||
NtProductLanManNt = 2, | |||||
NtProductServer = 3 | |||||
} NT_PRODUCT_TYPE; | |||||
typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE | |||||
{ | |||||
StandardDesign = 0, | |||||
NEC98x86 = 1, | |||||
EndAlternatives = 2 | |||||
} ALTERNATIVE_ARCHITECTURE_TYPE; | |||||
typedef struct _KUSER_SHARED_DATA | |||||
{ | |||||
ULONG TickCountLowDeprecated; | |||||
ULONG TickCountMultiplier; | |||||
KSYSTEM_TIME InterruptTime; | |||||
KSYSTEM_TIME SystemTime; | |||||
KSYSTEM_TIME TimeZoneBias; | |||||
WORD ImageNumberLow; | |||||
WORD ImageNumberHigh; | |||||
WCHAR NtSystemRoot[260]; | |||||
ULONG MaxStackTraceDepth; | |||||
ULONG CryptoExponent; | |||||
ULONG TimeZoneId; | |||||
ULONG LargePageMinimum; | |||||
ULONG Reserved2[7]; | |||||
NT_PRODUCT_TYPE NtProductType; | |||||
UCHAR ProductTypeIsValid; | |||||
ULONG NtMajorVersion; | |||||
ULONG NtMinorVersion; | |||||
UCHAR ProcessorFeatures[64]; | |||||
ULONG Reserved1; | |||||
ULONG Reserved3; | |||||
ULONG TimeSlip; | |||||
ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; | |||||
LARGE_INTEGER SystemExpirationDate; | |||||
ULONG SuiteMask; | |||||
UCHAR KdDebuggerEnabled; | |||||
UCHAR NXSupportPolicy; | |||||
ULONG ActiveConsoleId; | |||||
ULONG DismountCount; | |||||
ULONG ComPlusPackage; | |||||
ULONG LastSystemRITEventTickCount; | |||||
ULONG NumberOfPhysicalPages; | |||||
UCHAR SafeBootMode; | |||||
ULONG SharedDataFlags; | |||||
ULONG DbgErrorPortPresent : 1; | |||||
ULONG DbgElevationEnabled : 1; | |||||
ULONG DbgVirtEnabled : 1; | |||||
ULONG DbgInstallerDetectEnabled : 1; | |||||
ULONG SystemDllRelocated : 1; | |||||
ULONG SpareBits : 27; | |||||
UINT64 TestRetInstruction; | |||||
ULONG SystemCall; | |||||
ULONG SystemCallReturn; | |||||
UINT64 SystemCallPad[3]; | |||||
union | |||||
{ | |||||
KSYSTEM_TIME TickCount; | |||||
UINT64 TickCountQuad; | |||||
}; | |||||
ULONG Cookie; | |||||
INT64 ConsoleSessionForegroundProcessId; | |||||
ULONG Wow64SharedInformation[16]; | |||||
WORD UserModeGlobalLogger[8]; | |||||
ULONG HeapTracingPid[2]; | |||||
ULONG CritSecTracingPid[2]; | |||||
ULONG ImageFileExecutionOptions; | |||||
union | |||||
{ | |||||
UINT64 AffinityPad; | |||||
ULONG ActiveProcessorAffinity; | |||||
}; | |||||
UINT64 InterruptTimeBias; | |||||
} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA; | |||||
#endif // STRUCTS_INCLUDE_HEADER |
#ifndef SYSCALL64_H | |||||
#define SYSCALL64_H | |||||
#include <malloc.h> // eww include in headers | |||||
extern "C" DWORD _cdecl syscall64(size_t cnt, DWORD id, ...); | |||||
#define NARG(...) Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) | |||||
#define Y_TUPLE_SIZE_II(__args) Y_TUPLE_SIZE_I __args | |||||
#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0 | |||||
#define Y_TUPLE_SIZE_I(__p0,__p1,__p2,__p3,__p4,__p5,__p6,__p7,__p8,__p9,__p10,__p11,__p12,__p13,__p14,__p15,__p16,__p17,__p18,__p19,__p20,__p21,__p22,__p23,__p24,__p25,__p26,__p27,__p28,__p29,__p30,__p31,__n,...) __n | |||||
#define DO_SYSCALL(id, ...) syscall64(NARG(__VA_ARGS__), id, __VA_ARGS__) | |||||
#define STR_VALUE(arg) #arg | |||||
#define ALLOC_STRUCTURE(type, name) uint8_t* name = (unsigned char*)_aligned_malloc(is_WOW64() ? sizeof(type<DWORD64>) : sizeof(type<DWORD>), 16); \ | |||||
memset(name, 0, is_WOW64() ? sizeof(type<DWORD64>) : sizeof(type<DWORD>)); \ | |||||
printf("%s %s @ %p\n", STR_VALUE(type), STR_VALUE(name), name); | |||||
#define FREE_STRUCTURE(type, name) _aligned_free(name); name = NULL; | |||||
#define GET_MEMBER_OFFSET64(type, member) offsetof(type<DWORD64>, member) | |||||
#define GET_MEMBER_OFFSET86(type, member) offsetof(type<DWORD>, member) | |||||
#define GET_MEMBER_OFFSET(type, member) (is_WOW64() ? GET_MEMBER_OFFSET64(type, member) : GET_MEMBER_OFFSET86(type, member)) | |||||
#define GET_MEMBER(type, member, object) (object + GET_MEMBER_OFFSET(type, member)) | |||||
#define SET_MEMBER(type, member, object, val) { \ | |||||
decltype(val)* tmpDst = (decltype(val)*)GET_MEMBER(type, member, object); \ | |||||
decltype(val) tmpSrc = val; \ | |||||
printf("cpy %X(%s) from/value of %X to %X\n", sizeof(tmpDst), STR_VALUE(member), val, tmpDst); \ | |||||
memcpy((void*)tmpDst, (void*)&tmpSrc, sizeof(tmpDst)); \ | |||||
} | |||||
#define SET_MEMBER_PTR(type, member, object, src) { \ | |||||
void* dstPtr = (void*)GET_MEMBER(type, member, object); \ | |||||
void* ptrToSrc = (void*)src; \ | |||||
printf("cpy ptr(%s) from %X to %X\n", STR_VALUE(member), src, dstPtr); \ | |||||
memcpy((void*)dstPtr, &ptrToSrc, 4); \ | |||||
} | |||||
#endif |
#include <array> | |||||
#include <ntdll.h> | |||||
#include <Windows.h> | |||||
#include <shlobj.h> | |||||
#include <Shlwapi.h> | |||||
#include "structs.h" | |||||
#include "misc.h" | |||||
#include "wow64ext.h" | |||||
#include "syscall64.h" | |||||
#include "get_syscall64_ids.h" | |||||
void WINAPI RtlInitUnicodeString( | |||||
unsigned char* target, | |||||
PCWSTR source) | |||||
{ | |||||
SET_MEMBER_PTR(_UNICODE_STRING_T, Buffer, target, source); | |||||
if(source) | |||||
{ | |||||
unsigned int length = lstrlenW(source) * sizeof(WCHAR); | |||||
if(length > 0xfffc) | |||||
length = 0xfffc; | |||||
SET_MEMBER(_UNICODE_STRING_T, Length, target, length); | |||||
SET_MEMBER(_UNICODE_STRING_T, MaximumLength, target, length + sizeof(WCHAR)); | |||||
} | |||||
else | |||||
{ | |||||
SET_MEMBER(_UNICODE_STRING_T, Length, target, 0); | |||||
SET_MEMBER(_UNICODE_STRING_T, MaximumLength, target, 0); | |||||
} | |||||
} | |||||
VOID initialize_object_attributes(unsigned char* p, LPVOID n, ULONG a) | |||||
{ | |||||
SET_MEMBER(_OBJECT_ATTRIBUTES_T, uLength, p, is_WOW64() ? sizeof(_OBJECT_ATTRIBUTES_T<DWORD64>) : sizeof(_OBJECT_ATTRIBUTES_T<DWORD>)); | |||||
SET_MEMBER(_OBJECT_ATTRIBUTES_T, hRootDirectory, p, NULL); | |||||
SET_MEMBER(_OBJECT_ATTRIBUTES_T, uAttributes, p, a); | |||||
SET_MEMBER_PTR(_OBJECT_ATTRIBUTES_T, pObjectName, p, n); | |||||
SET_MEMBER(_OBJECT_ATTRIBUTES_T, pSecurityDescriptor, p, NULL); // Actually a ptr but we set a NULL | |||||
SET_MEMBER(_OBJECT_ATTRIBUTES_T, pSecurityQualityOfService, p, NULL); | |||||
} | |||||
BOOL file_test() | |||||
{ | |||||
ALLOC_STRUCTURE(_UNICODE_STRING_T, filename); | |||||
wchar_t desktopPath[MAX_PATH]; | |||||
lstrcpyW(desktopPath, L"\\??\\"); | |||||
if(!SHGetSpecialFolderPathW(HWND_DESKTOP, &desktopPath[lstrlenW(desktopPath)], CSIDL_DESKTOPDIRECTORY, FALSE)) | |||||
return FALSE; | |||||
PathAppendW(desktopPath, L"WaitAMinute.HowDidThisGetHere.txt"); | |||||
RtlInitUnicodeString(filename, desktopPath); | |||||
printf("Desktop: %ws\n", desktopPath); | |||||
ALLOC_STRUCTURE(_OBJECT_ATTRIBUTES_T, obja); | |||||
initialize_object_attributes(obja, (void*)filename, OBJ_CASE_INSENSITIVE); | |||||
ALLOC_STRUCTURE(_HANDLE_T, fileHandle); | |||||
ALLOC_STRUCTURE(_IO_STATUS_BLOCK_T, iostatusblock); | |||||
NTSTATUS stat = DO_SYSCALL(get_syscall_ID(NTCREATEFILE), fileHandle, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE, | |||||
obja, iostatusblock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OVERWRITE_IF, | |||||
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); | |||||
if(STATUS_SUCCESS != stat) | |||||
{ | |||||
printf("NTSTATUS: %X\n", stat); | |||||
return FALSE; | |||||
} | |||||
printf("Handle: %X\tIO.uInformation:%X\n", *(PHANDLE)GET_MEMBER(_HANDLE_T, h, fileHandle), *(PDWORD)GET_MEMBER(_IO_STATUS_BLOCK_T, uInformation, iostatusblock)); | |||||
FREE_STRUCTURE(_UNICODE_STRING_T, filename); | |||||
FREE_STRUCTURE(_OBJECT_ATTRIBUTES_T, obja); | |||||
const char TEST_STRING[] = {"0123456789ABCDEF"}; | |||||
if(STATUS_SUCCESS != (stat = DO_SYSCALL(get_syscall_ID(NTWRITEFILE), *(PHANDLE)GET_MEMBER(_HANDLE_T, h, fileHandle), | |||||
NULL, NULL, NULL, iostatusblock, TEST_STRING, lstrlenA(TEST_STRING), NULL, NULL))) | |||||
{ | |||||
printf("Write: %X\t\n", stat); | |||||
return FALSE; | |||||
} | |||||
FlushFileBuffers(*(PHANDLE)GET_MEMBER(_HANDLE_T, h, fileHandle)); | |||||
char buffer[sizeof(TEST_STRING)+1] = {0}; | |||||
LARGE_INTEGER offset = {0}; | |||||
if(STATUS_SUCCESS != (stat = DO_SYSCALL(get_syscall_ID(NTREADFILE), *(PHANDLE)GET_MEMBER(_HANDLE_T, h, fileHandle), | |||||
NULL, NULL, NULL, iostatusblock, buffer, sizeof(buffer), &offset, NULL))) | |||||
{ | |||||
printf("Reading failed: %X\t%X != %X\n", stat, sizeof(buffer), offset.LowPart); | |||||
return FALSE; | |||||
} | |||||
buffer[*(PDWORD)GET_MEMBER(_IO_STATUS_BLOCK_T, uInformation, iostatusblock)] = 0; | |||||
printf("io stat: %X\tio inf: %X\tread: %X\n", *(PDWORD)GET_MEMBER(_IO_STATUS_BLOCK_T, Status, iostatusblock), *(PDWORD)GET_MEMBER(_IO_STATUS_BLOCK_T, uInformation, iostatusblock), offset.LowPart); | |||||
DO_SYSCALL(get_syscall_ID(NTCLOSE), *(PHANDLE)GET_MEMBER(_HANDLE_T, h, fileHandle)); | |||||
FREE_STRUCTURE(_HANDLE_T, fileHandle); | |||||
printf("'%s' == '%s'\n", TEST_STRING, buffer); | |||||
return 0 == lstrcmpA(TEST_STRING, buffer); | |||||
} |
/** | |||||
* | |||||
* 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 | |||||
#ifndef STATUS_SUCCESS | |||||
# define STATUS_SUCCESS 0 | |||||
#endif | |||||
#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 | |||||
{ | |||||
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; | |||||
}; | |||||
// 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) | |||||
// My changes | |||||
template <class T> | |||||
struct _OBJECT_ATTRIBUTES_T | |||||
{ | |||||
union | |||||
{ | |||||
ULONG uLength; | |||||
T dummy; | |||||
}; | |||||
T hRootDirectory; | |||||
T pObjectName; | |||||
union | |||||
{ | |||||
ULONG uAttributes; | |||||
T dummy2; | |||||
}; | |||||
T pSecurityDescriptor; | |||||
T pSecurityQualityOfService; | |||||
}; | |||||
template <class T> | |||||
struct _HANDLE_T | |||||
{ | |||||
T h; | |||||
}; | |||||
/* Extremly weird. sizeof(IO_STATUS_BLOCK) == 8 on x86 & x64. | |||||
However NtCreateFile doesn't seem to agree | |||||
UNICODE_STRING filename = {0}; | |||||
RtlInitUnicodeString(&filename, L"\\??\\D:\\abc.txt"); | |||||
OBJECT_ATTRIBUTES obja = {0}; | |||||
IO_STATUS_BLOCK iostatusblock = {0}; | |||||
InitializeObjectAttributes(&obja, &filename, OBJ_CASE_INSENSITIVE, NULL, NULL); | |||||
HANDLE h = INVALID_HANDLE_VALUE; | |||||
NTSTATUS stat = NtCreateFile(&h, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE, | |||||
&obja, &iostatusblock, | |||||
NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OVERWRITE_IF, | |||||
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); | |||||
Run in Debug mode and see Run-Time Check Failure #2 - Stack around the variable 'iostatusblock' was corrupted. | |||||
*/ | |||||
template <class T> | |||||
struct _IO_STATUS_BLOCK_T | |||||
{ | |||||
union | |||||
{ | |||||
NTSTATUS Status; | |||||
T dummy; | |||||
}; | |||||
union | |||||
{ | |||||
ULONG uInformation; | |||||
T dummy; | |||||
}; | |||||
}; | |||||
#pragma pack(pop) |