├── README.md ├── pcileech ├── pcileech │ ├── vmm.lib │ ├── leechcore.lib │ └── leechcore.h └── vm.cpp ├── ksj ├── CMakeLists.txt └── src │ └── vm.cpp ├── shared ├── vm_linux.h └── vm_windows.h ├── km_ctx └── vm.cpp ├── linux └── vm.cpp ├── um └── vm.cpp ├── sgv ├── km.h └── vm.cpp ├── proton └── vm.cpp ├── vm.h └── km └── vm.cpp /README.md: -------------------------------------------------------------------------------- 1 | # vm 2 | Minimal memory library for Windows / Linux 3 | -------------------------------------------------------------------------------- /pcileech/pcileech/vmm.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ekknod/vm/HEAD/pcileech/pcileech/vmm.lib -------------------------------------------------------------------------------- /pcileech/pcileech/leechcore.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ekknod/vm/HEAD/pcileech/pcileech/leechcore.lib -------------------------------------------------------------------------------- /ksj/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(vm) 3 | 4 | set(OUT vm) 5 | 6 | set(LINKTYPE STATIC) 7 | 8 | add_library ( ${OUT} ${LINKTYPE} 9 | src/vm.cpp ) 10 | 11 | set_target_properties(${OUT} PROPERTIES LINKER_LANGUAGE CXX) 12 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall -DNDEBUG -Wno-format-truncation -O3 -s") 13 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wno-format-truncation") 14 | 15 | if (NOT CMAKE_BUILD_TYPE) 16 | set(CMAKE_BUILD_TYPE Release) 17 | endif() -------------------------------------------------------------------------------- /shared/vm_linux.h: -------------------------------------------------------------------------------- 1 | #ifndef VM_LINUX_H 2 | #define VM_LINUX_H 3 | 4 | #include "../vm.h" 5 | #include 6 | #include 7 | 8 | // 9 | // wmwin is private header used by vm.cpp only 10 | // 11 | namespace vmlinux 12 | { 13 | inline QWORD get_elf_address(vm_handle process, QWORD base, int tag) 14 | { 15 | BOOL wow64 = (vm::read_i16(process, base + 0x12) == 62) ? 0 : 1; 16 | 17 | int pht_count; 18 | int pht_file_offset; 19 | int pht_size; 20 | 21 | if (wow64) 22 | { 23 | pht_count = 0x2C, pht_file_offset = 0x1C, pht_size = 32; 24 | } 25 | else 26 | { 27 | pht_count = 0x38, pht_file_offset = 0x20, pht_size = 56; 28 | } 29 | 30 | QWORD a0 = vm::read_i32(process, base + pht_file_offset) + base; 31 | 32 | for (WORD i = 0; i < vm::read_i16(process, base + pht_count); i++) 33 | { 34 | QWORD a2 = pht_size * i + a0; 35 | if (vm::read_i32(process, a2) == tag) 36 | { 37 | return a2; 38 | } 39 | } 40 | return 0; 41 | } 42 | 43 | inline QWORD get_dyn_address(vm_handle process, QWORD base, QWORD tag) 44 | { 45 | QWORD dyn = get_elf_address(process, base, 2); 46 | if (dyn == 0) 47 | { 48 | return 0; 49 | } 50 | 51 | BOOL wow64 = (vm::read_i16(process, base + 0x12) == 62) ? 0 : 1; 52 | 53 | int reg_size = wow64 ? 4 : 8; 54 | 55 | vm::read(process, dyn + (2*reg_size), &dyn, reg_size); 56 | 57 | dyn += base; 58 | 59 | while (1) 60 | { 61 | QWORD dyn_tag = 0; 62 | vm::read(process, dyn, &dyn_tag, reg_size); 63 | 64 | if (dyn_tag == 0) 65 | { 66 | break; 67 | } 68 | 69 | if (dyn_tag == tag) 70 | { 71 | QWORD address = 0; 72 | vm::read(process, dyn + reg_size, &address, reg_size); 73 | return address; 74 | } 75 | 76 | dyn += (2*reg_size); 77 | } 78 | return 0; 79 | } 80 | 81 | QWORD get_module_export(vm_handle process, QWORD base, PCSTR export_name) 82 | { 83 | int offset, add, length; 84 | 85 | BOOL wow64 = (vm::read_i16(process, base + 0x12) == 62) ? 0 : 1; 86 | if (wow64) 87 | { 88 | offset = 0x20, add = 0x10, length = 0x04; 89 | } 90 | else 91 | { 92 | offset = 0x40, add = 0x18, length = 0x08; 93 | } 94 | 95 | QWORD str_tab = get_dyn_address(process, base, 5); 96 | QWORD sym_tab = get_dyn_address(process, base, 6); 97 | 98 | sym_tab += add; 99 | 100 | uint32_t st_name = 1; 101 | do 102 | { 103 | char sym_name[120]{}; 104 | if (vm::read(process, str_tab + st_name, &sym_name, sizeof(sym_name)) == -1) 105 | break; 106 | 107 | if (strcmpi_imp(sym_name, export_name) == 0) 108 | { 109 | vm::read(process, sym_tab + length, &sym_tab, length); 110 | return sym_tab + base; 111 | } 112 | sym_tab += add; 113 | } while (vm::read(process, sym_tab, &st_name, sizeof(st_name)) != -1); 114 | 115 | return 0; 116 | } 117 | 118 | inline PVOID dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 119 | { 120 | Elf64_Ehdr ehdr; 121 | vm::read(process, base, &ehdr, sizeof(ehdr)); 122 | QWORD module_size = (ehdr.e_shoff + (ehdr.e_shentsize * ehdr.e_shnum)); 123 | 124 | if (module_size == 0) 125 | { 126 | return 0; 127 | } 128 | 129 | QWORD dump = (QWORD)malloc(module_size + 16); 130 | 131 | if (dump == 0) 132 | { 133 | return 0; 134 | } 135 | 136 | *(QWORD*)(dump + 0x00) = base; 137 | *(QWORD*)(dump + 0x08) = module_size; 138 | 139 | dump += 16; 140 | 141 | if (!vm::read(process, base, (PVOID)dump, module_size)) 142 | { 143 | dump -= 16; 144 | 145 | free((PVOID)dump); 146 | return 0; 147 | } 148 | 149 | return (PVOID)dump; 150 | } 151 | 152 | inline void free_module(PVOID dumped_module) 153 | { 154 | QWORD a0 = (QWORD)dumped_module; 155 | 156 | a0 -= 16; 157 | #ifdef _KERNEL_MODE 158 | ExFreePoolWithTag((void*)a0, 'ofnI'); 159 | #else 160 | free((void*)a0); 161 | #endif 162 | } 163 | 164 | inline QWORD scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 165 | { 166 | QWORD base = *(QWORD*)((QWORD)dumped_module - 16); 167 | QWORD size = *(QWORD*)((QWORD)dumped_module - 8); 168 | QWORD address = utils::FindPatternEx((QWORD)dumped_module, size - length, (BYTE*)pattern, (char*)mask); 169 | if (address) 170 | { 171 | return (address - (QWORD)dumped_module) + base; 172 | } 173 | return 0; 174 | } 175 | 176 | QWORD scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 177 | { 178 | if (base == 0) 179 | { 180 | return 0; 181 | } 182 | 183 | PVOID dumped_module = dump_module(process, base, VM_MODULE_TYPE::CodeSectionsOnly); 184 | if (dumped_module == 0) 185 | { 186 | return 0; 187 | } 188 | 189 | QWORD patt = scan_pattern(dumped_module, pattern, mask, length); 190 | 191 | free_module(dumped_module); 192 | return patt; 193 | } 194 | } 195 | 196 | 197 | 198 | #endif 199 | 200 | -------------------------------------------------------------------------------- /km_ctx/vm.cpp: -------------------------------------------------------------------------------- 1 | #include "../shared/vm_windows.h" 2 | #include 3 | #include 4 | 5 | extern "C" __declspec(dllimport) PCSTR PsGetProcessImageFileName(PEPROCESS); 6 | extern "C" __declspec(dllimport) BOOLEAN PsGetProcessExitProcessCalled(PEPROCESS); 7 | extern "C" __declspec(dllimport) PVOID PsGetProcessPeb(PEPROCESS); 8 | extern "C" __declspec(dllimport) PVOID PsGetProcessWow64Process(PEPROCESS); 9 | 10 | namespace km 11 | { 12 | extern BOOL memcpy_impl(void *dest, const void *src, QWORD size); 13 | } 14 | 15 | static vm_handle get_process_by_name(PCSTR process_name) 16 | { 17 | QWORD process; 18 | QWORD entry; 19 | 20 | DWORD gActiveProcessLink = *(DWORD*)((BYTE*)PsGetProcessId + 3) + 8; 21 | process = (QWORD)PsInitialSystemProcess; 22 | 23 | entry = process; 24 | do { 25 | if (PsGetProcessExitProcessCalled((PEPROCESS)entry)) 26 | goto L0; 27 | 28 | if (PsGetProcessImageFileName((PEPROCESS)entry) && 29 | strcmpi_imp(PsGetProcessImageFileName((PEPROCESS)entry), process_name) == 0) { 30 | return (vm_handle)entry; 31 | } 32 | L0: 33 | entry = *(QWORD*)(entry + gActiveProcessLink) - gActiveProcessLink; 34 | } while (entry != process); 35 | 36 | return 0; 37 | } 38 | 39 | VmOs vm::get_target_os(void) 40 | { 41 | return VmOs::Windows; 42 | } 43 | 44 | BOOL vm::process_exists(PCSTR process_name) 45 | { 46 | return get_process_by_name(process_name) != 0; 47 | } 48 | 49 | vm_handle vm::open_process(PCSTR process_name) 50 | { 51 | UNREFERENCED_PARAMETER(process_name); 52 | return *(vm_handle*)(__readgsqword(0x188) + 0xB8); 53 | } 54 | 55 | vm_handle vm::open_process_ex(PCSTR process_name, PCSTR dll_name) 56 | { 57 | UNREFERENCED_PARAMETER(process_name); 58 | UNREFERENCED_PARAMETER(dll_name); 59 | return *(vm_handle*)(__readgsqword(0x188) + 0xB8); 60 | } 61 | 62 | vm_handle vm::open_process_by_module_name(PCSTR dll_name) 63 | { 64 | UNREFERENCED_PARAMETER(dll_name); 65 | return *(vm_handle*)(__readgsqword(0x188) + 0xB8); 66 | } 67 | 68 | void vm::close(vm_handle process) 69 | { 70 | UNREFERENCED_PARAMETER(process); 71 | } 72 | 73 | BOOL vm::running(vm_handle process) 74 | { 75 | if (process == 0) 76 | return 0; 77 | return PsGetProcessExitProcessCalled((PEPROCESS)process) == 0; 78 | } 79 | 80 | BOOL vm::read(vm_handle process, QWORD address, PVOID buffer, QWORD length) 81 | { 82 | if (!running(process)) 83 | { 84 | return 0; 85 | } 86 | if ((address + length) > (ULONG_PTR)0x7FFFFFFEFFFF) 87 | { 88 | return 0; 89 | } 90 | if (address < (QWORD)0x10000) 91 | { 92 | return 0; 93 | } 94 | QWORD physical_address = (QWORD)PAGE_ALIGN(MmGetPhysicalAddress((PVOID)address).QuadPart); 95 | if (physical_address == 0) 96 | { 97 | return 0; 98 | } 99 | if (!MmIsAddressValid((PVOID)address)) 100 | { 101 | return 0; 102 | } 103 | return km::memcpy_impl(buffer, (PVOID)address, length); 104 | } 105 | 106 | BOOL vm::write(vm_handle process, QWORD address, PVOID buffer, QWORD length) 107 | { 108 | if (!running(process)) 109 | { 110 | return 0; 111 | } 112 | if ((address + length) > (ULONG_PTR)0x7FFFFFFEFFFF) 113 | { 114 | return 0; 115 | } 116 | if (address < (QWORD)0x10000) 117 | { 118 | return 0; 119 | } 120 | QWORD physical_address = (QWORD)PAGE_ALIGN(MmGetPhysicalAddress((PVOID)address).QuadPart); 121 | if (physical_address == 0) 122 | { 123 | return 0; 124 | } 125 | if (!MmIsAddressValid((PVOID)address)) 126 | { 127 | return 0; 128 | } 129 | return km::memcpy_impl((void *)address, buffer, length); 130 | } 131 | 132 | QWORD vm::get_peb(vm_handle process) 133 | { 134 | if (process == 0) 135 | return 0; 136 | return (QWORD)PsGetProcessPeb((PEPROCESS)process); 137 | } 138 | 139 | QWORD vm::get_wow64_process(vm_handle process) 140 | { 141 | if (process == 0) 142 | return 0; 143 | return (QWORD)PsGetProcessWow64Process((PEPROCESS)process); 144 | } 145 | 146 | QWORD vm::get_module(vm_handle process, PCSTR dll_name) 147 | { 148 | return vmwin::get_module(process, dll_name); 149 | } 150 | 151 | QWORD vm::get_module_export(vm_handle process, QWORD base, PCSTR export_name) 152 | { 153 | return vmwin::get_module_export(process, base, export_name); 154 | } 155 | 156 | PVOID vm::dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 157 | { 158 | return vmwin::dump_module(process, base, module_type); 159 | } 160 | 161 | void vm::free_module(PVOID dumped_module) 162 | { 163 | return vmwin::free_module(dumped_module); 164 | } 165 | 166 | QWORD vm::get_dump_export(PVOID dumped_module, PCSTR export_name) 167 | { 168 | return vmwin::get_dump_export(dumped_module, export_name); 169 | } 170 | 171 | QWORD vm::scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 172 | { 173 | return vmwin::scan_pattern(dumped_module, pattern, mask, length); 174 | } 175 | 176 | QWORD vm::scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 177 | { 178 | return vmwin::scan_pattern_direct(process, base, pattern, mask, length); 179 | } 180 | 181 | -------------------------------------------------------------------------------- /linux/vm.cpp: -------------------------------------------------------------------------------- 1 | #include "../shared/vm_linux.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int get_process_id(const char *process_name) 10 | { 11 | int process_id = 0; 12 | 13 | DIR *dir = opendir("/proc/"); 14 | if (dir == 0) 15 | { 16 | return 0; 17 | } 18 | 19 | struct dirent *a0; 20 | while ((a0 = readdir(dir))) 21 | { 22 | if (a0->d_type != DT_DIR) 23 | { 24 | continue; 25 | } 26 | 27 | char buffer[266]{}; 28 | snprintf(buffer, sizeof(buffer), "/proc/%s/exe", a0->d_name); 29 | 30 | if (readlink(buffer, buffer, sizeof(buffer)) == -1) 31 | { 32 | continue; 33 | } 34 | 35 | const char *name = strrchr(buffer, '/'); 36 | if (name == 0) 37 | { 38 | continue; 39 | } 40 | 41 | int pid = atoi(a0->d_name); 42 | if (pid < 1 || pid > 2147483647) 43 | { 44 | continue; 45 | } 46 | 47 | if (!strcmp(name + 1, process_name)) 48 | { 49 | process_id = pid; 50 | break; 51 | } 52 | } 53 | closedir(dir); 54 | return process_id; 55 | } 56 | 57 | static size_t 58 | read_line(int fd, char *buffer, size_t length) 59 | { 60 | size_t pos = 0; 61 | while (--length > 0 && read(fd, &buffer[pos], 1)) 62 | { 63 | if (buffer[pos] == '\n') 64 | { 65 | buffer[pos] = '\0'; 66 | return pos; 67 | } 68 | pos++; 69 | } 70 | return 0; 71 | } 72 | 73 | QWORD get_module_base(int process_id, const char *module_name) 74 | { 75 | QWORD base = 0; 76 | 77 | char buffer[512]{}; 78 | snprintf(buffer, sizeof(buffer), "/proc/%d/maps", process_id); 79 | 80 | int fd = open(buffer, O_RDONLY); 81 | if (fd == -1) 82 | { 83 | return 0; 84 | } 85 | 86 | while (read_line(fd, buffer, sizeof(buffer))) 87 | { 88 | const char *name = strrchr(buffer, '/'); 89 | 90 | if (name == 0) 91 | { 92 | continue; 93 | } 94 | 95 | if (!strcmpi_imp(name + 1, module_name)) 96 | { 97 | name = buffer; 98 | base = strtoul(buffer, (char**)&name, 16); 99 | break; 100 | } 101 | } 102 | 103 | close(fd); 104 | 105 | return base; 106 | } 107 | 108 | VmOs vm::get_target_os(void) 109 | { 110 | return VmOs::Linux; 111 | } 112 | 113 | BOOL vm::process_exists(PCSTR process_name) 114 | { 115 | return get_process_id(process_name) != 0; 116 | } 117 | 118 | vm_handle vm::open_process(PCSTR process_name) 119 | { 120 | int pid = get_process_id(process_name); 121 | if (pid == 0) 122 | { 123 | return 0; 124 | } 125 | 126 | char dir[23]; 127 | snprintf(dir, sizeof(dir), "/proc/%d/mem", pid); 128 | 129 | int fd = open(dir, O_RDWR); 130 | if (fd == -1) 131 | { 132 | return 0; 133 | } 134 | 135 | vm_handle process = 0; 136 | ((int*)&process)[0] = fd; 137 | ((int*)&process)[1] = pid; 138 | 139 | return process; 140 | } 141 | 142 | vm_handle vm::open_process_ex(PCSTR process_name, PCSTR dll_name) 143 | { 144 | int pid = get_process_id(process_name); 145 | 146 | if (pid == 0) 147 | { 148 | return 0; 149 | } 150 | 151 | if (get_module_base(pid, dll_name) == 0) 152 | { 153 | return 0; 154 | } 155 | 156 | char dir[23]; 157 | snprintf(dir, sizeof(dir), "/proc/%d/mem", pid); 158 | 159 | int fd = open(dir, O_RDWR); 160 | if (fd == -1) 161 | { 162 | return 0; 163 | } 164 | 165 | vm_handle process = 0; 166 | ((int*)&process)[0] = fd; 167 | ((int*)&process)[1] = pid; 168 | 169 | return process; 170 | } 171 | 172 | inline void close_file(int fd) 173 | { 174 | close(fd); 175 | } 176 | 177 | void vm::close(vm_handle process) 178 | { 179 | close_file(((int*)&process)[0]); 180 | } 181 | 182 | BOOL vm::running(vm_handle process) 183 | { 184 | return fcntl(((int*)&process)[0], F_GETFD) == 0; 185 | } 186 | 187 | BOOL vm::read(vm_handle process, QWORD address, PVOID buffer, QWORD length) 188 | { 189 | return pread(((int*)&process)[0], buffer, length, address) == length; 190 | } 191 | 192 | BOOL vm::write(vm_handle process, QWORD address, PVOID buffer, QWORD length) 193 | { 194 | return pwrite(((int*)&process)[0], buffer, length, address) == length; 195 | } 196 | 197 | QWORD vm::get_module(vm_handle process, PCSTR dll_name) 198 | { 199 | return get_module_base(((int*)&process)[1], dll_name); 200 | } 201 | 202 | QWORD vm::get_module_export(vm_handle process, QWORD base, PCSTR export_name) 203 | { 204 | return vmlinux::get_module_export(process, base, export_name); 205 | } 206 | 207 | PVOID vm::dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 208 | { 209 | return vmlinux::dump_module(process, base, module_type); 210 | } 211 | 212 | void vm::free_module(PVOID dumped_module) 213 | { 214 | return vmlinux::free_module(dumped_module); 215 | } 216 | 217 | QWORD vm::get_dump_export(PVOID dumped_module, PCSTR export_name) 218 | { 219 | return 0; 220 | } 221 | 222 | QWORD vm::scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 223 | { 224 | return vmlinux::scan_pattern(dumped_module, pattern, mask, length); 225 | } 226 | 227 | QWORD vm::scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 228 | { 229 | return vmlinux::scan_pattern_direct(process, base, pattern, mask, length); 230 | } 231 | -------------------------------------------------------------------------------- /pcileech/vm.cpp: -------------------------------------------------------------------------------- 1 | #pragma warning(disable: 4200) 2 | 3 | #include "./pcileech/leechcore.h" 4 | #include "./pcileech/vmmdll.h" 5 | #include "../shared/vm_windows.h" 6 | 7 | #pragma comment(lib, "..\\..\\library\\vm\\pcileech\\pcileech\\leechcore.lib") 8 | #pragma comment(lib, "..\\..\\library\\vm\\pcileech\\pcileech\\vmm.lib") 9 | 10 | 11 | static VMM_HANDLE vmdll = 0; 12 | 13 | static BOOL initialize(void) 14 | { 15 | if (vmdll == 0) 16 | { 17 | LPSTR args[] = { (LPSTR)"", (LPSTR)"-device", (LPSTR)"FPGA" }; 18 | vmdll = VMMDLL_Initialize(3, args); 19 | } 20 | 21 | return vmdll != 0; 22 | } 23 | 24 | VmOs vm::get_target_os(void) 25 | { 26 | return VmOs::Windows; 27 | } 28 | 29 | BOOL vm::process_exists(PCSTR process_name) 30 | { 31 | DWORD pid = 0; 32 | 33 | if (!initialize()) return 0; 34 | 35 | return VMMDLL_PidGetFromName(vmdll, (LPSTR)process_name, &pid); 36 | } 37 | 38 | vm_handle vm::open_process(PCSTR process_name) 39 | { 40 | if (!initialize()) return 0; 41 | 42 | DWORD pid = 0; 43 | if (!VMMDLL_PidGetFromName(vmdll, (LPSTR)process_name, &pid)) 44 | { 45 | return 0; 46 | } 47 | 48 | return (vm_handle)(QWORD)pid; 49 | } 50 | 51 | vm_handle vm::open_process_ex(PCSTR process_name, PCSTR dll_name) 52 | { 53 | if (!initialize()) return 0; 54 | 55 | DWORD i, pid = 0; 56 | 57 | SIZE_T process_count = 0; 58 | if (!VMMDLL_PidList(vmdll, 0, &process_count)) 59 | { 60 | return 0; 61 | } 62 | 63 | DWORD *pid_array = (DWORD*)malloc(process_count*4); 64 | 65 | if (!VMMDLL_PidList(vmdll, pid_array, &process_count)) 66 | { 67 | goto E0; 68 | } 69 | 70 | 71 | for (i = 0; i < process_count; i++) 72 | { 73 | VMMDLL_MAP_MODULE *module_map = 0; 74 | if (!VMMDLL_Map_GetModuleU(vmdll, pid_array[i], &module_map, 0)) 75 | { 76 | continue; 77 | } 78 | 79 | DWORD count=0; 80 | DWORD target_count = 2; 81 | 82 | if (process_name == 0) 83 | { 84 | target_count = 1; 85 | } 86 | 87 | for (DWORD j = 0; j < module_map->cMap; j++) 88 | { 89 | if (process_name && !_strcmpi(module_map->pMap[j].uszText, process_name)) 90 | { 91 | count++; 92 | } 93 | 94 | else if (!_strcmpi(module_map->pMap[j].uszText, dll_name)) 95 | { 96 | count++; 97 | } 98 | 99 | if (count == target_count) 100 | { 101 | break; 102 | } 103 | } 104 | 105 | if (count == target_count) 106 | { 107 | pid = pid_array[i]; 108 | } 109 | 110 | VMMDLL_MemFree(module_map); 111 | 112 | if (pid != 0) 113 | { 114 | target_count++; 115 | break; 116 | } 117 | } 118 | E0: 119 | free(pid_array); 120 | return (vm_handle)(QWORD)pid; 121 | } 122 | 123 | vm_handle vm::open_process_by_module_name(PCSTR dll_name) 124 | { 125 | if (!initialize()) return 0; 126 | 127 | return open_process_ex(0, dll_name); 128 | } 129 | 130 | void vm::close(vm_handle process) 131 | { 132 | UNREFERENCED_PARAMETER(process); 133 | } 134 | 135 | BOOL vm::running(vm_handle process) 136 | { 137 | UNREFERENCED_PARAMETER(process); 138 | 139 | if (!initialize()) return 0; 140 | // 141 | // not implemented yet 142 | // 143 | 144 | return 1; 145 | } 146 | 147 | BOOL vm::read(vm_handle process, QWORD address, PVOID buffer, QWORD length) 148 | { 149 | if (!initialize()) return 0; 150 | 151 | return VMMDLL_MemReadEx(vmdll, (DWORD)(QWORD)process, address, (PBYTE)buffer, (DWORD)length, 0, VMMDLL_FLAG_NOCACHE); 152 | } 153 | 154 | BOOL vm::write(vm_handle process, QWORD address, PVOID buffer, QWORD length) 155 | { 156 | if (!initialize()) return 0; 157 | 158 | return VMMDLL_MemWrite(vmdll, (DWORD)(QWORD)process, address, (PBYTE)buffer, (DWORD)length); 159 | } 160 | 161 | QWORD vm::get_peb(vm_handle process) 162 | { 163 | if (!initialize()) return 0; 164 | 165 | SIZE_T info_size = sizeof(VMMDLL_PROCESS_INFORMATION); 166 | VMMDLL_PROCESS_INFORMATION info{}; 167 | info.magic = VMMDLL_PROCESS_INFORMATION_MAGIC; 168 | info.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION; 169 | if (!VMMDLL_ProcessGetInformation(vmdll, (DWORD)(QWORD)process, &info, &info_size)) 170 | { 171 | return 0; 172 | } 173 | return info.win.vaPEB; 174 | } 175 | 176 | QWORD vm::get_wow64_process(vm_handle process) 177 | { 178 | if (!initialize()) return 0; 179 | 180 | SIZE_T info_size = sizeof(VMMDLL_PROCESS_INFORMATION); 181 | VMMDLL_PROCESS_INFORMATION info{}; 182 | info.magic = VMMDLL_PROCESS_INFORMATION_MAGIC; 183 | info.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION; 184 | if (!VMMDLL_ProcessGetInformation(vmdll, (DWORD)(QWORD)process, &info, &info_size)) 185 | { 186 | return 0; 187 | } 188 | return info.win.vaPEB32; 189 | } 190 | 191 | QWORD vm::get_module(vm_handle process, PCSTR dll_name) 192 | { 193 | return vmwin::get_module(process, dll_name); 194 | } 195 | 196 | QWORD vm::get_module_export(vm_handle process, QWORD base, PCSTR export_name) 197 | { 198 | return vmwin::get_module_export(process, base, export_name); 199 | } 200 | 201 | PVOID vm::dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 202 | { 203 | return vmwin::dump_module(process, base, module_type); 204 | } 205 | 206 | void vm::free_module(PVOID dumped_module) 207 | { 208 | return vmwin::free_module(dumped_module); 209 | } 210 | 211 | QWORD vm::get_dump_export(PVOID dumped_module, PCSTR export_name) 212 | { 213 | return vmwin::get_dump_export(dumped_module, export_name); 214 | } 215 | 216 | QWORD vm::scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 217 | { 218 | return vmwin::scan_pattern(dumped_module, pattern, mask, length); 219 | } 220 | 221 | QWORD vm::scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 222 | { 223 | return vmwin::scan_pattern_direct(process, base, pattern, mask, length); 224 | } 225 | 226 | -------------------------------------------------------------------------------- /um/vm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // vmwin 3 | // 4 | #include "../shared/vm_windows.h" 5 | 6 | #include 7 | #pragma comment(lib, "ntdll.lib") 8 | 9 | extern "C" __kernel_entry NTSTATUS NtQueryInformationProcess( 10 | HANDLE ProcessHandle, 11 | ULONG ProcessInformationClass, 12 | PVOID ProcessInformation, 13 | ULONG ProcessInformationLength, 14 | PULONG ReturnLength 15 | ); 16 | 17 | VmOs vm::get_target_os(void) 18 | { 19 | return VmOs::Windows; 20 | } 21 | 22 | BOOL vm::process_exists(PCSTR process_name) 23 | { 24 | BOOL found = 0; 25 | 26 | PROCESSENTRY32 entry{}; 27 | entry.dwSize = sizeof(PROCESSENTRY32); 28 | 29 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 30 | 31 | while (Process32Next(snapshot, &entry)) 32 | { 33 | if (!strcmpi_imp(entry.szExeFile, process_name)) 34 | { 35 | found = 1; 36 | break; 37 | } 38 | } 39 | 40 | CloseHandle(snapshot); 41 | 42 | return found; 43 | } 44 | 45 | vm_handle vm::open_process(PCSTR process_name) 46 | { 47 | vm_handle process_handle = 0; 48 | 49 | PROCESSENTRY32 entry{}; 50 | entry.dwSize = sizeof(PROCESSENTRY32); 51 | 52 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 53 | 54 | while (Process32Next(snapshot, &entry)) 55 | { 56 | if (!strcmpi_imp(entry.szExeFile, process_name)) 57 | { 58 | process_handle = OpenProcess(PROCESS_ALL_ACCESS, 0, entry.th32ProcessID); 59 | break; 60 | } 61 | } 62 | 63 | CloseHandle(snapshot); 64 | 65 | return process_handle; 66 | } 67 | 68 | vm_handle vm::open_process_ex(PCSTR process_name, PCSTR dll_name) 69 | { 70 | vm_handle process_handle = 0; 71 | 72 | PROCESSENTRY32 entry{}; 73 | entry.dwSize = sizeof(PROCESSENTRY32); 74 | 75 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 76 | 77 | while (Process32Next(snapshot, &entry)) 78 | { 79 | if (!strcmpi_imp(entry.szExeFile, process_name)) 80 | { 81 | process_handle = OpenProcess(PROCESS_ALL_ACCESS, 0, entry.th32ProcessID); 82 | 83 | if (!process_handle) 84 | { 85 | continue; 86 | } 87 | 88 | if (get_module(process_handle, dll_name)) 89 | { 90 | break; 91 | } 92 | 93 | CloseHandle(process_handle); 94 | process_handle = 0; 95 | } 96 | } 97 | 98 | CloseHandle(snapshot); 99 | 100 | return process_handle; 101 | } 102 | 103 | vm_handle vm::open_process_by_module_name(PCSTR dll_name) 104 | { 105 | vm_handle process_handle = 0; 106 | 107 | PROCESSENTRY32 entry{}; 108 | entry.dwSize = sizeof(PROCESSENTRY32); 109 | 110 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 111 | 112 | while (Process32Next(snapshot, &entry)) 113 | { 114 | process_handle = OpenProcess(PROCESS_ALL_ACCESS, 0, entry.th32ProcessID); 115 | 116 | if (!process_handle) 117 | { 118 | continue; 119 | } 120 | 121 | if (get_module(process_handle, dll_name)) 122 | { 123 | break; 124 | } 125 | 126 | CloseHandle(process_handle); 127 | process_handle = 0; 128 | } 129 | 130 | CloseHandle(snapshot); 131 | 132 | return process_handle; 133 | } 134 | 135 | void vm::close(vm_handle process) 136 | { 137 | if (process) 138 | { 139 | CloseHandle(process); 140 | } 141 | } 142 | 143 | BOOL vm::running(vm_handle process) 144 | { 145 | if (!process) 146 | return 0; 147 | 148 | DWORD ret = 0; 149 | GetExitCodeProcess(process, &ret); 150 | 151 | return ret == STATUS_PENDING; 152 | } 153 | 154 | BOOL vm::read(vm_handle process, QWORD address, PVOID buffer, QWORD length) 155 | { 156 | if (process == 0) 157 | return 0; 158 | 159 | SIZE_T ret = 0; 160 | if (!ReadProcessMemory(process, (LPCVOID)address, buffer, length, &ret)) 161 | { 162 | return 0; 163 | } 164 | return ret == length; 165 | } 166 | 167 | BOOL vm::write(vm_handle process, QWORD address, PVOID buffer, QWORD length) 168 | { 169 | if (process == 0) 170 | return 0; 171 | 172 | SIZE_T ret = 0; 173 | if (!WriteProcessMemory(process, (LPVOID)address, buffer, length, &ret)) 174 | { 175 | return 0; 176 | } 177 | return ret == length; 178 | } 179 | 180 | QWORD vm::get_peb(vm_handle process) 181 | { 182 | QWORD peb[6]{}; 183 | 184 | if (NtQueryInformationProcess(process, 0, &peb, 48, 0) != 0) 185 | { 186 | return 0; 187 | } 188 | 189 | return peb[1]; 190 | } 191 | 192 | QWORD vm::get_wow64_process(vm_handle process) 193 | { 194 | QWORD wow64_process = 0; 195 | 196 | if (process == 0) 197 | return wow64_process; 198 | 199 | if (NtQueryInformationProcess(process, 26, &wow64_process, 8, 0) != 0) 200 | { 201 | return 0; 202 | } 203 | 204 | return wow64_process; 205 | } 206 | 207 | QWORD vm::get_module(vm_handle process, PCSTR dll_name) 208 | { 209 | return vmwin::get_module(process, dll_name); 210 | } 211 | 212 | QWORD vm::get_module_export(vm_handle process, QWORD base, PCSTR export_name) 213 | { 214 | return vmwin::get_module_export(process, base, export_name); 215 | } 216 | 217 | PVOID vm::dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 218 | { 219 | return vmwin::dump_module(process, base, module_type); 220 | } 221 | 222 | void vm::free_module(PVOID dumped_module) 223 | { 224 | return vmwin::free_module(dumped_module); 225 | } 226 | 227 | QWORD vm::get_dump_export(PVOID dumped_module, PCSTR export_name) 228 | { 229 | return vmwin::get_dump_export(dumped_module, export_name); 230 | } 231 | 232 | QWORD vm::scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 233 | { 234 | return vmwin::scan_pattern(dumped_module, pattern, mask, length); 235 | } 236 | 237 | QWORD vm::scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 238 | { 239 | return vmwin::scan_pattern_direct(process, base, pattern, mask, length); 240 | } 241 | 242 | -------------------------------------------------------------------------------- /sgv/km.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #pragma comment(lib, "ntdll.lib") 8 | 9 | typedef ULONG_PTR QWORD; 10 | 11 | #define LOG(...) printf("[Client.exe] " __VA_ARGS__) 12 | #define NTOSKRNL_EXPORT(EXPORT_NAME) km::DLL_EXPORT EXPORT_NAME((QWORD)#EXPORT_NAME) 13 | 14 | #pragma pack(1) 15 | typedef struct { 16 | std::string path; 17 | std::string name; 18 | QWORD base; 19 | QWORD size; 20 | } FILE_INFO ; 21 | 22 | #pragma pack(push, 8) 23 | typedef struct _RTL_PROCESS_MODULE_INFORMATION 24 | { 25 | HANDLE Section; 26 | PVOID MappedBase; 27 | PVOID ImageBase; 28 | ULONG ImageSize; 29 | ULONG Flags; 30 | USHORT LoadOrderIndex; 31 | USHORT InitOrderIndex; 32 | USHORT LoadCount; 33 | USHORT OffsetToFileName; 34 | UCHAR FullPathName[256]; 35 | } RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION; 36 | 37 | typedef struct _RTL_PROCESS_MODULES 38 | { 39 | ULONG NumberOfModules; 40 | RTL_PROCESS_MODULE_INFORMATION Modules[1]; 41 | } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES; 42 | 43 | std::vector get_kernel_modules(void) 44 | { 45 | std::vector driver_information; 46 | 47 | 48 | ULONG req = 0; 49 | NTSTATUS status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)11, 0, 0, &req); 50 | if (status != 0xC0000004) 51 | { 52 | return driver_information; 53 | } 54 | 55 | PRTL_PROCESS_MODULES system_modules = (PRTL_PROCESS_MODULES)VirtualAlloc(NULL, req, MEM_COMMIT, PAGE_READWRITE); 56 | 57 | status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)11, system_modules, req, &req); 58 | 59 | if (status != 0) 60 | { 61 | VirtualFree(system_modules, 0, MEM_RELEASE); 62 | return driver_information; 63 | } 64 | 65 | for (ULONG i = system_modules->NumberOfModules; i--;) 66 | { 67 | RTL_PROCESS_MODULE_INFORMATION entry = system_modules->Modules[i]; 68 | char *sub_string = strstr((char *const)entry.FullPathName, "system32"); 69 | if (sub_string == 0) 70 | { 71 | sub_string = strstr((char *const)entry.FullPathName, "System32"); 72 | } 73 | 74 | std::string path; 75 | if (sub_string) 76 | { 77 | path = "C:\\Windows\\" + std::string(sub_string); 78 | } 79 | else 80 | { 81 | path = std::string((const char *)entry.FullPathName); 82 | } 83 | 84 | PCSTR name = (PCSTR)&entry.FullPathName[entry.OffsetToFileName]; 85 | 86 | FILE_INFO temp_information; 87 | temp_information.path = path; 88 | temp_information.name = name; 89 | temp_information.base = (QWORD)entry.ImageBase; 90 | temp_information.size = (QWORD)entry.ImageSize; 91 | driver_information.push_back(temp_information); 92 | } 93 | 94 | VirtualFree(system_modules, 0, MEM_RELEASE); 95 | 96 | return driver_information; 97 | } 98 | 99 | QWORD get_kernel_export(QWORD base, PCSTR driver_name, PCSTR export_name) 100 | { 101 | HMODULE ntos = LoadLibraryA(driver_name); 102 | 103 | if (ntos == 0) 104 | { 105 | return 0; 106 | } 107 | 108 | QWORD export_address = (QWORD)GetProcAddress(ntos, export_name); 109 | if (export_address == 0) 110 | { 111 | goto cleanup; 112 | } 113 | 114 | export_address = export_address - (QWORD)ntos; 115 | export_address = export_address + base; 116 | 117 | cleanup: 118 | FreeLibrary(ntos); 119 | return export_address; 120 | } 121 | 122 | extern "C" NTSTATUS NTAPI RtlAdjustPrivilege(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN); 123 | extern "C" NTSTATUS NTAPI NtQuerySystemEnvironmentValueEx(PUNICODE_STRING, LPGUID, PVOID, PULONG, PULONG); 124 | 125 | namespace km 126 | { 127 | extern std::vector global_export_list; 128 | extern FILE_INFO global_ntoskrnl; 129 | 130 | class DLL_EXPORT 131 | { 132 | QWORD address; 133 | public: 134 | DLL_EXPORT(QWORD address) : address(address) 135 | { 136 | global_export_list.push_back((QWORD)&this->address); 137 | } 138 | operator QWORD () const { return address; } 139 | }; 140 | 141 | QWORD call(QWORD kernel_address, QWORD r1 = 0, QWORD r2 = 0, QWORD r3 = 0, QWORD r4 = 0, QWORD r5 = 0, QWORD r6 = 0, QWORD r7 = 0) 142 | { 143 | #pragma pack(push,1) 144 | typedef struct { 145 | QWORD param_1; 146 | QWORD param_2; 147 | QWORD param_3; 148 | QWORD param_4; 149 | QWORD param_5; 150 | QWORD param_6; 151 | QWORD param_7; 152 | } PAYLOAD ; 153 | #pragma pack(pop) 154 | 155 | PAYLOAD parameters; 156 | parameters.param_1 = r1; 157 | parameters.param_2 = r2; 158 | parameters.param_3 = r3; 159 | parameters.param_4 = r4; 160 | parameters.param_5 = r5; 161 | parameters.param_6 = r6; 162 | parameters.param_7 = r7; 163 | 164 | QWORD peb = __readgsqword(0x60); 165 | peb = *(QWORD*)(peb + 0x18); 166 | peb = *(QWORD*)(peb + 0x20); 167 | 168 | *(QWORD*)(peb + 0x18) = kernel_address; 169 | *(QWORD*)(peb + 0x10) = (QWORD)¶meters; 170 | 171 | UNICODE_STRING string; 172 | RtlInitUnicodeString(&string, L"SecureBoot"); 173 | 174 | ULONG ret = 0; 175 | ULONG ret_len = 1; 176 | ULONG attributes = 0; 177 | 178 | GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; 179 | NTSTATUS status = NtQuerySystemEnvironmentValueEx(&string, 180 | &gEfiGlobalVariableGuid, 181 | &ret, 182 | &ret_len, 183 | &attributes); 184 | 185 | QWORD rax = *(QWORD*)(peb + 0x18); 186 | *(QWORD*)(peb + 0x18) = 0; 187 | *(QWORD*)(peb + 0x10) = 0; 188 | 189 | if (NT_SUCCESS(status)) 190 | return 0; 191 | 192 | return rax; 193 | } 194 | 195 | template 196 | T call(QWORD kernel_address, QWORD r1 = 0, QWORD r2 = 0, QWORD r3 = 0, QWORD r4 = 0, QWORD r5 = 0, QWORD r6 = 0, QWORD r7 = 0) 197 | { 198 | QWORD ret = call(kernel_address, r1, r2, r3, r4, r5, r6, r7); 199 | return *(T*)&ret; 200 | } 201 | 202 | BOOL initialize(void) 203 | { 204 | 205 | for (auto &drv : get_kernel_modules()) 206 | { 207 | if (!_strcmpi(drv.name.c_str(), "ntoskrnl.exe")) 208 | { 209 | global_ntoskrnl = drv; 210 | break; 211 | } 212 | } 213 | 214 | if (global_ntoskrnl.base == 0) 215 | { 216 | LOG("ntoskrnl.exe base address not found\n"); 217 | return 0; 218 | } 219 | 220 | for (auto &i : global_export_list) 221 | { 222 | QWORD temp = *(QWORD*)i; 223 | 224 | *(QWORD*)i = get_kernel_export(global_ntoskrnl.base, "ntoskrnl.exe", (PCSTR)temp); 225 | if (*(QWORD*)i == 0) 226 | { 227 | LOG("export %s not found\n", (PCSTR)temp); 228 | return 0; 229 | } 230 | } 231 | 232 | BOOLEAN privs=1; 233 | if (RtlAdjustPrivilege(22, 1, 0, &privs) != 0l) 234 | { 235 | LOG("run as admin\n"); 236 | return 0; 237 | } 238 | return 1; 239 | } 240 | } 241 | 242 | -------------------------------------------------------------------------------- /proton/vm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../shared/vm_windows.h" 8 | 9 | int get_process_id(const char *process_name) 10 | { 11 | int process_id = 0; 12 | 13 | DIR *dir = opendir("/proc/"); 14 | if (dir == 0) 15 | { 16 | return 0; 17 | } 18 | 19 | struct dirent *a0; 20 | while ((a0 = readdir(dir))) 21 | { 22 | if (a0->d_type != DT_DIR) 23 | { 24 | continue; 25 | } 26 | 27 | char buffer[266]{}; 28 | snprintf(buffer, sizeof(buffer), "/proc/%s/exe", a0->d_name); 29 | 30 | if (readlink(buffer, buffer, sizeof(buffer)) == -1) 31 | { 32 | continue; 33 | } 34 | 35 | const char *name = strrchr(buffer, '/'); 36 | if (name == 0) 37 | { 38 | continue; 39 | } 40 | 41 | int pid = atoi(a0->d_name); 42 | if (pid < 1 || pid > 2147483647) 43 | { 44 | continue; 45 | } 46 | 47 | if (!strcmp(name + 1, process_name)) 48 | { 49 | process_id = pid; 50 | break; 51 | } 52 | } 53 | closedir(dir); 54 | return process_id; 55 | } 56 | 57 | static size_t 58 | read_line(int fd, char *buffer, size_t length) 59 | { 60 | size_t pos = 0; 61 | while (--length > 0 && read(fd, &buffer[pos], 1)) 62 | { 63 | if (buffer[pos] == '\n') 64 | { 65 | buffer[pos] = '\0'; 66 | return pos; 67 | } 68 | pos++; 69 | } 70 | return 0; 71 | } 72 | 73 | QWORD get_module_base(int process_id, const char *module_name) 74 | { 75 | QWORD base = 0; 76 | 77 | char buffer[512]{}; 78 | snprintf(buffer, sizeof(buffer), "/proc/%d/maps", process_id); 79 | 80 | int fd = open(buffer, O_RDONLY); 81 | if (fd == -1) 82 | { 83 | return 0; 84 | } 85 | 86 | while (read_line(fd, buffer, sizeof(buffer))) 87 | { 88 | const char *name = strrchr(buffer, '/'); 89 | 90 | if (name == 0) 91 | { 92 | continue; 93 | } 94 | 95 | if (!strcmpi_imp(name + 1, module_name)) 96 | { 97 | name = buffer; 98 | base = strtoul(buffer, (char**)&name, 16); 99 | break; 100 | } 101 | } 102 | 103 | close(fd); 104 | 105 | return base; 106 | } 107 | 108 | int get_process_id2(const char *process_name, const char *module_name) 109 | { 110 | int process_id = 0; 111 | 112 | DIR *dir = opendir("/proc/"); 113 | if (dir == 0) 114 | { 115 | return 0; 116 | } 117 | 118 | struct dirent *a0; 119 | while ((a0 = readdir(dir))) 120 | { 121 | if (a0->d_type != DT_DIR) 122 | { 123 | continue; 124 | } 125 | 126 | char buffer[266]{}; 127 | snprintf(buffer, sizeof(buffer), "/proc/%s/exe", a0->d_name); 128 | 129 | if (readlink(buffer, buffer, sizeof(buffer)) == -1) 130 | { 131 | continue; 132 | } 133 | 134 | const char *name = strrchr(buffer, '/'); 135 | if (name == 0) 136 | { 137 | continue; 138 | } 139 | 140 | int pid = atoi(a0->d_name); 141 | if (pid < 1 || pid > 2147483647) 142 | { 143 | continue; 144 | } 145 | 146 | if (strcmp(name + 1, process_name)) 147 | { 148 | continue; 149 | } 150 | 151 | QWORD base = get_module_base(pid, module_name); 152 | if (base == 0) 153 | { 154 | continue; 155 | } 156 | process_id = pid; 157 | break; 158 | } 159 | closedir(dir); 160 | return process_id; 161 | } 162 | 163 | VmOs vm::get_target_os(void) 164 | { 165 | return VmOs::Windows; 166 | } 167 | 168 | BOOL vm::process_exists(PCSTR process_name) 169 | { 170 | return get_process_id(process_name) != 0; 171 | } 172 | 173 | vm_handle vm::open_process(PCSTR process_name) 174 | { 175 | // 176 | // we don't care about process_name really 177 | // 178 | int pid = get_process_id2("wine64-preloader", "EOSSDK-Win64-Shipping.dll"); // get_process_id(process_name); 179 | if (pid == 0) 180 | { 181 | return 0; 182 | } 183 | 184 | char dir[23]; 185 | snprintf(dir, sizeof(dir), "/proc/%d/mem", pid); 186 | 187 | int fd = open(dir, O_RDWR); 188 | if (fd == -1) 189 | { 190 | return 0; 191 | } 192 | 193 | vm_handle process = 0; 194 | ((int*)&process)[0] = fd; 195 | ((int*)&process)[1] = pid; 196 | 197 | return process; 198 | } 199 | 200 | vm_handle vm::open_process_ex(PCSTR process_name, PCSTR dll_name) 201 | { 202 | int pid = get_process_id2("wine64-preloader", "EOSSDK-Win64-Shipping.dll"); // get_process_id(process_name); 203 | 204 | if (pid == 0) 205 | { 206 | return 0; 207 | } 208 | 209 | char dir[23]; 210 | snprintf(dir, sizeof(dir), "/proc/%d/mem", pid); 211 | 212 | int fd = open(dir, O_RDWR); 213 | if (fd == -1) 214 | { 215 | return 0; 216 | } 217 | 218 | vm_handle process = 0; 219 | ((int*)&process)[0] = fd; 220 | ((int*)&process)[1] = pid; 221 | 222 | return process; 223 | } 224 | 225 | inline void close_file(int fd) 226 | { 227 | close(fd); 228 | } 229 | 230 | void vm::close(vm_handle process) 231 | { 232 | close_file(((int*)&process)[0]); 233 | } 234 | 235 | BOOL vm::running(vm_handle process) 236 | { 237 | return fcntl(((int*)&process)[0], F_GETFD) == 0; 238 | } 239 | 240 | BOOL vm::read(vm_handle process, QWORD address, PVOID buffer, QWORD length) 241 | { 242 | return pread(((int*)&process)[0], buffer, length, address) == length; 243 | } 244 | 245 | BOOL vm::write(vm_handle process, QWORD address, PVOID buffer, QWORD length) 246 | { 247 | return pwrite(((int*)&process)[0], buffer, length, address) == length; 248 | } 249 | 250 | QWORD vm::get_peb(vm_handle process) 251 | { 252 | /* 253 | QWORD peb[6]{}; 254 | 255 | if (NtQueryInformationProcess(process, 0, &peb, 48, 0) != 0) 256 | { 257 | return 0; 258 | } 259 | 260 | return peb[1]; 261 | */ 262 | return 0; 263 | } 264 | 265 | QWORD vm::get_wow64_process(vm_handle process) 266 | { 267 | /* 268 | QWORD wow64_process = 0; 269 | 270 | if (process == 0) 271 | return wow64_process; 272 | 273 | if (NtQueryInformationProcess(process, 26, &wow64_process, 8, 0) != 0) 274 | { 275 | return 0; 276 | } 277 | 278 | return wow64_process; 279 | */ 280 | return 0; 281 | } 282 | 283 | QWORD vm::get_module(vm_handle process, PCSTR dll_name) 284 | { 285 | return (QWORD)0x140000000; // return vmwin::get_module(process, dll_name); 286 | } 287 | 288 | QWORD vm::get_module_export(vm_handle process, QWORD base, PCSTR export_name) 289 | { 290 | return vmwin::get_module_export(process, base, export_name); 291 | } 292 | 293 | PVOID vm::dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 294 | { 295 | return vmwin::dump_module(process, base, module_type); 296 | } 297 | 298 | void vm::free_module(PVOID dumped_module) 299 | { 300 | return vmwin::free_module(dumped_module); 301 | } 302 | 303 | QWORD vm::get_dump_export(PVOID dumped_module, PCSTR export_name) 304 | { 305 | return vmwin::get_dump_export(dumped_module, export_name); 306 | } 307 | 308 | QWORD vm::scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 309 | { 310 | return vmwin::scan_pattern(dumped_module, pattern, mask, length); 311 | } 312 | 313 | QWORD vm::scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 314 | { 315 | return vmwin::scan_pattern_direct(process, base, pattern, mask, length); 316 | } 317 | 318 | -------------------------------------------------------------------------------- /vm.h: -------------------------------------------------------------------------------- 1 | #ifndef VM_H 2 | #define VM_H 3 | 4 | #ifdef _KERNEL_MODE 5 | #pragma warning (disable: 4996) 6 | #include 7 | typedef unsigned __int8 BYTE; 8 | typedef unsigned __int16 WORD; 9 | typedef unsigned long DWORD; 10 | typedef unsigned __int64 QWORD; 11 | typedef int BOOL; 12 | 13 | extern QWORD g_memory_range_low; 14 | extern QWORD g_memory_range_high; 15 | #else 16 | 17 | #ifdef __linux__ 18 | 19 | #include 20 | #include 21 | typedef unsigned char BYTE; 22 | typedef unsigned short WORD; 23 | typedef unsigned int DWORD; 24 | typedef unsigned long QWORD; 25 | typedef void *PVOID; 26 | typedef int BOOL; 27 | typedef char BOOLEAN; 28 | typedef int INT32; 29 | typedef const char *PCSTR; 30 | 31 | #else 32 | 33 | #include 34 | typedef unsigned __int64 QWORD; 35 | 36 | #endif 37 | 38 | 39 | #endif 40 | 41 | 42 | 43 | 44 | inline int to_lower_imp(int c) 45 | { 46 | if (c >= 'A' && c <= 'Z') 47 | return c + 'a' - 'A'; 48 | else 49 | return c; 50 | } 51 | 52 | inline int strcmpi_imp(const char* s1, const char* s2) 53 | { 54 | while (*s1 && (to_lower_imp(*s1) == to_lower_imp(*s2))) 55 | { 56 | s1++; 57 | s2++; 58 | } 59 | return *(const unsigned char*)s1 - *(const unsigned char*)s2; 60 | } 61 | 62 | inline int wcscmpi_imp(unsigned short* s1, unsigned short* s2) 63 | { 64 | while (*s1 && (to_lower_imp(*s1) == to_lower_imp(*s2))) 65 | { 66 | s1++; 67 | s2++; 68 | } 69 | return *(unsigned short*)s1 - *(unsigned short*)s2; 70 | } 71 | 72 | // 73 | // sometimes compiler uses precompiled strlen, this is added to prevent that happen in any case. 74 | // 75 | inline unsigned long long strlen_imp(const char *str) 76 | { 77 | const char *s; 78 | 79 | for (s = str; *s; ++s) 80 | ; 81 | 82 | return (s - str); 83 | } 84 | 85 | inline unsigned long long wcslen_imp(const short *str) 86 | { 87 | const short *s; 88 | 89 | for (s = str; *s; ++s) 90 | ; 91 | 92 | return (s - str); 93 | } 94 | 95 | inline void wcs2str(short *buffer, QWORD length) 96 | { 97 | for (QWORD i = 0; i < length; i++) 98 | { 99 | ((char*)buffer)[i] = (char)buffer[i]; 100 | } 101 | } 102 | 103 | namespace utils 104 | { 105 | inline BOOL bDataCompare(const BYTE* pData, const BYTE* bPattern, const char* szMask) 106 | { 107 | 108 | for (; *szMask; ++szMask, ++pData, ++bPattern) 109 | if (*szMask == 'x' && *pData != *bPattern) 110 | return 0; 111 | 112 | return (*szMask) == 0; 113 | } 114 | 115 | inline QWORD FindPatternEx(QWORD dwAddress, QWORD dwLen, BYTE* bPattern, char* szMask) 116 | { 117 | 118 | if (dwLen <= 0) 119 | return 0; 120 | for (QWORD i = 0; i < dwLen; i++) 121 | if (bDataCompare((BYTE*)(dwAddress + i), bPattern, szMask)) 122 | return (QWORD)(dwAddress + i); 123 | 124 | return 0; 125 | } 126 | } 127 | 128 | 129 | typedef void* vm_handle; 130 | enum class VM_MODULE_TYPE { 131 | Full = 1, 132 | CodeSectionsOnly = 2, 133 | Raw = 3, // used for dump to file 134 | ReadOnly = 4, 135 | }; 136 | 137 | enum class VmOs 138 | { 139 | Windows=0, 140 | Linux=1 141 | }; 142 | 143 | namespace vm 144 | { 145 | VmOs get_target_os(void); 146 | 147 | 148 | BOOL process_exists(PCSTR process_name); 149 | 150 | 151 | vm_handle open_process(PCSTR process_name); 152 | vm_handle open_process_ex(PCSTR process_name, PCSTR dll_name); 153 | vm_handle open_process_by_module_name(PCSTR dll_name); 154 | 155 | 156 | void close(vm_handle process); 157 | BOOL running(vm_handle process); 158 | 159 | 160 | BOOL read(vm_handle process, QWORD address, PVOID buffer, QWORD length); 161 | BOOL write(vm_handle process, QWORD address, PVOID buffer, QWORD length); 162 | 163 | 164 | QWORD get_peb(vm_handle process); 165 | QWORD get_wow64_process(vm_handle process); 166 | 167 | 168 | QWORD get_module(vm_handle process, PCSTR dll_name); 169 | QWORD get_module_export(vm_handle process, QWORD base, PCSTR export_name); 170 | 171 | 172 | PVOID dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type); 173 | void free_module(PVOID dumped_module); 174 | 175 | QWORD get_dump_export(PVOID dumped_module, PCSTR export_name); 176 | 177 | 178 | QWORD scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length); 179 | QWORD scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length); 180 | 181 | 182 | inline BYTE read_i8(vm_handle process, QWORD address); 183 | inline WORD read_i16(vm_handle process, QWORD address); 184 | inline DWORD read_i32(vm_handle process, QWORD address); 185 | inline QWORD read_i64(vm_handle process, QWORD address); 186 | inline float read_float(vm_handle process, QWORD address); 187 | 188 | inline BOOL write_i8(vm_handle process, QWORD address, BYTE value); 189 | inline BOOL write_i16(vm_handle process, QWORD address, WORD value); 190 | inline BOOL write_i32(vm_handle process, QWORD address, DWORD value); 191 | inline BOOL write_i64(vm_handle process, QWORD address, QWORD value); 192 | inline BOOL write_float(vm_handle process, QWORD address, float value); 193 | inline QWORD get_relative_address(vm_handle process, QWORD instruction, DWORD offset, DWORD instruction_size); 194 | } 195 | 196 | inline BYTE vm::read_i8(vm_handle process, QWORD address) 197 | { 198 | BYTE result = 0; 199 | if (!read(process, address, &result, sizeof(result))) 200 | { 201 | return 0; 202 | } 203 | return result; 204 | } 205 | 206 | inline WORD vm::read_i16(vm_handle process, QWORD address) 207 | { 208 | WORD result = 0; 209 | if (!read(process, address, &result, sizeof(result))) 210 | { 211 | return 0; 212 | } 213 | return result; 214 | } 215 | 216 | inline DWORD vm::read_i32(vm_handle process, QWORD address) 217 | { 218 | DWORD result = 0; 219 | if (!read(process, address, &result, sizeof(result))) 220 | { 221 | return 0; 222 | } 223 | return result; 224 | } 225 | 226 | inline QWORD vm::read_i64(vm_handle process, QWORD address) 227 | { 228 | QWORD result = 0; 229 | if (!read(process, address, &result, sizeof(result))) 230 | { 231 | return 0; 232 | } 233 | return result; 234 | } 235 | 236 | inline float vm::read_float(vm_handle process, QWORD address) 237 | { 238 | float result = 0; 239 | if (!read(process, address, &result, sizeof(result))) 240 | { 241 | return 0; 242 | } 243 | return result; 244 | } 245 | 246 | inline BOOL vm::write_i8(vm_handle process, QWORD address, BYTE value) 247 | { 248 | return write(process, address, &value, sizeof(value)); 249 | } 250 | 251 | inline BOOL vm::write_i16(vm_handle process, QWORD address, WORD value) 252 | { 253 | return write(process, address, &value, sizeof(value)); 254 | } 255 | 256 | inline BOOL vm::write_i32(vm_handle process, QWORD address, DWORD value) 257 | { 258 | return write(process, address, &value, sizeof(value)); 259 | } 260 | 261 | inline BOOL vm::write_i64(vm_handle process, QWORD address, QWORD value) 262 | { 263 | return write(process, address, &value, sizeof(value)); 264 | } 265 | 266 | inline BOOL vm::write_float(vm_handle process, QWORD address, float value) 267 | { 268 | return write(process, address, &value, sizeof(value)); 269 | } 270 | 271 | inline QWORD vm::get_relative_address(vm_handle process, QWORD instruction, DWORD offset, DWORD instruction_size) 272 | { 273 | INT32 rip_address = read_i32(process, instruction + offset); 274 | return (QWORD)(instruction + instruction_size + rip_address); 275 | } 276 | 277 | #endif /* VM_H */ 278 | 279 | -------------------------------------------------------------------------------- /shared/vm_windows.h: -------------------------------------------------------------------------------- 1 | #ifndef VM_WINDOWS_H 2 | #define VM_WINDOWS_H 3 | 4 | #include "../vm.h" 5 | 6 | // 7 | // wmwin is private header used by vm.cpp only 8 | // 9 | namespace vmwin 10 | { 11 | inline QWORD read_i32w(vm_handle process, QWORD address) { return (QWORD)vm::read_i32(process, address); } 12 | inline QWORD get_module(vm_handle process, PCSTR dll_name) 13 | { 14 | QWORD peb = vm::get_wow64_process(process); 15 | 16 | DWORD a0[6]{}; 17 | QWORD a1, a2, a4; 18 | unsigned char a3[240]{}; 19 | 20 | QWORD(*read_ptr)(vm_handle process, QWORD address) = 0; 21 | if (peb) 22 | { 23 | read_ptr = read_i32w; 24 | a0[0] = 0x04, a0[1] = 0x0C, a0[2] = 0x14, a0[3] = 0x28, a0[4] = 0x10, a0[5] = 0x20; 25 | } 26 | else 27 | { 28 | read_ptr = vm::read_i64; 29 | peb = vm::get_peb(process); 30 | a0[0] = 0x08, a0[1] = 0x18, a0[2] = 0x20, a0[3] = 0x50, a0[4] = 0x20, a0[5] = 0x40; 31 | } 32 | 33 | if (peb == 0) 34 | { 35 | return 0; 36 | } 37 | 38 | a1 = read_ptr(process, peb + a0[1]); 39 | if (a1 == 0) 40 | { 41 | return 0; 42 | } 43 | 44 | a1 = read_ptr(process, a1 + a0[2]); 45 | if (a1 == 0) 46 | { 47 | return 0; 48 | } 49 | 50 | 51 | // 52 | // return first list entry, if parameter is null 53 | // 54 | if (dll_name == 0) 55 | return read_ptr(process, a1 + a0[4]); 56 | 57 | 58 | int name_length = (int)strlen_imp(dll_name); 59 | if (name_length > 119) 60 | name_length = 119; 61 | 62 | 63 | a2 = read_ptr(process, a1 + a0[0]); 64 | while (a1 != a2) 65 | { 66 | a4 = read_ptr(process, a1 + a0[3]); 67 | 68 | // 69 | // if no module name, we skip the module 70 | // 71 | if (a4 == 0) 72 | { 73 | goto next_entry; 74 | } 75 | 76 | vm::read(process, a4, a3, (name_length*2)+2); 77 | wcs2str((short*)a3, name_length+1); 78 | a3[name_length+1] = 0; 79 | 80 | if (strcmpi_imp((PCSTR)a3, dll_name) == 0) 81 | { 82 | return read_ptr(process, a1 + a0[4]); 83 | } 84 | next_entry: 85 | a1 = read_ptr(process, a1); 86 | if (a1 == 0) 87 | { 88 | break; 89 | } 90 | } 91 | return 0; 92 | } 93 | 94 | QWORD get_module_export(vm_handle process, QWORD base, PCSTR export_name) 95 | { 96 | QWORD a0; 97 | DWORD a1[4]{}; 98 | char a2[120]{}; 99 | 100 | a0 = base + vm::read_i16(process, base + 0x3C); 101 | if (a0 == base) 102 | { 103 | return 0; 104 | } 105 | 106 | DWORD wow64_off = vm::read_i16(process, a0 + 0x4) == 0x8664 ? 0x88 : 0x78; 107 | 108 | a0 = base + (QWORD)vm::read_i32(process, a0 + wow64_off); 109 | if (a0 == base) 110 | { 111 | return 0; 112 | } 113 | 114 | int name_length = (int)strlen_imp(export_name); 115 | if (name_length > 119) 116 | name_length = 119; 117 | 118 | vm::read(process, a0 + 0x18, &a1, sizeof(a1)); 119 | while (a1[0]--) 120 | { 121 | a0 = (QWORD)vm::read_i32(process, base + a1[2] + ((QWORD)a1[0] * 4)); 122 | if (a0 == 0) 123 | { 124 | continue; 125 | } 126 | 127 | vm::read(process, base + a0, &a2, name_length + 1); 128 | a2[name_length + 1] = 0; 129 | 130 | if (!strcmpi_imp(a2, export_name)) 131 | { 132 | a0 = vm::read_i16(process, base + a1[3] + ((QWORD)a1[0] * 2)) * 4; 133 | a0 = vm::read_i32(process, base + a1[1] + a0); 134 | return (base + a0); 135 | } 136 | } 137 | return 0; 138 | } 139 | 140 | inline PVOID dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 141 | { 142 | if (base == 0) 143 | { 144 | return 0; 145 | } 146 | 147 | QWORD nt_header = (QWORD)vm::read_i32(process, base + 0x03C) + base; 148 | if (nt_header == base) 149 | { 150 | return 0; 151 | } 152 | 153 | DWORD image_size = vm::read_i32(process, nt_header + 0x050); 154 | if (image_size == 0) 155 | { 156 | return 0; 157 | } 158 | 159 | #ifdef _KERNEL_MODE 160 | BYTE *ret = (BYTE*)ExAllocatePoolWithTag(NonPagedPoolNx, (QWORD)(image_size + 16), 'ofnI'); 161 | #else 162 | BYTE *ret = (BYTE*)malloc((QWORD)image_size + 16); 163 | #endif 164 | if (ret == 0) 165 | return 0; 166 | 167 | *(QWORD*)(ret + 0) = base; 168 | *(QWORD*)(ret + 8) = image_size; 169 | ret += 16; 170 | 171 | DWORD headers_size = vm::read_i32(process, nt_header + 0x54); 172 | vm::read(process, base, ret, headers_size); 173 | 174 | WORD machine = vm::read_i16(process, nt_header + 0x4); 175 | QWORD section_header = machine == 0x8664 ? 176 | nt_header + 0x0108 : 177 | nt_header + 0x00F8; 178 | 179 | 180 | for (WORD i = 0; i < vm::read_i16(process, nt_header + 0x06); i++) { 181 | QWORD section = section_header + ((QWORD)i * 40); 182 | if (module_type == VM_MODULE_TYPE::CodeSectionsOnly) 183 | { 184 | DWORD section_characteristics = vm::read_i32(process, section + 0x24); 185 | if (!(section_characteristics & 0x00000020)) 186 | continue; 187 | } 188 | 189 | else if (module_type == VM_MODULE_TYPE::ReadOnly) 190 | { 191 | DWORD section_characteristics = vm::read_i32(process, section + 0x24); 192 | if (!(section_characteristics & 0x40000000)) // IMAGE_SCN_MEM_READ 193 | { 194 | continue; 195 | } 196 | if ((section_characteristics & 0x80000000)) // IMAGE_SCN_MEM_WRITE 197 | { 198 | continue; 199 | } 200 | if ((section_characteristics & 0x20000000)) // IMAGE_SCN_MEM_EXECUTE 201 | { 202 | continue; 203 | } 204 | if ((section_characteristics & 0x02000000)) // IMAGE_SCN_MEM_DISCARDABLE 205 | { 206 | continue; 207 | } 208 | } 209 | 210 | QWORD target_address = (QWORD)ret + (QWORD)vm::read_i32(process, section + ((module_type == VM_MODULE_TYPE::Raw) ? 0x14 : 0x0C)); 211 | QWORD virtual_address = base + (QWORD)vm::read_i32(process, section + 0x0C); 212 | DWORD virtual_size = vm::read_i32(process, section + 0x08); 213 | vm::read(process, virtual_address, (PVOID)target_address, virtual_size); 214 | } 215 | return (PVOID)ret; 216 | } 217 | 218 | inline void free_module(PVOID dumped_module) 219 | { 220 | QWORD a0 = (QWORD)dumped_module; 221 | 222 | a0 -= 16; 223 | #ifdef _KERNEL_MODE 224 | ExFreePoolWithTag((void*)a0, 'ofnI'); 225 | #else 226 | free((void*)a0); 227 | #endif 228 | } 229 | 230 | inline QWORD get_dump_export(PVOID dumped_module, PCSTR export_name) 231 | { 232 | QWORD a0; 233 | DWORD a1[4]{}; 234 | 235 | 236 | QWORD base = (QWORD)dumped_module; 237 | 238 | 239 | a0 = base + *(WORD*)(base + 0x3C); 240 | if (a0 == base) 241 | { 242 | return 0; 243 | } 244 | 245 | DWORD wow64_off = *(WORD*)(a0 + 0x4) == 0x8664 ? 0x88 : 0x78; 246 | 247 | a0 = base + (QWORD)*(DWORD*)(a0 + wow64_off); 248 | if (a0 == base) 249 | { 250 | return 0; 251 | } 252 | 253 | memcpy(&a1, (const void *)(a0 + 0x18), sizeof(a1)); 254 | while (a1[0]--) 255 | { 256 | a0 = (QWORD)*(DWORD*)(base + a1[2] + ((QWORD)a1[0] * 4)); 257 | if (a0 == 0) 258 | { 259 | continue; 260 | } 261 | 262 | if (!strcmpi_imp((const char*)(base + a0), export_name)) 263 | { 264 | a0 = *(WORD*)(base + a1[3] + ((QWORD)a1[0] * 2)) * 4; 265 | a0 = *(DWORD*)(base + a1[1] + a0); 266 | return (*(QWORD*)((QWORD)dumped_module - 16) + a0); 267 | } 268 | } 269 | return 0; 270 | } 271 | 272 | inline QWORD scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 273 | { 274 | QWORD ret = 0; 275 | 276 | if (dumped_module == 0) 277 | return 0; 278 | 279 | QWORD dos_header = (QWORD)dumped_module; 280 | QWORD nt_header = (QWORD) * (DWORD*)(dos_header + 0x03C) + dos_header; 281 | WORD machine = *(WORD*)(nt_header + 0x4); 282 | 283 | QWORD section_header = machine == 0x8664 ? 284 | nt_header + 0x0108 : 285 | nt_header + 0x00F8; 286 | 287 | for (WORD i = 0; i < *(WORD*)(nt_header + 0x06); i++) { 288 | 289 | QWORD section = section_header + ((QWORD)i * 40); 290 | DWORD section_characteristics = *(DWORD*)(section + 0x24); 291 | 292 | if (section_characteristics & 0x00000020) 293 | { 294 | QWORD section_address = dos_header + (QWORD) * (DWORD*)(section + 0x0C); 295 | DWORD section_size = *(DWORD*)(section + 0x08); 296 | QWORD address = utils::FindPatternEx(section_address, section_size - length, (BYTE*)pattern, (char*)mask); 297 | if (address) 298 | { 299 | ret = (address - (QWORD)dumped_module) + 300 | *(QWORD*)((QWORD)dumped_module - 16); 301 | break; 302 | } 303 | } 304 | 305 | } 306 | return ret; 307 | } 308 | 309 | QWORD scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 310 | { 311 | if (base == 0) 312 | { 313 | return 0; 314 | } 315 | 316 | PVOID dumped_module = dump_module(process, base, VM_MODULE_TYPE::CodeSectionsOnly); 317 | if (dumped_module == 0) 318 | { 319 | return 0; 320 | } 321 | 322 | QWORD patt = scan_pattern(dumped_module, pattern, mask, length); 323 | 324 | free_module(dumped_module); 325 | return patt; 326 | } 327 | } 328 | 329 | 330 | 331 | #endif 332 | 333 | -------------------------------------------------------------------------------- /km/vm.cpp: -------------------------------------------------------------------------------- 1 | #include "../shared/vm_windows.h" 2 | 3 | namespace pm 4 | { 5 | static BOOL read(QWORD address, PVOID buffer, QWORD length, QWORD* ret); 6 | static BOOL write(QWORD address, PVOID buffer, QWORD length); 7 | static QWORD read_i64(QWORD address); 8 | static QWORD translate(QWORD dir, QWORD va); 9 | } 10 | 11 | extern "C" __declspec(dllimport) PCSTR PsGetProcessImageFileName(PEPROCESS); 12 | extern "C" __declspec(dllimport) BOOLEAN PsGetProcessExitProcessCalled(PEPROCESS); 13 | extern "C" __declspec(dllimport) PVOID PsGetProcessPeb(PEPROCESS); 14 | extern "C" __declspec(dllimport) PVOID PsGetProcessWow64Process(PEPROCESS); 15 | 16 | static vm_handle get_process_by_name(PCSTR process_name) 17 | { 18 | QWORD process; 19 | QWORD entry; 20 | 21 | DWORD gActiveProcessLink = *(DWORD*)((BYTE*)PsGetProcessId + 3) + 8; 22 | process = (QWORD)PsInitialSystemProcess; 23 | 24 | entry = process; 25 | do { 26 | if (PsGetProcessExitProcessCalled((PEPROCESS)entry)) 27 | goto L0; 28 | 29 | if (PsGetProcessImageFileName((PEPROCESS)entry) && 30 | strcmpi_imp(PsGetProcessImageFileName((PEPROCESS)entry), process_name) == 0) { 31 | return (vm_handle)entry; 32 | } 33 | L0: 34 | entry = *(QWORD*)(entry + gActiveProcessLink) - gActiveProcessLink; 35 | } while (entry != process); 36 | 37 | return 0; 38 | } 39 | 40 | VmOs vm::get_target_os(void) 41 | { 42 | return VmOs::Windows; 43 | } 44 | 45 | BOOL vm::process_exists(PCSTR process_name) 46 | { 47 | return get_process_by_name(process_name) != 0; 48 | } 49 | 50 | vm_handle vm::open_process(PCSTR process_name) 51 | { 52 | return get_process_by_name(process_name); 53 | } 54 | 55 | vm_handle vm::open_process_ex(PCSTR process_name, PCSTR dll_name) 56 | { 57 | QWORD process; 58 | QWORD entry; 59 | 60 | DWORD gActiveProcessLink = *(DWORD*)((BYTE*)PsGetProcessId + 3) + 8; 61 | process = (QWORD)PsInitialSystemProcess; 62 | 63 | entry = process; 64 | do { 65 | if (PsGetProcessExitProcessCalled((PEPROCESS)entry)) 66 | goto L0; 67 | 68 | if (PsGetProcessImageFileName((PEPROCESS)entry) && 69 | strcmpi_imp(PsGetProcessImageFileName((PEPROCESS)entry), process_name) == 0) { 70 | 71 | if (get_module((vm_handle)entry, dll_name)) 72 | return (vm_handle)entry; 73 | } 74 | L0: 75 | entry = *(QWORD*)(entry + gActiveProcessLink) - gActiveProcessLink; 76 | } while (entry != process); 77 | 78 | return 0; 79 | } 80 | 81 | vm_handle vm::open_process_by_module_name(PCSTR dll_name) 82 | { 83 | QWORD process; 84 | QWORD entry; 85 | 86 | DWORD gActiveProcessLink = *(DWORD*)((BYTE*)PsGetProcessId + 3) + 8; 87 | process = (QWORD)PsInitialSystemProcess; 88 | 89 | entry = process; 90 | do { 91 | if (PsGetProcessExitProcessCalled((PEPROCESS)entry)) 92 | goto L0; 93 | 94 | if (get_module((vm_handle)entry, dll_name)) 95 | return (vm_handle)entry; 96 | L0: 97 | entry = *(QWORD*)(entry + gActiveProcessLink) - gActiveProcessLink; 98 | } while (entry != process); 99 | 100 | return 0; 101 | } 102 | 103 | void vm::close(vm_handle process) 104 | { 105 | // 106 | // do nothing 107 | // 108 | UNREFERENCED_PARAMETER(process); 109 | } 110 | 111 | BOOL vm::running(vm_handle process) 112 | { 113 | if (process == 0) 114 | return 0; 115 | return PsGetProcessExitProcessCalled((PEPROCESS)process) == 0; 116 | } 117 | 118 | BOOL vm::read(vm_handle process, QWORD address, PVOID buffer, QWORD length) 119 | { 120 | if (process == 0) 121 | { 122 | return 0; 123 | } 124 | 125 | QWORD cr3 = *(QWORD*)((QWORD)process + 0x28); 126 | if (cr3 == 0) 127 | { 128 | return 0; 129 | } 130 | 131 | QWORD total_size = length; 132 | QWORD offset = 0; 133 | QWORD bytes_read=0; 134 | QWORD physical_address; 135 | QWORD current_size; 136 | 137 | while (total_size) 138 | { 139 | physical_address = pm::translate(cr3, address + offset); 140 | if (!physical_address) 141 | { 142 | if (total_size >= 0x1000) 143 | { 144 | bytes_read = 0x1000; 145 | } 146 | else 147 | { 148 | bytes_read = total_size; 149 | } 150 | goto E0; 151 | } 152 | 153 | current_size = min(0x1000 - (physical_address & 0xFFF), total_size); 154 | if (!pm::read(physical_address, (PVOID)((QWORD)buffer + offset), current_size, &bytes_read)) 155 | { 156 | break; 157 | } 158 | E0: 159 | total_size -= bytes_read; 160 | offset += bytes_read; 161 | } 162 | return 1; 163 | } 164 | 165 | BOOL vm::write(vm_handle process, QWORD address, PVOID buffer, QWORD length) 166 | { 167 | if (process == 0) 168 | { 169 | return 0; 170 | } 171 | 172 | QWORD cr3 = *(QWORD*)((QWORD)process + 0x28); 173 | if (cr3 == 0) 174 | { 175 | return 0; 176 | } 177 | 178 | QWORD total_size = length; 179 | QWORD offset = 0; 180 | QWORD bytes_write=0; 181 | 182 | QWORD physical_address; 183 | QWORD current_size; 184 | 185 | while (total_size) { 186 | physical_address = pm::translate(cr3, address + offset); 187 | if (!physical_address) { 188 | if (total_size >= 0x1000) 189 | { 190 | bytes_write = 0x1000; 191 | } 192 | else 193 | { 194 | bytes_write = total_size; 195 | } 196 | goto E0; 197 | } 198 | current_size = min(0x1000 - (physical_address & 0xFFF), total_size); 199 | if (!pm::write(physical_address, (PVOID)((QWORD)buffer + offset), current_size)) 200 | { 201 | break; 202 | } 203 | bytes_write = current_size; 204 | E0: 205 | total_size -= bytes_write; 206 | offset += bytes_write; 207 | } 208 | return 1; 209 | } 210 | 211 | QWORD vm::get_peb(vm_handle process) 212 | { 213 | if (process == 0) 214 | return 0; 215 | return (QWORD)PsGetProcessPeb((PEPROCESS)process); 216 | } 217 | 218 | QWORD vm::get_wow64_process(vm_handle process) 219 | { 220 | if (process == 0) 221 | return 0; 222 | return (QWORD)PsGetProcessWow64Process((PEPROCESS)process); 223 | } 224 | 225 | QWORD vm::get_module(vm_handle process, PCSTR dll_name) 226 | { 227 | return vmwin::get_module(process, dll_name); 228 | } 229 | 230 | QWORD vm::get_module_export(vm_handle process, QWORD base, PCSTR export_name) 231 | { 232 | return vmwin::get_module_export(process, base, export_name); 233 | } 234 | 235 | PVOID vm::dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 236 | { 237 | return vmwin::dump_module(process, base, module_type); 238 | } 239 | 240 | void vm::free_module(PVOID dumped_module) 241 | { 242 | return vmwin::free_module(dumped_module); 243 | } 244 | 245 | QWORD vm::get_dump_export(PVOID dumped_module, PCSTR export_name) 246 | { 247 | return vmwin::get_dump_export(dumped_module, export_name); 248 | } 249 | 250 | QWORD vm::scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 251 | { 252 | return vmwin::scan_pattern(dumped_module, pattern, mask, length); 253 | } 254 | 255 | QWORD vm::scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 256 | { 257 | return vmwin::scan_pattern_direct(process, base, pattern, mask, length); 258 | } 259 | 260 | static BYTE MM_COPY_BUFFER[0x1000]; 261 | static BOOL pm::read(QWORD address, PVOID buffer, QWORD length, QWORD* ret) 262 | { 263 | if (address < (QWORD)g_memory_range_low) 264 | { 265 | return 0; 266 | } 267 | 268 | if (address + length > g_memory_range_high) 269 | { 270 | return 0; 271 | } 272 | 273 | if (length > 0x1000) 274 | { 275 | length = 0x1000; 276 | } 277 | 278 | MM_COPY_ADDRESS physical_address{}; 279 | physical_address.PhysicalAddress.QuadPart = (LONGLONG)address; 280 | 281 | BOOL v = MmCopyMemory(MM_COPY_BUFFER, physical_address, length, MM_COPY_MEMORY_PHYSICAL, &length) == 0; 282 | if (v) 283 | { 284 | for (QWORD i = length; i--;) 285 | { 286 | ((unsigned char*)buffer)[i] = ((unsigned char*)MM_COPY_BUFFER)[i]; 287 | } 288 | } 289 | 290 | if (ret) 291 | *ret = length; 292 | 293 | return v; 294 | } 295 | 296 | static BOOL pm::write(QWORD address, PVOID buffer, QWORD length) 297 | { 298 | if (address < (QWORD)g_memory_range_low) 299 | { 300 | return 0; 301 | } 302 | 303 | if (address + length > g_memory_range_high) 304 | { 305 | return 0; 306 | } 307 | 308 | PVOID va = MmMapIoSpace(*(PHYSICAL_ADDRESS*)&address, length, MEMORY_CACHING_TYPE::MmNonCached); 309 | if (va) 310 | { 311 | for (QWORD i = length; i--;) 312 | { 313 | ((BYTE*)va)[i] = ((BYTE*)buffer)[i]; 314 | } 315 | MmUnmapIoSpace(va, length); 316 | return 1; 317 | } 318 | return 0; 319 | } 320 | 321 | static QWORD pm::read_i64(QWORD address) 322 | { 323 | QWORD result = 0; 324 | if (!read(address, &result, sizeof(result), 0)) 325 | { 326 | return 0; 327 | } 328 | return result; 329 | } 330 | 331 | static QWORD pm::translate(QWORD dir, QWORD va) 332 | { 333 | __int64 v2; // rax 334 | __int64 v3; // rax 335 | __int64 v5; // rax 336 | __int64 v6; // rax 337 | 338 | v2 = pm::read_i64(8 * ((va >> 39) & 0x1FF) + dir); 339 | if ( !v2 ) 340 | return 0i64; 341 | 342 | if ( (v2 & 1) == 0 ) 343 | return 0i64; 344 | 345 | v3 = pm::read_i64((v2 & 0xFFFFFFFFF000i64) + 8 * ((va >> 30) & 0x1FF)); 346 | if ( !v3 || (v3 & 1) == 0 ) 347 | return 0i64; 348 | 349 | if ( (v3 & 0x80u) != 0i64 ) 350 | return (va & 0x3FFFFFFF) + (v3 & 0xFFFFFFFFF000i64); 351 | 352 | v5 = pm::read_i64((v3 & 0xFFFFFFFFF000i64) + 8 * ((va >> 21) & 0x1FF)); 353 | if ( !v5 || (v5 & 1) == 0 ) 354 | return 0i64; 355 | 356 | if ( (v5 & 0x80u) != 0i64 ) 357 | return (va & 0x1FFFFF) + (v5 & 0xFFFFFFFFF000i64); 358 | 359 | v6 = pm::read_i64((v5 & 0xFFFFFFFFF000i64) + 8 * ((va >> 12) & 0x1FF)); 360 | if ( v6 && (v6 & 1) != 0 ) 361 | return (va & 0xFFF) + (v6 & 0xFFFFFFFFF000i64); 362 | 363 | return 0i64; 364 | } 365 | 366 | -------------------------------------------------------------------------------- /ksj/src/vm.cpp: -------------------------------------------------------------------------------- 1 | #ifdef __linux__ 2 | #include 3 | #include 4 | #include 5 | 6 | typedef int SOCKET; 7 | 8 | #else 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #pragma comment(lib, "Ws2_32.lib") 15 | 16 | #include 17 | #include 18 | #include 19 | #endif 20 | 21 | #include "../../shared/vm_windows.h" 22 | 23 | #include 24 | 25 | #define SOCKET_NAME "vm" 26 | #define IOCTL_READPHYS 1 27 | #define IOCTL_WRITEPHYS 2 28 | #define IOCTL_VIRT2PHYS 3 29 | #define IOCTL_READVIRT 4 30 | #define IOCTL_WRITEVIRT 5 31 | #define IOCTL_CR3 6 32 | #define IOCTL_NTOSKRNL 7 33 | 34 | struct _vm_handle { 35 | QWORD cr3; 36 | QWORD object; 37 | QWORD exit_status; 38 | QWORD wow64_process; 39 | QWORD peb; 40 | } ; 41 | 42 | namespace vm 43 | { 44 | static SOCKET fd; 45 | static struct _vm_handle system_proc; 46 | static QWORD PsInitialSystemProcess; 47 | static QWORD PsLoadedModuleList; 48 | static DWORD offset_PsGetProcessExitProcessCalled; 49 | static DWORD offset_PsGetProcessImageFileName; 50 | static DWORD offset_ActiveProcessLinks; 51 | static DWORD offset_PsGetProcessWow64Process; 52 | static DWORD offset_PsGetProcessPeb; 53 | static BOOL initialize(void); 54 | } 55 | 56 | namespace client 57 | { 58 | namespace pm 59 | { 60 | BOOL read(SOCKET fd, QWORD address, PVOID buffer, QWORD length); 61 | BOOL write(SOCKET fd, QWORD address, PVOID buffer, QWORD length); 62 | template 63 | t read(SOCKET fd, QWORD address) 64 | { 65 | t b; 66 | if (!client::pm::read(fd, address, &b, sizeof(b))) 67 | { 68 | b = 0; 69 | } 70 | return b; 71 | } 72 | } 73 | 74 | namespace vm 75 | { 76 | QWORD get_physical_address(SOCKET fd, QWORD cr3, QWORD virtual_address); 77 | BOOL read(SOCKET fd, QWORD cr3, QWORD address, PVOID buffer, QWORD length); 78 | BOOL write(SOCKET fd, QWORD cr3, QWORD address, PVOID buffer, QWORD length); 79 | } 80 | QWORD get_system_cr3(SOCKET fd); 81 | QWORD get_ntoskrnl_base(SOCKET fd); 82 | } 83 | 84 | VmOs vm::get_target_os() 85 | { 86 | return VmOs::Windows; 87 | } 88 | 89 | static QWORD PsLookupProcessByProcessName(const char *process_name) 90 | { 91 | QWORD entry; 92 | char image_name[15]={0}; 93 | 94 | entry = vm::PsInitialSystemProcess; 95 | do { 96 | vm::read(&vm::system_proc, entry + vm::offset_PsGetProcessImageFileName, image_name, 15); 97 | image_name[14]=0; 98 | 99 | DWORD exitcalled = vm::read_i32(&vm::system_proc, entry + vm::offset_PsGetProcessExitProcessCalled); 100 | exitcalled = exitcalled >> 2; 101 | exitcalled = exitcalled & 1; 102 | 103 | if (!exitcalled && strcmpi_imp(process_name, image_name) == 0) 104 | { 105 | return entry; 106 | } 107 | 108 | entry = vm::read_i64(&vm::system_proc, entry + vm::offset_ActiveProcessLinks); 109 | if (entry == 0) 110 | break; 111 | 112 | entry = entry - vm::offset_ActiveProcessLinks; 113 | } while (entry != vm::PsInitialSystemProcess) ; 114 | return 0; 115 | } 116 | 117 | BOOL vm::process_exists(PCSTR process_name) 118 | { 119 | if (!vm::initialize()) 120 | { 121 | return 0; 122 | } 123 | return PsLookupProcessByProcessName(process_name) != 0; 124 | } 125 | 126 | vm_handle vm::open_process(PCSTR process_name) 127 | { 128 | if (!vm::initialize()) 129 | { 130 | return 0; 131 | } 132 | 133 | if (process_name == 0 || *process_name == '\0') { 134 | return (vm_handle)&system_proc; 135 | } 136 | 137 | QWORD process_object = PsLookupProcessByProcessName(process_name); 138 | if (process_object == 0) 139 | { 140 | return 0; 141 | } 142 | 143 | struct _vm_handle *temp_handle = (struct _vm_handle*)malloc(sizeof(struct _vm_handle)); 144 | temp_handle->object=process_object; 145 | temp_handle->cr3=vm::read_i64(&system_proc, process_object + 0x28); 146 | temp_handle->exit_status=client::vm::get_physical_address(fd, system_proc.cr3, process_object + offset_PsGetProcessExitProcessCalled); 147 | temp_handle->wow64_process=client::vm::get_physical_address(fd, system_proc.cr3,process_object + vm::offset_PsGetProcessWow64Process); 148 | temp_handle->peb=client::vm::get_physical_address(fd, system_proc.cr3,process_object + vm::offset_PsGetProcessPeb); 149 | return temp_handle; 150 | } 151 | 152 | vm_handle vm::open_process_ex(PCSTR process_name, PCSTR dll_name) 153 | { 154 | return open_process(process_name); 155 | } 156 | 157 | vm_handle vm::open_process_by_module_name(PCSTR dll_name) 158 | { 159 | return 0; 160 | } 161 | 162 | void vm::close(vm_handle process) 163 | { 164 | free(process); 165 | } 166 | 167 | BOOL vm::running(vm_handle process) 168 | { 169 | if (process == 0) 170 | return 0; 171 | 172 | struct _vm_handle *proc = (struct _vm_handle *)process; 173 | DWORD eax = client::pm::read(fd, proc->exit_status); 174 | eax = eax >> 2; 175 | eax = eax & 1; 176 | return eax == 0; 177 | } 178 | 179 | BOOL vm::read(vm_handle process, QWORD address, PVOID buffer, QWORD length) 180 | { 181 | struct _vm_handle *proc = (struct _vm_handle*)process; 182 | return client::vm::read(fd, proc->cr3, address, buffer, length); 183 | } 184 | 185 | BOOL vm::write(vm_handle process, QWORD address, PVOID buffer, QWORD length) 186 | { 187 | struct _vm_handle *proc = (struct _vm_handle*)process; 188 | return client::vm::write(fd, proc->cr3, address, buffer, length); 189 | } 190 | 191 | QWORD vm::get_peb(vm_handle process) 192 | { 193 | if (process == 0) 194 | return 0; 195 | 196 | struct _vm_handle *proc = (struct _vm_handle *)process; 197 | 198 | return client::pm::read(fd, proc->peb); 199 | } 200 | 201 | QWORD vm::get_wow64_process(vm_handle process) 202 | { 203 | if (process == 0) 204 | return 0; 205 | 206 | struct _vm_handle *proc = (struct _vm_handle *)process; 207 | QWORD rax = client::pm::read(fd, proc->wow64_process); 208 | 209 | return vm::read_i64(&vm::system_proc, rax); 210 | } 211 | 212 | QWORD vm::get_module(vm_handle process, PCSTR dll_name) 213 | { 214 | return vmwin::get_module(process, dll_name); 215 | } 216 | 217 | QWORD vm::get_module_export(vm_handle process, QWORD base, PCSTR export_name) 218 | { 219 | return vmwin::get_module_export(process, base, export_name); 220 | } 221 | 222 | PVOID vm::dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 223 | { 224 | return vmwin::dump_module(process, base, module_type); 225 | } 226 | 227 | void vm::free_module(PVOID dumped_module) 228 | { 229 | return vmwin::free_module(dumped_module); 230 | } 231 | 232 | QWORD vm::get_dump_export(PVOID dumped_module, PCSTR export_name) 233 | { 234 | return vmwin::get_dump_export(dumped_module, export_name); 235 | } 236 | 237 | QWORD vm::scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 238 | { 239 | return vmwin::scan_pattern(dumped_module, pattern, mask, length); 240 | } 241 | 242 | QWORD vm::scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 243 | { 244 | return vmwin::scan_pattern_direct(process, base, pattern, mask, length); 245 | } 246 | 247 | static void socket_close(SOCKET fd) 248 | { 249 | #ifdef __linux__ 250 | close(fd); 251 | #else 252 | closesocket(fd); 253 | #endif 254 | } 255 | 256 | static SOCKET socket_open(void) 257 | { 258 | #ifndef __linux__ 259 | WSADATA data; 260 | WSAStartup(MAKEWORD(2, 2), &data); 261 | #endif // !__linux__ 262 | 263 | 264 | struct sockaddr addr{}; 265 | 266 | SOCKET data_socket = socket(AF_UNIX, SOCK_STREAM, 0); 267 | 268 | 269 | addr.sa_family = AF_UNIX; 270 | memcpy(addr.sa_data, SOCKET_NAME, strlen(SOCKET_NAME)); 271 | 272 | int ret = connect (data_socket, (const struct sockaddr *) &addr, sizeof(struct sockaddr)); 273 | 274 | if (ret == -1) 275 | { 276 | socket_close(data_socket); 277 | data_socket = 0; 278 | } 279 | 280 | return data_socket; 281 | } 282 | 283 | static QWORD socket_read(SOCKET fd, PVOID buffer, QWORD length) 284 | { 285 | #ifdef __linux__ 286 | return recv(fd, (char *)buffer, (int)length, MSG_WAITALL); 287 | #else 288 | return recv(fd, (char *)buffer, (int)length, 0); 289 | #endif 290 | } 291 | 292 | static QWORD socket_write(SOCKET fd, PVOID buffer, QWORD length) 293 | { 294 | #ifdef __linux__ 295 | return write(fd, buffer, length); 296 | #else 297 | return send(fd, (const char*)buffer, (int)length, 0); 298 | #endif 299 | } 300 | 301 | #ifdef __linux__ 302 | #define FIELD_OFFSET(type, field) (DWORD)((long)&(((type *)0)->field)) 303 | #endif 304 | 305 | namespace client 306 | { 307 | #ifdef __linux__ 308 | typedef struct __attribute__((__packed__)) { 309 | #else 310 | #pragma pack(1) 311 | typedef struct { 312 | #endif 313 | unsigned char ioctl; 314 | } SERVER_PACKET; 315 | 316 | #ifdef __linux__ 317 | typedef struct __attribute__((__packed__)) { 318 | #else 319 | #pragma pack(1) 320 | typedef struct { 321 | #endif 322 | SERVER_PACKET header; 323 | QWORD cr3; 324 | QWORD virtual_address; 325 | } SERVER_VIRT2PHYS; 326 | 327 | #ifdef __linux__ 328 | typedef struct __attribute__((__packed__)) { 329 | #else 330 | #pragma pack(1) 331 | typedef struct { 332 | #endif 333 | SERVER_PACKET header; 334 | QWORD address; 335 | DWORD size; 336 | } SERVER_READWRITEPHYS; 337 | 338 | #ifdef __linux__ 339 | typedef struct __attribute__((__packed__)) { 340 | #else 341 | #pragma pack(1) 342 | typedef struct { 343 | #endif 344 | SERVER_PACKET header; 345 | QWORD cr3; 346 | QWORD address; 347 | DWORD size; 348 | } SERVER_READWRITEVIRT; 349 | 350 | namespace pm 351 | { 352 | BOOL read(SOCKET fd, QWORD address, PVOID buffer, QWORD length) 353 | { 354 | SERVER_READWRITEPHYS packet; 355 | packet.header.ioctl = IOCTL_READPHYS; 356 | packet.address = address; 357 | packet.size = (DWORD)length; 358 | socket_write(fd, &packet, sizeof(packet)); 359 | 360 | BOOLEAN status=0; 361 | if (socket_read(fd, &status, sizeof(status)) != sizeof(status)) 362 | { 363 | return 0; 364 | } 365 | 366 | if (status == 0) 367 | { 368 | return 0; 369 | } 370 | 371 | return socket_read(fd, buffer, length) == length; 372 | } 373 | 374 | BOOL write(SOCKET fd, QWORD address, PVOID buffer, QWORD length) 375 | { 376 | QWORD packet_size = length + sizeof(SERVER_READWRITEPHYS); 377 | 378 | SERVER_READWRITEPHYS *packet = (SERVER_READWRITEPHYS *)malloc(packet_size); 379 | packet->header.ioctl = IOCTL_WRITEPHYS; 380 | packet->address = address; 381 | packet->size = (DWORD)length; 382 | 383 | DWORD offset = FIELD_OFFSET(SERVER_READWRITEPHYS, size) + 4; 384 | 385 | memcpy( 386 | (char*)packet + offset, 387 | buffer, 388 | length 389 | ); 390 | 391 | socket_write(fd, (void *)packet, packet_size); 392 | 393 | free(packet); 394 | 395 | unsigned char status=0; 396 | socket_read(fd, &status, 1); 397 | 398 | return (BOOL)status; 399 | } 400 | } 401 | 402 | namespace vm 403 | { 404 | QWORD get_physical_address(SOCKET fd, QWORD cr3, QWORD virtual_address) 405 | { 406 | SERVER_VIRT2PHYS packet{}; 407 | packet.header.ioctl = IOCTL_VIRT2PHYS; 408 | packet.cr3 = cr3; 409 | packet.virtual_address = virtual_address; 410 | socket_write(fd, &packet, sizeof(packet)); 411 | 412 | QWORD physical_address = 0; 413 | socket_read(fd, &physical_address, sizeof(physical_address)); 414 | 415 | return physical_address; 416 | } 417 | 418 | BOOL read(SOCKET fd, QWORD cr3, QWORD address, PVOID buffer, QWORD length) 419 | { 420 | SERVER_READWRITEVIRT packet{}; 421 | packet.header.ioctl = IOCTL_READVIRT; 422 | packet.cr3 = cr3; 423 | packet.address = address; 424 | packet.size = (DWORD)length; 425 | socket_write(fd, &packet, sizeof(packet)); 426 | 427 | BOOLEAN status=0; 428 | if (socket_read(fd, &status, sizeof(status)) != sizeof(status)) 429 | { 430 | return 0; 431 | } 432 | 433 | if (status == 0) 434 | { 435 | return 0; 436 | } 437 | return socket_read(fd, buffer, length) == length; 438 | } 439 | 440 | BOOL write(SOCKET fd, QWORD cr3, QWORD address, PVOID buffer, QWORD length) 441 | { 442 | QWORD packet_size = length + sizeof(SERVER_READWRITEVIRT); 443 | 444 | SERVER_READWRITEVIRT *packet = (SERVER_READWRITEVIRT *)malloc(packet_size); 445 | packet->header.ioctl = IOCTL_WRITEVIRT; 446 | packet->cr3 = cr3; 447 | packet->address = address; 448 | packet->size = (DWORD)length; 449 | 450 | DWORD offset = FIELD_OFFSET(SERVER_READWRITEVIRT, size) + 4; 451 | 452 | memcpy( 453 | (char*)packet + offset, 454 | buffer, 455 | length 456 | ); 457 | 458 | socket_write(fd, (void *)packet, packet_size); 459 | 460 | free(packet); 461 | 462 | unsigned char status=0; 463 | socket_read(fd, &status, 1); 464 | 465 | return (BOOL)status; 466 | } 467 | } 468 | 469 | QWORD get_system_cr3(SOCKET fd) 470 | { 471 | SERVER_PACKET packet; 472 | packet.ioctl = IOCTL_CR3; 473 | socket_write(fd, &packet, sizeof(packet)); 474 | 475 | QWORD cr3 = 0; 476 | socket_read(fd, &cr3, sizeof(cr3)); 477 | 478 | return cr3; 479 | } 480 | 481 | QWORD get_ntoskrnl_base(SOCKET fd) 482 | { 483 | SERVER_PACKET packet; 484 | packet.ioctl = IOCTL_NTOSKRNL; 485 | socket_write(fd, &packet, sizeof(packet)); 486 | 487 | QWORD base = 0; 488 | socket_read(fd, &base, sizeof(base)); 489 | 490 | return base; 491 | } 492 | } 493 | 494 | static BOOL vm::initialize(void) 495 | { 496 | // 497 | // if we are ready for vm calls 498 | // 499 | if (fd != 0) 500 | { 501 | return 1; 502 | } 503 | 504 | fd = socket_open(); 505 | if (fd == 0) 506 | { 507 | return 0; 508 | } 509 | 510 | QWORD cr3 = client::get_system_cr3(fd); 511 | QWORD ntoskrnl = client::get_ntoskrnl_base(fd); 512 | 513 | if (cr3 == 0 || ntoskrnl == 0) 514 | { 515 | E0: 516 | socket_close(fd); 517 | fd = 0; 518 | return 0; 519 | } 520 | 521 | struct _vm_handle process{}; 522 | process.cr3 = cr3; 523 | 524 | PVOID ntoskrnl_dump = vm::dump_module(&process, ntoskrnl, VM_MODULE_TYPE::ReadOnly); 525 | if (ntoskrnl_dump == 0) 526 | { 527 | goto E0; 528 | } 529 | 530 | QWORD PsGetProcessId,PsGetProcessExitProcessCalled,PsGetProcessImageFileName,PsGetProcessWow64Process,PsGetProcessPeb; 531 | 532 | PsInitialSystemProcess = vm::get_dump_export(ntoskrnl_dump, "PsInitialSystemProcess"); 533 | PsLoadedModuleList = vm::get_dump_export(ntoskrnl_dump, "PsLoadedModuleList"); 534 | PsGetProcessId = vm::get_dump_export(ntoskrnl_dump, "PsGetProcessId"); 535 | PsGetProcessExitProcessCalled = vm::get_dump_export(ntoskrnl_dump, "PsGetProcessExitProcessCalled"); 536 | PsGetProcessImageFileName = vm::get_dump_export(ntoskrnl_dump, "PsGetProcessImageFileName"); 537 | PsGetProcessWow64Process = vm::get_dump_export(ntoskrnl_dump, "PsGetProcessWow64Process"); 538 | PsGetProcessPeb = vm::get_dump_export(ntoskrnl_dump, "PsGetProcessPeb"); 539 | 540 | vm::free_module(ntoskrnl_dump); 541 | 542 | offset_PsGetProcessExitProcessCalled = vm::read_i32(&process, PsGetProcessExitProcessCalled + 2); 543 | offset_PsGetProcessImageFileName = vm::read_i32(&process, PsGetProcessImageFileName + 3); 544 | offset_ActiveProcessLinks = vm::read_i32(&process, PsGetProcessId + 3) + 8; 545 | offset_PsGetProcessWow64Process = vm::read_i32(&process, PsGetProcessWow64Process + 3); 546 | offset_PsGetProcessPeb = vm::read_i32(&process, PsGetProcessPeb + 3); 547 | PsInitialSystemProcess = vm::read_i64(&process, PsInitialSystemProcess); 548 | PsLoadedModuleList = vm::read_i64(&process, PsLoadedModuleList); 549 | 550 | process.object = PsInitialSystemProcess; 551 | system_proc = process; 552 | 553 | return fd != 0; 554 | } 555 | 556 | -------------------------------------------------------------------------------- /sgv/vm.cpp: -------------------------------------------------------------------------------- 1 | #include "km.h" 2 | #include "../shared/vm_windows.h" 3 | 4 | 5 | // 6 | // MMCOPYMEMORY is slower, but 100% crash free 7 | // if you run to any issues uncomment it. 8 | // 9 | // #define MMCOPYMEMORY 10 | 11 | 12 | #include 13 | #pragma comment(lib, "ntdll.lib") 14 | 15 | #define POOLTAG (DWORD)'ECSG' 16 | #define PAGE_SIZE 0x1000 17 | #define PAGE_MASK 0xFFF 18 | #define PAGE_SHIFT 12 19 | #define SIZE_TO_PAGES(Size) (((Size) >> PAGE_SHIFT) + (((Size) & PAGE_MASK) ? 1 : 0)) 20 | #define PAGES_TO_SIZE(Pages) ((Pages) << PAGE_SIZE) 21 | 22 | std::vector km::global_export_list; 23 | FILE_INFO km::global_ntoskrnl; 24 | 25 | NTOSKRNL_EXPORT(MmGetPhysicalMemoryRanges); 26 | NTOSKRNL_EXPORT(ExAllocatePool2); 27 | NTOSKRNL_EXPORT(ExFreePool); 28 | NTOSKRNL_EXPORT(HalPrivateDispatchTable); 29 | NTOSKRNL_EXPORT(PsLookupProcessByProcessId); 30 | NTOSKRNL_EXPORT(PsGetProcessExitProcessCalled); 31 | NTOSKRNL_EXPORT(PsGetProcessPeb); 32 | NTOSKRNL_EXPORT(PsGetProcessWow64Process); 33 | NTOSKRNL_EXPORT(MmCopyMemory); 34 | 35 | namespace kernel 36 | { 37 | NTOSKRNL_EXPORT(memcpy); 38 | } 39 | 40 | NTOSKRNL_EXPORT(PsGetCurrentProcess); 41 | NTOSKRNL_EXPORT(PsGetCurrentProcessId); 42 | 43 | namespace pm 44 | { 45 | #ifdef MMCOPYMEMORY 46 | static BOOL read(QWORD address, PVOID buffer, QWORD length, QWORD* res); 47 | #else 48 | static BOOL read(QWORD address, PVOID buffer, QWORD length); 49 | #endif 50 | static BOOL write(QWORD address, PVOID buffer, QWORD length); 51 | static QWORD read_i64(QWORD address); 52 | static QWORD translate(QWORD dir, QWORD va); 53 | } 54 | 55 | QWORD g_memory_range_low; 56 | QWORD g_memory_range_high; 57 | QWORD KdMapPhysicalMemory64; 58 | QWORD KdUnmapVirtualAddress; 59 | 60 | typedef struct _PHYSICAL_MEMORY_RANGE 61 | { 62 | union _LARGE_INTEGER BaseAddress; //0x0 63 | union _LARGE_INTEGER NumberOfBytes; //0x8 64 | } PHYSICAL_MEMORY_RANGE; 65 | 66 | typedef struct 67 | { 68 | QWORD object; 69 | QWORD cr3; 70 | } vm_handle_s; 71 | 72 | namespace vm 73 | { 74 | static BOOL init = 0; 75 | 76 | static QWORD allocate_memory(QWORD size) 77 | { 78 | return km::call(ExAllocatePool2, 0x0000000000000080UI64, PAGE_SIZE + size, POOLTAG); 79 | } 80 | 81 | static void free_memory(QWORD address) 82 | { 83 | km::call(ExFreePool, address, POOLTAG, 0, 0); 84 | } 85 | 86 | static BOOL initialize(void) 87 | { 88 | if (init) 89 | return 1; 90 | 91 | init = km::initialize(); 92 | if (init) 93 | { 94 | QWORD memory_range_ptr = km::call(MmGetPhysicalMemoryRanges); 95 | 96 | int counter=0; 97 | while (1) 98 | { 99 | PHYSICAL_MEMORY_RANGE memory_range{}; 100 | km::call(kernel::memcpy, (QWORD)&memory_range, memory_range_ptr + (counter * sizeof(PHYSICAL_MEMORY_RANGE)), sizeof(PHYSICAL_MEMORY_RANGE) ); 101 | if (memory_range.BaseAddress.QuadPart == 0) 102 | { 103 | break; 104 | } 105 | counter++; 106 | } 107 | 108 | PHYSICAL_MEMORY_RANGE memory_range{}; 109 | 110 | 111 | km::call(kernel::memcpy, (QWORD)&memory_range, memory_range_ptr + (0 * sizeof(PHYSICAL_MEMORY_RANGE)), sizeof(PHYSICAL_MEMORY_RANGE) ); 112 | g_memory_range_low = memory_range.BaseAddress.QuadPart; 113 | 114 | km::call(kernel::memcpy, (QWORD)&memory_range, memory_range_ptr + ((counter-1) * sizeof(PHYSICAL_MEMORY_RANGE)), sizeof(PHYSICAL_MEMORY_RANGE) ); 115 | g_memory_range_high = memory_range.BaseAddress.QuadPart + memory_range.NumberOfBytes.QuadPart; 116 | 117 | 118 | km::call(ExFreePool, memory_range_ptr); 119 | 120 | KdMapPhysicalMemory64 = (QWORD)HalPrivateDispatchTable; 121 | KdMapPhysicalMemory64 += 0x90; 122 | km::call(kernel::memcpy, (QWORD)&KdMapPhysicalMemory64, KdMapPhysicalMemory64, sizeof(KdMapPhysicalMemory64)); 123 | 124 | KdUnmapVirtualAddress = (QWORD)HalPrivateDispatchTable; 125 | KdUnmapVirtualAddress += 0x98; 126 | km::call(kernel::memcpy, (QWORD)&KdUnmapVirtualAddress, KdUnmapVirtualAddress, sizeof(KdUnmapVirtualAddress)); 127 | 128 | if (KdMapPhysicalMemory64 < km::global_ntoskrnl.base || KdMapPhysicalMemory64 > (km::global_ntoskrnl.base + km::global_ntoskrnl.size)) 129 | { 130 | // 131 | // function is hooked, exit process 132 | // 133 | 134 | LOG("KdMapPhysicalMemory64 can't be used\n"); 135 | 136 | ExitProcess(0); 137 | 138 | return 0; 139 | } 140 | 141 | if (KdUnmapVirtualAddress < km::global_ntoskrnl.base || KdUnmapVirtualAddress > (km::global_ntoskrnl.base + km::global_ntoskrnl.size)) 142 | { 143 | // 144 | // function is hooked, exit process 145 | // 146 | 147 | LOG("KdUnmapVirtualAddress can't be used\n"); 148 | 149 | ExitProcess(0); 150 | 151 | return 0; 152 | } 153 | } 154 | 155 | return init; 156 | } 157 | } 158 | 159 | VmOs vm::get_target_os(void) 160 | { 161 | return VmOs::Windows; 162 | } 163 | 164 | BOOL vm::process_exists(PCSTR process_name) 165 | { 166 | BOOL found = 0; 167 | 168 | PROCESSENTRY32 entry{}; 169 | entry.dwSize = sizeof(PROCESSENTRY32); 170 | 171 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 172 | 173 | while (Process32Next(snapshot, &entry)) 174 | { 175 | if (!strcmpi_imp(entry.szExeFile, process_name)) 176 | { 177 | found = 1; 178 | break; 179 | } 180 | } 181 | 182 | CloseHandle(snapshot); 183 | 184 | return found; 185 | } 186 | 187 | vm_handle vm::open_process(PCSTR process_name) 188 | { 189 | if (!initialize()) 190 | return 0; 191 | 192 | vm_handle process_handle = 0; 193 | 194 | PROCESSENTRY32 entry{}; 195 | entry.dwSize = sizeof(PROCESSENTRY32); 196 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 197 | while (Process32Next(snapshot, &entry)) 198 | { 199 | if (!strcmpi_imp(entry.szExeFile, process_name)) 200 | { 201 | if (km::call(PsLookupProcessByProcessId, (QWORD)entry.th32ProcessID, (QWORD)&process_handle) != 0) 202 | { 203 | process_handle = 0; 204 | } 205 | break; 206 | } 207 | } 208 | CloseHandle(snapshot); 209 | 210 | if (process_handle) 211 | { 212 | QWORD cr3=0; 213 | km::call(kernel::memcpy, (QWORD)&cr3, (QWORD)process_handle + 0x28, sizeof(cr3)); 214 | 215 | vm_handle_s *s = (vm_handle_s*)malloc(sizeof(vm_handle_s)); 216 | s->object = (QWORD)process_handle; 217 | s->cr3 = cr3; 218 | 219 | process_handle = (vm_handle)s; 220 | } 221 | 222 | return process_handle; 223 | } 224 | 225 | vm_handle vm::open_process_ex(PCSTR process_name, PCSTR dll_name) 226 | { 227 | if (!initialize()) 228 | return 0; 229 | 230 | vm_handle process_handle = 0; 231 | 232 | PROCESSENTRY32 entry{}; 233 | entry.dwSize = sizeof(PROCESSENTRY32); 234 | 235 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 236 | 237 | while (Process32Next(snapshot, &entry)) 238 | { 239 | if (!strcmpi_imp(entry.szExeFile, process_name)) 240 | { 241 | if (km::call(PsLookupProcessByProcessId, (QWORD)entry.th32ProcessID, (QWORD)&process_handle) != 0) 242 | { 243 | process_handle = 0; 244 | continue; 245 | } 246 | 247 | 248 | QWORD cr3=0; 249 | km::call(kernel::memcpy, (QWORD)&cr3, (QWORD)process_handle + 0x28, sizeof(cr3)); 250 | 251 | vm_handle_s *s = (vm_handle_s*)malloc(sizeof(vm_handle_s)); 252 | s->object = (QWORD)process_handle; 253 | s->cr3 = cr3; 254 | 255 | process_handle = (vm_handle)s; 256 | 257 | 258 | if (get_module(process_handle, dll_name)) 259 | { 260 | break; 261 | } 262 | 263 | vm::close((vm_handle)process_handle); 264 | process_handle = 0; 265 | } 266 | } 267 | 268 | CloseHandle(snapshot); 269 | 270 | return process_handle; 271 | } 272 | 273 | vm_handle vm::open_process_by_module_name(PCSTR dll_name) 274 | { 275 | if (!initialize()) 276 | return 0; 277 | 278 | vm_handle process_handle = 0; 279 | 280 | PROCESSENTRY32 entry{}; 281 | entry.dwSize = sizeof(PROCESSENTRY32); 282 | 283 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 284 | 285 | while (Process32Next(snapshot, &entry)) 286 | { 287 | if (km::call(PsLookupProcessByProcessId, (QWORD)entry.th32ProcessID, (QWORD)&process_handle) != 0) 288 | { 289 | process_handle = 0; 290 | continue; 291 | } 292 | 293 | QWORD cr3=0; 294 | km::call(kernel::memcpy, (QWORD)&cr3, (QWORD)process_handle + 0x28, sizeof(cr3)); 295 | 296 | vm_handle_s *s = (vm_handle_s*)malloc(sizeof(vm_handle_s)); 297 | s->object = (QWORD)process_handle; 298 | s->cr3 = cr3; 299 | 300 | process_handle = (vm_handle)s; 301 | 302 | 303 | if (get_module(process_handle, dll_name)) 304 | { 305 | break; 306 | } 307 | 308 | vm::close((vm_handle)process_handle); 309 | process_handle = 0; 310 | } 311 | 312 | CloseHandle(snapshot); 313 | 314 | return process_handle; 315 | } 316 | 317 | void vm::close(vm_handle process) 318 | { 319 | if (process) 320 | { 321 | free(process); 322 | } 323 | } 324 | 325 | BOOL vm::running(vm_handle process) 326 | { 327 | if (!initialize()) 328 | return 0; 329 | 330 | if (process == 0) 331 | return 0; 332 | 333 | vm_handle_s *s = (vm_handle_s*)process; 334 | 335 | QWORD exit_called = km::call(PsGetProcessExitProcessCalled, (QWORD)s->object); 336 | return ((BOOLEAN*)&exit_called)[0] == 0; 337 | } 338 | 339 | BOOL vm::read(vm_handle process, QWORD address, PVOID buffer, QWORD length) 340 | { 341 | if (!initialize()) 342 | return 0; 343 | 344 | if (process == 0) 345 | return 0; 346 | 347 | vm_handle_s *s = (vm_handle_s*)process; 348 | 349 | QWORD total_size = length; 350 | QWORD offset = 0; 351 | QWORD bytes_read=0; 352 | QWORD physical_address; 353 | QWORD current_size; 354 | int cnt=0; 355 | 356 | while (total_size) 357 | { 358 | physical_address = pm::translate(s->cr3, address + offset); 359 | if (!physical_address) 360 | { 361 | if (total_size >= 0x1000) 362 | { 363 | bytes_read = 0x1000; 364 | } 365 | else 366 | { 367 | bytes_read = total_size; 368 | } 369 | memset((PVOID)((QWORD)buffer + offset), 0, bytes_read); 370 | goto E0; 371 | } 372 | 373 | current_size = min(0x1000 - (physical_address & 0xFFF), total_size); 374 | #ifdef MMCOPYMEMORY 375 | if (!pm::read(physical_address, (PVOID)((QWORD)buffer + offset), current_size, &bytes_read)) 376 | { 377 | break; 378 | } 379 | #else 380 | if (!pm::read(physical_address, (PVOID)((QWORD)buffer + offset), current_size)) 381 | { 382 | break; 383 | } 384 | bytes_read = current_size; 385 | #endif 386 | cnt++; 387 | E0: 388 | total_size -= bytes_read; 389 | offset += bytes_read; 390 | } 391 | return cnt != 0; 392 | } 393 | 394 | BOOL vm::write(vm_handle process, QWORD address, PVOID buffer, QWORD length) 395 | { 396 | if (!initialize()) 397 | return 0; 398 | 399 | if (process == 0) 400 | return 0; 401 | 402 | vm_handle_s *s = (vm_handle_s*)process; 403 | 404 | QWORD total_size = length; 405 | QWORD offset = 0; 406 | QWORD bytes_write=0; 407 | 408 | QWORD physical_address; 409 | QWORD current_size; 410 | int cnt=0; 411 | 412 | while (total_size) { 413 | physical_address = pm::translate(s->cr3, address + offset); 414 | if (!physical_address) { 415 | if (total_size >= 0x1000) 416 | { 417 | bytes_write = 0x1000; 418 | } 419 | else 420 | { 421 | bytes_write = total_size; 422 | } 423 | goto E0; 424 | } 425 | current_size = min(0x1000 - (physical_address & 0xFFF), total_size); 426 | if (!pm::write(physical_address, (PVOID)((QWORD)buffer + offset), current_size)) 427 | { 428 | break; 429 | } 430 | cnt++; 431 | bytes_write = current_size; 432 | E0: 433 | total_size -= bytes_write; 434 | offset += bytes_write; 435 | } 436 | return cnt != 0; 437 | } 438 | 439 | QWORD vm::get_peb(vm_handle process) 440 | { 441 | if (!initialize()) 442 | return 0; 443 | 444 | if (process == 0) 445 | return 0; 446 | 447 | vm_handle_s *s = (vm_handle_s*)process; 448 | 449 | return (QWORD)km::call(PsGetProcessPeb, (QWORD)s->object); 450 | } 451 | 452 | QWORD vm::get_wow64_process(vm_handle process) 453 | { 454 | if (!initialize()) 455 | return 0; 456 | 457 | if (process == 0) 458 | return 0; 459 | 460 | vm_handle_s *s = (vm_handle_s*)process; 461 | 462 | return (QWORD)km::call(PsGetProcessWow64Process, (QWORD)s->object); 463 | } 464 | 465 | QWORD vm::get_module(vm_handle process, PCSTR dll_name) 466 | { 467 | return vmwin::get_module(process, dll_name); 468 | } 469 | 470 | QWORD vm::get_module_export(vm_handle process, QWORD base, PCSTR export_name) 471 | { 472 | return vmwin::get_module_export(process, base, export_name); 473 | } 474 | 475 | 476 | PVOID vm::dump_module(vm_handle process, QWORD base, VM_MODULE_TYPE module_type) 477 | { 478 | return vmwin::dump_module(process, base, module_type); 479 | } 480 | 481 | void vm::free_module(PVOID dumped_module) 482 | { 483 | return vmwin::free_module(dumped_module); 484 | } 485 | 486 | QWORD vm::get_dump_export(PVOID dumped_module, PCSTR export_name) 487 | { 488 | return vmwin::get_dump_export(dumped_module, export_name); 489 | } 490 | 491 | QWORD vm::scan_pattern(PVOID dumped_module, PCSTR pattern, PCSTR mask, QWORD length) 492 | { 493 | return vmwin::scan_pattern(dumped_module, pattern, mask, length); 494 | } 495 | 496 | QWORD vm::scan_pattern_direct(vm_handle process, QWORD base, PCSTR pattern, PCSTR mask, DWORD length) 497 | { 498 | return vmwin::scan_pattern_direct(process, base, pattern, mask, length); 499 | } 500 | 501 | #ifdef MMCOPYMEMORY 502 | static BOOL pm::read(QWORD address, PVOID buffer, QWORD length, QWORD* res) 503 | { 504 | if (address < (QWORD)g_memory_range_low) 505 | { 506 | return 0; 507 | } 508 | 509 | if (address + length > g_memory_range_high) 510 | { 511 | return 0; 512 | } 513 | 514 | if (length > 0x1000) 515 | { 516 | length = 0x1000; 517 | } 518 | 519 | QWORD alloc_buffer = (QWORD)vm::allocate_memory(length); 520 | if (alloc_buffer == 0) 521 | { 522 | return 0; 523 | } 524 | 525 | QWORD bytes_read = 0; 526 | QWORD status = km::call(MmCopyMemory, (QWORD)alloc_buffer, address, length, 0x01, (QWORD)&bytes_read); 527 | if (status == 0) 528 | { 529 | km::call(kernel::memcpy, (QWORD)buffer, alloc_buffer, bytes_read); 530 | if (res) 531 | { 532 | *res = bytes_read; 533 | } 534 | } 535 | vm::free_memory(alloc_buffer); 536 | return status == 0; 537 | } 538 | #else 539 | static BOOL pm::read(QWORD address, PVOID buffer, QWORD length) 540 | { 541 | if (address < (QWORD)g_memory_range_low) 542 | { 543 | return 0; 544 | } 545 | 546 | if (address + length > g_memory_range_high) 547 | { 548 | return 0; 549 | } 550 | 551 | 552 | BOOL status = 0; 553 | ULONG page_count = (ULONG)SIZE_TO_PAGES(length); 554 | QWORD va = km::call(KdMapPhysicalMemory64, address, page_count, 1); 555 | if (va) 556 | { 557 | km::call(kernel::memcpy, (QWORD)buffer, va, length); 558 | km::call(KdUnmapVirtualAddress, va, page_count, 0); 559 | status = 1; 560 | } 561 | return status; 562 | } 563 | #endif 564 | 565 | static BOOL pm::write(QWORD address, PVOID buffer, QWORD length) 566 | { 567 | if (address < (QWORD)g_memory_range_low) 568 | { 569 | return 0; 570 | } 571 | 572 | if (address + length > g_memory_range_high) 573 | { 574 | return 0; 575 | } 576 | 577 | BOOL status = 0; 578 | ULONG page_count = (ULONG)SIZE_TO_PAGES(length); 579 | QWORD va = km::call(KdMapPhysicalMemory64, address, page_count, 1); 580 | 581 | if (va) 582 | { 583 | km::call(kernel::memcpy, va, (QWORD)buffer, length); 584 | 585 | km::call(KdUnmapVirtualAddress, va, page_count, 0); 586 | 587 | status = 1; 588 | } 589 | 590 | return status; 591 | } 592 | 593 | static QWORD pm::read_i64(QWORD address) 594 | { 595 | QWORD result = 0; 596 | #ifdef MMCOPYMEMORY 597 | if (!read(address, &result, sizeof(result), 0)) 598 | #else 599 | if (!read(address, &result, sizeof(result))) 600 | #endif 601 | { 602 | return 0; 603 | } 604 | return result; 605 | } 606 | 607 | static QWORD pm::translate(QWORD dir, QWORD va) 608 | { 609 | __int64 v2; // rax 610 | __int64 v3; // rax 611 | __int64 v5; // rax 612 | __int64 v6; // rax 613 | 614 | v2 = pm::read_i64(8 * ((va >> 39) & 0x1FF) + dir); 615 | if ( !v2 ) 616 | return 0i64; 617 | 618 | if ( (v2 & 1) == 0 ) 619 | return 0i64; 620 | 621 | v3 = pm::read_i64((v2 & 0xFFFFFFFFF000i64) + 8 * ((va >> 30) & 0x1FF)); 622 | if ( !v3 || (v3 & 1) == 0 ) 623 | return 0i64; 624 | 625 | if ( (v3 & 0x80u) != 0i64 ) 626 | return (va & 0x3FFFFFFF) + (v3 & 0xFFFFFFFFF000i64); 627 | 628 | v5 = pm::read_i64((v3 & 0xFFFFFFFFF000i64) + 8 * ((va >> 21) & 0x1FF)); 629 | if ( !v5 || (v5 & 1) == 0 ) 630 | return 0i64; 631 | 632 | if ( (v5 & 0x80u) != 0i64 ) 633 | return (va & 0x1FFFFF) + (v5 & 0xFFFFFFFFF000i64); 634 | 635 | v6 = pm::read_i64((v5 & 0xFFFFFFFFF000i64) + 8 * ((va >> 12) & 0x1FF)); 636 | if ( v6 && (v6 & 1) != 0 ) 637 | return (va & 0xFFF) + (v6 & 0xFFFFFFFFF000i64); 638 | 639 | return 0i64; 640 | } 641 | 642 | -------------------------------------------------------------------------------- /pcileech/pcileech/leechcore.h: -------------------------------------------------------------------------------- 1 | // leechcore.h : external header of the LeechCore library. 2 | // 3 | // LeechCore is a library which abstracts away reading and writing to various 4 | // software and hardware acquisition sources. Sources ranges from memory dump 5 | // files to driver backed live memory to hardware (FPGA) DMA backed memory. 6 | // 7 | // LeechCore built-in device support may be extended with external plugin 8 | // device drivers placed as .dll or .so files in the same folder as LeechCore. 9 | // 10 | // For more information please consult the LeechCore information on Github: 11 | // - README: https://github.com/ufrisk/LeechCore 12 | // - GUIDE: https://github.com/ufrisk/LeechCore/wiki 13 | // 14 | // (c) Ulf Frisk, 2020-2023 15 | // Author: Ulf Frisk, pcileech@frizk.net 16 | // 17 | // Header Version: 2.16.1 18 | // 19 | 20 | #ifndef __LEECHCORE_H__ 21 | #define __LEECHCORE_H__ 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif /* __cplusplus */ 25 | 26 | //----------------------------------------------------------------------------- 27 | // OS COMPATIBILITY BELOW: 28 | //----------------------------------------------------------------------------- 29 | 30 | #ifdef _WIN32 31 | 32 | #include 33 | #define EXPORTED_FUNCTION __declspec(dllexport) 34 | typedef unsigned __int64 QWORD, *PQWORD; 35 | 36 | #endif /* _WIN32 */ 37 | #ifdef LINUX 38 | 39 | #include 40 | #include 41 | #define EXPORTED_FUNCTION __attribute__((visibility("default"))) 42 | typedef void VOID, *PVOID, *HANDLE, **PHANDLE, *HMODULE; 43 | typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64; 44 | typedef size_t SIZE_T, *PSIZE_T; 45 | typedef uint64_t FILETIME, *PFILETIME; 46 | typedef uint32_t DWORD, *PDWORD, *LPDWORD, BOOL, *PBOOL, NTSTATUS; 47 | typedef uint16_t WORD, *PWORD; 48 | typedef uint8_t BYTE, *PBYTE, *LPBYTE, UCHAR; 49 | typedef char CHAR, *PCHAR, *LPSTR, *LPCSTR; 50 | typedef uint16_t WCHAR, *PWCHAR, *LPWSTR, *LPCWSTR; 51 | #define MAX_PATH 260 52 | #define _In_ 53 | #define _In_z_ 54 | #define _In_opt_ 55 | #define _In_reads_(x) 56 | #define _In_reads_bytes_(x) 57 | #define _In_reads_bytes_opt_(x) 58 | #define _In_reads_opt_(x) 59 | #define _Inout_ 60 | #define _Inout_bytecount_(x) 61 | #define _Inout_opt_ 62 | #define _Inout_updates_opt_(x) 63 | #define _Out_ 64 | #define _Out_opt_ 65 | #define _Out_writes_(x) 66 | #define _Out_writes_bytes_opt_(x) 67 | #define _Out_writes_opt_(x) 68 | #define _Out_writes_to_(x,y) 69 | #define _When_(x,y) 70 | #define _Frees_ptr_opt_ 71 | #define _Post_ptr_invalid_ 72 | #define _Check_return_opt_ 73 | #define _Printf_format_string_ 74 | #define _Success_(x) 75 | 76 | #endif /* LINUX */ 77 | 78 | 79 | 80 | //----------------------------------------------------------------------------- 81 | // Create and Close LeechCore devices: 82 | // It's possible to create multiple LeechCore devices in parallel and also of 83 | // different types if the underlying device will allow this. LeechCore will 84 | // automatically take care of and abstract away any hardware/software issues 85 | // with regards to the underlying devices. 86 | // 87 | // For more information about supported devices please check out the LeechCore 88 | // guide at: https://github.com/ufrisk/LeechCore/wiki 89 | //----------------------------------------------------------------------------- 90 | 91 | #define LC_CONFIG_VERSION 0xc0fd0002 92 | #define LC_CONFIG_ERRORINFO_VERSION 0xc0fe0002 93 | 94 | #define LC_CONFIG_PRINTF_ENABLED 0x01 95 | #define LC_CONFIG_PRINTF_V 0x02 96 | #define LC_CONFIG_PRINTF_VV 0x04 97 | #define LC_CONFIG_PRINTF_VVV 0x08 98 | 99 | typedef struct LC_CONFIG { 100 | // below are set by caller 101 | DWORD dwVersion; // must equal LC_CREATE_VERSION 102 | DWORD dwPrintfVerbosity; // printf verbosity according to LC_PRINTF_* 103 | CHAR szDevice[MAX_PATH]; // device configuration - see wiki for additional info. 104 | CHAR szRemote[MAX_PATH]; // remote configuration - see wiki for additional info. 105 | _Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const *const _Format, ...); 106 | // below are set by caller, updated by LeecCore 107 | QWORD paMax; // max physical address (disables any max address auto-detect). 108 | // below are set by LeechCore 109 | BOOL fVolatile; 110 | BOOL fWritable; 111 | BOOL fRemote; 112 | BOOL fRemoteDisableCompress; 113 | CHAR szDeviceName[MAX_PATH]; // device name - such as 'fpga' or 'file'. 114 | } LC_CONFIG, *PLC_CONFIG; 115 | 116 | typedef struct tdLC_CONFIG_ERRORINFO { 117 | DWORD dwVersion; // must equal LC_CONFIG_ERRORINFO_VERSION 118 | DWORD cbStruct; 119 | DWORD _FutureUse[16]; 120 | BOOL fUserInputRequest; 121 | DWORD cwszUserText; 122 | WCHAR wszUserText[]; 123 | } LC_CONFIG_ERRORINFO, *PLC_CONFIG_ERRORINFO, **PPLC_CONFIG_ERRORINFO; 124 | 125 | /* 126 | * Create a new LeechCore device according to the supplied configuration. 127 | * CALLER LcMemFree: ppLcCreateErrorInfo 128 | * -- pLcCreateConfig 129 | * -- ppLcCreateErrorInfo = ptr to receive function allocated struct with error 130 | * information upon function failure. This info may contain a user message 131 | * requesting user action as an example. Any returned struct should be 132 | * free'd by a call to LcMemFree(). 133 | * -- return 134 | */ 135 | EXPORTED_FUNCTION _Success_(return != NULL) 136 | HANDLE LcCreate( 137 | _Inout_ PLC_CONFIG pLcCreateConfig 138 | ); 139 | 140 | EXPORTED_FUNCTION _Success_(return != NULL) 141 | HANDLE LcCreateEx( 142 | _Inout_ PLC_CONFIG pLcCreateConfig, 143 | _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo 144 | ); 145 | 146 | /* 147 | * Close a LeechCore handle and free any resources no longer needed. 148 | */ 149 | EXPORTED_FUNCTION 150 | VOID LcClose( 151 | _In_opt_ _Post_ptr_invalid_ HANDLE hLC 152 | ); 153 | 154 | 155 | 156 | //----------------------------------------------------------------------------- 157 | // Read and Write memory from underlying device either using contiguous method 158 | // or more recommended scatter method. 159 | // 160 | // The MEM_SCATTER struct allows reading and writing of discontiguous memory 161 | // chunks which must adhere to the following rules: 162 | // - maximum size = 0x1000 (4096) bytes = recommended size. 163 | // - minimum size = 2 DWORDs (8 bytes). 164 | // - must be DWORD (4 byte) aligned. 165 | // - must never cross 0x1000 page boundary. 166 | // - max value of iStack = MEM_SCATTER_STACK_SIZE - 2. 167 | //----------------------------------------------------------------------------- 168 | 169 | #define MEM_SCATTER_VERSION 0xc0fe0002 170 | #define MEM_SCATTER_STACK_SIZE 12 171 | 172 | typedef struct tdMEM_SCATTER { 173 | DWORD version; // MEM_SCATTER_VERSION 174 | BOOL f; // TRUE = success data in pb, FALSE = fail or not yet read. 175 | QWORD qwA; // address of memory to read 176 | union { 177 | PBYTE pb; // buffer to hold memory contents 178 | QWORD _Filler; 179 | }; 180 | DWORD cb; // size of buffer to hold memory contents. 181 | DWORD iStack; // internal stack pointer 182 | QWORD vStack[MEM_SCATTER_STACK_SIZE]; // internal stack 183 | } MEM_SCATTER, *PMEM_SCATTER, **PPMEM_SCATTER; 184 | 185 | #define MEM_SCATTER_ADDR_INVALID ((QWORD)-1) 186 | #define MEM_SCATTER_ADDR_ISINVALID(pMEM) (pMEM->qwA == (QWORD)-1) 187 | #define MEM_SCATTER_ADDR_ISVALID(pMEM) (pMEM->qwA != (QWORD)-1) 188 | #define MEM_SCATTER_STACK_PUSH(pMEM, v) (pMEM->vStack[pMEM->iStack++] = (QWORD)(v)) 189 | #define MEM_SCATTER_STACK_PEEK(pMEM, i) (pMEM->vStack[pMEM->iStack - i]) 190 | #define MEM_SCATTER_STACK_SET(pMEM, i, v) (pMEM->vStack[pMEM->iStack - i] = (QWORD)(v)) 191 | #define MEM_SCATTER_STACK_ADD(pMEM, i, v) (pMEM->vStack[pMEM->iStack - i] += (QWORD)(v)) 192 | #define MEM_SCATTER_STACK_POP(pMEM) (pMEM->vStack[--pMEM->iStack]) 193 | 194 | /* 195 | * Free LeechCore allocated memory such as memory allocated by the 196 | * LcAllocScatter / LcCommand functions. 197 | * -- pv 198 | */ 199 | EXPORTED_FUNCTION 200 | VOID LcMemFree( 201 | _Frees_ptr_opt_ PVOID pv 202 | ); 203 | 204 | /* 205 | * Allocate and pre-initialize empty MEMs including a 0x1000 buffer for each 206 | * pMEM. The result should be freed by LcFree when its no longer needed. 207 | * -- cMEMs 208 | * -- pppMEMs = pointer to receive ppMEMs 209 | * -- return 210 | */ 211 | EXPORTED_FUNCTION _Success_(return) 212 | BOOL LcAllocScatter1( 213 | _In_ DWORD cMEMs, 214 | _Out_ PPMEM_SCATTER *pppMEMs 215 | ); 216 | 217 | /* 218 | * Allocate and pre-initialize empty MEMs excluding the 0x1000 buffer which 219 | * will be accounted towards the pbData buffer in a contiguous way. 220 | * The result should be freed by LcFree when its no longer needed. 221 | * -- cbData = size of pbData (must be cMEMs * 0x1000) 222 | * -- pbData = buffer used for MEM.pb 223 | * -- cMEMs 224 | * -- pppMEMs = pointer to receive ppMEMs 225 | * -- return 226 | */ 227 | EXPORTED_FUNCTION _Success_(return) 228 | BOOL LcAllocScatter2( 229 | _In_ DWORD cbData, 230 | _Inout_updates_opt_(cbData) PBYTE pbData, 231 | _In_ DWORD cMEMs, 232 | _Out_ PPMEM_SCATTER *pppMEMs 233 | ); 234 | 235 | /* 236 | * Allocate and pre-initialize empty MEMs excluding the 0x1000 buffer which 237 | * will be accounted towards the pbData buffer in a contiguous way. 238 | * -- pbDataFirstPage = optional buffer of first page 239 | * -- pbDataLastPage = optional buffer of last page 240 | * -- cbData = size of pbData 241 | * -- pbData = buffer used for MEM.pb except first/last if exists 242 | * -- cMEMs 243 | * -- pppMEMs = pointer to receive ppMEMs 244 | * -- return 245 | */ 246 | EXPORTED_FUNCTION _Success_(return) 247 | BOOL LcAllocScatter3( 248 | _Inout_updates_opt_(0x1000) PBYTE pbDataFirstPage, 249 | _Inout_updates_opt_(0x1000) PBYTE pbDataLastPage, 250 | _In_ DWORD cbData, 251 | _Inout_updates_opt_(cbData) PBYTE pbData, 252 | _In_ DWORD cMEMs, 253 | _Out_ PPMEM_SCATTER *pppMEMs 254 | ); 255 | 256 | /* 257 | * Read memory in a scattered non-contiguous way. This is recommended for reads. 258 | * -- hLC 259 | * -- cMEMs 260 | * -- ppMEMs 261 | */ 262 | EXPORTED_FUNCTION 263 | VOID LcReadScatter( 264 | _In_ HANDLE hLC, 265 | _In_ DWORD cMEMs, 266 | _Inout_ PPMEM_SCATTER ppMEMs 267 | ); 268 | 269 | /* 270 | * Read memory in a contiguous way. Note that if multiple memory segments are 271 | * to be read LcReadScatter() may be more efficient. 272 | * -- hLC, 273 | * -- pa 274 | * -- cb 275 | * -- pb 276 | * -- return 277 | */ 278 | EXPORTED_FUNCTION _Success_(return) 279 | BOOL LcRead( 280 | _In_ HANDLE hLC, 281 | _In_ QWORD pa, 282 | _In_ DWORD cb, 283 | _Out_writes_(cb) PBYTE pb 284 | ); 285 | 286 | /* 287 | * Write memory in a scattered non-contiguous way. 288 | * -- hLC 289 | * -- cMEMs 290 | * -- ppMEMs 291 | */ 292 | EXPORTED_FUNCTION 293 | VOID LcWriteScatter( 294 | _In_ HANDLE hLC, 295 | _In_ DWORD cMEMs, 296 | _Inout_ PPMEM_SCATTER ppMEMs 297 | ); 298 | 299 | /* 300 | * Write memory in a contiguous way. 301 | * -- hLC 302 | * -- pa 303 | * -- cb 304 | * -- pb 305 | * -- return 306 | */ 307 | EXPORTED_FUNCTION _Success_(return) 308 | BOOL LcWrite( 309 | _In_ HANDLE hLC, 310 | _In_ QWORD pa, 311 | _In_ DWORD cb, 312 | _In_reads_(cb) PBYTE pb 313 | ); 314 | 315 | 316 | 317 | //----------------------------------------------------------------------------- 318 | // Get/Set/Command functionality may be used to query and/or update LeechCore 319 | // or its devices in various ways. 320 | //----------------------------------------------------------------------------- 321 | 322 | /* 323 | * Set an option as defined by LC_OPT_*. (R option). 324 | * -- hLC 325 | * -- fOption = LC_OPT_* 326 | * -- cbData 327 | * -- pbData 328 | * -- pcbData 329 | */ 330 | EXPORTED_FUNCTION _Success_(return) 331 | BOOL LcGetOption( 332 | _In_ HANDLE hLC, 333 | _In_ QWORD fOption, 334 | _Out_ PQWORD pqwValue 335 | ); 336 | 337 | /* 338 | * Get an option as defined by LC_OPT_*. (W option). 339 | * -- hLC 340 | * -- fOption = LC_OPT_* 341 | * -- cbData 342 | * -- pbData 343 | */ 344 | EXPORTED_FUNCTION _Success_(return) 345 | BOOL LcSetOption( 346 | _In_ HANDLE hLC, 347 | _In_ QWORD fOption, 348 | _In_ QWORD qwValue 349 | ); 350 | 351 | /* 352 | * Execute a command and retrieve a result (if any) at the same time. 353 | * NB! If *ppbDataOut contains a memory allocation on exit this should be free'd 354 | * by calling LcMemFree(). 355 | * CALLER LcFreeMem: *ppbDataOut 356 | * -- hLC 357 | * -- fCommand = LC_CMD_* 358 | * -- cbDataIn 359 | * -- pbDataIn 360 | * -- ppbDataOut 361 | * -- pcbDataOut 362 | */ 363 | EXPORTED_FUNCTION _Success_(return) 364 | BOOL LcCommand( 365 | _In_ HANDLE hLC, 366 | _In_ QWORD fCommand, 367 | _In_ DWORD cbDataIn, 368 | _In_reads_opt_(cbDataIn) PBYTE pbDataIn, 369 | _Out_opt_ PBYTE *ppbDataOut, 370 | _Out_opt_ PDWORD pcbDataOut 371 | ); 372 | 373 | #define LC_OPT_CORE_PRINTF_ENABLE 0x4000000100000000 // RW 374 | #define LC_OPT_CORE_VERBOSE 0x4000000200000000 // RW 375 | #define LC_OPT_CORE_VERBOSE_EXTRA 0x4000000300000000 // RW 376 | #define LC_OPT_CORE_VERBOSE_EXTRA_TLP 0x4000000400000000 // RW 377 | #define LC_OPT_CORE_VERSION_MAJOR 0x4000000500000000 // R 378 | #define LC_OPT_CORE_VERSION_MINOR 0x4000000600000000 // R 379 | #define LC_OPT_CORE_VERSION_REVISION 0x4000000700000000 // R 380 | #define LC_OPT_CORE_ADDR_MAX 0x1000000800000000 // R 381 | #define LC_OPT_CORE_STATISTICS_CALL_COUNT 0x4000000900000000 // R [lo-dword: LC_STATISTICS_ID_*] 382 | #define LC_OPT_CORE_STATISTICS_CALL_TIME 0x4000000a00000000 // R [lo-dword: LC_STATISTICS_ID_*] 383 | #define LC_OPT_CORE_VOLATILE 0x1000000b00000000 // R 384 | #define LC_OPT_CORE_READONLY 0x1000000c00000000 // R 385 | 386 | #define LC_OPT_MEMORYINFO_VALID 0x0200000100000000 // R 387 | #define LC_OPT_MEMORYINFO_FLAG_32BIT 0x0200000300000000 // R 388 | #define LC_OPT_MEMORYINFO_FLAG_PAE 0x0200000400000000 // R 389 | #define LC_OPT_MEMORYINFO_ARCH 0x0200001200000000 // R - LC_ARCH_TP 390 | #define LC_OPT_MEMORYINFO_OS_VERSION_MINOR 0x0200000500000000 // R 391 | #define LC_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x0200000600000000 // R 392 | #define LC_OPT_MEMORYINFO_OS_DTB 0x0200000700000000 // R 393 | #define LC_OPT_MEMORYINFO_OS_PFN 0x0200000800000000 // R 394 | #define LC_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x0200000900000000 // R 395 | #define LC_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a00000000 // R 396 | #define LC_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b00000000 // R 397 | #define LC_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c00000000 // R 398 | #define LC_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d00000000 // R 399 | #define LC_OPT_MEMORYINFO_OS_UPTIME 0x0200000e00000000 // R 400 | #define LC_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f00000000 // R 401 | #define LC_OPT_MEMORYINFO_OS_KERNELHINT 0x0200001000000000 // R 402 | #define LC_OPT_MEMORYINFO_OS_KdDebuggerDataBlock 0x0200001100000000 // R 403 | 404 | #define LC_OPT_FPGA_PROBE_MAXPAGES 0x0300000100000000 // RW 405 | #define LC_OPT_FPGA_MAX_SIZE_RX 0x0300000300000000 // RW 406 | #define LC_OPT_FPGA_MAX_SIZE_TX 0x0300000400000000 // RW 407 | #define LC_OPT_FPGA_DELAY_PROBE_READ 0x0300000500000000 // RW - uS 408 | #define LC_OPT_FPGA_DELAY_PROBE_WRITE 0x0300000600000000 // RW - uS 409 | #define LC_OPT_FPGA_DELAY_WRITE 0x0300000700000000 // RW - uS 410 | #define LC_OPT_FPGA_DELAY_READ 0x0300000800000000 // RW - uS 411 | #define LC_OPT_FPGA_RETRY_ON_ERROR 0x0300000900000000 // RW 412 | #define LC_OPT_FPGA_DEVICE_ID 0x0300008000000000 // RW - bus:dev:fn (ex: 04:00.0 == 0x0400). 413 | #define LC_OPT_FPGA_FPGA_ID 0x0300008100000000 // R 414 | #define LC_OPT_FPGA_VERSION_MAJOR 0x0300008200000000 // R 415 | #define LC_OPT_FPGA_VERSION_MINOR 0x0300008300000000 // R 416 | #define LC_OPT_FPGA_ALGO_TINY 0x0300008400000000 // RW - 1/0 use tiny 128-byte/tlp read algorithm. 417 | #define LC_OPT_FPGA_ALGO_SYNCHRONOUS 0x0300008500000000 // RW - 1/0 use synchronous (old) read algorithm. 418 | #define LC_OPT_FPGA_CFGSPACE_XILINX 0x0300008600000000 // RW - [lo-dword: register address in bytes] [bytes: 0-3: data, 4-7: byte_enable(if wr/set); top bit = cfg_mgmt_wr_rw1c_as_rw] 419 | #define LC_OPT_FPGA_TLP_READ_CB_WITHINFO 0x0300009000000000 // RW - 1/0 call TLP read callback with additional string info in szInfo 420 | #define LC_OPT_FPGA_TLP_READ_CB_FILTERCPL 0x0300009100000000 // RW - 1/0 call TLP read callback with memory read completions from read calls filtered 421 | 422 | #define LC_CMD_FPGA_PCIECFGSPACE 0x0000010300000000 // R 423 | #define LC_CMD_FPGA_CFGREGPCIE 0x0000010400000000 // RW - [lo-dword: register address] 424 | #define LC_CMD_FPGA_CFGREGCFG 0x0000010500000000 // RW - [lo-dword: register address] 425 | #define LC_CMD_FPGA_CFGREGDRP 0x0000010600000000 // RW - [lo-dword: register address] 426 | #define LC_CMD_FPGA_CFGREGCFG_MARKWR 0x0000010700000000 // W - write with mask [lo-dword: register address] [bytes: 0-1: data, 2-3: mask] 427 | #define LC_CMD_FPGA_CFGREGPCIE_MARKWR 0x0000010800000000 // W - write with mask [lo-dword: register address] [bytes: 0-1: data, 2-3: mask] 428 | #define LC_CMD_FPGA_CFGREG_DEBUGPRINT 0x0000010a00000000 // N/A 429 | #define LC_CMD_FPGA_PROBE 0x0000010b00000000 // RW 430 | #define LC_CMD_FPGA_CFGSPACE_SHADOW_RD 0x0000010c00000000 // R 431 | #define LC_CMD_FPGA_CFGSPACE_SHADOW_WR 0x0000010d00000000 // W - [lo-dword: config space write base address] 432 | #define LC_CMD_FPGA_TLP_WRITE_SINGLE 0x0000011000000000 // W - write single tlp BYTE:s 433 | #define LC_CMD_FPGA_TLP_WRITE_MULTIPLE 0x0000011100000000 // W - write multiple LC_TLP:s 434 | #define LC_CMD_FPGA_TLP_TOSTRING 0x0000011200000000 // RW - convert single TLP to LPSTR; *pcbDataOut includes NULL terminator. 435 | 436 | #define LC_CMD_FPGA_TLP_CONTEXT 0x2000011400000000 // W - set/unset TLP user-defined context to be passed to callback function. (pbDataIn == LPVOID user context). [not remote]. 437 | #define LC_CMD_FPGA_TLP_CONTEXT_RD 0x2000011b00000000 // R - get TLP user-defined context to be passed to callback function. [not remote]. 438 | #define LC_CMD_FPGA_TLP_FUNCTION_CALLBACK 0x2000011500000000 // W - set/unset TLP callback function (pbDataIn == PLC_TLP_CALLBACK). [not remote]. 439 | #define LC_CMD_FPGA_TLP_FUNCTION_CALLBACK_RD 0x2000011c00000000 // R - get TLP callback function. [not remote]. 440 | #define LC_CMD_FPGA_BAR_CONTEXT 0x2000012000000000 // W - set/unset BAR user-defined context to be passed to callback function. (pbDataIn == LPVOID user context). [not remote]. 441 | #define LC_CMD_FPGA_BAR_CONTEXT_RD 0x2000012100000000 // R - get BAR user-defined context to be passed to callback function. [not remote]. 442 | #define LC_CMD_FPGA_BAR_FUNCTION_CALLBACK 0x2000012200000000 // W - set/unset BAR callback function (pbDataIn == PLC_BAR_CALLBACK). [not remote]. 443 | #define LC_CMD_FPGA_BAR_FUNCTION_CALLBACK_RD 0x2000012300000000 // R - get BAR callback function. [not remote]. 444 | #define LC_CMD_FPGA_BAR_INFO 0x0000012400000000 // R - get BAR info (pbDataOut == LC_BAR_INFO[6]). 445 | 446 | #define LC_CMD_FILE_DUMPHEADER_GET 0x0000020100000000 // R 447 | 448 | #define LC_CMD_STATISTICS_GET 0x4000010000000000 // R 449 | #define LC_CMD_MEMMAP_GET 0x4000020000000000 // R - MEMMAP as LPSTR 450 | #define LC_CMD_MEMMAP_SET 0x4000030000000000 // W - MEMMAP as LPSTR 451 | #define LC_CMD_MEMMAP_GET_STRUCT 0x4000040000000000 // R - MEMMAP as LC_MEMMAP_ENTRY[] 452 | #define LC_CMD_MEMMAP_SET_STRUCT 0x4000050000000000 // W - MEMMAP as LC_MEMMAP_ENTRY[] 453 | 454 | #define LC_CMD_AGENT_EXEC_PYTHON 0x8000000100000000 // RW - [lo-dword: optional timeout in ms] 455 | #define LC_CMD_AGENT_EXIT_PROCESS 0x8000000200000000 // - [lo-dword: process exit code] 456 | #define LC_CMD_AGENT_VFS_LIST 0x8000000300000000 // RW 457 | #define LC_CMD_AGENT_VFS_READ 0x8000000400000000 // RW 458 | #define LC_CMD_AGENT_VFS_WRITE 0x8000000500000000 // RW 459 | #define LC_CMD_AGENT_VFS_OPT_GET 0x8000000600000000 // RW 460 | #define LC_CMD_AGENT_VFS_OPT_SET 0x8000000700000000 // RW 461 | #define LC_CMD_AGENT_VFS_INITIALIZE 0x8000000800000000 // RW 462 | #define LC_CMD_AGENT_VFS_CONSOLE 0x8000000900000000 // RW 463 | 464 | #define LC_CMD_AGENT_VFS_REQ_VERSION 0xfeed0001 465 | #define LC_CMD_AGENT_VFS_RSP_VERSION 0xfeee0001 466 | 467 | #define LC_STATISTICS_VERSION 0xe1a10002 468 | #define LC_STATISTICS_ID_OPEN 0x00 469 | #define LC_STATISTICS_ID_READ 0x01 470 | #define LC_STATISTICS_ID_READSCATTER 0x02 471 | #define LC_STATISTICS_ID_WRITE 0x03 472 | #define LC_STATISTICS_ID_WRITESCATTER 0x04 473 | #define LC_STATISTICS_ID_GETOPTION 0x05 474 | #define LC_STATISTICS_ID_SETOPTION 0x06 475 | #define LC_STATISTICS_ID_COMMAND 0x07 476 | #define LC_STATISTICS_ID_MAX 0x07 477 | 478 | typedef struct tdLC_CMD_AGENT_VFS_REQ { 479 | DWORD dwVersion; 480 | DWORD _FutureUse; 481 | CHAR uszPathFile[2*MAX_PATH]; // file path to list/read/write 482 | union { 483 | QWORD qwOffset; // offset to read/write 484 | QWORD fOption; // option to get/set (qword data in *pb) 485 | }; 486 | DWORD dwLength; // length to read 487 | DWORD cb; 488 | BYTE pb[0]; 489 | } LC_CMD_AGENT_VFS_REQ, *PLC_CMD_AGENT_VFS_REQ; 490 | 491 | typedef struct tdLC_CMD_AGENT_VFS_RSP { 492 | DWORD dwVersion; 493 | DWORD dwStatus; // ntstatus of read/write 494 | DWORD cbReadWrite; // number of bytes read/written 495 | DWORD _FutureUse[2]; 496 | DWORD cb; 497 | BYTE pb[0]; 498 | } LC_CMD_AGENT_VFS_RSP, *PLC_CMD_AGENT_VFS_RSP; 499 | 500 | static LPCSTR LC_STATISTICS_NAME[] = { 501 | "LcOpen", 502 | "LcRead", 503 | "LcReadScatter", 504 | "LcWrite", 505 | "LcWriteScatter", 506 | "LcGetOption", 507 | "LcSetOption", 508 | "LcCommand", 509 | }; 510 | 511 | typedef struct tdLC_STATISTICS { 512 | DWORD dwVersion; 513 | DWORD _Reserved; 514 | QWORD qwFreq; 515 | struct { 516 | QWORD c; 517 | QWORD tm; // total time in qwFreq ticks 518 | } Call[LC_STATISTICS_ID_MAX + 1]; 519 | } LC_STATISTICS, *PLC_STATISTICS; 520 | 521 | typedef struct tdLC_MEMMAP_ENTRY { 522 | QWORD pa; 523 | QWORD cb; 524 | QWORD paRemap; 525 | } LC_MEMMAP_ENTRY, *PLC_MEMMAP_ENTRY; 526 | 527 | typedef enum tdLC_ARCH_TP { 528 | LC_ARCH_NA = 0, 529 | LC_ARCH_X86 = 1, 530 | LC_ARCH_X86PAE = 2, 531 | LC_ARCH_X64 = 3, 532 | LC_ARCH_ARM64 = 4, 533 | } LC_ARCH_TP; 534 | 535 | 536 | 537 | //----------------------------------------------------------------------------- 538 | // RAW TLP READ/WRITE SUPPORT: 539 | //----------------------------------------------------------------------------- 540 | 541 | /* 542 | * TLP structure to be used with LC_CMD_FPGA_TLP_WRITE_MULTIPLE. 543 | */ 544 | typedef struct tdLC_TLP { 545 | DWORD cb; 546 | DWORD _Reserved1; 547 | PBYTE pb; 548 | } LC_TLP, *PLC_TLP; 549 | 550 | /* 551 | * Custom FPGA callback function called when a TLP is received. 552 | * Callback function set by command LC_CMD_FPGA_TLP_FUNCTION_CALLBACK. 553 | * User-defined context is set by command: LC_CMD_FPGA_TLP_CONTEXT. 554 | */ 555 | typedef VOID(*PLC_TLP_FUNCTION_CALLBACK)( 556 | _In_opt_ PVOID ctx, 557 | _In_ DWORD cbTlp, 558 | _In_ PBYTE pbTlp, 559 | _In_opt_ DWORD cbInfo, 560 | _In_opt_ LPSTR szInfo 561 | ); 562 | 563 | #define LC_TLP_FUNCTION_CALLBACK_DISABLE (PLC_TLP_FUNCTION_CALLBACK)(NULL) 564 | #define LC_TLP_FUNCTION_CALLBACK_DUMMY (PLC_TLP_FUNCTION_CALLBACK)(-1) 565 | 566 | 567 | 568 | //----------------------------------------------------------------------------- 569 | // PCIE BAR SUPPORT: 570 | //----------------------------------------------------------------------------- 571 | 572 | typedef struct tdLC_BAR { 573 | BOOL fValid; 574 | BOOL fIO; 575 | BOOL f64Bit; 576 | BOOL fPrefetchable; 577 | DWORD _Filler[3]; 578 | DWORD iBar; 579 | QWORD pa; 580 | QWORD cb; 581 | } LC_BAR, *PLC_BAR; 582 | 583 | typedef struct tdLC_BAR_REQUEST { 584 | PVOID ctx; // user context (set by command LC_CMD_FPGA_BAR_CONTEXT) 585 | PLC_BAR pBar; // BAR info 586 | BYTE bTag; // TLP tag (0-255) 587 | BYTE bFirstBE; // First byte enable (0-3) [relevant for writes] 588 | BYTE bLastBE; // Last byte enable (0-3) [relevant for writes] 589 | BYTE _Filler; 590 | BOOL f64; // 64-bit bar access (false = 32-bit) 591 | BOOL fRead; // BAR read request, called function should update pbData with read data and set fReadReply = TRUE on success. 592 | BOOL fReadReply; // Read success - should be updated by called function upon read success (after updating pbData). 593 | BOOL fWrite; // BAR write request (no reply should be sent, check byte-enables bFirstBE/bLastBE) 594 | DWORD cbData; // number of bytes to read/write 595 | QWORD oData; // data offset in BAR. 596 | BYTE pbData[4096]; // bytes to write or read data (to be updated by called function). 597 | } LC_BAR_REQUEST, *PLC_BAR_REQUEST; 598 | 599 | /* 600 | * Custom FPGA callback function to be called when BAR read/write is received. 601 | * Callback function set by command LC_CMD_FPGA_BAR_FUNCTION_CALLBACK. 602 | * User-defined context is set by command: LC_CMD_FPGA_BAR_CONTEXT. 603 | * Read reply is sent by updating pbData with read data and fReadReply = TRUE. 604 | * To return Unsupported Request (UR) set fReadReply = FALSE on a MRd request. 605 | */ 606 | typedef VOID(*PLC_BAR_FUNCTION_CALLBACK)(_Inout_ PLC_BAR_REQUEST pBarRequest); 607 | 608 | #define LC_BAR_FUNCTION_CALLBACK_DISABLE (PLC_BAR_FUNCTION_CALLBACK)(NULL) 609 | #define LC_BAR_FUNCTION_CALLBACK_ZEROBAR (PLC_BAR_FUNCTION_CALLBACK)(-1) 610 | 611 | 612 | #ifdef __cplusplus 613 | } 614 | #endif /* __cplusplus */ 615 | #endif /* __LEECHCORE_H__ */ 616 | --------------------------------------------------------------------------------