mirror of
https://github.com/maxDcb/C2Core
synced 2026-06-08 15:48:01 +00:00
504 lines
13 KiB
C++
504 lines
13 KiB
C++
#pragma once
|
|
|
|
#include <windows.h>
|
|
#include <tlhelp32.h>
|
|
#include "include.hpp"
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
|
|
extern DWORD GlobalHash;
|
|
|
|
EXTERN_C DWORD getGlobalHash();
|
|
DWORD SW3_HashSyscall(PCSTR FunctionName);
|
|
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
|
|
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtAllocateVirtualMemory(
|
|
IN HANDLE ProcessHandle,
|
|
IN OUT PVOID * BaseAddress,
|
|
IN ULONG ZeroBits,
|
|
IN OUT PSIZE_T RegionSize,
|
|
IN ULONG AllocationType,
|
|
IN ULONG Protect);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtWaitForSingleObject(
|
|
IN HANDLE ObjectHandle,
|
|
IN BOOLEAN Alertable,
|
|
IN PLARGE_INTEGER TimeOut OPTIONAL);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtCreateThreadEx(
|
|
OUT PHANDLE ThreadHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
|
IN HANDLE ProcessHandle,
|
|
IN PVOID StartRoutine,
|
|
IN PVOID Argument OPTIONAL,
|
|
IN ULONG CreateFlags,
|
|
IN SIZE_T ZeroBits,
|
|
IN SIZE_T StackSize,
|
|
IN SIZE_T MaximumStackSize,
|
|
IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtClose(
|
|
IN HANDLE Handle);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtWriteVirtualMemory(
|
|
IN HANDLE ProcessHandle,
|
|
IN PVOID BaseAddress,
|
|
IN PVOID Buffer,
|
|
IN SIZE_T NumberOfBytesToWrite,
|
|
OUT PSIZE_T NumberOfBytesWritten OPTIONAL);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtProtectVirtualMemory(
|
|
IN HANDLE ProcessHandle,
|
|
IN OUT PVOID * BaseAddress,
|
|
IN OUT PSIZE_T RegionSize,
|
|
IN ULONG NewProtect,
|
|
OUT PULONG OldProtect);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtOpenProcess(
|
|
OUT PHANDLE ProcessHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN CLIENT_ID* ClientId OPTIONAL);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtCreateProcess(
|
|
OUT PHANDLE ProcessHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
|
IN HANDLE ParentProcess,
|
|
IN BOOLEAN InheritObjectTable,
|
|
IN HANDLE SectionHandle OPTIONAL,
|
|
IN HANDLE DebugPort OPTIONAL,
|
|
IN HANDLE ExceptionPort OPTIONAL );
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtQueueApcThread(
|
|
IN HANDLE ThreadHandle,
|
|
IN PIO_APC_ROUTINE ApcRoutine,
|
|
IN PVOID ApcRoutineContext OPTIONAL,
|
|
IN PIO_STATUS_BLOCK ApcStatusBlock OPTIONAL,
|
|
IN ULONG pcReserved OPTIONAL );
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtResumeThread(
|
|
IN HANDLE ThreadHandle,
|
|
OUT PULONG SuspendCount OPTIONAL );
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtOpenProcessToken(
|
|
IN HANDLE ProcessHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
OUT PHANDLE TokenHandle);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtAdjustPrivilegesToken(
|
|
IN HANDLE TokenHandle,
|
|
IN BOOLEAN DisableAllPrivileges,
|
|
IN PTOKEN_PRIVILEGES NewState OPTIONAL,
|
|
IN ULONG BufferLength,
|
|
OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
|
|
OUT PULONG ReturnLength OPTIONAL);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtQueryVirtualMemory(
|
|
IN HANDLE ProcessHandle,
|
|
IN PVOID BaseAddress,
|
|
IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
|
|
OUT PVOID MemoryInformation,
|
|
IN SIZE_T MemoryInformationLength,
|
|
OUT PSIZE_T ReturnLength OPTIONAL);
|
|
|
|
|
|
EXTERN_C NTSTATUS Sw3NtReadVirtualMemory(
|
|
IN HANDLE ProcessHandle,
|
|
IN PVOID BaseAddress OPTIONAL,
|
|
OUT PVOID Buffer,
|
|
IN SIZE_T BufferSize,
|
|
OUT PSIZE_T NumberOfBytesRead OPTIONAL);
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtAllocateVirtualMemory_(Args&&... args)
|
|
{
|
|
// need to put Zw for the syscall
|
|
// char *FunctionName = "ZwAllocateVirtualMemory";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwAllocateVirtualMemory " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 806327511;
|
|
return Sw3NtAllocateVirtualMemory(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtWaitForSingleObject_(Args&&... args)
|
|
{
|
|
// char *FunctionName = "ZwWaitForSingleObject";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwWaitForSingleObject " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 3941435821;
|
|
return Sw3NtWaitForSingleObject(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtClose_(Args&&... args)
|
|
{
|
|
// char *FunctionName = "ZwClose";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwClose " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 745328858;
|
|
return Sw3NtClose(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtWriteVirtualMemory_(Args&&... args)
|
|
{
|
|
// char *FunctionName = "ZwWriteVirtualMemory";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwWriteVirtualMemory " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 4080026747;
|
|
return Sw3NtWriteVirtualMemory(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtProtectVirtualMemory_(Args&&... args)
|
|
{
|
|
// char *FunctionName = "ZwProtectVirtualMemory";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwProtectVirtualMemory " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 699580991;
|
|
return Sw3NtProtectVirtualMemory(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtOpenProcess_(Args&&... args)
|
|
{
|
|
// char *FunctionName = "ZwOpenProcess";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwAllocateVirtualMemory " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 3548847587;
|
|
// __debugbreak();
|
|
return Sw3NtOpenProcess(std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtCreateThreadEx_(Args&&... args)
|
|
{
|
|
// char *FunctionName = "ZwCreateThreadEx";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwCreateThreadEx " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 3653557611;
|
|
return Sw3NtCreateThreadEx(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtCreateProcess_(Args&&... args)
|
|
{
|
|
// PCSTR FunctionName = "ZwCreateProcess";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwCreateProcess " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 1768521463;
|
|
return Sw3NtCreateProcess(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtQueueApcThread_(Args&&... args)
|
|
{
|
|
// PCSTR FunctionName = "ZwQueueApcThread";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwQueueApcThread " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 735850453;
|
|
return Sw3NtQueueApcThread(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtResumeThread_(Args&&... args)
|
|
{
|
|
// PCSTR FunctionName = "ZwResumeThread";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << "ZwResumeThread " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 4130550557;
|
|
return Sw3NtResumeThread(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtOpenProcessToken_(Args&&... args)
|
|
{
|
|
// PCSTR FunctionName = "ZwOpenProcessToken";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << FunctionName << " " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 2590718720;
|
|
return Sw3NtOpenProcessToken(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtAdjustPrivilegesToken_(Args&&... args)
|
|
{
|
|
// PCSTR FunctionName = "ZwAdjustPrivilegesToken";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << FunctionName << " " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 2243258122;
|
|
return Sw3NtAdjustPrivilegesToken(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtQueryVirtualMemory_(Args&&... args)
|
|
{
|
|
// PCSTR FunctionName = "ZwQueryVirtualMemory";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << FunctionName << " " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 422492770;
|
|
return Sw3NtQueryVirtualMemory(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
template <typename... Args>
|
|
NTSTATUS Sw3NtReadVirtualMemory_(Args&&... args)
|
|
{
|
|
// PCSTR FunctionName = "ZwReadVirtualMemory";
|
|
// GlobalHash = SW3_HashSyscall(FunctionName);
|
|
// std::cout << FunctionName << " " << GlobalHash << std::endl;
|
|
|
|
GlobalHash = 663422542;
|
|
return Sw3NtReadVirtualMemory(std::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
class Entry
|
|
{
|
|
public:
|
|
Entry(DWORD hash, DWORD address, PVOID syscallAddress)
|
|
: m_hash(hash)
|
|
, m_address(address)
|
|
, m_syscallAddress(syscallAddress)
|
|
{
|
|
}
|
|
|
|
DWORD getHash()
|
|
{
|
|
return m_hash;
|
|
}
|
|
|
|
DWORD getAddress()
|
|
{
|
|
return m_address;
|
|
}
|
|
|
|
PVOID getSyscallAddress()
|
|
{
|
|
return m_syscallAddress;
|
|
}
|
|
|
|
|
|
private:
|
|
DWORD m_hash;
|
|
DWORD m_address;
|
|
PVOID m_syscallAddress;
|
|
};
|
|
|
|
|
|
bool compareEntry(Entry i1, Entry i2);
|
|
|
|
|
|
class SyscallList
|
|
{
|
|
private:
|
|
|
|
PVOID getNtdllExportDirectory()
|
|
{
|
|
PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
|
|
|
|
PSW3_PEB_LDR_DATA Ldr = Peb->Ldr;
|
|
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
|
|
m_dllBase = NULL;
|
|
|
|
// Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
|
|
// in the list, so it's safer to loop through the full list and find it.
|
|
PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
|
|
for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
|
|
{
|
|
m_dllBase = LdrEntry->DllBase;
|
|
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)m_dllBase;
|
|
PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, m_dllBase, DosHeader->e_lfanew);
|
|
PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
|
|
DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
|
if (VirtualAddress == 0) continue;
|
|
|
|
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, m_dllBase, VirtualAddress);
|
|
|
|
// If this is NTDLL.dll, exit loop.
|
|
PCHAR DllName = SW3_RVA2VA(PCHAR, m_dllBase, ExportDirectory->Name);
|
|
|
|
if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e)
|
|
continue;
|
|
if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c)
|
|
break;
|
|
}
|
|
|
|
if (!ExportDirectory)
|
|
return NULL;
|
|
|
|
return (PVOID)ExportDirectory;
|
|
}
|
|
|
|
void fillSyscallEntryList(PVOID add)
|
|
{
|
|
PIMAGE_EXPORT_DIRECTORY ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)add;
|
|
DWORD NumberOfNames = ExportDirectory->NumberOfNames;
|
|
PDWORD Functions = SW3_RVA2VA(PDWORD, m_dllBase, ExportDirectory->AddressOfFunctions);
|
|
PDWORD Names = SW3_RVA2VA(PDWORD, m_dllBase, ExportDirectory->AddressOfNames);
|
|
PWORD Ordinals = SW3_RVA2VA(PWORD, m_dllBase, ExportDirectory->AddressOfNameOrdinals);
|
|
|
|
// Populate SW3_SyscallList with unsorted Zw* entries.
|
|
do
|
|
{
|
|
PCHAR FunctionName = SW3_RVA2VA(PCHAR, m_dllBase, Names[NumberOfNames - 1]);
|
|
|
|
// Is this a system call?
|
|
// start with Zw
|
|
if (*(USHORT*)FunctionName == 0x775a)
|
|
{
|
|
DWORD Hash = SW3_HashSyscall(FunctionName);
|
|
|
|
DWORD Address = Functions[Ordinals[NumberOfNames - 1]];
|
|
PVOID SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, m_dllBase, Address));
|
|
|
|
Entry newEntry(Hash, Address, SyscallAddress);
|
|
m_syscallEntry.push_back(std::move(newEntry));
|
|
|
|
}
|
|
} while (--NumberOfNames);
|
|
|
|
// sort for the getSyscallNumber
|
|
std::sort(m_syscallEntry.begin(), m_syscallEntry.end(), compareEntry);
|
|
}
|
|
|
|
|
|
PVOID SC_Address(PVOID NtApiAddress)
|
|
{
|
|
DWORD searchLimit = 512;
|
|
PVOID SyscallAddress;
|
|
|
|
// If the process is 64-bit on a 64-bit OS, we need to search for syscall
|
|
BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
|
|
ULONG distance_to_syscall = 0x12;
|
|
|
|
// we don't really care if there is a 'jmp' between
|
|
// NtApiAddress and the 'syscall; ret' instructions
|
|
SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);
|
|
|
|
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
|
|
{
|
|
// we can use the original code for this system call :)
|
|
return SyscallAddress;
|
|
}
|
|
|
|
// the 'syscall; ret' intructions have not been found,
|
|
// we will try to use one near it, similarly to HalosGate
|
|
for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
|
|
{
|
|
// let's try with an Nt* API below our syscall
|
|
SyscallAddress = SW3_RVA2VA(
|
|
PVOID,
|
|
NtApiAddress,
|
|
distance_to_syscall + num_jumps * 0x20);
|
|
|
|
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
|
|
{
|
|
return SyscallAddress;
|
|
}
|
|
|
|
// let's try with an Nt* API above our syscall
|
|
SyscallAddress = SW3_RVA2VA(
|
|
PVOID,
|
|
NtApiAddress,
|
|
distance_to_syscall - num_jumps * 0x20);
|
|
|
|
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
|
|
{
|
|
return SyscallAddress;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PVOID m_dllBase;
|
|
std::vector<Entry> m_syscallEntry;
|
|
|
|
protected:
|
|
SyscallList()
|
|
{
|
|
PVOID add = getNtdllExportDirectory();
|
|
fillSyscallEntryList(add);
|
|
}
|
|
|
|
static SyscallList* singleton_;
|
|
|
|
public:
|
|
|
|
SyscallList(SyscallList &other) = delete;
|
|
void operator=(const SyscallList &) = delete;
|
|
static SyscallList *GetInstance();
|
|
|
|
// need to be sorted to be able to get the syscall number from the entry index
|
|
DWORD getSyscallNumber(DWORD hash)
|
|
{
|
|
for(int i=0; i<m_syscallEntry.size(); i++)
|
|
{
|
|
if(m_syscallEntry[i].getHash() == hash)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
PVOID getSyscallAddress(DWORD hash)
|
|
{
|
|
for(int i=0; i<m_syscallEntry.size(); i++)
|
|
{
|
|
if(m_syscallEntry[i].getHash() == hash)
|
|
{
|
|
return m_syscallEntry[i].getSyscallAddress();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
};
|