Files
2025-12-02 21:33:26 +01:00

274 lines
16 KiB
C

#pragma once
#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
#include <winbase.h>
#define STATUS_SUCCESS (NTSTATUS)0x00000000L
#define PRINTXD(FUNCTION_NAME, NTSTATUS_ERROR) \
do { \
fprintf(stderr, FUNCTION_NAME " line %d, error: 0x%lx\n", __LINE__, NTSTATUS_ERROR); \
} while (0)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004)
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
typedef LONG NTSTATUS;
typedef struct _PS_ATTRIBUTE {
ULONG Attribute;
SIZE_T Size;
union
{
ULONG Value;
PVOID ValuePtr;
} u1;
PSIZE_T ReturnLength;
} PS_ATTRIBUTE, * PPS_ATTRIBUTE;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
typedef const UNICODE_STRING* PCUNICODE_STRING;
typedef const OBJECT_ATTRIBUTES* PCOBJECT_ATTRIBUTES;
typedef struct _INITIAL_TEB {
struct {
PVOID OldStackBase; // Pointer to the base address of the previous stack.
PVOID OldStackLimit; // Pointer to the limit address of the previous stack.
} OldInitialTeb;
PVOID StackBase; // Pointer to the base address of the new stack.
PVOID StackLimit; // Pointer to the limit address of the new stack.
PVOID StackAllocationBase; // Pointer to the base address where the stack was allocated.
} INITIAL_TEB, * PINITIAL_TEB;
typedef struct _CLIENT_ID {
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID, * PCLIENT_ID;
typedef struct _PS_ATTRIBUTE_LIST {
SIZE_T TotalLength;
PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST;
typedef LONG KPRIORITY, * PKPRIORITY;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemProcessInformation = 5
} SYSTEM_INFORMATION_CLASS;
typedef enum _KWAIT_REASON
{
Executive, // Waiting for an executive event.
FreePage, // Waiting for a free page.
PageIn, // Waiting for a page to be read in.
PoolAllocation, // Waiting for a pool allocation.
DelayExecution, // Waiting due to a delay execution. // NtDelayExecution
Suspended, // Waiting because the thread is suspended. // NtSuspendThread
UserRequest, // Waiting due to a user request. // NtWaitForSingleObject
WrExecutive, // Waiting for an executive event.
WrFreePage, // Waiting for a free page.
WrPageIn, // Waiting for a page to be read in.
WrPoolAllocation, // Waiting for a pool allocation. // 10
WrDelayExecution, // Waiting due to a delay execution.
WrSuspended, // Waiting because the thread is suspended.
WrUserRequest, // Waiting due to a user request.
WrEventPair, // Waiting for an event pair. // NtCreateEventPair
WrQueue, // Waiting for a queue. // NtRemoveIoCompletion
WrLpcReceive, // Waiting for an LPC receive. // NtReplyWaitReceivePort
WrLpcReply, // Waiting for an LPC reply. // NtRequestWaitReplyPort
WrVirtualMemory, // Waiting for virtual memory.
WrPageOut, // Waiting for a page to be written out. // NtFlushVirtualMemory
WrRendezvous, // Waiting for a rendezvous. // 20
WrKeyedEvent, // Waiting for a keyed event. // NtCreateKeyedEvent
WrTerminated, // Waiting for thread termination.
WrProcessInSwap, // Waiting for a process to be swapped in.
WrCpuRateControl, // Waiting for CPU rate control.
WrCalloutStack, // Waiting for a callout stack.
WrKernel, // Waiting for a kernel event.
WrResource, // Waiting for a resource.
WrPushLock, // Waiting for a push lock.
WrMutex, // Waiting for a mutex.
WrQuantumEnd, // Waiting for the end of a quantum. // 30
WrDispatchInt, // Waiting for a dispatch interrupt.
WrPreempted, // Waiting because the thread was preempted.
WrYieldExecution, // Waiting to yield execution.
WrFastMutex, // Waiting for a fast mutex.
WrGuardedMutex, // Waiting for a guarded mutex.
WrRundown, // Waiting for a rundown.
WrAlertByThreadId, // Waiting for an alert by thread ID.
WrDeferredPreempt, // Waiting for a deferred preemption.
WrPhysicalFault, // Waiting for a physical fault.
WrIoRing, // Waiting for an I/O ring. // 40
WrMdlCache, // Waiting for an MDL cache.
WrRcu, // Waiting for read-copy-update (RCU) synchronization.
MaximumWaitReason
} KWAIT_REASON, * PKWAIT_REASON;
typedef enum _KTHREAD_STATE
{
Initialized,
Ready,
Running,
Standby,
Terminated,
Waiting,
Transition,
DeferredReady,
GateWaitObsolete,
WaitingForProcessInSwap,
MaximumThreadState
} KTHREAD_STATE, * PKTHREAD_STATE;
typedef struct _SYSTEM_THREAD_INFORMATION
{
LARGE_INTEGER KernelTime; // Number of 100-nanosecond intervals spent executing kernel code.
LARGE_INTEGER UserTime; // Number of 100-nanosecond intervals spent executing user code.
LARGE_INTEGER CreateTime; // The date and time when the thread was created.
ULONG WaitTime; // The current time spent in ready queue or waiting (depending on the thread state).
PVOID StartAddress; // The initial start address of the thread.
CLIENT_ID ClientId; // The identifier of the thread and the process owning the thread.
KPRIORITY Priority; // The dynamic priority of the thread.
KPRIORITY BasePriority; // The starting priority of the thread.
ULONG ContextSwitches; // The total number of context switches performed.
KTHREAD_STATE ThreadState; // The current state of the thread.
KWAIT_REASON WaitReason; // The current reason the thread is waiting.
} SYSTEM_THREAD_INFORMATION, * PSYSTEM_THREAD_INFORMATION;
typedef struct _SYSTEM_PROCESS_INFORMATION
{
ULONG NextEntryOffset; // The address of the previous item plus the value in the NextEntryOffset member. For the last item in the array, NextEntryOffset is 0.
ULONG NumberOfThreads; // The NumberOfThreads member contains the number of threads in the process.
ULONGLONG WorkingSetPrivateSize; // The total private memory that a process currently has allocated and is physically resident in memory. // since VISTA
ULONG HardFaultCount; // The total number of hard faults for data from disk rather than from in-memory pages. // since WIN7
ULONG NumberOfThreadsHighWatermark; // The peak number of threads that were running at any given point in time, indicative of potential performance bottlenecks related to thread management.
ULONGLONG CycleTime; // The sum of the cycle time of all threads in the process.
LARGE_INTEGER CreateTime; // Number of 100-nanosecond intervals since the creation time of the process. Not updated during system timezone changes.
LARGE_INTEGER UserTime; // Number of 100-nanosecond intervals the process has executed in user mode.
LARGE_INTEGER KernelTime; // Number of 100-nanosecond intervals the process has executed in kernel mode.
UNICODE_STRING ImageName; // The file name of the executable image.
KPRIORITY BasePriority; // The starting priority of the process.
HANDLE UniqueProcessId; // The identifier of the process.
HANDLE InheritedFromUniqueProcessId; // The identifier of the process that created this process. Not updated and incorrectly refers to processes with recycled identifiers.
ULONG HandleCount; // The current number of open handles used by the process.
ULONG SessionId; // The identifier of the Remote Desktop Services session under which the specified process is running.
ULONG_PTR UniqueProcessKey; // since VISTA (requires SystemExtendedProcessInformation)
SIZE_T PeakVirtualSize; // The peak size, in bytes, of the virtual memory used by the process.
SIZE_T VirtualSize; // The current size, in bytes, of virtual memory used by the process.
ULONG PageFaultCount; // The total number of page faults for data that is not currently in memory. The value wraps around to zero on average 24 hours.
SIZE_T PeakWorkingSetSize; // The peak size, in kilobytes, of the working set of the process.
SIZE_T WorkingSetSize; // The number of pages visible to the process in physical memory. These pages are resident and available for use without triggering a page fault.
SIZE_T QuotaPeakPagedPoolUsage; // The peak quota charged to the process for pool usage, in bytes.
SIZE_T QuotaPagedPoolUsage; // The quota charged to the process for paged pool usage, in bytes.
SIZE_T QuotaPeakNonPagedPoolUsage; // The peak quota charged to the process for nonpaged pool usage, in bytes.
SIZE_T QuotaNonPagedPoolUsage; // The current quota charged to the process for nonpaged pool usage.
SIZE_T PagefileUsage; // The total number of bytes of page file storage in use by the process.
SIZE_T PeakPagefileUsage; // The maximum number of bytes of page-file storage used by the process.
SIZE_T PrivatePageCount; // The number of memory pages allocated for the use by the process.
LARGE_INTEGER ReadOperationCount; // The total number of read operations performed.
LARGE_INTEGER WriteOperationCount; // The total number of write operations performed.
LARGE_INTEGER OtherOperationCount; // The total number of I/O operations performed other than read and write operations.
LARGE_INTEGER ReadTransferCount; // The total number of bytes read during a read operation.
LARGE_INTEGER WriteTransferCount; // The total number of bytes written during a write operation.
LARGE_INTEGER OtherTransferCount; // The total number of bytes transferred during operations other than read and write operations.
SYSTEM_THREAD_INFORMATION Threads[1]; // This type is not defined in the structure but was added for convenience.
} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;
#ifndef InitializeObjectAttributes
#define InitializeObjectAttributes( p, n, a, r, s ) { \
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
#endif
#ifndef _In_
#define _In_
#endif
#ifndef _Out_opt_
#define _Out_opt_
#endif
#ifndef _Out_writes_bytes_opt_
#define _Out_writes_bytes_opt_(x)
#endif
BOOL HijackThread(IN HANDLE hThread, IN PVOID pAddress);
VOID temp(VOID);
BOOL GetProcessNative(LPCWSTR processName, DWORD* outPid);
BOOL GetThreadNative(DWORD pid, DWORD* outTid);
VOID IndirectPrelude(_In_ HMODULE NtdllHandle, _In_ LPCSTR NtFunctionName, _Out_ PDWORD NtFunctionSSN, _Out_ PUINT_PTR NtFunctionSyscall);
typedef unsigned __int64 QWORD;
DWORD h_NtOpenProcessSSN;
QWORD h_NtOpenProcessSyscall;
DWORD h_NtAllocateVirtualMemorySSN;
QWORD h_NtAllocateVirtualMemorySyscall;
DWORD h_NtWriteVirtualMemorySSN;
QWORD h_NtWriteVirtualMemorySyscall;
DWORD h_NtProtectVirtualMemorySSN;
QWORD h_NtProtectVirtualMemorySyscall;
DWORD h_NtCreateThreadExSSN;
QWORD h_NtCreateThreadExSyscall;
DWORD h_NtWaitForSingleObjectSSN;
QWORD h_NtWaitForSingleObjectSyscall;
DWORD h_NtFreeVirtualMemorySSN;
QWORD h_NtFreeVirtualMemorySyscall;
DWORD h_NtCloseSSN;
QWORD h_NtCloseSyscall;
DWORD h_NtSuspendThreadSSN;
QWORD h_NtSuspendThreadSyscall;
DWORD h_NtResumeThreadSSN;
QWORD h_NtResumeThreadSyscall;
DWORD h_NtQuerySystemInformationSSN;
QWORD h_NtQuerySystemInformationSyscall;
DWORD h_NtGetContextThreadSSN;
QWORD h_NtGetContextThreadSyscall;
DWORD h_NtSetContextThreadSSN;
QWORD h_NtSetContextThreadSyscall;
DWORD h_NtOpenThreadSSN;
QWORD h_NtOpenThreadSyscall;
extern NTSTATUS NtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId OPTIONAL);
extern NTSTATUS NtAllocateVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN ULONG ZeroBits, IN OUT PSIZE_T RegionSize, IN ULONG AllocationType, IN ULONG Protect);
extern NTSTATUS NtProtectVirtualMemory(_In_ HANDLE ProcessHandle, _Inout_ PVOID* BaseAddress, _Inout_ PSIZE_T RegionSize, _In_ ULONG NewProtect, _Out_ PULONG OldProtect);
extern NTSTATUS NtWriteVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite, OUT PSIZE_T NumberOfBytesWritten OPTIONAL);
extern NTSTATUS NtCreateThreadEx(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 NTSTATUS NtCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, _In_opt_ PCOBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, _Out_ PCLIENT_ID ClientId, _In_ PCONTEXT ThreadContext, _In_ PINITIAL_TEB InitialTeb, _In_ BOOLEAN CreateSuspended);
extern NTSTATUS NtWaitForSingleObject(_In_ HANDLE Handle, _In_ BOOLEAN Alertable, _In_opt_ PLARGE_INTEGER Timeout);
extern NTSTATUS NtFreeVirtualMemory(_In_ HANDLE ProcessHandle, _Inout_ PVOID* BaseAddress, _Inout_ PSIZE_T RegionSize, _In_ ULONG FreeType);
extern NTSTATUS NtClose(IN HANDLE Handle);
extern NTSTATUS NtQuerySystemInformation(_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength);
extern NTSTATUS NtSuspendThread(_In_ HANDLE ThreadHandle, _Out_opt_ PULONG PreviousSuspendCount);
extern NTSTATUS NtResumeThread(_In_ HANDLE ThreadHandle, _Out_opt_ PULONG PreviousSuspendCount);
extern NTSTATUS NtGetContextThread(_In_ HANDLE ThreadHandle, _Inout_ PCONTEXT ThreadContext);
extern NTSTATUS NtSetContextThread(_In_ HANDLE ThreadHandle, _In_ PCONTEXT ThreadContext);
extern NTSTATUS NtOpenThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId OPTIONAL);
/* stealthier version
FARPROC GetNtFunctionAddressManual(LPCSTR functionName) {
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
if (!ntdll) return NULL;
BYTE* base = (BYTE*)ntdll;
IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base;
IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew);
IMAGE_EXPORT_DIRECTORY* exp = (IMAGE_EXPORT_DIRECTORY*)
(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* names = (DWORD*)(base + exp->AddressOfNames);
WORD* ordinals = (WORD*)(base + exp->AddressOfNameOrdinals);
DWORD* functions = (DWORD*)(base + exp->AddressOfFunctions);
for (DWORD i = 0; i < exp->NumberOfNames; ++i) {
char* name = (char*)(base + names[i]);
if (strcmp(name, functionName) == 0) {
return (FARPROC)(base + functions[ordinals[i]]);
}
}
return NULL;
}
*/