├── .gitattributes ├── LICENSE.md ├── README.md └── src ├── ColdMDLoader.cpp └── ColdMDLoader.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Rat431 inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ColdMDLoader 2 | A simple open source module injector library x86/x64 for Windows 3 | -------------------------------------------------------------------------------- /src/ColdMDLoader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Rat431 (https://github.com/Rat431). 3 | This software is under the MIT license, for more informations check the LICENSE file. 4 | */ 5 | 6 | #include "ColdMDLoader.h" 7 | 8 | // Custom MACROs 9 | #define RLC_FLAG64b(Data) ((Data >> 12) == IMAGE_REL_BASED_DIR64) 10 | #define RLC_FLAG32b(Data) ((Data >> 12) == IMAGE_REL_BASED_HIGHLOW) 11 | #ifdef _WIN64 12 | #define RLC_FLAG RLC_FLAG64b 13 | #define VALID_MACHINE IMAGE_FILE_MACHINE_AMD64 14 | #else 15 | #define RLC_FLAG RLC_FLAG32b 16 | #define VALID_MACHINE IMAGE_FILE_MACHINE_I386 17 | #endif 18 | 19 | // For the remote code 20 | typedef HMODULE(WINAPI* __LoadLibA__)(LPCSTR); 21 | typedef HMODULE(WINAPI* __LoadLibExA__)(LPCSTR, HANDLE, DWORD); 22 | typedef FARPROC(WINAPI* __GetProcAddress__)(HMODULE, LPCSTR); 23 | typedef BOOL(APIENTRY* __DllMain__)(HMODULE, DWORD, LPVOID); 24 | typedef BOOL(WINAPI* __FreeLibrary__)(HMODULE); 25 | 26 | struct InjectionRC_Info 27 | { 28 | int32_t LFlag; 29 | int32_t Signal; 30 | 31 | void* BaseAddr; 32 | char* LibraryN; 33 | IMAGE_NT_HEADERS* pNt; 34 | 35 | __GetProcAddress__ __GetProcAddress; 36 | __LoadLibExA__ __LoadLibExA; 37 | __LoadLibA__ __LoadLibA; 38 | __FreeLibrary__ __FreeLibrary; 39 | }; 40 | namespace CMDLoader_Vars 41 | { 42 | bool Inited = false; 43 | int32_t CurrentID = 0; 44 | std::multimap RegisteredModules; 45 | std::mutex Thread; 46 | } 47 | namespace CMDLoader_Service_Private 48 | { 49 | // This function will run in the remote process 50 | void REMOTECODEF RemoteInjector(InjectionRC_Info* InjectionData) 51 | { 52 | if (InjectionData) { 53 | if (InjectionData->LFlag == MANUAL_INJECTION) { 54 | // Declare some variables 55 | __LoadLibA__ LoadLibraryFA = InjectionData->__LoadLibA; 56 | __GetProcAddress__ GetProcAddr = InjectionData->__GetProcAddress; 57 | 58 | // Let's start doing relocations 59 | DWORD_PTR Delta = (DWORD_PTR)InjectionData->BaseAddr - InjectionData->pNt->OptionalHeader.ImageBase; 60 | 61 | // If the difference is 0, the allocated base address as the image base, so we don't need to fix relocations. 62 | if (Delta != NULL) { 63 | // Check if there are relocations to fix 64 | if (InjectionData->pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0) { 65 | IMAGE_BASE_RELOCATION* pBaseRelocation = (IMAGE_BASE_RELOCATION*)((ULONG_PTR)InjectionData->BaseAddr + InjectionData->pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); 66 | while (pBaseRelocation->VirtualAddress) { 67 | if (pBaseRelocation->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION)) { 68 | UINT CountRelocs = (pBaseRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); 69 | WORD* list = (WORD*)(pBaseRelocation + 1); 70 | 71 | for (UINT i = 0; i < CountRelocs; i++, list++) { 72 | // Check if the bits contains the right flags 73 | if (RLC_FLAG(*list)) { 74 | DWORD_PTR* PatchData = (DWORD_PTR*)((DWORD_PTR)InjectionData->BaseAddr + pBaseRelocation->VirtualAddress + (*list & 0xFFF)); 75 | if (PatchData) { 76 | *PatchData += Delta; 77 | } 78 | else { 79 | InjectionData->Signal = FALIED_INJECTION; 80 | return; 81 | } 82 | } 83 | } 84 | } 85 | pBaseRelocation = (IMAGE_BASE_RELOCATION*)((ULONG_PTR)pBaseRelocation + pBaseRelocation->SizeOfBlock); 86 | } 87 | } 88 | } 89 | // IAT now 90 | if (InjectionData->pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0) { 91 | IMAGE_IMPORT_DESCRIPTOR* pImportD = (IMAGE_IMPORT_DESCRIPTOR*)((ULONG_PTR)InjectionData->BaseAddr + InjectionData->pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 92 | while (pImportD->Characteristics && pImportD->Name) { 93 | // Load the library 94 | auto pName = (LPSTR)((ULONG_PTR)InjectionData->BaseAddr + pImportD->Name); 95 | HMODULE hLib = LoadLibraryFA(pName); 96 | 97 | if (hLib) { 98 | IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)((ULONG_PTR)InjectionData->BaseAddr + pImportD->FirstThunk); 99 | IMAGE_THUNK_DATA* pOrigThunk = (IMAGE_THUNK_DATA*)((ULONG_PTR)InjectionData->BaseAddr + pImportD->OriginalFirstThunk); 100 | while (pOrigThunk->u1.AddressOfData) { 101 | if (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) { 102 | ULONG_PTR FunctionL = (ULONG_PTR)GetProcAddr(hLib, (LPSTR)IMAGE_ORDINAL(pOrigThunk->u1.Ordinal)); 103 | pThunk->u1.Function = FunctionL; 104 | } 105 | else { 106 | IMAGE_IMPORT_BY_NAME* pNameImport = (IMAGE_IMPORT_BY_NAME*)((ULONG_PTR)InjectionData->BaseAddr + pOrigThunk->u1.AddressOfData); 107 | ULONG_PTR FunctionL = (ULONG_PTR)GetProcAddr(hLib, (LPSTR)pNameImport->Name); 108 | pThunk->u1.Function = FunctionL; 109 | } 110 | pThunk++; 111 | pOrigThunk++; 112 | } 113 | } 114 | pImportD++; 115 | } 116 | } 117 | 118 | // TLS Callbacks 119 | if (InjectionData->pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size > 0) { 120 | IMAGE_TLS_DIRECTORY* pTLSDir = (IMAGE_TLS_DIRECTORY*)((ULONG_PTR)InjectionData->BaseAddr + InjectionData->pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); 121 | PIMAGE_TLS_CALLBACK Call = nullptr; 122 | void** Callback = nullptr; 123 | Callback = (void**)pTLSDir->AddressOfCallBacks; 124 | while (Callback && *Callback) { 125 | Call = (PIMAGE_TLS_CALLBACK)*Callback; 126 | Call(InjectionData->BaseAddr, DLL_PROCESS_ATTACH, NULL); 127 | Callback++; 128 | } 129 | } 130 | 131 | // Entry point 132 | if (InjectionData->pNt->OptionalHeader.AddressOfEntryPoint) { 133 | __DllMain__ Main = (__DllMain__)((ULONG_PTR)InjectionData->BaseAddr + InjectionData->pNt->OptionalHeader.AddressOfEntryPoint); 134 | Main((HMODULE)InjectionData->BaseAddr, DLL_PROCESS_ATTACH, NULL); 135 | } 136 | InjectionData->Signal = SUCCESS_RETURNED; 137 | } 138 | else if (InjectionData->LFlag == STANDARD_INJECTION) { 139 | // Declare some variables 140 | __LoadLibExA__ LoadLibraryExFA = InjectionData->__LoadLibExA; 141 | HMODULE Module; 142 | 143 | // Load the module 144 | Module = LoadLibraryExFA(InjectionData->LibraryN, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 145 | if (!Module) { 146 | InjectionData->Signal = FALIED_MODULE_LOAD; 147 | } 148 | else { 149 | InjectionData->Signal = SUCCESS_RETURNED; 150 | InjectionData->BaseAddr = (void*)Module; 151 | } 152 | } 153 | else { 154 | InjectionData->Signal = FALIED_INJECTION; 155 | } 156 | } 157 | else { 158 | InjectionData->Signal = FALIED_INJECTION; 159 | } 160 | } 161 | bool IsProcessSameArch(HANDLE hProcess, void* MainModuleBase, int32_t* OutErrorCode) 162 | { 163 | IMAGE_DOS_HEADER Dos = { 0 }; 164 | IMAGE_NT_HEADERS Nt = { 0 }; 165 | SIZE_T ReadData; 166 | 167 | if (!ReadProcessMemory(hProcess, MainModuleBase, &Dos, sizeof(IMAGE_DOS_HEADER), &ReadData)) { 168 | if (OutErrorCode > NULL) { 169 | *OutErrorCode = FALIED_READING_PROCESS_MEM; 170 | } 171 | return false; 172 | } 173 | if (!ReadProcessMemory(hProcess, (void*)((ULONG_PTR)MainModuleBase + Dos.e_lfanew), &Nt, sizeof(IMAGE_NT_HEADERS), &ReadData)) { 174 | if (OutErrorCode > NULL) { 175 | *OutErrorCode = FALIED_READING_PROCESS_MEM; 176 | } 177 | return false; 178 | } 179 | if (Nt.FileHeader.Machine != VALID_MACHINE) { 180 | if (OutErrorCode > NULL) { 181 | *OutErrorCode = NULL; 182 | } 183 | return false; 184 | } 185 | if (OutErrorCode > NULL) { 186 | *OutErrorCode = NULL; 187 | } 188 | return true; 189 | } 190 | } 191 | 192 | namespace CMDLoader_Service 193 | { 194 | // Mapping functions 195 | int32_t InitModuleInjection(HANDLE hProcess, const char* DllFileName, int32_t LFlag, ModuleMap_Info* OutMapInfo, int32_t* OutErrorCode) 196 | { 197 | // Paramaters first checks 198 | if (hProcess == INVALID_HANDLE_VALUE) { 199 | if (OutErrorCode > NULL) { 200 | *OutErrorCode = FALIED_INVALID_PARAMETER; 201 | } 202 | return NULL; 203 | } 204 | if (!DllFileName) { 205 | if (OutErrorCode > NULL) { 206 | *OutErrorCode = FALIED_INVALID_PARAMETER; 207 | } 208 | return NULL; 209 | } 210 | if (!OutMapInfo) { 211 | if (OutErrorCode > NULL) { 212 | *OutErrorCode = FALIED_INVALID_PARAMETER; 213 | } 214 | return NULL; 215 | } 216 | 217 | // Check if the service is started 218 | if (!CMDLoader_Vars::Inited) { 219 | if (OutErrorCode > NULL) { 220 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 221 | } 222 | return NULL; 223 | } 224 | 225 | // Thread safe 226 | CMDLoader_Vars::Thread.lock(); 227 | 228 | // For the remote code 229 | InjectionRC_Info InjectionStructure; 230 | LPVOID PageRemoteCodeLoader = VirtualAllocEx(hProcess, NULL, 0x7000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 231 | LPVOID PageRemoteCodeStructure = VirtualAllocEx(hProcess, NULL, sizeof(InjectionRC_Info), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 232 | 233 | if (!PageRemoteCodeLoader) { 234 | if (OutErrorCode > NULL) { 235 | *OutErrorCode = FALIED_MEM_ALLOCATION; 236 | } 237 | CMDLoader_Vars::Thread.unlock(); 238 | return NULL; 239 | } 240 | if (!PageRemoteCodeStructure) { 241 | if (OutErrorCode > NULL) { 242 | *OutErrorCode = FALIED_MEM_ALLOCATION; 243 | } 244 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 245 | CMDLoader_Vars::Thread.unlock(); 246 | return NULL; 247 | } 248 | 249 | // Check which type of injection should be performed. 250 | if (LFlag == STANDARD_INJECTION) 251 | { 252 | // Declare variables 253 | HANDLE RemoteThread; 254 | LPVOID PageString; 255 | SIZE_T LString; 256 | 257 | // Start by getting the length of the requested module file string 258 | LString = lstrlenA(DllFileName); 259 | 260 | // Allocate to the target process a page which will be used to store our module file name. 261 | PageString = VirtualAllocEx(hProcess, NULL, LString + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 262 | if (PageString == NULL) { 263 | if (OutErrorCode > NULL) { 264 | *OutErrorCode = FALIED_MEM_ALLOCATION; 265 | } 266 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 267 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 268 | CMDLoader_Vars::Thread.unlock(); 269 | return NULL; 270 | } 271 | 272 | // Copy the string 273 | if (!WriteProcessMemory(hProcess, PageString, DllFileName, LString, NULL)) { 274 | if (OutErrorCode > NULL) { 275 | *OutErrorCode = FALIED_INJECTION; 276 | } 277 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 278 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 279 | VirtualFreeEx(hProcess, PageString, NULL, MEM_RELEASE); 280 | CMDLoader_Vars::Thread.unlock(); 281 | return NULL; 282 | } 283 | InjectionStructure.LFlag = STANDARD_INJECTION; 284 | 285 | InjectionStructure.LibraryN = (char*)PageString; 286 | InjectionStructure.BaseAddr = nullptr; 287 | InjectionStructure.pNt = nullptr; 288 | 289 | InjectionStructure.__LoadLibExA = (__LoadLibExA__)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryExA"); 290 | InjectionStructure.__FreeLibrary = NULL; 291 | InjectionStructure.__GetProcAddress = NULL; 292 | InjectionStructure.__LoadLibA = NULL; 293 | 294 | InjectionStructure.Signal = 0; 295 | 296 | // Copy the filled structure 297 | if (!WriteProcessMemory(hProcess, PageRemoteCodeStructure, &InjectionStructure, sizeof(InjectionRC_Info), NULL)) { 298 | if (OutErrorCode > NULL) { 299 | *OutErrorCode = FALIED_INJECTION; 300 | } 301 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 302 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 303 | VirtualFreeEx(hProcess, PageString, NULL, MEM_RELEASE); 304 | CMDLoader_Vars::Thread.unlock(); 305 | return NULL; 306 | } 307 | 308 | if (!WriteProcessMemory(hProcess, PageRemoteCodeLoader, CMDLoader_Service_Private::RemoteInjector, 0x7000, NULL)) { 309 | if (OutErrorCode > NULL) { 310 | *OutErrorCode = FALIED_INJECTION; 311 | } 312 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 313 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 314 | VirtualFreeEx(hProcess, PageString, NULL, MEM_RELEASE); 315 | CMDLoader_Vars::Thread.unlock(); 316 | return NULL; 317 | } 318 | 319 | RemoteThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)PageRemoteCodeLoader, PageRemoteCodeStructure, 0, NULL); 320 | if (RemoteThread == NULL) { 321 | if (OutErrorCode > NULL) { 322 | *OutErrorCode = FALIED_REMOTE_THREAD_CREATION; 323 | } 324 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 325 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 326 | VirtualFreeEx(hProcess, PageString, NULL, MEM_RELEASE); 327 | CMDLoader_Vars::Thread.unlock(); 328 | return NULL; 329 | } 330 | 331 | // Wait for the finished signal 332 | while (InjectionStructure.Signal == 0) 333 | { 334 | if (!ReadProcessMemory(hProcess, PageRemoteCodeStructure, &InjectionStructure, sizeof(InjectionRC_Info), NULL)) { 335 | InjectionStructure.Signal = WARN_NO_RETURN_SIGNAL; 336 | break; 337 | } 338 | // Sleep for 1 second and try again 339 | Sleep(1000); 340 | } 341 | 342 | if (OutErrorCode > NULL) { 343 | *OutErrorCode = InjectionStructure.Signal; 344 | } 345 | 346 | // Wait the thread for finish 347 | WaitForSingleObject(RemoteThread, INFINITE); 348 | 349 | if (InjectionStructure.Signal == SUCCESS_RETURNED) { 350 | 351 | // Fill the informations struct 352 | OutMapInfo->StatusLoaded = true; 353 | OutMapInfo->PID = GetProcessId(hProcess); 354 | OutMapInfo->MBaseAddress = InjectionStructure.BaseAddr; 355 | OutMapInfo->LFlag = STANDARD_INJECTION; 356 | 357 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 358 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 359 | VirtualFreeEx(hProcess, PageString, NULL, MEM_RELEASE); 360 | 361 | CMDLoader_Vars::CurrentID++; 362 | CMDLoader_Vars::Thread.unlock(); 363 | return CMDLoader_Vars::CurrentID; 364 | } 365 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 366 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 367 | VirtualFreeEx(hProcess, PageString, NULL, MEM_RELEASE); 368 | CMDLoader_Vars::Thread.unlock(); 369 | return NULL; 370 | } 371 | else if (LFlag == MANUAL_INJECTION) 372 | { 373 | // Declare variables 374 | HANDLE RemoteThread; 375 | HANDLE FileHandle; 376 | 377 | LPVOID PEHeader = NULL; 378 | LPVOID FileBData; 379 | 380 | DWORD tmp; 381 | SIZE_T FileSize; 382 | 383 | IMAGE_DOS_HEADER* pDosHeader = NULL; 384 | IMAGE_NT_HEADERS* pNtHeader = NULL; 385 | IMAGE_SECTION_HEADER* pSecHeader = NULL; 386 | 387 | // Start by creating a new handle to the requested file. 388 | FileHandle = CreateFileA(DllFileName, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 389 | if (FileHandle == INVALID_HANDLE_VALUE) { 390 | if (OutErrorCode > NULL) { 391 | *OutErrorCode = FALIED_FILE_HANDLE_INVALID; 392 | } 393 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 394 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 395 | CMDLoader_Vars::Thread.unlock(); 396 | return NULL; 397 | } 398 | FileSize = GetFileSize(FileHandle, NULL); 399 | if (FileSize < 0x1000) { 400 | if (OutErrorCode > NULL) { 401 | *OutErrorCode = FALIED_INVALID_PE; 402 | } 403 | CloseHandle(FileHandle); 404 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 405 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 406 | CMDLoader_Vars::Thread.unlock(); 407 | return NULL; 408 | } 409 | FileBData = VirtualAlloc(NULL, FileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 410 | if (FileBData == NULL) { 411 | if (OutErrorCode > NULL) { 412 | *OutErrorCode = FALIED_ALLOCATION; 413 | } 414 | CloseHandle(FileHandle); 415 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 416 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 417 | CMDLoader_Vars::Thread.unlock(); 418 | return NULL; 419 | } 420 | 421 | // Read the file bytes. 422 | if (!ReadFile(FileHandle, FileBData, FileSize, &tmp, NULL)) { 423 | if (OutErrorCode > NULL) { 424 | *OutErrorCode = FALIED_FILE_READ; 425 | } 426 | CloseHandle(FileHandle); 427 | VirtualFree(FileBData, NULL, MEM_RELEASE); 428 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 429 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 430 | CMDLoader_Vars::Thread.unlock(); 431 | return NULL; 432 | } 433 | 434 | // Read headers now 435 | pDosHeader = (IMAGE_DOS_HEADER*)FileBData; 436 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 437 | if (OutErrorCode > NULL) { 438 | *OutErrorCode = FALIED_INVALID_PE; 439 | } 440 | CloseHandle(FileHandle); 441 | VirtualFree(FileBData, NULL, MEM_RELEASE); 442 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 443 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 444 | CMDLoader_Vars::Thread.unlock(); 445 | return NULL; 446 | } 447 | pNtHeader = (IMAGE_NT_HEADERS*)((ULONG_PTR)FileBData + pDosHeader->e_lfanew); 448 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 449 | if (OutErrorCode > NULL) { 450 | *OutErrorCode = FALIED_INVALID_PE; 451 | } 452 | CloseHandle(FileHandle); 453 | VirtualFree(FileBData, NULL, MEM_RELEASE); 454 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 455 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 456 | CMDLoader_Vars::Thread.unlock(); 457 | return NULL; 458 | } 459 | if (pNtHeader->FileHeader.Machine != VALID_MACHINE) { 460 | if (OutErrorCode > NULL) { 461 | *OutErrorCode = FALIED_INVALID_PE_ARCH; 462 | } 463 | CloseHandle(FileHandle); 464 | VirtualFree(FileBData, NULL, MEM_RELEASE); 465 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 466 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 467 | CMDLoader_Vars::Thread.unlock(); 468 | return NULL; 469 | } 470 | 471 | // Allocate a new buffer to the target process which will be used for the remote module. 472 | // We firstly try to allocate a page with the same base address as the target image base to avoid to fix relocations 473 | PEHeader = VirtualAllocEx(hProcess, (LPVOID)pNtHeader->OptionalHeader.ImageBase, pNtHeader->OptionalHeader.SizeOfImage, 474 | MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 475 | if (PEHeader == NULL) { 476 | PEHeader = VirtualAllocEx(hProcess, NULL, pNtHeader->OptionalHeader.SizeOfImage, 477 | MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 478 | if (PEHeader == NULL) { 479 | if (OutErrorCode > NULL) { 480 | *OutErrorCode = FALIED_MEM_ALLOCATION; 481 | } 482 | CloseHandle(FileHandle); 483 | VirtualFree(FileBData, NULL, MEM_RELEASE); 484 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 485 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 486 | CMDLoader_Vars::Thread.unlock(); 487 | return NULL; 488 | } 489 | } 490 | 491 | // Copy headers first 492 | if (!WriteProcessMemory(hProcess, PEHeader, FileBData, pNtHeader->OptionalHeader.SizeOfHeaders, NULL)) { 493 | if (OutErrorCode > NULL) { 494 | *OutErrorCode = FALIED_INJECTION; 495 | } 496 | CloseHandle(FileHandle); 497 | VirtualFree(FileBData, NULL, MEM_RELEASE); 498 | VirtualFreeEx(hProcess, PEHeader, NULL, MEM_RELEASE); 499 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 500 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 501 | CMDLoader_Vars::Thread.unlock(); 502 | return NULL; 503 | } 504 | 505 | // Sectiions 506 | if (pNtHeader->FileHeader.NumberOfSections > 0) { 507 | pSecHeader = IMAGE_FIRST_SECTION(pNtHeader); 508 | 509 | for (DWORD i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++, pSecHeader++) 510 | { 511 | // Check if the raw size and the virtual size is always more than 0. 512 | if (pSecHeader->SizeOfRawData > 0) { 513 | if (!WriteProcessMemory(hProcess, (LPVOID)((ULONG_PTR)PEHeader + pSecHeader->VirtualAddress), 514 | (LPVOID)((ULONG_PTR)FileBData + pSecHeader->PointerToRawData), min(pSecHeader->Misc.VirtualSize, pSecHeader->SizeOfRawData), NULL)) 515 | { 516 | if (OutErrorCode > NULL) { 517 | *OutErrorCode = FALIED_INJECTION; 518 | } 519 | CloseHandle(FileHandle); 520 | VirtualFree(FileBData, NULL, MEM_RELEASE); 521 | VirtualFreeEx(hProcess, PEHeader, NULL, MEM_RELEASE); 522 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 523 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 524 | CMDLoader_Vars::Thread.unlock(); 525 | return NULL; 526 | } 527 | } 528 | } 529 | } 530 | HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); 531 | 532 | InjectionStructure.LFlag = MANUAL_INJECTION; 533 | InjectionStructure.Signal = 0; 534 | 535 | InjectionStructure.__LoadLibA = (__LoadLibA__)GetProcAddress(hKernel32, "LoadLibraryA"); 536 | InjectionStructure.__LoadLibExA = NULL; 537 | InjectionStructure.__GetProcAddress = (__GetProcAddress__)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetProcAddress"); 538 | InjectionStructure.__FreeLibrary = NULL; 539 | 540 | InjectionStructure.LibraryN = nullptr; 541 | InjectionStructure.BaseAddr = PEHeader; 542 | InjectionStructure.pNt = (IMAGE_NT_HEADERS*)((ULONG_PTR)PEHeader + pDosHeader->e_lfanew); 543 | 544 | // Copy the filled structure 545 | if (!WriteProcessMemory(hProcess, PageRemoteCodeStructure, &InjectionStructure, sizeof(InjectionRC_Info), NULL)) { 546 | if (OutErrorCode > NULL) { 547 | *OutErrorCode = FALIED_INJECTION; 548 | } 549 | CloseHandle(FileHandle); 550 | VirtualFree(FileBData, NULL, MEM_RELEASE); 551 | VirtualFreeEx(hProcess, PEHeader, NULL, MEM_RELEASE); 552 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 553 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 554 | CMDLoader_Vars::Thread.unlock(); 555 | return NULL; 556 | } 557 | 558 | // Write our code to the target process 559 | if (!WriteProcessMemory(hProcess, PageRemoteCodeLoader, CMDLoader_Service_Private::RemoteInjector, 0x7000, NULL)) { 560 | if (OutErrorCode > NULL) { 561 | *OutErrorCode = FALIED_INJECTION; 562 | } 563 | CloseHandle(FileHandle); 564 | VirtualFree(FileBData, NULL, MEM_RELEASE); 565 | VirtualFreeEx(hProcess, PEHeader, NULL, MEM_RELEASE); 566 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 567 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 568 | CMDLoader_Vars::Thread.unlock(); 569 | return NULL; 570 | } 571 | RemoteThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)PageRemoteCodeLoader, PageRemoteCodeStructure, 0, NULL); 572 | if (RemoteThread == NULL) { 573 | if (OutErrorCode > NULL) { 574 | *OutErrorCode = FALIED_REMOTE_THREAD_CREATION; 575 | } 576 | CloseHandle(FileHandle); 577 | VirtualFree(FileBData, NULL, MEM_RELEASE); 578 | VirtualFreeEx(hProcess, PEHeader, NULL, MEM_RELEASE); 579 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 580 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 581 | CMDLoader_Vars::Thread.unlock(); 582 | return NULL; 583 | } 584 | 585 | // Wait for the finished signal 586 | while (InjectionStructure.Signal == 0) 587 | { 588 | if (!ReadProcessMemory(hProcess, PageRemoteCodeStructure, &InjectionStructure, sizeof(InjectionRC_Info), NULL)) { 589 | InjectionStructure.Signal = WARN_NO_RETURN_SIGNAL; 590 | break; 591 | } 592 | // Sleep for 1 second and try again 593 | Sleep(1000); 594 | } 595 | 596 | if (OutErrorCode > NULL) { 597 | *OutErrorCode = InjectionStructure.Signal; 598 | } 599 | 600 | // Wait the thread for finish 601 | WaitForSingleObject(RemoteThread, INFINITE); 602 | 603 | if (InjectionStructure.Signal == SUCCESS_RETURNED) { 604 | 605 | // Fill the informations struct 606 | OutMapInfo->StatusLoaded = true; 607 | OutMapInfo->PID = GetProcessId(hProcess); 608 | OutMapInfo->MBaseAddress = InjectionStructure.BaseAddr; 609 | OutMapInfo->LFlag = MANUAL_INJECTION; 610 | 611 | CloseHandle(FileHandle); 612 | 613 | VirtualFree(FileBData, NULL, MEM_RELEASE); 614 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 615 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 616 | 617 | CMDLoader_Vars::CurrentID++; 618 | CMDLoader_Vars::Thread.unlock(); 619 | return CMDLoader_Vars::CurrentID; 620 | } 621 | 622 | CloseHandle(FileHandle); 623 | 624 | VirtualFree(FileBData, NULL, MEM_RELEASE); 625 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 626 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 627 | 628 | CMDLoader_Vars::Thread.unlock(); 629 | return NULL; 630 | } 631 | else 632 | { 633 | if (OutErrorCode > NULL) { 634 | *OutErrorCode = FALIED_INVALID_PARAMETER; 635 | } 636 | VirtualFreeEx(hProcess, PageRemoteCodeLoader, NULL, MEM_RELEASE); 637 | VirtualFreeEx(hProcess, PageRemoteCodeStructure, NULL, MEM_RELEASE); 638 | CMDLoader_Vars::Thread.unlock(); 639 | return NULL; 640 | } 641 | } 642 | 643 | // Init And shut down 644 | bool ServiceGlobalInit(int32_t* OutErrorCode) 645 | { 646 | // Safe thread 647 | CMDLoader_Vars::Thread.lock(); 648 | 649 | if (!CMDLoader_Vars::Inited) 650 | { 651 | if (!CMDLoader_Vars::RegisteredModules.empty()) { 652 | CMDLoader_Vars::RegisteredModules.clear(); 653 | } 654 | if (OutErrorCode > NULL) { 655 | *OutErrorCode = NULL; 656 | } 657 | CMDLoader_Vars::Inited = true; 658 | CMDLoader_Vars::CurrentID = NULL; 659 | CMDLoader_Vars::Thread.unlock(); 660 | return true; 661 | } 662 | else 663 | { 664 | if (OutErrorCode > NULL) { 665 | *OutErrorCode = FALIED_ALREADY_INITIALIZED; 666 | } 667 | } 668 | CMDLoader_Vars::Thread.unlock(); 669 | return false; 670 | } 671 | bool ServiceGlobalShutDown(int32_t* OutErrorCode) 672 | { 673 | // Safe thread 674 | CMDLoader_Vars::Thread.lock(); 675 | 676 | if (CMDLoader_Vars::Inited) 677 | { 678 | if (OutErrorCode > NULL) { 679 | *OutErrorCode = NULL; 680 | } 681 | 682 | CMDLoader_Vars::Inited = false; 683 | CMDLoader_Vars::CurrentID = NULL; 684 | CMDLoader_Vars::Thread.unlock(); 685 | return true; 686 | } 687 | else 688 | { 689 | if (OutErrorCode > NULL) { 690 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 691 | } 692 | } 693 | CMDLoader_Vars::Thread.unlock(); 694 | return false; 695 | } 696 | 697 | // Informations and helpers 698 | bool RetrieveProcessHandleByPID(DWORD InPID, HANDLE* OutHandle, int32_t* OutErrorCode) 699 | { 700 | // Paramaters first checks 701 | if (InPID <= 0) { 702 | if (OutErrorCode > NULL) { 703 | *OutErrorCode = FALIED_INVALID_PARAMETER; 704 | } 705 | return false; 706 | } 707 | if (!OutHandle) { 708 | if (OutErrorCode > NULL) { 709 | *OutErrorCode = FALIED_INVALID_PARAMETER; 710 | } 711 | return false; 712 | } 713 | 714 | // Check if the service is started 715 | if (!CMDLoader_Vars::Inited) { 716 | if (OutErrorCode > NULL) { 717 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 718 | } 719 | return false; 720 | } 721 | 722 | // Safe thread 723 | CMDLoader_Vars::Thread.lock(); 724 | 725 | // Declare some variables 726 | HANDLE hSnapshot; 727 | HANDLE hProcess; 728 | PROCESSENTRY32 Processes = { 0 }; 729 | 730 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 731 | if (hSnapshot == INVALID_HANDLE_VALUE) { 732 | if (OutErrorCode > NULL) { 733 | *OutErrorCode = FALIED_HANDLE_INVALID; 734 | } 735 | CMDLoader_Vars::Thread.unlock(); 736 | return false; 737 | } 738 | 739 | Processes.dwSize = sizeof(PROCESSENTRY32); 740 | 741 | if (Process32First(hSnapshot, &Processes)) 742 | { 743 | do 744 | { 745 | if (Processes.th32ProcessID == InPID) 746 | { 747 | hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, InPID); 748 | if (hProcess == INVALID_HANDLE_VALUE) { 749 | if (OutErrorCode > NULL) { 750 | *OutErrorCode = FALIED_HANDLE_INVALID; 751 | } 752 | CloseHandle(hSnapshot); 753 | CMDLoader_Vars::Thread.unlock(); 754 | return false; 755 | } 756 | if (OutErrorCode > NULL) { 757 | *OutErrorCode = NULL; 758 | } 759 | *OutHandle = hProcess; 760 | CloseHandle(hSnapshot); 761 | CMDLoader_Vars::Thread.unlock(); 762 | return true; 763 | } 764 | } while (Process32Next(hSnapshot, &Processes)); 765 | } 766 | CloseHandle(hSnapshot); 767 | if (OutErrorCode > NULL) { 768 | *OutErrorCode = FALIED_PROCESS_NOT_FOUND; 769 | } 770 | CMDLoader_Vars::Thread.unlock(); 771 | return false; 772 | } 773 | bool RetrieveProcessHandleByName(const wchar_t* InPName, HANDLE* OutHandle, int32_t* OutErrorCode) 774 | { 775 | // Paramaters first checks 776 | if (!InPName) { 777 | if (OutErrorCode > NULL) { 778 | *OutErrorCode = FALIED_INVALID_PARAMETER; 779 | } 780 | return false; 781 | } 782 | if (!OutHandle) { 783 | if (OutErrorCode > NULL) { 784 | *OutErrorCode = FALIED_INVALID_PARAMETER; 785 | } 786 | return false; 787 | } 788 | 789 | // Check if the service is started 790 | if (!CMDLoader_Vars::Inited) { 791 | if (OutErrorCode > NULL) { 792 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 793 | } 794 | return false; 795 | } 796 | 797 | // Safe thread 798 | CMDLoader_Vars::Thread.lock(); 799 | 800 | // Declare some variables 801 | HANDLE hSnapshot; 802 | HANDLE hProcess; 803 | PROCESSENTRY32 Processes = { 0 }; 804 | 805 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 806 | if (hSnapshot == INVALID_HANDLE_VALUE) { 807 | if (OutErrorCode > NULL) { 808 | *OutErrorCode = FALIED_HANDLE_INVALID; 809 | } 810 | CMDLoader_Vars::Thread.unlock(); 811 | return false; 812 | } 813 | 814 | Processes.dwSize = sizeof(PROCESSENTRY32); 815 | 816 | if (Process32First(hSnapshot, &Processes)) 817 | { 818 | do 819 | { 820 | if (lstrcmp(Processes.szExeFile, InPName) == 0) 821 | { 822 | hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Processes.th32ProcessID); 823 | if (hProcess == INVALID_HANDLE_VALUE) { 824 | if (OutErrorCode > NULL) { 825 | *OutErrorCode = FALIED_HANDLE_INVALID; 826 | } 827 | CloseHandle(hSnapshot); 828 | CMDLoader_Vars::Thread.unlock(); 829 | return false; 830 | } 831 | if (OutErrorCode > NULL) { 832 | *OutErrorCode = NULL; 833 | } 834 | *OutHandle = hProcess; 835 | CloseHandle(hSnapshot); 836 | CMDLoader_Vars::Thread.unlock(); 837 | return true; 838 | } 839 | } while (Process32Next(hSnapshot, &Processes)); 840 | } 841 | CloseHandle(hSnapshot); 842 | if (OutErrorCode > NULL) { 843 | *OutErrorCode = FALIED_PROCESS_NOT_FOUND; 844 | } 845 | CMDLoader_Vars::Thread.unlock(); 846 | return false; 847 | } 848 | bool RetrieveModuleInfoByID(ModuleMap_Info* OutputInfo, int32_t MID, int32_t* OutErrorCode) 849 | { 850 | // Paramaters 851 | if (!OutputInfo) { 852 | if (OutErrorCode > NULL) { 853 | *OutErrorCode = FALIED_INVALID_PARAMETER; 854 | } 855 | return false; 856 | } 857 | if (MID <= 0) { 858 | if (OutErrorCode > NULL) { 859 | *OutErrorCode = FALIED_INVALID_PARAMETER; 860 | } 861 | return false; 862 | } 863 | 864 | // Check if the service is started 865 | if (!CMDLoader_Vars::Inited) { 866 | if (OutErrorCode > NULL) { 867 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 868 | } 869 | return false; 870 | } 871 | 872 | // Safe thread 873 | CMDLoader_Vars::Thread.lock(); 874 | 875 | for (auto iter = CMDLoader_Vars::RegisteredModules.begin(); iter != CMDLoader_Vars::RegisteredModules.end(); iter++) 876 | { 877 | if (iter->first == MID) { 878 | CopyMemory(OutputInfo, &iter->second, sizeof(ModuleMap_Info)); 879 | if (OutErrorCode > NULL) { 880 | *OutErrorCode = NULL; 881 | } 882 | CMDLoader_Vars::Thread.unlock(); 883 | return true; 884 | } 885 | } 886 | if (OutErrorCode > NULL) { 887 | *OutErrorCode = FALIED_MODULE_NOT_FOUND; 888 | } 889 | CMDLoader_Vars::Thread.unlock(); 890 | return false; 891 | } 892 | bool RetrieveModuleIDByInfo(ModuleMap_Info* InputInfo, int32_t* OutMID, int32_t* OutErrorCode) 893 | { 894 | // Paramaters 895 | if (!InputInfo) { 896 | if (OutErrorCode > NULL) { 897 | *OutErrorCode = FALIED_INVALID_PARAMETER; 898 | } 899 | return false; 900 | } 901 | if (!OutMID) { 902 | if (OutErrorCode > NULL) { 903 | *OutErrorCode = FALIED_INVALID_PARAMETER; 904 | } 905 | return false; 906 | } 907 | 908 | // Check if the service is started 909 | if (!CMDLoader_Vars::Inited) { 910 | if (OutErrorCode > NULL) { 911 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 912 | } 913 | return false; 914 | } 915 | 916 | // Safe thread 917 | CMDLoader_Vars::Thread.lock(); 918 | 919 | for (auto iter = CMDLoader_Vars::RegisteredModules.begin(); iter != CMDLoader_Vars::RegisteredModules.end(); iter++) 920 | { 921 | if (memcmp(&iter->second, InputInfo, sizeof(ModuleMap_Info)) == 0) { 922 | *OutMID = iter->first; 923 | if (OutErrorCode > NULL) { 924 | *OutErrorCode = NULL; 925 | } 926 | CMDLoader_Vars::Thread.unlock(); 927 | return true; 928 | } 929 | } 930 | if (OutErrorCode > NULL) { 931 | *OutErrorCode = FALIED_MODULE_NOT_FOUND; 932 | } 933 | CMDLoader_Vars::Thread.unlock(); 934 | return false; 935 | } 936 | bool RetrieveRunningProcessesList(std::multimap &DataList) 937 | { 938 | // Vars 939 | DWORD aProcesses[1024], cbNeeded, cProcesses; 940 | HANDLE hProcess = INVALID_HANDLE_VALUE; 941 | unsigned int i; 942 | 943 | // Thread safe 944 | CMDLoader_Vars::Thread.lock(); 945 | 946 | // Enum 947 | if (EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) 948 | { 949 | if (DataList.size() > 0) 950 | DataList.clear(); 951 | 952 | cProcesses = cbNeeded / sizeof(DWORD); 953 | for (i = 0; i < cProcesses; i++) 954 | { 955 | if (aProcesses[i] != 0) 956 | { 957 | CHAR ProcNameFormat[MAX_PATH] = { "Unknown" }; 958 | CHAR OutString[1024] = { 0 }; 959 | bool Print = false; 960 | int32_t ErrorC; 961 | 962 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | 963 | PROCESS_VM_READ, 964 | FALSE, aProcesses[i]); 965 | if (hProcess != NULL) 966 | { 967 | HMODULE hMod; 968 | DWORD cbNeeded; 969 | 970 | if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), 971 | &cbNeeded)) 972 | { 973 | if (CMDLoader_Service_Private::IsProcessSameArch(hProcess, (void*)hMod, &ErrorC)) { 974 | if (ErrorC == NULL) { 975 | Print = true; 976 | 977 | GetModuleBaseNameA(hProcess, hMod, ProcNameFormat, 978 | sizeof(ProcNameFormat) / sizeof(CHAR)); 979 | } 980 | } 981 | } 982 | CloseHandle(hProcess); 983 | } 984 | if (Print) { 985 | std::sprintf(OutString, "%u: %s", aProcesses[i], ProcNameFormat); 986 | DataList.insert(std::make_pair(aProcesses[i], OutString)); 987 | } 988 | } 989 | } 990 | CMDLoader_Vars::Thread.unlock(); 991 | return true; 992 | } 993 | CMDLoader_Vars::Thread.unlock(); 994 | return false; 995 | } 996 | 997 | // Process helpers 998 | bool StartANewProcess(const char* InPName, char* InPCommandLine, PROCESS_INFORMATION* OutProcessInfo, int32_t* OutErrorCode) 999 | { 1000 | // Paramaters 1001 | if (!InPName) { 1002 | if (OutErrorCode > NULL) { 1003 | *OutErrorCode = FALIED_INVALID_PARAMETER; 1004 | } 1005 | return false; 1006 | } 1007 | if (!InPCommandLine) { 1008 | if (OutErrorCode > NULL) { 1009 | *OutErrorCode = FALIED_INVALID_PARAMETER; 1010 | } 1011 | return false; 1012 | } 1013 | if (!OutProcessInfo) { 1014 | if (OutErrorCode > NULL) { 1015 | *OutErrorCode = FALIED_INVALID_PARAMETER; 1016 | } 1017 | return false; 1018 | } 1019 | 1020 | // Check if the service is started 1021 | if (!CMDLoader_Vars::Inited) { 1022 | if (OutErrorCode > NULL) { 1023 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 1024 | } 1025 | return false; 1026 | } 1027 | 1028 | // Safe thread 1029 | CMDLoader_Vars::Thread.lock(); 1030 | 1031 | // Declare some variables 1032 | HANDLE hSnapshot; 1033 | HANDLE hProcess; 1034 | STARTUPINFOA info = { sizeof(info) }; 1035 | PROCESS_INFORMATION processInfo; 1036 | 1037 | if (GetFileAttributesA(InPName) == INVALID_FILE_ATTRIBUTES) { 1038 | if (OutErrorCode > NULL) { 1039 | *OutErrorCode = FALIED_FILE_NOT_EXISTS; 1040 | } 1041 | CMDLoader_Vars::Thread.unlock(); 1042 | return false; 1043 | } 1044 | if (!CreateProcessA(InPName, InPCommandLine, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &info, &processInfo)) { 1045 | if (OutErrorCode > NULL) { 1046 | *OutErrorCode = FALIED_STARTING_PROCESS; 1047 | } 1048 | CMDLoader_Vars::Thread.unlock(); 1049 | return false; 1050 | } 1051 | CopyMemory(OutProcessInfo, &processInfo, sizeof(PROCESS_INFORMATION)); 1052 | if (OutErrorCode > NULL) { 1053 | *OutErrorCode = NULL; 1054 | } 1055 | CMDLoader_Vars::Thread.unlock(); 1056 | return true; 1057 | } 1058 | bool DetachStartedProcess(PROCESS_INFORMATION* InProcessInfo, int32_t* OutErrorCode) 1059 | { 1060 | // Paramaters 1061 | if (!InProcessInfo) { 1062 | if (OutErrorCode > NULL) { 1063 | *OutErrorCode = FALIED_INVALID_PARAMETER; 1064 | } 1065 | return false; 1066 | } 1067 | 1068 | // Check if the service is started 1069 | if (!CMDLoader_Vars::Inited) { 1070 | if (OutErrorCode > NULL) { 1071 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 1072 | } 1073 | return false; 1074 | } 1075 | 1076 | // Safe thread 1077 | CMDLoader_Vars::Thread.lock(); 1078 | 1079 | // Firstly resume the thread 1080 | if (ResumeThread(InProcessInfo->hThread) == (DWORD)-1) { 1081 | if (OutErrorCode > NULL) { 1082 | *OutErrorCode = FALIED_RESUMING_THREAD; 1083 | } 1084 | CMDLoader_Vars::Thread.unlock(); 1085 | return false; 1086 | } 1087 | if (!CloseHandle(InProcessInfo->hProcess)) { 1088 | if (OutErrorCode > NULL) { 1089 | *OutErrorCode = FALIED_CLOSING_HANDLE; 1090 | } 1091 | CMDLoader_Vars::Thread.unlock(); 1092 | return false; 1093 | } 1094 | if (!CloseHandle(InProcessInfo->hThread)) { 1095 | if (OutErrorCode > NULL) { 1096 | *OutErrorCode = FALIED_CLOSING_HANDLE; 1097 | } 1098 | CMDLoader_Vars::Thread.unlock(); 1099 | return false; 1100 | } 1101 | 1102 | if (OutErrorCode > NULL) { 1103 | *OutErrorCode = NULL; 1104 | } 1105 | CMDLoader_Vars::Thread.unlock(); 1106 | return true; 1107 | } 1108 | bool CloseProcessHandle(HANDLE hProcess, int32_t* OutErrorCode) 1109 | { 1110 | // Just close the handle 1111 | if (!CloseHandle(hProcess)) { 1112 | if (OutErrorCode > NULL) { 1113 | *OutErrorCode = FALIED_CLOSING_HANDLE; 1114 | } 1115 | return false; 1116 | } 1117 | if (OutErrorCode > NULL) { 1118 | *OutErrorCode = NULL; 1119 | } 1120 | return true; 1121 | } 1122 | 1123 | bool ServiceRegisterModuleInformation(ModuleMap_Info* InputInfo, int32_t MID, int32_t* OutErrorCode) 1124 | { 1125 | // Paramaters 1126 | if (!InputInfo) { 1127 | if (OutErrorCode > NULL) { 1128 | *OutErrorCode = FALIED_INVALID_PARAMETER; 1129 | } 1130 | return false; 1131 | } 1132 | if (MID <= 0) { 1133 | if (OutErrorCode > NULL) { 1134 | *OutErrorCode = FALIED_INVALID_PARAMETER; 1135 | } 1136 | return false; 1137 | } 1138 | 1139 | // Check if the service is started 1140 | if (!CMDLoader_Vars::Inited) { 1141 | if (OutErrorCode > NULL) { 1142 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 1143 | } 1144 | return false; 1145 | } 1146 | 1147 | // Safe thread 1148 | CMDLoader_Vars::Thread.lock(); 1149 | 1150 | // Vars 1151 | ModuleMap_Info MapInfo; 1152 | CopyMemory(&MapInfo, InputInfo, sizeof(ModuleMap_Info)); 1153 | 1154 | // Check if already exists first 1155 | for (auto iter = CMDLoader_Vars::RegisteredModules.begin(); iter != CMDLoader_Vars::RegisteredModules.end(); iter++) 1156 | { 1157 | if (memcmp(&iter->second, InputInfo, sizeof(ModuleMap_Info)) == 0) { 1158 | if (OutErrorCode > NULL) { 1159 | *OutErrorCode = FALIED_ALREADY_EXISTS; 1160 | } 1161 | CMDLoader_Vars::Thread.unlock(); 1162 | return false; 1163 | } 1164 | if (iter->first == MID) { 1165 | if (OutErrorCode > NULL) { 1166 | *OutErrorCode = FALIED_ALREADY_EXISTS; 1167 | } 1168 | CMDLoader_Vars::Thread.unlock(); 1169 | return false; 1170 | } 1171 | } 1172 | CMDLoader_Vars::RegisteredModules.insert(std::make_pair(MID, MapInfo)); 1173 | if (OutErrorCode > NULL) { 1174 | *OutErrorCode = NULL; 1175 | } 1176 | CMDLoader_Vars::Thread.unlock(); 1177 | return true; 1178 | } 1179 | bool ServiceUnRegisterModuleInformation(int32_t MID, int32_t* OutErrorCode) 1180 | { 1181 | // Paramaters 1182 | if (MID <= 0) { 1183 | if (OutErrorCode > NULL) { 1184 | *OutErrorCode = FALIED_INVALID_PARAMETER; 1185 | } 1186 | return false; 1187 | } 1188 | 1189 | // Check if the service is started 1190 | if (!CMDLoader_Vars::Inited) { 1191 | if (OutErrorCode > NULL) { 1192 | *OutErrorCode = FALIED_NEEDS_INITIALIZATION; 1193 | } 1194 | return false; 1195 | } 1196 | 1197 | // Safe thread 1198 | CMDLoader_Vars::Thread.lock(); 1199 | 1200 | // Check if already exists first 1201 | for (auto iter = CMDLoader_Vars::RegisteredModules.begin(); iter != CMDLoader_Vars::RegisteredModules.end(); iter++) 1202 | { 1203 | if (iter->first == MID) { 1204 | CMDLoader_Vars::RegisteredModules.erase(iter); 1205 | if (OutErrorCode > NULL) { 1206 | *OutErrorCode = NULL; 1207 | } 1208 | CMDLoader_Vars::Thread.unlock(); 1209 | return true; 1210 | } 1211 | } 1212 | if (OutErrorCode > NULL) { 1213 | *OutErrorCode = FALIED_MODULE_NOT_FOUND; 1214 | } 1215 | CMDLoader_Vars::Thread.unlock(); 1216 | return false; 1217 | } 1218 | 1219 | // Error handler 1220 | const char* RetrieveErrorCodeString(int32_t InErrorCode) 1221 | { 1222 | const char* ErrorString; 1223 | switch (InErrorCode) 1224 | { 1225 | case NULL: 1226 | ErrorString = "SUCCESS_NO_ERROR"; 1227 | break; 1228 | case FALIED_NEEDS_INITIALIZATION: 1229 | ErrorString = "FALIED_NEEDS_INITIALIZATION"; 1230 | break; 1231 | case FALIED_ALREADY_INITIALIZED: 1232 | ErrorString = "FALIED_ALREADY_INITIALIZED"; 1233 | break; 1234 | case FALIED_BUFFER_CREATION: 1235 | ErrorString = "FALIED_BUFFER_CREATION"; 1236 | break; 1237 | case FALIED_INVALID_PARAMETER: 1238 | ErrorString = "FALIED_INVALID_PARAMETER"; 1239 | break; 1240 | case FALIED_ALREADY_EXISTS: 1241 | ErrorString = "FALIED_ALREADY_EXISTS"; 1242 | break; 1243 | case FALIED_NOT_EXISTS: 1244 | ErrorString = "FALIED_NOT_EXISTS"; 1245 | break; 1246 | case FALIED_FREE_MEMORY: 1247 | ErrorString = "FALIED_FREE_MEMORY"; 1248 | break; 1249 | case FALIED_UNLOAD: 1250 | ErrorString = "FALIED_UNLOAD"; 1251 | break; 1252 | case FALIED_LOAD: 1253 | ErrorString = "FALIED_LOAD"; 1254 | break; 1255 | case FALIED_NOT_ALLOWED: 1256 | ErrorString = "FALIED_NOT_ALLOWED"; 1257 | break; 1258 | case FALIED_ALLOCATION: 1259 | ErrorString = "FALIED_ALLOCATION"; 1260 | break; 1261 | case FALIED_NO_ACCESS: 1262 | ErrorString = "FALIED_NO_ACCESS"; 1263 | break; 1264 | case FALIED_MODULE_NOT_FOUND: 1265 | ErrorString = "FALIED_MODULE_NOT_FOUND"; 1266 | break; 1267 | case FALIED_FUNCTION_NOT_FOUND: 1268 | ErrorString = "FALIED_FUNCTION_NOT_FOUND"; 1269 | break; 1270 | case FALIED_OUT_RANGE: 1271 | ErrorString = "FALIED_OUT_RANGE"; 1272 | break; 1273 | case FALIED_MEM_ALLOCATION: 1274 | ErrorString = "FALIED_MEM_ALLOCATION"; 1275 | break; 1276 | case FALIED_INJECTION: 1277 | ErrorString = "FALIED_INJECTION"; 1278 | break; 1279 | case FALIED_REMOTE_THREAD_CREATION: 1280 | ErrorString = "FALIED_REMOTE_THREAD_CREATION"; 1281 | break; 1282 | case FALIED_FILE_HANDLE_INVALID: 1283 | ErrorString = "FALIED_FILE_HANDLE_INVALID"; 1284 | break; 1285 | case FALIED_FILE_READMAP: 1286 | ErrorString = "FALIED_FILE_READMAP"; 1287 | break; 1288 | case FALIED_INVALID_PE: 1289 | ErrorString = "FALIED_INVALID_PE"; 1290 | break; 1291 | case FALIED_INVALID_PE_ARCH: 1292 | ErrorString = "FALIED_INVALID_PE_ARCH"; 1293 | break; 1294 | case FALIED_LIBRARY_UNLOAD: 1295 | ErrorString = "FALIED_LIBRARY_UNLOAD"; 1296 | break; 1297 | case FALIED_HANDLE_INVALID: 1298 | ErrorString = "FALIED_HANDLE_INVALID"; 1299 | break; 1300 | case FALIED_PROCESS_NOT_FOUND: 1301 | ErrorString = "FALIED_PROCESS_NOT_FOUND"; 1302 | break; 1303 | case FALIED_FILE_NOT_EXISTS: 1304 | ErrorString = "FALIED_FILE_NOT_EXISTS"; 1305 | break; 1306 | case FALIED_STARTING_PROCESS: 1307 | ErrorString = "FALIED_STARTING_PROCESS"; 1308 | break; 1309 | case FALIED_RESUMING_THREAD: 1310 | ErrorString = "FALIED_RESUMING_THREAD"; 1311 | break; 1312 | case FALIED_CLOSING_HANDLE: 1313 | ErrorString = "FALIED_CLOSING_HANDLE"; 1314 | break; 1315 | case FALIED_MODULE_LOAD: 1316 | ErrorString = "FALIED_MODULE_LOAD"; 1317 | break; 1318 | case FALIED_FILE_READ: 1319 | ErrorString = "FALIED_FILE_READ"; 1320 | break; 1321 | case FALIED_READING_PROCESS_MEM: 1322 | ErrorString = "FALIED_READING_PROCESS_MEM"; 1323 | break; 1324 | case WARN_32_BIT: 1325 | ErrorString = "WARN_32_BIT"; 1326 | break; 1327 | case WARN_NO_RETURN_SIGNAL: 1328 | ErrorString = "WARN_NO_RETURN_SIGNAL"; 1329 | break; 1330 | case SUCCESS_RETURNED: 1331 | ErrorString = "SUCCESS_RETURNED"; 1332 | break; 1333 | default: 1334 | ErrorString = "Unknown error"; 1335 | break; 1336 | } 1337 | return ErrorString; 1338 | } 1339 | } -------------------------------------------------------------------------------- /src/ColdMDLoader.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Rat431 (https://github.com/Rat431). 3 | This software is under the MIT license, for more informations check the LICENSE file. 4 | */ 5 | 6 | #pragma once 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define REMOTECODEF _stdcall 16 | #define STANDARD_INJECTION 1 17 | #define MANUAL_INJECTION 2 18 | #define UNLOAD_LIBRARY 44 19 | 20 | // Errors 21 | enum CMDL_Error_Info 22 | { 23 | FALIED_NEEDS_INITIALIZATION = 40, 24 | FALIED_ALREADY_INITIALIZED, 25 | FALIED_BUFFER_CREATION, 26 | FALIED_INVALID_PARAMETER, 27 | FALIED_ALREADY_EXISTS, 28 | FALIED_NOT_EXISTS, 29 | FALIED_FREE_MEMORY, 30 | FALIED_UNLOAD, 31 | FALIED_LOAD, 32 | FALIED_NOT_ALLOWED, 33 | FALIED_ALLOCATION, 34 | FALIED_NO_ACCESS, 35 | FALIED_MODULE_NOT_FOUND, 36 | FALIED_FUNCTION_NOT_FOUND, 37 | FALIED_OUT_RANGE, 38 | FALIED_MEM_ALLOCATION, 39 | FALIED_INJECTION, 40 | FALIED_REMOTE_THREAD_CREATION, 41 | FALIED_FILE_HANDLE_INVALID, 42 | FALIED_FILE_READMAP, 43 | FALIED_INVALID_PE, 44 | FALIED_INVALID_PE_ARCH, 45 | FALIED_LIBRARY_UNLOAD, 46 | FALIED_HANDLE_INVALID, 47 | FALIED_PROCESS_NOT_FOUND, 48 | FALIED_FILE_NOT_EXISTS, 49 | FALIED_STARTING_PROCESS, 50 | FALIED_RESUMING_THREAD, 51 | FALIED_CLOSING_HANDLE, 52 | FALIED_MODULE_LOAD, 53 | FALIED_FILE_READ, 54 | FALIED_READING_PROCESS_MEM, 55 | 56 | WARN_32_BIT, 57 | WARN_NO_RETURN_SIGNAL, 58 | 59 | SUCCESS_RETURNED 60 | }; 61 | 62 | struct ModuleMap_Info 63 | { 64 | bool StatusLoaded; 65 | int32_t LFlag; 66 | void* MBaseAddress; 67 | DWORD PID; 68 | }; 69 | 70 | namespace CMDLoader_Service 71 | { 72 | // Mapping functions 73 | int32_t InitModuleInjection(HANDLE hProcess, const char* DllFileName, int32_t LFlag, ModuleMap_Info* OutMapInfo, int32_t* OutErrorCode); 74 | 75 | // Init And shut down 76 | bool ServiceGlobalInit(int32_t* OutErrorCode); 77 | bool ServiceGlobalShutDown(int32_t* OutErrorCode); 78 | 79 | // Informations and helpers 80 | bool RetrieveProcessHandleByPID(DWORD InPID, HANDLE* OutHandle, int32_t* OutErrorCode); 81 | bool RetrieveProcessHandleByName(const wchar_t* InPName, HANDLE* OutHandle, int32_t* OutErrorCode); 82 | bool RetrieveModuleInfoByID(ModuleMap_Info* OutputInfo, int32_t MID, int32_t* OutErrorCode); 83 | bool RetrieveModuleIDByInfo(ModuleMap_Info* InputInfo, int32_t* OutMID, int32_t* OutErrorCode); 84 | bool RetrieveRunningProcessesList(std::multimap &DataList); 85 | 86 | // Process helpers 87 | bool StartANewProcess(const char* InPName, char* InPCommandLine, PROCESS_INFORMATION* OutProcessInfo, int32_t* OutErrorCode); 88 | bool DetachStartedProcess(PROCESS_INFORMATION* InProcessInfo, int32_t* OutErrorCode); 89 | bool CloseProcessHandle(HANDLE hProcess, int32_t* OutErrorCode); 90 | 91 | bool ServiceRegisterModuleInformation(ModuleMap_Info* InputInfo, int32_t MID, int32_t* OutErrorCode); 92 | bool ServiceUnRegisterModuleInformation(int32_t MID, int32_t* OutErrorCode); 93 | 94 | // Error handler 95 | const char* RetrieveErrorCodeString(int32_t InErrorCode); 96 | } --------------------------------------------------------------------------------