Skip to content

Instantly share code, notes, and snippets.

@wbenny
Last active September 17, 2020 16:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wbenny/66545f68a1681168ee9270cf9b8f4ec6 to your computer and use it in GitHub Desktop.
Save wbenny/66545f68a1681168ee9270cf9b8f4ec6 to your computer and use it in GitHub Desktop.
#include <ntdll_windows.h>
#include <ntdll.h>
// extern "C"
// UINT_PTR
// NTAPI
// MwGenericCall(
// ULONG SyscallNumber,
// ULONG ArgumentCount,
// va_list ArgumentList
// );
#pragma section(".text")
__declspec(allocate(".text"))
UCHAR MwSyscallCode[] = { //
// ;
// ; Save r12 to the shadow space.
// ; This register will be held as a temporary
// ; stack pointer for the syscall.
// ;
0x4C, 0x89, 0x64, 0x24, 0x08, // mov qword ptr [rsp + 8], r12
//
// ;
// ; eax = SyscallNumber
// ; r10 = ArgumentCount
// ; r11 = ArgumentList
// ; r12 = ArgumentList - sizeof(PVOID)
// ; (space for return address)
// ;
//
0x8B, 0xC1, // mov eax, ecx
0x44, 0x8B, 0xD2, // mov r10d, edx
0x4D, 0x8B, 0xD8, // mov r11, r8
0x4D, 0x8D, 0x63, 0xF8, // lea r12, qword ptr [r11 - 8]
//
// ;
// ; Assign first 4 arguments (rcx, rdx, r8, r9)
// ; from the ArgumentList.
// ;
0x41, 0x83, 0xFA, 0x01, // cmp r10d, 1
0x49, 0x0F, 0x43, 0x0B, // cmovae rcx, qword ptr [r11 + 0]
//
0x41, 0x83, 0xFA, 0x02, // cmp r10d, 2
0x49, 0x0F, 0x43, 0x53, 0x08, // cmovae rdx, qword ptr [r11 + 8]
//
0x41, 0x83, 0xFA, 0x03, // cmp r10d, 3
0x4D, 0x0F, 0x43, 0x43, 0x10, // cmovae r8, qword ptr [r11 + 16]
//
0x41, 0x83, 0xFA, 0x04, // cmp r10d, 4
0x4D, 0x0F, 0x43, 0x4B, 0x18, // cmovae r9, qword ptr [r11 + 24]
//
// ;
// ; The syscall handler expects the first
// ; parameter in the r10 register.
// ;
0x4C, 0x8B, 0xD1, // mov r10, rcx
//
// ;
// ; Stack pivot, syscall, restore stack.
// ;
0x4C, 0x87, 0xE4, // xchg r12, rsp
0x0F, 0x05, // syscall
0x4C, 0x87, 0xE4, // xchg r12, rsp
//
// ;
// ; Restore r12 register from the shadow space.
// ;
0x4C, 0x8B, 0x64, 0x24, 0x08, // mov r12, qword ptr [rsp + 8]
//
0xC3, // retn
}; //
typedef UINT_PTR (NTAPI* GENERIC_CALL_FN)(
_In_ ULONG SyscallNumber,
_In_ ULONG ArgumentCount,
_In_ va_list ArgumentList
);
GENERIC_CALL_FN MwGenericCall = (GENERIC_CALL_FN)&MwSyscallCode;
static const unsigned char ASM_MOV_EAX_IMM = 0xb8; // followed by DWORD
static const unsigned char ASM_RET = 0xc3;
static const unsigned char ASM_MOV_R10_RCX[] = { 0x4c, 0x8b, 0xD1 };
static const unsigned char ASM_SYSCALL[] = { 0x0f, 0x05 };
static const unsigned char ASM_SYSCALL_STUB[] = {
0x4c, 0x8b, 0xD1, // mov r10, rcx
0xb8 // mov eax, imm32 - follows DWORD
};
NTSTATUS
NTAPI
MwDisasmGetSyscallNumber(
VOID* FunctionAddress,
ULONG* SyscallNumber
)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if ((*(PULONG)FunctionAddress) == (*(PULONG)ASM_SYSCALL_STUB))
{
*SyscallNumber = *(ULONG*)((BYTE*)FunctionAddress + sizeof(ASM_SYSCALL_STUB));
Status = STATUS_SUCCESS;
}
return Status;
}
NTSTATUS
NTAPI
MwGetFunctionAddress(
VOID* ImageBase,
const CHAR* FunctionName,
VOID** FunctionAddress,
ULONG* SyscallNumber
)
{
TEB* Teb = NtCurrentTeb();
LIST_ENTRY* ModuleListHead = &Teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList;
LIST_ENTRY* ModuleListNextEntry;
BYTE* NtdllBase;
for (
ModuleListNextEntry = ModuleListHead;
ModuleListNextEntry->Flink != ModuleListHead;
ModuleListNextEntry = ModuleListNextEntry->Flink
)
{
LDR_DATA_TABLE_ENTRY* LdrEntry = (LDR_DATA_TABLE_ENTRY*)ModuleListNextEntry->Flink;
if (!wcscmp(LdrEntry->BaseDllName.Buffer, L"ntdll.dll"))
{
NtdllBase = (BYTE*)LdrEntry->DllBase;
break;
}
}
IMAGE_DOS_HEADER* DosHeader = (IMAGE_DOS_HEADER*)NtdllBase;
IMAGE_NT_HEADERS* NtHeader = (IMAGE_NT_HEADERS*)(NtdllBase + DosHeader->e_lfanew);
IMAGE_DATA_DIRECTORY* ExportDataDirectory = (IMAGE_DATA_DIRECTORY*)&NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
IMAGE_EXPORT_DIRECTORY* ExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(NtdllBase + ExportDataDirectory->VirtualAddress);
DWORD* FunctionPtrRvaArray = (DWORD*)(NtdllBase + ExportDirectory->AddressOfFunctions);
DWORD* FunctionNameRvaArray = (DWORD*)(NtdllBase + ExportDirectory->AddressOfNames);
USHORT* FunctionOrdinalRvaArray = (USHORT*)(NtdllBase + ExportDirectory->AddressOfNameOrdinals);
int FunctionNameRvaArraySize = ExportDirectory->NumberOfNames;
CHAR* ExportFunctionName;
VOID* ExportFunctionPtr;
for (int i = 0; i < FunctionNameRvaArraySize; i++)
{
ExportFunctionName = (CHAR*)(NtdllBase + FunctionNameRvaArray[i]);
ExportFunctionPtr = (VOID*)(NtdllBase + FunctionPtrRvaArray[FunctionOrdinalRvaArray[i]]);
if (!strcmp(ExportFunctionName, FunctionName))
{
MwDisasmGetSyscallNumber(ExportFunctionPtr, SyscallNumber);
*FunctionAddress = ExportFunctionPtr;
return STATUS_SUCCESS;
}
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
NTAPI
MwCallNtdll(
const CHAR* FunctionName,
ULONG ArgumentCount,
...
)
{
VOID* FunctionAddress;
ULONG SyscallNumber;
MwGetFunctionAddress(NULL, FunctionName, &FunctionAddress, &SyscallNumber);
va_list ArgumentList;
va_start(ArgumentList, ArgumentCount);
UINT_PTR Result = MwGenericCall(SyscallNumber, ArgumentCount, ArgumentList);
va_end(ArgumentList);
return (NTSTATUS)Result;
}
//
// Variadic macro rape.
//
#define MW_MACRO_EVAL(...) __VA_ARGS__
#define MW_MACRO_EXPAND(expr) expr
#define MW_VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define MW_VA_NUM_ARGS(...) MW_MACRO_EXPAND(MW_VA_NUM_ARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
#define MW_CALL_WITH_NUM_ARGS(FunctionName, ArgumentCount, ...) MwCallNtdll(FunctionName, ArgumentCount, __VA_ARGS__)
#define MW_CALL_VA_STR(FunctionName, ...) MW_CALL_WITH_NUM_ARGS(FunctionName, MW_VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
#define MW_CALL_VA(FunctionName, ...) MW_CALL_WITH_NUM_ARGS(#FunctionName, MW_VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
#define MW_CALL_STR(FunctionName, Args) MW_CALL_VA_STR(FunctionName, MW_MACRO_EVAL Args)
#define MW_CALL(FunctionName, Args) MW_CALL_VA_STR(#FunctionName, MW_MACRO_EVAL Args)
#define NtCall MW_CALL
void NtMain()
{
NTSTATUS Status;
HANDLE SectionHandle;
LARGE_INTEGER MaximumSize;
MaximumSize.QuadPart = 4096;
Status = NtCall(NtCreateSection, (&SectionHandle, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL));
PVOID BaseAddress = NULL;
SIZE_T ViewSize = 4096;
Status = NtCall(NtMapViewOfSection, (SectionHandle, NtCurrentProcess(), &BaseAddress, 0, 4096, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE));
RtlCopyMemory(BaseAddress, "HELLO", 6);
NtTestAlert();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment