반응형
드디어 기본적인 틀은 다짰다.
이걸 어떻게 x64로 적용할지가 문제긴 한데 일단 x86을 먼저 시도해놨으니까 괜찮지 않을까 싶다.
ZwCreateThreadEx함수에서 ProcessHandle이 -1 이거나 커널영역의 핸들일 경우는 그냥 보내주고
아닐 때만 판별해낸다.
아래는 결과적으로 만든 드라이버 소스다.
#include <ntifs.h> #pragma warning(disable: 4201) typedef unsigned short WORD; typedef unsigned char BYTE; #define WP_MASK 0x0FFFEFFFF //WP bit mask #define SYSCALL_INDEX(_Func) *(PULONG) ((PUCHAR)_Func+1) #define SYSTEM_SERVICE(_Func) KeServiceDescriptorTable.ServiceTableBase[SYSCALL_INDEX(_Func)] #define SYSTEM_SERVICE_INDEX(Index) KeServiceDescriptorTable.ServiceTableBase[Index] #define HOOK_SYSCALL(CurrentFunc, ChangeFunc) InterlockedExchange((PLONG)&SYSTEM_SERVICE(CurrentFunc), (LONG)ChangeFunc) #define HOOK_SYSCALL_INDEX(Index, ChangeFunc) InterlockedExchange((PLONG)&SYSTEM_SERVICE_INDEX(Index), (LONG)ChangeFunc) void writeCR0(); void readCR0(); NTSTATUS SetHookProc(); NTSTATUS SetUnHookProc(); NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); void UnloadRoutine( IN PDRIVER_OBJECT DriverObject ); typedef unsigned int DWORD; typedef unsigned int* LPDWORD; typedef void* LPVOID; typedef int BOOL; #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; unsigned int NumberOfServices; unsigned char *ParamTableBase; } SSDT_ENTRY; #pragma pack() typedef struct _SYSTEM_THREADS_INFORMATION { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientIs; KPRIORITY Priority; KPRIORITY BasePriority; ULONG ContextSwitchCount; ULONG ThreadState; KWAIT_REASON WaitReason; }SYSTEM_THREADS_INFORMATION, *PSYSTEM_THREADS_INFORMATION; typedef struct _SYSTEM_PROCESS_INFORMATION { ULONG NextEntryDelta; ULONG ThreadCount; ULONG Reserved[6]; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ProcessName; KPRIORITY BasePriority; ULONG ProcessId; ULONG InheritedFromProcessId; ULONG HandleCount; ULONG Reserved2[2]; VM_COUNTERS VmCounters; IO_COUNTERS IoCounters; //windows 2000 only SYSTEM_THREADS_INFORMATION Threads[1]; }SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESSES_INFORMATION; EXTERN_C __declspec(dllimport) SSDT_ENTRY KeServiceDescriptorTable; typedef NTSTATUS(*ZWCREATETHREADEX) ( OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN OPTIONAL POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PVOID StartRoutine, IN OPTIONAL PVOID Argument, IN ULONG CreateFlags, IN OPTIONAL ULONG_PTR ZeroBits, IN OPTIONAL SIZE_T StackSize, IN OPTIONAL SIZE_T MaximumStackSize, IN OPTIONAL PVOID AttributeList ); NTSTATUS ZwCreateThreadEx( OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN OPTIONAL POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PVOID StartRoutine, IN OPTIONAL PVOID Argument, IN ULONG CreateFlags, IN OPTIONAL ULONG_PTR ZeroBits, IN OPTIONAL SIZE_T StackSize, IN OPTIONAL SIZE_T MaximumStackSize, IN OPTIONAL PVOID AttributeList ); typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation, SystemPathInformation, SystemProcessInformation, SystemCallCountInformation, SystemDeviceInformation, SystemProcessorPerformanceInformation, SystemFlagsInformation, SystemCallTimeInformation, SystemModuleInformation, SystemLocksInformation, SystemStackTraceInformation, SystemPagedPoolInformation, SystemNonPagedPoolInformation, SystemHandleInformation, SystemObjectInformation, SystemPageFileInformation, SystemVdmInstemulInformation, SystemVdmBopInformation, SystemFileCacheInformation, SystemPoolTagInformation, SystemInterruptInformation, SystemDpcBehaviorInformation, SystemFullMemoryInformation, SystemLoadGdiDriverInformation, SystemUnloadGdiDriverInformation, SystemTimeAdjustmentInformation, SystemSummaryMemoryInformation, SystemNextEventIdInformation, SystemEventIdsInformation, SystemCrashDumpInformation, SystemExceptionInformation, SystemCrashDumpStateInformation, SystemKernelDebuggerInformation, SystemContextSwitchInformation, SystemRegistryQuotaInformation, SystemExtendServiceTableInformation, SystemPrioritySeperation, SystemPlugPlayBusInformation, SystemDockInformation, SystemPowerInformation_, SystemProcessorSpeedInformation, SystemCurrentTimeZoneInformation, SystemLookasideInformation } SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS; EXTERN_C NTKERNELAPI NTSTATUS NTAPI ZwQuerySystemInformation( _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, _Inout_ PVOID SystemInformation, _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength ); EXTERN_C NTKERNELAPI NTSTATUS NTAPI ZwOpenProcess( OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN OPTIONAL PCLIENT_ID ClientId ); typedef struct _SYSTEM_HANDLE { ULONG ProcessId; BYTE ObjectTypeNumber; BYTE Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; } SYSTEM_HANDLE, *PSYSTEM_HANDLE; typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG HandleCount; /* Or NumberOfHandles if you prefer. */ SYSTEM_HANDLE Handles[1]; } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
#include "Hook.h" #pragma warning(disable:4054) // casting-warning disable #pragma warning(disable:4305) // casting-warning disable - high to low void writeCR0(){ __asm { push eax mov eax, CR0 and eax, 0FFFEFFFFh mov CR0, eax pop eax }; } void readCR0(){ __asm { push eax mov eax, CR0 or eax, NOT 0FFFEFFFFh mov CR0, eax pop eax }; } ZWCREATETHREADEX OrgZwCreateThreadEx; #define ZWCREATETHREADEX_INDEX 0x58 NTSTATUS ZwCreateThreadEx( OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN OPTIONAL POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PVOID StartRoutine, IN OPTIONAL PVOID Argument, IN ULONG CreateFlags, IN OPTIONAL ULONG_PTR ZeroBits, IN OPTIONAL SIZE_T StackSize, IN OPTIONAL SIZE_T MaximumStackSize, IN OPTIONAL PVOID AttributeList ){ DbgPrint("ZwCreateThreadEx(Hooked)"); DbgPrint("Routine Address : %p", StartRoutine); if ((DWORD)ProcessHandle == 0xffffffff || (DWORD)ProcessHandle >= 0x80000000){ DbgPrint("Call Original ZwCreateThreadEx"); return OrgZwCreateThreadEx(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, StartRoutine, Argument, CreateFlags, ZeroBits, StackSize, MaximumStackSize, AttributeList); } else{ ULONG dum, dum2; SYSTEM_HANDLE_INFORMATION dummy = { 0, }; NTSTATUS result = ZwQuerySystemInformation(SystemHandleInformation, &dummy, sizeof(SYSTEM_HANDLE_INFORMATION), &dum); PVOID *proc = NULL; DWORD pid = 0xffffffff; if (result == STATUS_INFO_LENGTH_MISMATCH){ proc = ExAllocatePoolWithTag(NonPagedPool, dum, 'GETK'); if (proc){ result = ZwQuerySystemInformation(SystemHandleInformation, proc, dum, &dum2); SYSTEM_HANDLE_INFORMATION *ptr = (SYSTEM_HANDLE_INFORMATION *)proc; for (ULONG idx = 0; idx < ptr->HandleCount; idx++){ if (ptr->Handles[idx].Handle == (USHORT)ProcessHandle && ptr->Handles[idx].ObjectTypeNumber == 7){ // 7 : process pid = ptr->Handles[idx].ProcessId; break; } } ExFreePool(proc); } else{ result = STATUS_UNSUCCESSFUL; return result; } } else if (NT_SUCCESS(result)){ proc = &dummy; DbgPrint("ZwQuerySystemInformation Success!"); SYSTEM_HANDLE_INFORMATION *ptr = (SYSTEM_HANDLE_INFORMATION *)proc; DbgPrint("Find pid from handle.."); for (ULONG idx = 0; idx < ptr->HandleCount; idx++){ DbgPrint("PID : %p", ptr->Handles[idx].Handle); if ((HANDLE)ptr->Handles[idx].Handle == ProcessHandle){ DbgPrint("Successfully done."); pid = ptr->Handles[idx].ProcessId; break; } } } SYSTEM_PROCESS_INFORMATION dummy2 = { 0, }; result = ZwQuerySystemInformation(SystemProcessInformation, &dummy2, sizeof(SYSTEM_PROCESS_INFORMATION), &dum); if (result == STATUS_INFO_LENGTH_MISMATCH){ proc = ExAllocatePoolWithTag(NonPagedPool, dum, 'GETK'); result = ZwQuerySystemInformation(SystemProcessInformation, proc, dum, &dum2); if (NT_SUCCESS(result)){ SYSTEM_PROCESS_INFORMATION *ptr = (SYSTEM_PROCESS_INFORMATION *)proc; for (; ptr; ptr = (SYSTEM_PROCESS_INFORMATION *)((char *)ptr + (ULONG)ptr->NextEntryDelta)){ if (pid == ptr->ProcessId){ PEPROCESS eProcess; result = PsLookupProcessByProcessId((HANDLE)pid, &eProcess); if (NT_SUCCESS(result)){ PVOID argu = NULL; KAPC_STATE apc_state; KeStackAttachProcess(eProcess, &apc_state); argu = ExAllocatePoolWithTag(NonPagedPool,strlen(Argument) + 1, 'GETK'); if (argu == NULL) return STATUS_UNSUCCESSFUL; RtlCopyMemory(argu, Argument, strlen(Argument)); KeUnstackDetachProcess(&apc_state); if (strstr((const char *)tolower((int)argu), ".dll") != NULL){ // DLL 파일이면 ExFreePool(argu); return OrgZwCreateThreadEx(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, StartRoutine, NULL, CreateFlags, ZeroBits, StackSize, MaximumStackSize, AttributeList); } ExFreePool(argu); return OrgZwCreateThreadEx(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, StartRoutine, Argument, CreateFlags, ZeroBits, StackSize, MaximumStackSize, AttributeList); } } } } if (proc) ExFreePool(proc); return STATUS_SUCCESS; } else if (NT_SUCCESS(result)){ SYSTEM_PROCESS_INFORMATION *ptr = (SYSTEM_PROCESS_INFORMATION *)&dummy2; for (; ptr; ptr = (SYSTEM_PROCESS_INFORMATION *)((char *)ptr + (ULONG)ptr->NextEntryDelta)){ if (pid == ptr->ProcessId){ PEPROCESS eProcess; result = PsLookupProcessByProcessId((HANDLE)pid, &eProcess); if (NT_SUCCESS(result)){ PVOID argu = NULL; KAPC_STATE apc_state; KeStackAttachProcess(eProcess, &apc_state); argu = ExAllocatePoolWithTag(NonPagedPool, strlen(Argument) + 1, 'GETK'); if (argu == NULL) return STATUS_UNSUCCESSFUL; RtlCopyMemory(argu, Argument, strlen(Argument)); KeUnstackDetachProcess(&apc_state); if (strstr((const char *)tolower((int)argu), ".dll") != NULL){ // DLL 파일이면 ExFreePool(argu); return OrgZwCreateThreadEx(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, StartRoutine, NULL, CreateFlags, ZeroBits, StackSize, MaximumStackSize, AttributeList); } ExFreePool(argu); return OrgZwCreateThreadEx(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, StartRoutine, Argument, CreateFlags, ZeroBits, StackSize, MaximumStackSize, AttributeList); } } } } return STATUS_UNSUCCESSFUL; } } NTSTATUS SetHookProc(){ DbgPrint("SetHookProc() Routine"); writeCR0(); OrgZwCreateThreadEx = (ZWCREATETHREADEX)SYSTEM_SERVICE_INDEX(ZWCREATETHREADEX_INDEX); HOOK_SYSCALL_INDEX(ZWCREATETHREADEX_INDEX, ZwCreateThreadEx); readCR0(); return STATUS_SUCCESS; } NTSTATUS SetUnHookProc(){ writeCR0(); HOOK_SYSCALL_INDEX(ZWCREATETHREADEX_INDEX, OrgZwCreateThreadEx); readCR0(); return STATUS_SUCCESS; } void UnloadRoutine(IN PDRIVER_OBJECT DriverObject){ UNREFERENCED_PARAMETER(DriverObject); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Unloaded\n"); SetUnHookProc(); } NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){ UNREFERENCED_PARAMETER(RegistryPath); DbgPrint("DriverEntry!"); DbgPrint("DriverObject Unload Function Setting"); DriverObject->DriverUnload = UnloadRoutine; SetHookProc(); return STATUS_SUCCESS; }
'Project' 카테고리의 다른 글
[Git] Gitolite 설치 (0) | 2017.03.21 |
---|---|
[행위기반탐지] 주저리1 (커널 드라이버와 통신) (0) | 2017.03.03 |
[행위기반탐지] 삽질2 (0) | 2017.02.01 |
[행위기반탐지] 삽질 1 (0) | 2017.01.31 |
[행위기반탐지] ZwCreateThreadEx 의 인자 분석 ( 32bit ) (0) | 2017.01.30 |
KuroNeko_
KuroNeko