@@ -0,0 +1,516 @@ | |||
#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 |
@@ -0,0 +1,71 @@ | |||
#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 | |||
@@ -0,0 +1,35 @@ | |||
/* | |||
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(); | |||
} | |||
@@ -0,0 +1,56 @@ | |||
#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; | |||
} |
@@ -0,0 +1,38 @@ | |||
#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 |
@@ -0,0 +1,85 @@ | |||
#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 |
@@ -0,0 +1,43 @@ | |||
#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 |
@@ -0,0 +1,100 @@ | |||
#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); | |||
} |
@@ -0,0 +1,409 @@ | |||
/** | |||
* | |||
* 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) |