Преглед изворни кода

direct syscalls independent of the underlying bit width

master
amo wacked пре 5 година
комит
c0007f7b78
9 измењених фајлова са 1353 додато и 0 уклоњено
  1. +516
    -0
      get_syscall64_ids.cpp
  2. +71
    -0
      get_syscall64_ids.h
  3. +35
    -0
      main.cpp
  4. +56
    -0
      misc.cpp
  5. +38
    -0
      misc.h
  6. +85
    -0
      structs.h
  7. +43
    -0
      syscall64.h
  8. +100
    -0
      tests.cpp
  9. +409
    -0
      wow64ext.h

+ 516
- 0
get_syscall64_ids.cpp Прегледај датотеку

@@ -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

+ 71
- 0
get_syscall64_ids.h Прегледај датотеку

@@ -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

+ 35
- 0
main.cpp Прегледај датотеку

@@ -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();
}

+ 56
- 0
misc.cpp Прегледај датотеку

@@ -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;
}

+ 38
- 0
misc.h Прегледај датотеку

@@ -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

+ 85
- 0
structs.h Прегледај датотеку

@@ -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

+ 43
- 0
syscall64.h Прегледај датотеку

@@ -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

+ 100
- 0
tests.cpp Прегледај датотеку

@@ -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);
}

+ 409
- 0
wow64ext.h Прегледај датотеку

@@ -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)

Loading…
Откажи
Сачувај