└── client ├── client.sln └── client ├── client.vcxproj ├── client.vcxproj.filters ├── client.vcxproj.user ├── driver.cpp ├── driver.hpp ├── encryption.hpp ├── main.cpp ├── nt.hpp ├── portable_executable.cpp ├── portable_executable.hpp ├── process.cpp ├── process.hpp ├── utils.cpp └── utils.hpp /client/client.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28803.202 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{99882DD6-DF3E-4415-BFCA-83A5395BC465}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Debug|x64.ActiveCfg = Debug|x64 17 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Debug|x64.Build.0 = Debug|x64 18 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Debug|x86.ActiveCfg = Debug|Win32 19 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Debug|x86.Build.0 = Debug|Win32 20 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Release|x64.ActiveCfg = Release|x64 21 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Release|x64.Build.0 = Release|x64 22 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Release|x86.ActiveCfg = Release|Win32 23 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A5EBC2E1-E5A7-4D64-832E-0C547027322D} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /client/client/client.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {99882DD6-DF3E-4415-BFCA-83A5395BC465} 24 | client 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v142 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v142 51 | true 52 | MultiByte 53 | false 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | ..\..\drvout 75 | 76 | 77 | 78 | Level4 79 | Disabled 80 | true 81 | true 82 | true 83 | stdcpp17 84 | 85 | 86 | Console 87 | 88 | 89 | 90 | 91 | Level4 92 | Disabled 93 | true 94 | true 95 | true 96 | stdcpp17 97 | 98 | 99 | Console 100 | 101 | 102 | 103 | 104 | Level3 105 | MaxSpeed 106 | true 107 | true 108 | true 109 | true 110 | 111 | 112 | Console 113 | true 114 | true 115 | 116 | 117 | 118 | 119 | Level4 120 | MaxSpeed 121 | true 122 | true 123 | true 124 | true 125 | true 126 | stdcpp17 127 | 128 | 129 | Console 130 | true 131 | true 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /client/client/client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | -------------------------------------------------------------------------------- /client/client/client.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /client/client/driver.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.hpp" 2 | 3 | NTSTATUS driver::CallDriverControl(PIO_BUFFER io_buffer) 4 | { 5 | using NtUserGetAutoRotationStateFn = bool(__stdcall*)(PIO_BUFFER); 6 | const auto NtUserGetAutoRotationState = reinterpret_cast(GetProcAddress(LoadLibrary(encryption::XorString("win32u.dll")), encryption::XorString("NtUserGetAutoRotationState"))); 7 | 8 | NtUserGetAutoRotationState(io_buffer); 9 | 10 | if (!NT_SUCCESS(io_buffer->status)) 11 | return STATUS_UNSUCCESSFUL; 12 | 13 | return io_buffer->driver_operation_status; 14 | } 15 | 16 | bool driver::ReadMemory(uint32_t process_id, uint64_t address, void* buffer, size_t size) 17 | { 18 | IO_BUFFER io_buffer = { 0 }; 19 | 20 | io_buffer.driver_operation = COPY_MEMORY; 21 | io_buffer.ul1 = process_id; // source process id 22 | io_buffer.ull1 = address; // source address 23 | io_buffer.ul2 = GetCurrentProcessId(); // target process id 24 | io_buffer.ull2 = reinterpret_cast(buffer); // target address 25 | io_buffer.size = size; 26 | 27 | return NT_SUCCESS(CallDriverControl(&io_buffer)); 28 | } 29 | 30 | bool driver::WriteMemory(uint32_t process_id, uint64_t address, void* buffer, size_t size) 31 | { 32 | IO_BUFFER io_buffer = { 0 }; 33 | 34 | io_buffer.driver_operation = COPY_MEMORY; 35 | io_buffer.ul1 = GetCurrentProcessId(); // source process id 36 | io_buffer.ull1 = reinterpret_cast(buffer); // source address 37 | io_buffer.ul2 = process_id; // target process id 38 | io_buffer.ull2 = address; // target address 39 | io_buffer.size = size; 40 | 41 | return NT_SUCCESS(CallDriverControl(&io_buffer)); 42 | } 43 | 44 | uint64_t driver::AllocateMemory(uint32_t process_id, size_t size, uint32_t protect) 45 | { 46 | IO_BUFFER io_buffer = { 0 }; 47 | 48 | io_buffer.driver_operation = ALLOCATE_MEMORY; 49 | io_buffer.ul1 = process_id; 50 | io_buffer.size = size; 51 | io_buffer.ul2 = protect; 52 | 53 | if (!NT_SUCCESS(CallDriverControl(&io_buffer))) 54 | return 0; 55 | 56 | return io_buffer.result; 57 | } 58 | 59 | bool driver::FreeMemory(uint32_t process_id, uint64_t address) 60 | { 61 | IO_BUFFER io_buffer = { 0 }; 62 | 63 | io_buffer.driver_operation = FREE_MEMORY; 64 | io_buffer.ul1 = process_id; 65 | io_buffer.ull1 = address; 66 | 67 | return NT_SUCCESS(CallDriverControl(&io_buffer)); 68 | } 69 | 70 | bool driver::ChangeMemoryProtection(uint32_t process_id, uint64_t address, size_t size, uint32_t new_protection, uint32_t* old_protection) 71 | { 72 | IO_BUFFER io_buffer = { 0 }; 73 | 74 | io_buffer.driver_operation = PROTECT_MEMORY; 75 | io_buffer.ul1 = process_id; 76 | io_buffer.ull1 = address; 77 | io_buffer.size = size; 78 | io_buffer.ul2 = new_protection; 79 | 80 | if (!NT_SUCCESS(CallDriverControl(&io_buffer))) 81 | return false; 82 | 83 | *old_protection = io_buffer.result; 84 | return true; 85 | } 86 | 87 | uint64_t driver::GetPebBase(uint32_t process_id) 88 | { 89 | IO_BUFFER io_buffer = { 0 }; 90 | 91 | io_buffer.driver_operation = GET_PROCESS_PEB_BASE; 92 | io_buffer.ul1 = process_id; 93 | 94 | if (!NT_SUCCESS(CallDriverControl(&io_buffer))) 95 | return 0; 96 | 97 | return io_buffer.result; 98 | } -------------------------------------------------------------------------------- /client/client/driver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma warning( disable : 4244 ) 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "nt.hpp" 11 | #include "encryption.hpp" 12 | #include "utils.hpp" 13 | #pragma comment(lib, "user32.lib") 14 | 15 | namespace driver 16 | { 17 | enum DRIVER_OPERATION 18 | { 19 | IDLE, 20 | COPY_MEMORY, 21 | ALLOCATE_MEMORY, 22 | FREE_MEMORY, 23 | PROTECT_MEMORY, 24 | GET_PROCESS_PEB_BASE 25 | }; 26 | 27 | 28 | typedef struct _IO_BUFFER 29 | { 30 | NTSTATUS status; 31 | NTSTATUS driver_operation_status; 32 | DRIVER_OPERATION driver_operation; 33 | uint64_t result; 34 | uint32_t ul1; 35 | uint32_t ul2; 36 | uint64_t ull1; 37 | uint64_t ull2; 38 | SIZE_T size; 39 | }IO_BUFFER, * PIO_BUFFER; 40 | 41 | NTSTATUS CallDriverControl(PIO_BUFFER io_buffer); 42 | 43 | bool ReadMemory(uint32_t process_id, uint64_t address, void* buffer, size_t size); 44 | bool WriteMemory(uint32_t process_id, uint64_t address, void* buffer, size_t size); 45 | uint64_t AllocateMemory(uint32_t process_id, size_t size, uint32_t protect); 46 | bool FreeMemory(uint32_t process_id, uint64_t address); 47 | bool ChangeMemoryProtection(uint32_t process_id, uint64_t address, size_t size, uint32_t new_protection, uint32_t* old_protection); 48 | uint64_t GetPebBase(uint32_t process_id); 49 | } -------------------------------------------------------------------------------- /client/client/encryption.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma warning( disable : 4172 ) 3 | #include 4 | 5 | // Credits: kwezee 6 | 7 | namespace encryption 8 | { 9 | template< class _t, const size_t _s, const _t _k = 'L' > 10 | class xstr { 11 | std::array< _t, _s > buffer; 12 | 13 | constexpr auto enc(const _t ch) const noexcept -> _t { 14 | return ch ^ _k; 15 | } 16 | 17 | auto dec(const _t ch) const noexcept -> _t { 18 | return ch ^ _k; 19 | } 20 | 21 | public: 22 | auto data() noexcept { 23 | for (auto i = _s; i--; ) { 24 | buffer[i] = dec(buffer[i]); 25 | } 26 | 27 | return buffer.data(); 28 | } 29 | 30 | template< size_t... _i > 31 | constexpr __forceinline xstr(const _t(&s)[_s], std::index_sequence< _i... >) noexcept 32 | : buffer{ enc(s[_i])... } {} 33 | }; 34 | 35 | template< class _t, size_t _s > 36 | constexpr __forceinline auto XorString(const _t(&s)[_s]) { 37 | return xstr< _t, _s >{ s, std::make_index_sequence< _s >() }.data(); 38 | } 39 | } -------------------------------------------------------------------------------- /client/client/main.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.hpp" 2 | #include "utils.hpp" 3 | #include "encryption.hpp" 4 | #include 5 | #include "process.hpp" 6 | #include 7 | 8 | int main() 9 | { 10 | Process process; 11 | std::string cmd_line; 12 | 13 | while (std::getline(std::cin, cmd_line)) 14 | { 15 | std::istringstream iss(cmd_line); 16 | std::vectorargs(std::istream_iterator{ iss }, std::istream_iterator()); 17 | 18 | if (args.empty()) 19 | continue; 20 | 21 | const std::string command = args[0]; 22 | 23 | if (!command.compare("a")) 24 | { 25 | // ATTACH TO A PROCESS 26 | 27 | if (args.size() != 2) 28 | { 29 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 30 | continue; 31 | } 32 | 33 | const std::string attach_arg = args[1]; 34 | /* 35 | if (std::experimental::filesystem::path(attach_arg).has_extension()) 36 | { 37 | const std::string process_name = attach_arg; 38 | process.Attach(process_name); 39 | } 40 | else 41 | { 42 | const std::uint32_t pid = std::stoul(attach_arg); 43 | process.Attach(pid); 44 | } 45 | */ 46 | 47 | const std::string process_name = attach_arg; 48 | process.Attach(process_name); 49 | } 50 | else if (!command.compare("d")) 51 | { 52 | // DETACH FROM A PROCESS 53 | 54 | process.Deattach(); 55 | } 56 | else if (!command.compare("db")) 57 | { 58 | // READ N BYTES 59 | 60 | if (args.size() != 3) 61 | { 62 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 63 | continue; 64 | } 65 | 66 | const uint64_t address = std::stoull(args[1], nullptr, 16); 67 | const size_t size = std::stoull(args[2]); 68 | 69 | size_t aligned_size = 0; 70 | 71 | if (!(size % 16)) 72 | aligned_size = size; 73 | else 74 | aligned_size = (size / 16) * 16 + 16; 75 | 76 | auto buffer = new uint8_t[aligned_size]; 77 | 78 | if (!process.ReadMemory(address, buffer, aligned_size)) 79 | { 80 | std::cout << encryption::XorString("[-] failed to read address 0x") << reinterpret_cast(address) << std::endl; 81 | delete[] buffer; 82 | continue; 83 | } 84 | 85 | for (auto i = 0u; i <= aligned_size - 16; i += 16) 86 | { 87 | std::cout << std::setw(16) << std::setfill('0') << std::hex << address + i << '\t'; 88 | 89 | for (auto j = 0u; j < 16; ++j) 90 | { 91 | std::cout << std::setw(2) << std::setfill('0') << std::hex << uint32_t(buffer[i + j]) << ' '; 92 | } 93 | 94 | std::cout << '\t'; 95 | 96 | for (auto k = 0u; k < 16; ++k) 97 | { 98 | if (isprint(buffer[i + k])) 99 | { 100 | std::cout << std::dec << buffer[i + k]; 101 | } 102 | else 103 | { 104 | std::cout << std::dec << '.'; 105 | } 106 | } 107 | 108 | std::cout << std::endl; 109 | } 110 | 111 | delete[] buffer; 112 | } 113 | else if (!command.compare("dc")) 114 | { 115 | // READ N DWORD ADDRESSES 116 | 117 | if (args.size() != 3) 118 | { 119 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 120 | continue; 121 | } 122 | 123 | const uint64_t address = std::stoull(args[1], nullptr, 16); 124 | const size_t count = std::stoull(args[2]); 125 | 126 | const size_t size = count * 4; 127 | size_t aligned_size = 0; 128 | 129 | if (!(size % 16)) 130 | aligned_size = size; 131 | else 132 | aligned_size = (size / 16) * 16 + 16; 133 | 134 | auto buffer = new uint8_t[aligned_size]; 135 | 136 | if (!process.ReadMemory(address, buffer, aligned_size)) 137 | { 138 | std::cout << encryption::XorString("[-] failed to read address 0x") << reinterpret_cast(address) << std::endl; 139 | delete[] buffer; 140 | continue; 141 | } 142 | 143 | for (auto i = 0u; i <= aligned_size - 16; i += 16) 144 | { 145 | std::cout << std::setw(16) << std::setfill('0') << std::hex << address + i << '\t'; 146 | 147 | for (auto j = 0u; j < 16; j += 4) 148 | { 149 | std::cout << std::setw(8) << std::setfill('0') << std::hex << *reinterpret_cast(reinterpret_cast(buffer) + i + j) << ' '; 150 | } 151 | 152 | std::cout << std::dec << std::endl; 153 | } 154 | 155 | delete[] buffer; 156 | } 157 | else if (!command.compare("dq")) 158 | { 159 | // READ N DWORD ADDRESSES 160 | 161 | if (args.size() != 3) 162 | { 163 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 164 | continue; 165 | } 166 | 167 | const uint64_t address = std::stoull(args[1], nullptr, 16); 168 | const size_t count = std::stoull(args[2]); 169 | 170 | const size_t size = count * 8; 171 | size_t aligned_size = 0; 172 | 173 | if (!(size % 16)) 174 | aligned_size = size; 175 | else 176 | aligned_size = (size / 16) * 16 + 16; 177 | 178 | auto buffer = new uint8_t[aligned_size]; 179 | 180 | if(!process.ReadMemory(address, buffer, aligned_size)) 181 | { 182 | std::cout << encryption::XorString("[-] failed to read address 0x") << reinterpret_cast(address) << std::endl; 183 | delete[] buffer; 184 | continue; 185 | } 186 | 187 | for (auto i = 0u; i <= aligned_size - 16; i += 16) 188 | { 189 | std::cout << std::setw(16) << std::setfill('0') << std::hex << address + i << '\t'; 190 | 191 | for (auto j = 0u; j < 16; j += 8) 192 | { 193 | std::cout << std::setw(16) << std::setfill('0') << std::hex << *reinterpret_cast(reinterpret_cast(buffer) + i + j) << ' '; 194 | } 195 | 196 | std::cout << std::dec << std::endl; 197 | } 198 | 199 | delete[] buffer; 200 | } 201 | else if (!command.compare("eb")) 202 | { 203 | // WRITE BYTE 204 | 205 | if (args.size() != 3) 206 | { 207 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 208 | continue; 209 | } 210 | 211 | const uint64_t address = std::stoull(args[1], nullptr, 16); 212 | uint8_t val = std::stoul(args[2], nullptr, 16); 213 | 214 | uint32_t new_protection = PAGE_EXECUTE_READWRITE, old_protection = 0; 215 | 216 | if (!process.ChangeMemoryProtection(address, sizeof(val), new_protection, &old_protection)) 217 | { 218 | std::cout << encryption::XorString("[-] failed to change memory protection of address 0x") << reinterpret_cast(address) << std::endl; 219 | continue; 220 | } 221 | 222 | if (!process.WriteMemory(address, &val, sizeof(val))) 223 | { 224 | std::cout << encryption::XorString("[-] failed to write to address 0x") << reinterpret_cast(address) << std::endl; 225 | continue; 226 | } 227 | 228 | process.ChangeMemoryProtection(address, sizeof(val), old_protection, &new_protection); 229 | } 230 | else if (!command.compare("ed")) 231 | { 232 | // WRITE DWORD 233 | 234 | if (args.size() != 3) 235 | { 236 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 237 | continue; 238 | } 239 | 240 | const uint64_t address = std::stoull(args[1], nullptr, 16); 241 | uint32_t val = std::stoul(args[2], nullptr, 16); 242 | 243 | uint32_t new_protection = PAGE_EXECUTE_READWRITE, old_protection = 0; 244 | 245 | if (!process.ChangeMemoryProtection(address, sizeof(val), new_protection, &old_protection)) 246 | { 247 | std::cout << encryption::XorString("[-] failed to change memory protection of address 0x") << reinterpret_cast(address) << std::endl; 248 | continue; 249 | } 250 | 251 | if (!process.WriteMemory(address, &val, sizeof(val))) 252 | { 253 | std::cout << encryption::XorString("[-] failed to write to address 0x") << reinterpret_cast(address) << std::endl; 254 | continue; 255 | } 256 | 257 | process.ChangeMemoryProtection(address, sizeof(val), old_protection, &new_protection); 258 | } 259 | else if (!command.compare("eq")) 260 | { 261 | // WRITE QWORD 262 | 263 | if (args.size() != 3) 264 | { 265 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 266 | continue; 267 | } 268 | 269 | const uint64_t address = std::stoull(args[1], nullptr, 16); 270 | uint64_t val = std::stoull(args[2], nullptr, 16); 271 | 272 | uint32_t new_protection = PAGE_EXECUTE_READWRITE, old_protection = 0; 273 | 274 | if(!process.ChangeMemoryProtection(address, sizeof(val), new_protection, &old_protection)) 275 | { 276 | std::cout << encryption::XorString("[-] failed to change memory protection of address 0x") << reinterpret_cast(address) << std::endl; 277 | continue; 278 | } 279 | 280 | if(!process.WriteMemory(address, &val, sizeof(val))) 281 | { 282 | std::cout << encryption::XorString("[-] failed to write to address 0x") << reinterpret_cast(address) << std::endl; 283 | continue; 284 | } 285 | 286 | process.ChangeMemoryProtection(address, sizeof(val), old_protection, &new_protection); 287 | } 288 | else if (!command.compare("b")) 289 | { 290 | // GET IMAGE BASE 291 | 292 | std::cout << std::setw(16) << std::setfill('0') << std::hex << process.GetImageBase() << std::endl; 293 | } 294 | else if (!command.compare("lm")) 295 | { 296 | // GET LOADED MODULES 297 | 298 | for (const auto& [module_name, base] : process.GetLoadedModules()) 299 | { 300 | std::cout << std::setw(16) << std::setfill('0') << std::hex << base << '\t' << std::dec << module_name << std::endl; 301 | } 302 | } 303 | else if (!command.compare("mb")) 304 | { 305 | // GET MODULE BASE 306 | 307 | if (args.size() != 2) 308 | { 309 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 310 | continue; 311 | } 312 | 313 | const std::string module_name = args[1]; 314 | const auto module_base = process.GetModuleBase(module_name); 315 | 316 | if (!module_base) 317 | { 318 | std::cout << encryption::XorString("[-] failed to get module base of ") << module_name << std::endl; 319 | continue; 320 | } 321 | 322 | std::cout << std::setw(16) << std::setfill('0') << std::hex << process.GetModuleBase(module_name) << std::dec << std::endl; 323 | } 324 | else if (!command.compare("me")) 325 | { 326 | // GET MODULE EXPORT 327 | 328 | if (args.size() != 3) 329 | { 330 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 331 | continue; 332 | } 333 | 334 | const std::string export_name = args[2]; 335 | uint64_t module_base = 0; 336 | 337 | if (std::experimental::filesystem::path(args[1]).has_extension()) 338 | { 339 | module_base = process.GetModuleBase(args[1]); 340 | 341 | if (!module_base) 342 | { 343 | std::cout << encryption::XorString("[-] failed to get module base of ") << args[1] << std::endl; 344 | continue; 345 | } 346 | } 347 | else 348 | { 349 | module_base = std::stoull(args[1], nullptr, 16); 350 | } 351 | 352 | const uint64_t module_export = process.GetModuleExport(module_base, export_name); 353 | 354 | if (!module_export) 355 | { 356 | std::cout << encryption::XorString("[-] failed to get module base of ") << export_name << ' ' << args[1] << std::endl; 357 | continue; 358 | } 359 | 360 | std::cout << std::setw(16) << std::setfill('0') << std::hex << module_export << std::dec << std::endl; 361 | } 362 | else if (!command.compare("mm")) 363 | { 364 | // MANUAL MAP 365 | 366 | if (args.size() != 2) 367 | { 368 | std::cout << encryption::XorString("[-] invalid usage") << std::endl; 369 | continue; 370 | } 371 | 372 | const std::string path = args[1]; 373 | 374 | if (!process.MapModule(path)) 375 | { 376 | std::cout << encryption::XorString("[-] failed to manual map ") << path << std::endl; 377 | } 378 | } 379 | else 380 | { 381 | std::cout << encryption::XorString("[-] unknown command \"") << command << '\"' << std::endl; 382 | } 383 | } 384 | 385 | } 386 | -------------------------------------------------------------------------------- /client/client/nt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #pragma comment(lib, "ntdll.lib") 5 | 6 | #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) 7 | 8 | namespace nt 9 | { 10 | constexpr auto STATUS_SUCCESS = 0; 11 | 12 | constexpr auto SE_DEBUG_PRIVILEGE = 20; 13 | constexpr auto STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; 14 | 15 | constexpr auto SystemModuleInformation = 11; 16 | 17 | typedef struct _PEB_LDR_DATA { 18 | ULONG Length; 19 | BOOLEAN Initialized; 20 | PVOID SsHandle; 21 | LIST_ENTRY InLoadOrderModuleList; 22 | LIST_ENTRY InMemoryOrderModuleList; 23 | LIST_ENTRY InInitializationOrderModuleList; 24 | } PEB_LDR_DATA, *PPEB_LDR_DATA; 25 | 26 | typedef struct _LDR_MODULE { 27 | LIST_ENTRY InLoadOrderModuleList; 28 | LIST_ENTRY InMemoryOrderModuleList; 29 | LIST_ENTRY InInitializationOrderModuleList; 30 | PVOID BaseAddress; 31 | PVOID EntryPoint; 32 | ULONG SizeOfImage; 33 | UNICODE_STRING FullDllName; 34 | UNICODE_STRING BaseDllName; 35 | ULONG Flags; 36 | SHORT LoadCount; 37 | SHORT TlsIndex; 38 | LIST_ENTRY HashTableEntry; 39 | ULONG TimeDateStamp; 40 | } LDR_MODULE, *PLDR_MODULE; 41 | 42 | typedef struct _PEB { 43 | BOOLEAN InheritedAddressSpace; 44 | BOOLEAN ReadImageFileExecOptions; 45 | BOOLEAN BeingDebugged; 46 | BOOLEAN Spare; 47 | HANDLE Mutant; 48 | PVOID ImageBaseAddress; 49 | PPEB_LDR_DATA LoaderData; 50 | PRTL_USER_PROCESS_PARAMETERS ProcessParameters; 51 | PVOID SubSystemData; 52 | PVOID ProcessHeap; 53 | PVOID FastPebLock; 54 | PVOID FastPebLockRoutine; 55 | PVOID FastPebUnlockRoutine; 56 | ULONG EnvironmentUpdateCount; 57 | PVOID* KernelCallbackTable; 58 | PVOID EventLogSection; 59 | PVOID EventLog; 60 | PVOID FreeList; 61 | ULONG TlsExpansionCounter; 62 | PVOID TlsBitmap; 63 | ULONG TlsBitmapBits[0x2]; 64 | PVOID ReadOnlySharedMemoryBase; 65 | PVOID ReadOnlySharedMemoryHeap; 66 | PVOID* ReadOnlyStaticServerData; 67 | PVOID AnsiCodePageData; 68 | PVOID OemCodePageData; 69 | PVOID UnicodeCaseTableData; 70 | ULONG NumberOfProcessors; 71 | ULONG NtGlobalFlag; 72 | BYTE Spare2[0x4]; 73 | LARGE_INTEGER CriticalSectionTimeout; 74 | ULONG HeapSegmentReserve; 75 | ULONG HeapSegmentCommit; 76 | ULONG HeapDeCommitTotalFreeThreshold; 77 | ULONG HeapDeCommitFreeBlockThreshold; 78 | ULONG NumberOfHeaps; 79 | ULONG MaximumNumberOfHeaps; 80 | PVOID* *ProcessHeaps; 81 | PVOID GdiSharedHandleTable; 82 | PVOID ProcessStarterHelper; 83 | PVOID GdiDCAttributeList; 84 | PVOID LoaderLock; 85 | ULONG OSMajorVersion; 86 | ULONG OSMinorVersion; 87 | ULONG OSBuildNumber; 88 | ULONG OSPlatformId; 89 | ULONG ImageSubSystem; 90 | ULONG ImageSubSystemMajorVersion; 91 | ULONG ImageSubSystemMinorVersion; 92 | ULONG GdiHandleBuffer[0x22]; 93 | ULONG PostProcessInitRoutine; 94 | ULONG TlsExpansionBitmap; 95 | BYTE TlsExpansionBitmapBits[0x80]; 96 | ULONG SessionId; 97 | } PEB, *PPEB; 98 | 99 | typedef struct _RTL_PROCESS_MODULE_INFORMATION 100 | { 101 | HANDLE Section; 102 | PVOID MappedBase; 103 | PVOID ImageBase; 104 | ULONG ImageSize; 105 | ULONG Flags; 106 | USHORT LoadOrderIndex; 107 | USHORT InitOrderIndex; 108 | USHORT LoadCount; 109 | USHORT OffsetToFileName; 110 | UCHAR FullPathName[256]; 111 | } RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION; 112 | 113 | typedef struct _RTL_PROCESS_MODULES 114 | { 115 | ULONG NumberOfModules; 116 | RTL_PROCESS_MODULE_INFORMATION Modules[1]; 117 | } RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES; 118 | } -------------------------------------------------------------------------------- /client/client/portable_executable.cpp: -------------------------------------------------------------------------------- 1 | #include "portable_executable.hpp" 2 | 3 | PIMAGE_NT_HEADERS64 portable_executable::GetNtHeaders(void* image_base) 4 | { 5 | const auto dos_header = reinterpret_cast(image_base); 6 | 7 | if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) 8 | return nullptr; 9 | 10 | const auto nt_headers = reinterpret_cast(reinterpret_cast(image_base) + dos_header->e_lfanew); 11 | 12 | if (nt_headers->Signature != IMAGE_NT_SIGNATURE) 13 | return nullptr; 14 | 15 | return nt_headers; 16 | } 17 | 18 | portable_executable::vec_relocs portable_executable::GetRelocs(void* image_base) 19 | { 20 | const PIMAGE_NT_HEADERS64 nt_headers = GetNtHeaders(image_base); 21 | 22 | if (!nt_headers) 23 | return {}; 24 | 25 | const auto reloc_data_directory = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 26 | 27 | if (!reloc_data_directory.VirtualAddress || !reloc_data_directory.Size) 28 | return {}; 29 | 30 | vec_relocs relocs; 31 | 32 | auto current_base_relocation = reinterpret_cast(reinterpret_cast(image_base) + reloc_data_directory.VirtualAddress); 33 | const auto reloc_end = reinterpret_cast(current_base_relocation) + reloc_data_directory.Size; 34 | 35 | while (current_base_relocation->VirtualAddress && current_base_relocation->VirtualAddress < reloc_end && current_base_relocation->SizeOfBlock) 36 | { 37 | RelocInfo reloc_info; 38 | 39 | reloc_info.address = reinterpret_cast(image_base) + current_base_relocation->VirtualAddress; 40 | reloc_info.item = reinterpret_cast(reinterpret_cast(current_base_relocation) + sizeof(IMAGE_BASE_RELOCATION)); 41 | reloc_info.count = (current_base_relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t); 42 | 43 | relocs.push_back(reloc_info); 44 | 45 | current_base_relocation = reinterpret_cast(reinterpret_cast(current_base_relocation) + current_base_relocation->SizeOfBlock); 46 | } 47 | 48 | return relocs; 49 | } 50 | 51 | portable_executable::vec_imports portable_executable::GetImports(void* image_base) 52 | { 53 | const PIMAGE_NT_HEADERS64 nt_headers = GetNtHeaders(image_base); 54 | 55 | if (!nt_headers) 56 | return {}; 57 | 58 | const auto import_data_directory = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 59 | 60 | if (!import_data_directory.VirtualAddress || !import_data_directory.Size) 61 | return {}; 62 | 63 | vec_imports imports; 64 | 65 | auto current_import_descriptor = reinterpret_cast(reinterpret_cast(image_base) + import_data_directory.VirtualAddress); 66 | 67 | while (current_import_descriptor->FirstThunk) 68 | { 69 | ImportInfo import_info; 70 | 71 | import_info.module_name = std::string(reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->Name)); 72 | 73 | auto current_first_thunk = reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->FirstThunk); 74 | auto current_originalFirstThunk = reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->OriginalFirstThunk); 75 | 76 | while (current_originalFirstThunk->u1.Function) 77 | { 78 | ImportFunctionInfo import_function_data; 79 | 80 | auto thunk_data = reinterpret_cast(reinterpret_cast(image_base) + current_originalFirstThunk->u1.AddressOfData); 81 | 82 | import_function_data.name = thunk_data->Name; 83 | import_function_data.address = ¤t_first_thunk->u1.Function; 84 | 85 | import_info.function_datas.push_back(import_function_data); 86 | 87 | ++current_originalFirstThunk; 88 | ++current_first_thunk; 89 | } 90 | 91 | imports.push_back(import_info); 92 | ++current_import_descriptor; 93 | } 94 | 95 | return imports; 96 | } 97 | 98 | uint32_t portable_executable::GetSectionProtection(uint32_t section_characteristics) 99 | { 100 | uint32_t result = 0; 101 | 102 | if (section_characteristics & IMAGE_SCN_MEM_NOT_CACHED) 103 | result |= PAGE_NOCACHE; 104 | 105 | if (section_characteristics & IMAGE_SCN_MEM_EXECUTE) 106 | { 107 | if (section_characteristics & IMAGE_SCN_MEM_READ) 108 | { 109 | if (section_characteristics & IMAGE_SCN_MEM_WRITE) 110 | result |= PAGE_EXECUTE_READWRITE; 111 | else 112 | result |= PAGE_EXECUTE_READ; 113 | } 114 | else 115 | { 116 | if (section_characteristics & IMAGE_SCN_MEM_WRITE) 117 | result |= PAGE_EXECUTE_WRITECOPY; 118 | else 119 | result |= PAGE_EXECUTE; 120 | } 121 | } 122 | else 123 | { 124 | if (section_characteristics & IMAGE_SCN_MEM_READ) 125 | { 126 | if (section_characteristics & IMAGE_SCN_MEM_WRITE) 127 | result |= PAGE_READWRITE; 128 | else 129 | result |= PAGE_READONLY; 130 | } 131 | else 132 | { 133 | if (section_characteristics & IMAGE_SCN_MEM_WRITE) 134 | result |= PAGE_WRITECOPY; 135 | else 136 | result |= PAGE_NOACCESS; 137 | } 138 | } 139 | 140 | return result; 141 | } -------------------------------------------------------------------------------- /client/client/portable_executable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma warning( disable : 4244 ) 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace portable_executable 9 | { 10 | struct RelocInfo 11 | { 12 | uint64_t address; 13 | uint16_t* item; 14 | uint32_t count; 15 | }; 16 | 17 | struct ImportFunctionInfo 18 | { 19 | std::string name; 20 | uint64_t* address; 21 | }; 22 | 23 | struct ImportInfo 24 | { 25 | std::string module_name; 26 | std::vector function_datas; 27 | }; 28 | 29 | using vec_sections = std::vector; 30 | using vec_relocs = std::vector; 31 | using vec_imports = std::vector; 32 | 33 | PIMAGE_NT_HEADERS64 GetNtHeaders(void* image_base); 34 | vec_relocs GetRelocs(void* image_base); 35 | vec_imports GetImports(void* image_base); 36 | uint32_t GetSectionProtection(uint32_t section_characteristics); 37 | } -------------------------------------------------------------------------------- /client/client/process.cpp: -------------------------------------------------------------------------------- 1 | #include "process.hpp" 2 | 3 | bool Process::Attach(uint32_t pid) 4 | { 5 | Deattach(); 6 | 7 | m_pid = pid; 8 | 9 | if (!utils::ProcessExists(m_pid)) 10 | { 11 | std::cerr << encryption::XorString("[-] Process doesn't exist") << std::endl; 12 | return false; 13 | } 14 | 15 | m_process_name = utils::GetProcessNameById(m_pid); 16 | 17 | m_is_attached = true; 18 | return true; 19 | } 20 | 21 | bool Process::Attach(std::string process_name) 22 | { 23 | Deattach(); 24 | 25 | m_process_name = process_name; 26 | 27 | if (!utils::ProcessExists(m_process_name)) 28 | { 29 | std::cerr << encryption::XorString("[-] Process doesn't exist") << std::endl; 30 | return false; 31 | } 32 | 33 | m_pid = utils::GetProcessIdByName(m_process_name); 34 | 35 | if (!m_pid) 36 | { 37 | std::cerr << encryption::XorString("[-] Failed to get process id") << std::endl; 38 | return false; 39 | } 40 | 41 | m_is_attached = true; 42 | return true; 43 | } 44 | 45 | bool Process::IsAttached() 46 | { 47 | return m_is_attached; 48 | } 49 | 50 | void Process::Deattach() 51 | { 52 | m_pid = 0; 53 | m_process_name.clear(); 54 | m_mapped_modules.clear(); 55 | m_is_attached = false; 56 | } 57 | 58 | bool Process::ReadMemory(uint64_t address, void* buffer, size_t size) 59 | { 60 | if (!m_is_attached) 61 | { 62 | return false; 63 | } 64 | 65 | return driver::ReadMemory(m_pid, address, buffer, size); 66 | } 67 | 68 | bool Process::WriteMemory(uint64_t address, void* buffer, size_t size) 69 | { 70 | if (!m_is_attached) 71 | { 72 | return false; 73 | } 74 | 75 | return driver::WriteMemory(m_pid, address, buffer, size); 76 | } 77 | 78 | uint64_t Process::AllocateMemory(size_t size, uint32_t protect) 79 | { 80 | if (!m_is_attached) 81 | { 82 | return false; 83 | } 84 | 85 | return driver::AllocateMemory(m_pid, size, protect); 86 | } 87 | bool Process::FreeMemory(uint64_t address) 88 | { 89 | if (!m_is_attached) 90 | { 91 | return false; 92 | } 93 | 94 | return driver::FreeMemory(m_pid, address); 95 | } 96 | 97 | bool Process::ChangeMemoryProtection(uint64_t address, size_t size, uint32_t new_protection, uint32_t* old_protection) 98 | { 99 | if (!m_is_attached) 100 | { 101 | return false; 102 | } 103 | 104 | return driver::ChangeMemoryProtection(m_pid, address, size, new_protection, old_protection); 105 | } 106 | 107 | uint64_t Process::GetImageBase() 108 | { 109 | if (!m_is_attached) 110 | { 111 | return false; 112 | } 113 | 114 | nt::PEB peb = { 0 }; 115 | 116 | const uint64_t peb_base = driver::GetPebBase(m_pid); 117 | 118 | if (!peb_base) 119 | { 120 | std::cerr << encryption::XorString("[-] Failed to get PEB base of ") << m_pid << std::endl; 121 | return 0; 122 | } 123 | 124 | if (!driver::ReadMemory(m_pid, peb_base, &peb, sizeof(peb))) 125 | { 126 | std::cerr << encryption::XorString("[-] Failed to read PEB of ") << m_pid << std::endl; 127 | return 0; 128 | } 129 | 130 | return reinterpret_cast(peb.ImageBaseAddress); 131 | } 132 | 133 | vec_modules Process::GetLoadedModules() 134 | { 135 | if (!m_is_attached) 136 | { 137 | return {}; 138 | } 139 | 140 | vec_modules result = {}; 141 | 142 | nt::PEB peb = { 0 }; 143 | 144 | const uint64_t peb_base = driver::GetPebBase(m_pid); 145 | 146 | if (!peb_base) 147 | { 148 | std::cout << encryption::XorString("[-] Failed to get PEB base of ") << m_pid << std::endl; 149 | return {}; 150 | } 151 | 152 | if (!ReadMemory(peb_base, &peb, sizeof(peb))) 153 | { 154 | std::cout << encryption::XorString("[-] Failed to read PEB of ") << m_pid << std::endl; 155 | return {}; 156 | } 157 | 158 | nt::PEB_LDR_DATA ldr_data; 159 | 160 | if (!ReadMemory(reinterpret_cast(peb.LoaderData), &ldr_data, sizeof(ldr_data))) 161 | { 162 | return {}; 163 | } 164 | 165 | const LIST_ENTRY* flink_start = ldr_data.InLoadOrderModuleList.Flink; 166 | LIST_ENTRY* flink_current = ldr_data.InLoadOrderModuleList.Flink; 167 | 168 | nt::LDR_MODULE current_module = { 0 }; 169 | 170 | do 171 | { 172 | if (!ReadMemory(reinterpret_cast(flink_current), ¤t_module, sizeof(current_module))) 173 | { 174 | return result; 175 | } 176 | 177 | wchar_t buffer[MAX_PATH] = { 0 }; 178 | 179 | if (!ReadMemory(reinterpret_cast(current_module.BaseDllName.Buffer), buffer, current_module.BaseDllName.Length)) 180 | { 181 | return result; 182 | } 183 | 184 | std::wstring wcurrent_module_name = buffer; 185 | std::string current_module_name = std::string(wcurrent_module_name.begin(), wcurrent_module_name.end()); 186 | 187 | Module mod = { current_module_name, reinterpret_cast(current_module.BaseAddress) }; 188 | result.push_back(mod); 189 | 190 | flink_current = current_module.InLoadOrderModuleList.Flink; 191 | 192 | } while (flink_current != flink_start); 193 | 194 | return result; 195 | } 196 | 197 | uint64_t Process::GetModuleExport(uint64_t module_base, const std::string& function_name) 198 | { 199 | if (!m_is_attached) 200 | { 201 | return 0; 202 | } 203 | 204 | IMAGE_DOS_HEADER dos_header = { 0 }; 205 | IMAGE_NT_HEADERS64 nt_headers = { 0 }; 206 | 207 | if (!ReadMemory(module_base, &dos_header, sizeof(dos_header)) || dos_header.e_magic != IMAGE_DOS_SIGNATURE || 208 | !ReadMemory(module_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers)) || nt_headers.Signature != IMAGE_NT_SIGNATURE) 209 | return 0; 210 | 211 | const auto export_base = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; 212 | const auto export_base_size = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; 213 | 214 | if (!export_base) 215 | return 0; 216 | 217 | const auto export_data = reinterpret_cast(VirtualAlloc(nullptr, export_base_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); 218 | 219 | if (!ReadMemory(module_base + export_base, export_data, export_base_size)) 220 | { 221 | VirtualFree(export_data, 0, MEM_RELEASE); 222 | return 0; 223 | } 224 | 225 | const auto delta = reinterpret_cast(export_data) - export_base; 226 | 227 | const auto name_table = reinterpret_cast(export_data->AddressOfNames + delta); 228 | const auto ordinal_table = reinterpret_cast(export_data->AddressOfNameOrdinals + delta); 229 | const auto function_table = reinterpret_cast(export_data->AddressOfFunctions + delta); 230 | 231 | for (auto i = 0u; i < export_data->NumberOfNames; ++i) 232 | { 233 | const std::string current_function_name = std::string(reinterpret_cast(name_table[i] + delta)); 234 | 235 | if (!_stricmp(current_function_name.c_str(), function_name.c_str())) 236 | { 237 | const auto current_ordinal_ = ordinal_table[i]; 238 | const auto current_address = module_base + function_table[current_ordinal_]; 239 | 240 | if (current_address >= module_base + export_base && current_address <= module_base + export_base + export_base_size) 241 | { 242 | char buffer[MAX_PATH]; 243 | ReadMemory(current_address, buffer, sizeof(buffer)); 244 | 245 | const std::string forwaded_name(buffer); 246 | 247 | const std::string forwaded_module_name = forwaded_name.substr(0, forwaded_name.find(".")) + encryption::XorString(".dll"); 248 | const std::string forwaded_function_name = forwaded_name.substr(forwaded_name.find(".") + 1, forwaded_function_name.npos); 249 | 250 | VirtualFree(export_data, 0, MEM_RELEASE); 251 | return GetModuleExport(GetModuleBase(forwaded_module_name), forwaded_function_name); 252 | } 253 | 254 | VirtualFree(export_data, 0, MEM_RELEASE); 255 | return current_address; 256 | } 257 | } 258 | 259 | VirtualFree(export_data, 0, MEM_RELEASE); 260 | return 0; 261 | } 262 | 263 | uint64_t Process::GetModuleBase(const std::string& module_name) 264 | { 265 | if (!m_is_attached) 266 | { 267 | return 0; 268 | } 269 | 270 | nt::PEB peb = { 0 }; 271 | 272 | const uint64_t peb_base = driver::GetPebBase(m_pid); 273 | 274 | if (!peb_base) 275 | { 276 | std::cout << encryption::XorString("[-] Failed to get PEB base of ") << m_pid << std::endl; 277 | return false; 278 | } 279 | 280 | if (!ReadMemory(peb_base, &peb, sizeof(peb))) 281 | { 282 | std::cout << encryption::XorString("[-] Failed to read PEB of ") << m_pid << std::endl; 283 | return false; 284 | } 285 | 286 | nt::PEB_LDR_DATA ldr_data; 287 | 288 | if (!ReadMemory(reinterpret_cast(peb.LoaderData), &ldr_data, sizeof(ldr_data))) 289 | return 0; 290 | 291 | const LIST_ENTRY* flink_start = ldr_data.InLoadOrderModuleList.Flink; 292 | LIST_ENTRY* flink_current = ldr_data.InLoadOrderModuleList.Flink; 293 | 294 | nt::LDR_MODULE current_module = { 0 }; 295 | 296 | do 297 | { 298 | if (!ReadMemory(reinterpret_cast(flink_current), ¤t_module, sizeof(current_module))) 299 | return 0; 300 | 301 | wchar_t buffer[MAX_PATH] = { 0 }; 302 | 303 | if (!ReadMemory(reinterpret_cast(current_module.BaseDllName.Buffer), buffer, current_module.BaseDllName.Length)) 304 | return false; 305 | 306 | std::wstring wcurrent_module_name = buffer; 307 | std::string current_module_name = std::string(wcurrent_module_name.begin(), wcurrent_module_name.end()); 308 | 309 | if (!_stricmp(current_module_name.c_str(), module_name.c_str())) 310 | return reinterpret_cast(current_module.BaseAddress); 311 | 312 | flink_current = current_module.InLoadOrderModuleList.Flink; 313 | 314 | } while (flink_current != flink_start); 315 | 316 | return 0; 317 | } 318 | 319 | uint64_t Process::GetIATAddress(uint64_t module_base, const std::string& import_module_name, const std::string& import_name) 320 | { 321 | if (!m_is_attached) 322 | { 323 | return 0; 324 | } 325 | 326 | IMAGE_DOS_HEADER dos_header = { 0 }; 327 | IMAGE_NT_HEADERS64 nt_headers = { 0 }; 328 | 329 | if (!ReadMemory(module_base, &dos_header, sizeof(dos_header)) || dos_header.e_magic != IMAGE_DOS_SIGNATURE || 330 | !ReadMemory(module_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers)) || nt_headers.Signature != IMAGE_NT_SIGNATURE) 331 | return 0; 332 | 333 | const uint64_t import_directory_entry = module_base + nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; 334 | const uint32_t import_directory_size = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; 335 | 336 | auto buffer = VirtualAlloc(nullptr, import_directory_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 337 | 338 | if (!ReadMemory(import_directory_entry, buffer, import_directory_size)) 339 | { 340 | VirtualFree(buffer, 0, MEM_RELEASE); 341 | return 0; 342 | } 343 | 344 | auto current_import_descriptor = static_cast(buffer); 345 | 346 | while (current_import_descriptor->FirstThunk) 347 | { 348 | char current_import_module_name[MAX_PATH] = { 0 }; 349 | 350 | if (!ReadMemory(module_base + current_import_descriptor->Name, current_import_module_name, sizeof(current_import_module_name))) 351 | { 352 | VirtualFree(buffer, 0, MEM_RELEASE); 353 | return 0; 354 | } 355 | 356 | if (_stricmp(import_module_name.c_str(), current_import_module_name)) 357 | { 358 | ++current_import_descriptor; 359 | continue; 360 | } 361 | 362 | auto buffer2 = VirtualAlloc(nullptr, 0x2000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 363 | 364 | if (!ReadMemory(module_base + current_import_descriptor->OriginalFirstThunk, buffer2, 0x2000)) 365 | { 366 | VirtualFree(buffer2, 0, MEM_RELEASE); 367 | VirtualFree(buffer, 0, MEM_RELEASE); 368 | 369 | return 0; 370 | } 371 | 372 | auto current_original_first_thunk = static_cast(buffer2); 373 | auto function_index = 0u; 374 | 375 | while (current_original_first_thunk->u1.Function) 376 | { 377 | auto thunk_data = static_cast(VirtualAlloc(nullptr, 0x2000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); 378 | 379 | if (!ReadMemory(module_base + current_original_first_thunk->u1.AddressOfData, thunk_data, 0x2000)) 380 | { 381 | VirtualFree(thunk_data, 0, MEM_RELEASE); 382 | VirtualFree(buffer2, 0, MEM_RELEASE); 383 | VirtualFree(buffer, 0, MEM_RELEASE); 384 | 385 | return 0; 386 | } 387 | 388 | if (!_stricmp(import_name.c_str(), thunk_data->Name)) 389 | { 390 | VirtualFree(thunk_data, 0, MEM_RELEASE); 391 | break; 392 | } 393 | 394 | VirtualFree(thunk_data, 0, MEM_RELEASE); 395 | 396 | ++current_original_first_thunk; 397 | ++function_index; 398 | } 399 | 400 | VirtualFree(buffer2, 0, MEM_RELEASE); 401 | 402 | if (!function_index) 403 | { 404 | VirtualFree(buffer, 0, MEM_RELEASE); 405 | return 0; 406 | } 407 | 408 | uint32_t first_thunk = current_import_descriptor->FirstThunk; 409 | VirtualFree(buffer, 0, MEM_RELEASE); 410 | 411 | return reinterpret_cast(function_index + reinterpret_cast(module_base + first_thunk)); 412 | } 413 | 414 | VirtualFree(buffer, 0, MEM_RELEASE); 415 | return 0; 416 | } 417 | 418 | uint64_t Process::MapModule(const std::string& module_path) 419 | { 420 | if (!m_is_attached) 421 | { 422 | return 0; 423 | } 424 | 425 | if (!std::experimental::filesystem::exists(module_path)) 426 | { 427 | std::cout << encryption::XorString("[-] ") << module_path << encryption::XorString(" doensn't exist") << std::endl; 428 | return false; 429 | } 430 | 431 | std::cout << encryption::XorString("Mapping module ") << module_path << std::endl; 432 | 433 | const std::string module_name = std::experimental::filesystem::path(module_path).filename().string(); 434 | std::vectorraw_image = { 0 }; 435 | 436 | if (!utils::ReadFileToMemory(module_path, &raw_image)) 437 | { 438 | std::cout << encryption::XorString("[-] Failed to read the module to memory") << std::endl; 439 | return false; 440 | } 441 | 442 | const PIMAGE_NT_HEADERS64 nt_headers = portable_executable::GetNtHeaders(raw_image.data()); 443 | 444 | if (!nt_headers) 445 | { 446 | std::cout << encryption::XorString("[-] Invalid image format") << std::endl; 447 | return 0; 448 | } 449 | 450 | if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) 451 | { 452 | std::cout << encryption::XorString("[-] Image is not 64 bit") << std::endl; 453 | return 0; 454 | } 455 | 456 | const uint32_t image_size = nt_headers->OptionalHeader.SizeOfImage; 457 | 458 | const auto local_image_base = VirtualAlloc(nullptr, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 459 | 460 | if (!local_image_base) 461 | { 462 | std::cout << encryption::XorString("[-] Failed to allocate local image base") << std::endl; 463 | return 0; 464 | } 465 | 466 | const uint64_t remote_image_base = AllocateMemory(image_size, PAGE_EXECUTE_READWRITE); 467 | 468 | if (!remote_image_base) 469 | { 470 | std::cout << encryption::XorString("[-] Failed to allocate memory for image in remote process") << std::endl; 471 | 472 | VirtualFree(local_image_base, 0, MEM_RELEASE); 473 | return 0; 474 | } 475 | 476 | std::cout << encryption::XorString("[+] Image base of ") << module_name << encryption::XorString(" has been allocated at 0x") << reinterpret_cast(remote_image_base) << std::endl; 477 | 478 | // Copy image headers 479 | 480 | memcpy(local_image_base, raw_image.data(), nt_headers->OptionalHeader.SizeOfHeaders); 481 | 482 | // Copy image sections 483 | 484 | const PIMAGE_SECTION_HEADER image_sections = IMAGE_FIRST_SECTION(nt_headers); 485 | 486 | for (auto i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i) 487 | { 488 | auto local_section = reinterpret_cast(reinterpret_cast(local_image_base) + image_sections[i].VirtualAddress); 489 | memcpy(local_section, reinterpret_cast(reinterpret_cast(raw_image.data()) + image_sections[i].PointerToRawData), image_sections[i].SizeOfRawData); 490 | } 491 | 492 | // Resolve relocs and imports 493 | 494 | RelocateImageByDelta(portable_executable::GetRelocs(local_image_base), remote_image_base - nt_headers->OptionalHeader.ImageBase); 495 | 496 | if (!ResolveImports(portable_executable::GetImports(local_image_base))) 497 | { 498 | std::cout << encryption::XorString("[-] Failed to resolve imports") << std::endl; 499 | 500 | VirtualFree(local_image_base, 0, MEM_RELEASE); 501 | FreeMemory(remote_image_base); 502 | 503 | return 0; 504 | } 505 | 506 | // Write fixed image in remote process 507 | 508 | if (!WriteMemory(remote_image_base, local_image_base, image_size)) 509 | { 510 | std::cout << encryption::XorString("[-] Failed to write fixed image in remote process") << std::endl; 511 | 512 | VirtualFree(local_image_base, 0, MEM_RELEASE); 513 | FreeMemory(remote_image_base); 514 | 515 | return 0; 516 | } 517 | 518 | VirtualFree(local_image_base, 0, MEM_RELEASE); 519 | 520 | // Set memory protection 521 | 522 | for (auto i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i) 523 | { 524 | uint32_t old_protection = 0; 525 | 526 | if (!ChangeMemoryProtection(remote_image_base + image_sections[i].VirtualAddress, image_sections[i].SizeOfRawData, 527 | portable_executable::GetSectionProtection(image_sections[i].Characteristics), &old_protection)) 528 | { 529 | std::cout << image_sections[i].SizeOfRawData << std::endl; 530 | std::cout << encryption::XorString("[-] Failed to set memory protection") << std::endl; 531 | FreeMemory(remote_image_base); 532 | 533 | return 0; 534 | } 535 | } 536 | 537 | // Call entry point 538 | 539 | const uint64_t address_of_entry_point = remote_image_base + nt_headers->OptionalHeader.AddressOfEntryPoint; 540 | 541 | std::cout << encryption::XorString("Calling entry point of ") << module_name << encryption::XorString(" 0x") << reinterpret_cast(address_of_entry_point) << std::endl; 542 | 543 | if (!CallDllMain(remote_image_base, address_of_entry_point)) 544 | { 545 | std::cout << encryption::XorString("[-] Failed to call DllMain") << std::endl; 546 | FreeMemory(remote_image_base); 547 | 548 | return 0; 549 | } 550 | 551 | MappedModule mapped_module = { module_name, remote_image_base }; 552 | m_mapped_modules.push_back(mapped_module); 553 | 554 | return remote_image_base; 555 | } 556 | 557 | void Process::RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta) 558 | { 559 | for (const auto& current_reloc : relocs) 560 | { 561 | for (auto i = 0u; i < current_reloc.count; ++i) 562 | { 563 | const uint16_t type = current_reloc.item[i] >> 12; 564 | const uint16_t offset = current_reloc.item[i] & 0xFFF; 565 | 566 | if (type == IMAGE_REL_BASED_DIR64) 567 | * reinterpret_cast(current_reloc.address + offset) += delta; 568 | } 569 | } 570 | } 571 | 572 | bool Process::ResolveImports(portable_executable::vec_imports imports) 573 | { 574 | for (const auto& current_import : imports) 575 | { 576 | char module_path[MAX_PATH]; 577 | 578 | if (!GetModuleFileName(LoadLibrary(current_import.module_name.c_str()), module_path, sizeof(module_path))) 579 | { 580 | std::cout << encryption::XorString("[-] Failed to get location of dependency ") << current_import.module_name << std::endl; 581 | return false; 582 | } 583 | 584 | const std::string resolved_module_name = std::experimental::filesystem::path(module_path).filename().string(); 585 | uint64_t module_base = 0; 586 | 587 | for (const auto& mapped_module : m_mapped_modules) 588 | { 589 | if (!resolved_module_name.compare(mapped_module.module_name)) 590 | { 591 | module_base = mapped_module.module_base; 592 | break; 593 | } 594 | } 595 | 596 | if (!module_base) 597 | { 598 | module_base = GetModuleBase(resolved_module_name); 599 | 600 | if (!module_base) 601 | { 602 | module_base = MapModule(module_path); 603 | 604 | if (!module_base) 605 | { 606 | std::cout << encryption::XorString("[-] Failed to load dependency ") << current_import.module_name << " (" << module_path << ")" << std::endl; 607 | return false; 608 | } 609 | } 610 | } 611 | 612 | for (auto& current_function_data : current_import.function_datas) 613 | { 614 | const uint64_t function_address = GetModuleExport(module_base, current_function_data.name); 615 | 616 | if (!function_address) 617 | { 618 | std::cout << encryption::XorString("[-] Failed to resolve import: ") << current_import.module_name << '!' << current_function_data.name << std::endl; 619 | return false; 620 | } 621 | 622 | //std::cout << encryption::XorString("[?] Export ") << resolved_module_name << '!' << current_function_data.name << encryption::XorString(": 0x") << reinterpret_cast(function_address) << std::endl; 623 | 624 | *current_function_data.address = function_address; 625 | } 626 | } 627 | 628 | return true; 629 | } 630 | 631 | bool Process::CallDllMain(uint64_t module_base, uint64_t entry_point_address) 632 | { 633 | const uint64_t NtUserGetMessage = GetModuleExport(GetModuleBase(encryption::XorString("win32u.dll")), encryption::XorString("NtUserGetMessage")); 634 | 635 | if (!NtUserGetMessage) 636 | { 637 | std::cout << encryption::XorString("[-] Failed to get export win32u!NtUserGetMessage") << std::endl; 638 | return false; 639 | } 640 | 641 | const uint64_t function_iat_address = GetIATAddress(GetModuleBase(encryption::XorString(("user32.dll"))), encryption::XorString("win32u.dll"), encryption::XorString("NtUserGetMessage")); 642 | 643 | if (!function_iat_address) 644 | { 645 | std::cout << encryption::XorString("[-] Failed to get IAT address of NtUserGetMessage") << std::endl; 646 | return false; 647 | } 648 | 649 | uint8_t shellcode[] = { 650 | 0x48, 0x83, 0xEC, 0x28, // sub rsp, 0x28 651 | 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, 0x0000000000000000 652 | 0x48, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rdi, 0x0000000000000000 653 | 0x48, 0x89, 0x38, // mov [rax], rdi 654 | 0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rcx, 0x0000000000000000 655 | 0x48, 0xC7, 0xC2, 0x01, 0x00, 0x00, 0x00, // mov rdx, 0x01 656 | 0x4D, 0x31, 0xC0, // xor r8, r8 657 | 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, 0x0000000000000000 658 | 0xFF, 0xD0, // call rax 659 | 0x48, 0x83, 0xC4, 0x28, // add rsp, 0x28 660 | 0xC3 // ret 661 | }; 662 | 663 | *reinterpret_cast(shellcode + 0x6) = function_iat_address; 664 | *reinterpret_cast(shellcode + 0x10) = NtUserGetMessage; 665 | *reinterpret_cast(shellcode + 0x1D) = module_base; 666 | *reinterpret_cast(shellcode + 0x31) = entry_point_address; 667 | 668 | uint64_t remote_shellcode = AllocateMemory(sizeof(shellcode), PAGE_EXECUTE_READWRITE); 669 | 670 | if (!remote_shellcode) 671 | return false; 672 | 673 | if (!WriteMemory(remote_shellcode, shellcode, sizeof(shellcode))) 674 | { 675 | FreeMemory(remote_shellcode); 676 | return false; 677 | } 678 | 679 | uint32_t old_protection = 0; 680 | uint32_t new_protection = PAGE_READWRITE; 681 | 682 | if (!ChangeMemoryProtection(function_iat_address, sizeof(uint64_t), new_protection, &old_protection)) 683 | { 684 | FreeMemory(remote_shellcode); 685 | return false; 686 | } 687 | 688 | if (!WriteMemory(function_iat_address, &remote_shellcode, sizeof(remote_shellcode))) 689 | { 690 | ChangeMemoryProtection(function_iat_address, sizeof(uint64_t), old_protection, &new_protection); 691 | FreeMemory(remote_shellcode); 692 | return false; 693 | } 694 | 695 | const auto thread_id = utils::GetThreadIdFromProcessId(m_pid); 696 | const bool result = PostThreadMessageW(thread_id, WM_USER + 400, 0, 0) != 0; 697 | 698 | Sleep(200); 699 | 700 | ChangeMemoryProtection(function_iat_address, sizeof(uint64_t), old_protection, &new_protection); 701 | FreeMemory(remote_shellcode); 702 | 703 | return result; 704 | } -------------------------------------------------------------------------------- /client/client/process.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "utils.hpp" 7 | #include "driver.hpp" 8 | #include "portable_executable.hpp" 9 | #include "encryption.hpp" 10 | 11 | struct Module 12 | { 13 | std::string name; 14 | uint64_t image_base; 15 | }; 16 | 17 | struct MappedModule 18 | { 19 | std::string module_name; 20 | uint64_t module_base; 21 | }; 22 | 23 | using vec_mapped_modules = std::vector; 24 | using vec_modules = std::vector; 25 | 26 | class Process 27 | { 28 | public: 29 | Process() : m_pid(0), m_process_name(""), m_is_attached(false) { } 30 | public: 31 | bool Attach(uint32_t pid); 32 | bool Attach(std::string process_name); 33 | bool IsAttached(); 34 | void Deattach(); 35 | bool ReadMemory(uint64_t address, void* buffer, size_t size); 36 | bool WriteMemory(uint64_t address, void* buffer, size_t size); 37 | uint64_t AllocateMemory(size_t size, uint32_t protect); 38 | bool FreeMemory(uint64_t address); 39 | bool ChangeMemoryProtection(uint64_t address, size_t size, uint32_t new_protection, uint32_t* old_protection); 40 | uint64_t GetImageBase(); 41 | vec_modules GetLoadedModules(); 42 | uint64_t GetModuleExport(uint64_t module_base, const std::string& function_name); 43 | uint64_t GetModuleBase(const std::string& module_name); 44 | uint64_t GetIATAddress(uint64_t module_base, const std::string& import_module_name, const std::string& import_name); 45 | uint64_t MapModule(const std::string& module_path); 46 | private: 47 | void RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta); 48 | bool ResolveImports(portable_executable::vec_imports imports); 49 | bool CallDllMain(uint64_t module_base, uint64_t entry_point_address); 50 | private: 51 | uint32_t m_pid; 52 | std::string m_process_name; 53 | bool m_is_attached; 54 | vec_mapped_modules m_mapped_modules; 55 | }; -------------------------------------------------------------------------------- /client/client/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | 3 | bool utils::ReadFileToMemory(const std::string& file_path, std::vector* out_buffer) 4 | { 5 | std::ifstream file_ifstream(file_path, std::ios::binary); 6 | 7 | if (!file_ifstream) 8 | return false; 9 | 10 | out_buffer->assign((std::istreambuf_iterator(file_ifstream)), std::istreambuf_iterator()); 11 | file_ifstream.close(); 12 | 13 | return true; 14 | } 15 | 16 | uint32_t utils::GetProcessIdByName(const std::string &process_name) 17 | { 18 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 19 | 20 | if (snapshot == INVALID_HANDLE_VALUE) 21 | return 0; 22 | 23 | PROCESSENTRY32 processEntry; 24 | processEntry.dwSize = sizeof(PROCESSENTRY32); 25 | 26 | if (!Process32First(snapshot, &processEntry)) 27 | { 28 | CloseHandle(snapshot); 29 | return 0; 30 | } 31 | 32 | do 33 | { 34 | if (!process_name.compare(processEntry.szExeFile)) 35 | { 36 | CloseHandle(snapshot); 37 | return processEntry.th32ProcessID; 38 | } 39 | } while (Process32Next(snapshot, &processEntry)); 40 | 41 | CloseHandle(snapshot); 42 | return 0; 43 | } 44 | 45 | std::string utils::GetProcessNameById(uint32_t pid) 46 | { 47 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 48 | 49 | if (snapshot == INVALID_HANDLE_VALUE) 50 | return ""; 51 | 52 | PROCESSENTRY32 processEntry; 53 | processEntry.dwSize = sizeof(PROCESSENTRY32); 54 | 55 | if (!Process32First(snapshot, &processEntry)) 56 | { 57 | CloseHandle(snapshot); 58 | return 0; 59 | } 60 | 61 | do 62 | { 63 | if (processEntry.th32ProcessID == pid) 64 | { 65 | CloseHandle(snapshot); 66 | return processEntry.szExeFile; 67 | } 68 | } while (Process32Next(snapshot, &processEntry)); 69 | 70 | CloseHandle(snapshot); 71 | return ""; 72 | } 73 | 74 | bool utils::ProcessExists(uint32_t pid) 75 | { 76 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 77 | 78 | if (snapshot == INVALID_HANDLE_VALUE) 79 | { 80 | return false; 81 | } 82 | 83 | PROCESSENTRY32 process_entry; 84 | process_entry.dwSize = sizeof(PROCESSENTRY32); 85 | 86 | if (!Process32First(snapshot, &process_entry)) 87 | { 88 | CloseHandle(snapshot); 89 | return false; 90 | } 91 | 92 | do 93 | { 94 | if (process_entry.th32ProcessID == pid) 95 | { 96 | return true; 97 | } 98 | } while (Process32Next(snapshot, &process_entry)); 99 | 100 | CloseHandle(snapshot); 101 | return false; 102 | } 103 | 104 | bool utils::ProcessExists(const std::string& process_name) 105 | { 106 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 107 | 108 | if (snapshot == INVALID_HANDLE_VALUE) 109 | { 110 | return false; 111 | } 112 | 113 | PROCESSENTRY32 process_entry; 114 | process_entry.dwSize = sizeof(PROCESSENTRY32); 115 | 116 | if (!Process32First(snapshot, &process_entry)) 117 | { 118 | CloseHandle(snapshot); 119 | return false; 120 | } 121 | 122 | do 123 | { 124 | if (!process_name.compare(process_entry.szExeFile)) 125 | { 126 | return true; 127 | } 128 | } while (Process32Next(snapshot, &process_entry)); 129 | 130 | CloseHandle(snapshot); 131 | return false; 132 | } 133 | 134 | uint64_t utils::GetKernelModuleAddress(const std::string& module_name) 135 | { 136 | void* buffer = nullptr; 137 | DWORD buffer_size = 0; 138 | 139 | NTSTATUS status = NtQuerySystemInformation(static_cast(nt::SystemModuleInformation), buffer, buffer_size, &buffer_size); 140 | 141 | while (status == nt::STATUS_INFO_LENGTH_MISMATCH) 142 | { 143 | VirtualFree(buffer, 0, MEM_RELEASE); 144 | 145 | buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 146 | status = NtQuerySystemInformation(static_cast(nt::SystemModuleInformation), buffer, buffer_size, &buffer_size); 147 | } 148 | 149 | if (!NT_SUCCESS(status)) 150 | { 151 | VirtualFree(buffer, 0, MEM_RELEASE); 152 | return 0; 153 | } 154 | 155 | const auto modules = static_cast(buffer); 156 | 157 | for (auto i = 0u; i < modules->NumberOfModules; ++i) 158 | { 159 | const std::string current_module_name = std::string(reinterpret_cast(modules->Modules[i].FullPathName) + modules->Modules[i].OffsetToFileName); 160 | 161 | if (!_stricmp(current_module_name.c_str(), module_name.c_str())) 162 | { 163 | const uint64_t result = reinterpret_cast(modules->Modules[i].ImageBase); 164 | 165 | VirtualFree(buffer, 0, MEM_RELEASE); 166 | return result; 167 | } 168 | } 169 | 170 | VirtualFree(buffer, 0, MEM_RELEASE); 171 | return 0; 172 | } 173 | 174 | DWORD utils::GetThreadIdFromProcessId(uint32_t process_id) 175 | { 176 | HWND current_window = NULL; 177 | 178 | do 179 | { 180 | current_window = FindWindowEx(NULL, current_window, NULL, NULL); 181 | 182 | DWORD current_pid = 0; 183 | uint32_t thread_id = GetWindowThreadProcessId(current_window, ¤t_pid); 184 | 185 | if (current_pid == process_id) 186 | return thread_id; 187 | 188 | } while (current_window != NULL); 189 | 190 | return 0; 191 | } 192 | -------------------------------------------------------------------------------- /client/client/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "nt.hpp" 10 | 11 | namespace utils 12 | { 13 | bool ReadFileToMemory(const std::string& file_path, std::vector* out_buffer); 14 | uint32_t GetProcessIdByName(const std::string& process_name); 15 | std::string GetProcessNameById(uint32_t pid); 16 | bool ProcessExists(uint32_t pid); 17 | bool ProcessExists(const std::string& process_name); 18 | uint64_t GetKernelModuleAddress(const std::string& module_name); 19 | DWORD GetThreadIdFromProcessId(uint32_t process_id); 20 | } --------------------------------------------------------------------------------