├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── zInjector.sln └── zInjector ├── includes.h ├── main.cpp ├── main.h ├── nt_create_thread.cpp ├── nt_create_thread.h ├── portable_executable.cpp ├── portable_executable.h ├── process.cpp ├── process.h ├── utilities.cpp ├── utilities.h └── zInjector.vcxproj /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | \.vs/zInjector/v15/Browse\.VC\.db 3 | 4 | *.ipch 5 | 6 | zInjector/zInjector\.vcxproj\.user 7 | 8 | zInjector/Release/main\.obj 9 | 10 | zInjector/Release/nt_create_thread\.obj 11 | 12 | zInjector/Release/portable_executable\.obj 13 | 14 | zInjector/Release/process\.obj 15 | 16 | zInjector/Release/utilities\.obj 17 | 18 | zInjector/Release/vc141\.pdb 19 | 20 | zInjector/Release/zInjector\.log 21 | 22 | zInjector/Release/zInjector\.tlog/CL\.command\.1\.tlog 23 | 24 | zInjector/Release/zInjector\.tlog/CL\.read\.1\.tlog 25 | 26 | zInjector/Release/zInjector\.tlog/CL\.write\.1\.tlog 27 | 28 | zInjector/Release/zInjector\.tlog/link\.command\.1\.tlog 29 | 30 | zInjector/Release/zInjector\.tlog/link\.read\.1\.tlog 31 | 32 | zInjector/Release/zInjector\.tlog/link\.write\.1\.tlog 33 | 34 | zInjector/Release/zInjector\.tlog/zInjector\.lastbuildstate 35 | 36 | zInjector/Release/zInjector\.tlog/zInjector\.write\.1u\.tlog 37 | 38 | \.vs/zInjector/v15/\.suo 39 | 40 | Release/zInjector\.exe 41 | 42 | Release/zInjector\.iobj 43 | 44 | Release/zInjector\.ipdb 45 | 46 | Release/zInjector\.pdb 47 | 48 | *.opendb 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Jeramie (https://github.com/EternityX/) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zInjector 2 | A command-line utility for injecting x86 dynamic link libraries (DLL) into external processes. 3 | 4 | # Building 5 | Open 'zInjector.sln' in Visual Studio and build the solution in Release mode to create zInjector.exe. 6 | 7 | # Usage 8 | 9 | ### Syntax 10 | zInjector [dll path] [process name] [method number] 11 | 12 | ### Injection Methods 13 | - CreateRemoteThread - 1 14 | - NtCreateThreadEx - 2 15 | 16 | #### Example 17 | ``` 18 | C:\zInjector.exe C:\Library.dll notepad.exe 1 19 | ``` 20 | 21 | # Credits 22 | - https://github.com/DarthTon/Blackbone/ 23 | - https://github.com/stephenfewer/ReflectiveDLLInjection/ 24 | - http://securityxploded.com/ntcreatethreadex.php/ 25 | - https://bitbucket.org/evolution536/crysearch-memory-scanner/ 26 | 27 | # License 28 | zInjector is licensed under the MIT License, see the LICENSE file for more information. 29 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /zInjector.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zInjector", "zInjector\zInjector.vcxproj", "{396176A5-FD67-4326-9B57-1B2090455EFD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {396176A5-FD67-4326-9B57-1B2090455EFD}.Debug|x64.ActiveCfg = Debug|x64 17 | {396176A5-FD67-4326-9B57-1B2090455EFD}.Debug|x64.Build.0 = Debug|x64 18 | {396176A5-FD67-4326-9B57-1B2090455EFD}.Debug|x86.ActiveCfg = Debug|Win32 19 | {396176A5-FD67-4326-9B57-1B2090455EFD}.Debug|x86.Build.0 = Debug|Win32 20 | {396176A5-FD67-4326-9B57-1B2090455EFD}.Release|x64.ActiveCfg = Release|x64 21 | {396176A5-FD67-4326-9B57-1B2090455EFD}.Release|x64.Build.0 = Release|x64 22 | {396176A5-FD67-4326-9B57-1B2090455EFD}.Release|x86.ActiveCfg = Release|Win32 23 | {396176A5-FD67-4326-9B57-1B2090455EFD}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /zInjector/includes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NOMINMAX 4 | 5 | #define WIN32_NO_STATUS 6 | #include 7 | #undef WIN32_NO_STATUS 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "process.h" 26 | #include "portable_executable.h" 27 | 28 | #include "utilities.h" 29 | 30 | #pragma comment (lib, "Shlwapi.lib") 31 | #pragma comment(lib,"psapi") -------------------------------------------------------------------------------- /zInjector/main.cpp: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | 3 | Copyright(c) 2019 (https://github.com/EternityX/) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files( the "Software" ), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions : 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | 22 | SOFTWARE. */ 23 | 24 | #include "main.h" 25 | #include "utilities.h" 26 | 27 | #include "nt_create_thread.h" 28 | 29 | bool initialize( const std::string &base_directory, const std::string &dll_path, const std::string &process_name, int injection_method ); 30 | bool do_injection_method( const wpm::Process &process, const std::string &dll_path, int injection_method ); 31 | 32 | int main( int argc, char *argv[] ) { 33 | if( argc != 4 ) { 34 | std::cout << "Usage: " << argv[ 0 ] << " [DLL] [Process Name] [Injection Method]\n"; 35 | std::cin.get(); 36 | return 1; 37 | } 38 | 39 | try { 40 | if( !initialize( argv[ 0 ], argv[ 1 ], argv[ 2 ], atoi( argv[ 3 ] ) ) ) { 41 | utilities::raise_error(); 42 | return 1; 43 | } 44 | } 45 | catch( ... ) { 46 | std::cout << "Unknown injection error. Are you using the correct arguments?\n"; 47 | std::cin.get(); 48 | return 1; 49 | } 50 | 51 | return 0; 52 | } 53 | 54 | bool initialize( const std::string &base_directory, const std::string &dll_path, const std::string &process_name, int injection_method ) { 55 | auto local_process = wpm::Process( GetCurrentProcessId( ), PROCESS_ALL_ACCESS ); 56 | 57 | auto process = wpm::Process( process_name, PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ ); 58 | if( !process.is_valid() ) { 59 | std::cout << "Target process '" << process_name << "' is not running.\n"; 60 | return false; 61 | } 62 | 63 | if( !process.open( FALSE ) || !local_process.open( FALSE ) ) { 64 | std::cout << "Failed to open process with error code: "; 65 | return false; 66 | } 67 | 68 | // make sure our process has the correct privileges 69 | if( !local_process.set_privilege( SE_DEBUG_NAME, TRUE ) ) { 70 | std::cout << "Unable to set privilege with error code: "; 71 | return false; 72 | } 73 | 74 | auto pe = wpm::PortableExecutable( &process ); 75 | if( !utilities::is_valid_library( pe, dll_path ) ) { 76 | std::cout << "Unable to retrieve image header with error code: "; 77 | return false; 78 | } 79 | 80 | // attempt to inject 81 | if( !do_injection_method( process, dll_path, injection_method ) ) 82 | return false; 83 | 84 | auto filename = dll_path + ".bat"; 85 | if( !std::experimental::filesystem::exists( filename ) ) { 86 | std::cout << "Create a batch file to easily run this program with the given arguments? [Y/N]" << std::endl; 87 | 88 | char input; 89 | std::cin >> input; 90 | 91 | if( input == 'y' || input == 'Y' ) { 92 | std::ofstream of_stream( filename, std::ofstream::out ); 93 | of_stream << base_directory << " " << dll_path << " " << process_name << " " << injection_method; 94 | } 95 | } 96 | 97 | return true; 98 | } 99 | 100 | bool do_injection_method( const wpm::Process &process, const std::string &dll_path, int injection_method ) { 101 | switch( injection_method ) { 102 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682437(v=vs.85).aspx 103 | case METHOD_CREATEREMOTETHREAD: { 104 | if( !process.load_library_external( dll_path ) ) 105 | return false; 106 | } 107 | break; 108 | // undocumented function 109 | case METHOD_NTCREATETHREAD: { 110 | if( !injection_methods::nt_create_thread( process, dll_path ) ) 111 | return false; 112 | } 113 | break; 114 | default: 115 | std::cout << "Invalid injection method." << std::endl; 116 | std::cout << "Available injection methods:" << std::endl << "1 - CreateRemoteThread" << std::endl << "2 - NtCreateThreadEx" << std::endl; 117 | break; 118 | } 119 | 120 | std::cout << "Injection successful." << std::endl; 121 | 122 | return true; 123 | } 124 | -------------------------------------------------------------------------------- /zInjector/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "process.h" 4 | 5 | enum InjectionMethods { 6 | METHOD_CREATEREMOTETHREAD = 1, 7 | METHOD_NTCREATETHREAD = 2 8 | }; -------------------------------------------------------------------------------- /zInjector/nt_create_thread.cpp: -------------------------------------------------------------------------------- 1 | #include "nt_create_thread.h" 2 | 3 | bool injection_methods::nt_create_thread( wpm::Process process, const std::string &library_path ) { 4 | auto process_handle = process.get_handle(); 5 | if( !process_handle ) 6 | return false; 7 | 8 | LPVOID base_address = VirtualAllocEx( process_handle, nullptr, library_path.length() + 1, MEM_COMMIT, PAGE_READWRITE ); 9 | if( !WriteProcessMemory( process_handle, base_address, library_path.c_str(), library_path.size() + 1, nullptr ) ) { 10 | VirtualFreeEx( process_handle, base_address, 0, MEM_RELEASE ); 11 | return false; 12 | } 13 | 14 | auto nt_create_thread_address = reinterpret_cast( GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "NtCreateThreadEx" ) ); 15 | auto load_library_address = reinterpret_cast( GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "LoadLibraryA" ) ); 16 | if( !nt_create_thread_address || load_library_address ) 17 | return false; 18 | 19 | 20 | DWORD temp1 = 0; 21 | 22 | NTCREATETHREAD_BUFFER buffer{}; 23 | buffer.m_size = sizeof( struct NTCREATETHREAD_BUFFER ); 24 | buffer.m_unknown1 = 0x10003; 25 | buffer.m_unknown2 = 0x8; 26 | buffer.m_unknown3 = nullptr; 27 | buffer.m_unknown4 = 0; 28 | buffer.m_unknown5 = 0x10004; 29 | buffer.m_unknown6 = 0x4; 30 | buffer.m_unknown7 = &temp1; 31 | buffer.m_unknown8 = 0; 32 | 33 | HANDLE remote_thread = nullptr; 34 | NTSTATUS status = nt_create_thread_address( &remote_thread, 0x1FFFFF, nullptr, process_handle, load_library_address, base_address, 0, 0, 0, 0, &buffer ); 35 | 36 | if( remote_thread == nullptr || NT_ERROR( status ) ) 37 | return false; 38 | 39 | WaitForSingleObject( remote_thread, 5000 ); 40 | CloseHandle( remote_thread ); 41 | VirtualFreeEx( remote_thread, base_address, 0, MEM_RELEASE ); 42 | 43 | return true; 44 | } 45 | -------------------------------------------------------------------------------- /zInjector/nt_create_thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "includes.h" 4 | 5 | struct NTCREATETHREAD_BUFFER { 6 | ULONG m_size; 7 | ULONG m_unknown1; 8 | ULONG m_unknown2; 9 | PULONG m_unknown3; 10 | ULONG m_unknown4; 11 | ULONG m_unknown5; 12 | ULONG m_unknown6; 13 | PULONG m_unknown7; 14 | ULONG m_unknown8; 15 | }; 16 | 17 | typedef NTSTATUS ( __stdcall *NTCREATETHREADEX) ( 18 | PHANDLE thread, 19 | ACCESS_MASK desired_access, 20 | LPVOID object_attributes, 21 | HANDLE process_handle, 22 | LPTHREAD_START_ROUTINE start_address, 23 | LPVOID lp, 24 | BOOL create_suspended, 25 | ULONG stack_zero_bits, 26 | ULONG size_of_stack_commit, 27 | ULONG size_of_stack_reserve, 28 | LPVOID bytes_buffer ); 29 | 30 | namespace injection_methods { 31 | bool nt_create_thread( wpm::Process process, const std::string &library_path ); 32 | } 33 | -------------------------------------------------------------------------------- /zInjector/portable_executable.cpp: -------------------------------------------------------------------------------- 1 | #include "portable_executable.h" 2 | 3 | namespace wpm { 4 | PortableExecutable::PortableExecutable( Process *process ) { 5 | m_process = process; 6 | } 7 | 8 | HANDLE PortableExecutable::create_map_view() { 9 | TCHAR buffer[ MAX_PATH ]; 10 | if( !K32GetModuleFileNameExA( m_process->get_handle( ), nullptr, buffer, MAX_PATH ) ) 11 | return nullptr; 12 | 13 | m_file = CreateFileA( buffer, GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ); 14 | if( m_file == INVALID_HANDLE_VALUE ) 15 | return nullptr; 16 | 17 | HANDLE map = CreateFileMappingA( m_file, nullptr, PAGE_READONLY, 0, 0, nullptr ); 18 | if( !map ) 19 | return nullptr; 20 | 21 | HANDLE map_view = MapViewOfFile( map, FILE_MAP_READ, 0, 0, 0 ); 22 | if( !map_view ) 23 | return nullptr; 24 | 25 | if( !CloseHandle( m_file ) && !CloseHandle( map ) && !CloseHandle( map_view ) ) 26 | return nullptr; 27 | 28 | return map_view; 29 | } 30 | 31 | PIMAGE_DOS_HEADER PortableExecutable::fetch_dos_header( HANDLE map_view ) { 32 | auto dos_header = static_cast( map_view ); 33 | if( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) 34 | return nullptr; 35 | 36 | return dos_header; 37 | } 38 | 39 | PIMAGE_NT_HEADERS PortableExecutable::fetch_image_header() { 40 | auto dos_header = PortableExecutable::fetch_dos_header( PortableExecutable::create_map_view( ) ); 41 | if( !dos_header ) 42 | return nullptr; 43 | 44 | auto image_header = reinterpret_cast( reinterpret_cast( dos_header ) + dos_header->e_lfanew ); 45 | if( image_header->Signature != IMAGE_NT_SIGNATURE ) 46 | return nullptr; 47 | 48 | return image_header; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /zInjector/portable_executable.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | 3 | Copyright(c) 2017 (https://github.com/EternityX/) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files( the "Software" ), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions : 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | 22 | SOFTWARE. */ 23 | 24 | #pragma once 25 | 26 | #include "process.h" 27 | 28 | namespace wpm { 29 | class PortableExecutable { 30 | public: 31 | struct IMPORT_INFO { 32 | DWORD m_library; 33 | DWORD m_function; 34 | }; 35 | 36 | public: 37 | /** 38 | * Constructor. 39 | * 40 | * @param process The process object. 41 | */ 42 | explicit PortableExecutable( Process *process ); 43 | 44 | /** 45 | * Maps a view of a file mapping into the address space of a calling process for use with FetchImageHeader. 46 | */ 47 | HANDLE create_map_view(); 48 | 49 | /** 50 | * Retrieves the DOS header for use with FetchImageHeader. 51 | * 52 | * @param map_view Handle to the map view. 53 | */ 54 | static PIMAGE_DOS_HEADER fetch_dos_header( HANDLE map_view ); 55 | 56 | /** 57 | * Retrieves PIMAGE_NT_HEADERS structure 58 | */ 59 | PIMAGE_NT_HEADERS fetch_image_header(); 60 | 61 | /** 62 | * Determines if the process is 64bit architecture by checking the file header for IMAGE_FILE_MACHINE_AMD64. 63 | */ 64 | bool is_64_bit(); 65 | 66 | // TODO: doc 67 | std::vector fetch_imports(); 68 | 69 | protected: 70 | HANDLE m_file = nullptr; // Handle to file 71 | 72 | private: 73 | Process *m_process; 74 | }; 75 | } -------------------------------------------------------------------------------- /zInjector/process.cpp: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | 3 | namespace wpm { 4 | Process::Process( DWORD process_id, DWORD desired_access ) { 5 | m_pid = process_id; 6 | m_desired_access = desired_access; 7 | m_hwnd = Process::fetch_primary_window_handle( ); 8 | m_handle = nullptr; 9 | } 10 | 11 | Process::Process( const std::string &process_name, DWORD desired_access ) { 12 | m_pid = Process::fetch_process_by_name( process_name ); 13 | m_desired_access = desired_access; 14 | m_hwnd = Process::fetch_primary_window_handle(); 15 | m_handle = nullptr; 16 | m_name = process_name; 17 | } 18 | 19 | Process::~Process() { 20 | Process::close_open_handle(); 21 | } 22 | 23 | bool Process::is_valid() const { 24 | return m_handle != INVALID_HANDLE_VALUE; 25 | } 26 | 27 | bool Process::open( BOOL inherit_handle ) { 28 | m_handle = OpenProcess( m_desired_access, inherit_handle, m_pid ); 29 | return m_handle != INVALID_HANDLE_VALUE; 30 | } 31 | 32 | bool Process::close_open_handle() const { 33 | return !( m_handle == INVALID_HANDLE_VALUE || !CloseHandle( m_handle ) ); 34 | } 35 | 36 | DWORD Process::fetch_process_by_name( const std::string &process_name ) { 37 | int count = 0; 38 | int pid = 0; 39 | 40 | HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); 41 | if( snapshot == INVALID_HANDLE_VALUE ) 42 | return -1; 43 | 44 | PROCESSENTRY32 process_entry = { sizeof( PROCESSENTRY32 ) }; 45 | Process32Next( snapshot, &process_entry ); 46 | do { 47 | if( process_name != std::string( process_entry.szExeFile ) ) { 48 | count++; 49 | pid = process_entry.th32ProcessID; 50 | } 51 | } while ( Process32Next( snapshot, &process_entry ) ); 52 | 53 | if( count > 1 ) 54 | pid = -1; 55 | 56 | CloseHandle( snapshot ); 57 | 58 | return pid; 59 | } 60 | 61 | HWND Process::fetch_primary_window_handle() { 62 | std::pair pair = { nullptr, m_pid }; 63 | 64 | auto result = EnumWindows( []( HWND hwnd, LPARAM lparam ) { 65 | auto params = reinterpret_cast*>( lparam ); 66 | 67 | DWORD processId; 68 | if( GetWindowThreadProcessId( hwnd, &processId ) && processId == params->second && GetWindow( hwnd, GW_OWNER ) == nullptr ) { 69 | params->first = hwnd; 70 | return FALSE; 71 | } 72 | 73 | return TRUE; 74 | }, reinterpret_cast( &pair ) ); 75 | 76 | if( !result && pair.first ) 77 | return pair.first; 78 | 79 | return nullptr; 80 | } 81 | 82 | HANDLE Process::fetch_access_token( DWORD desired_access ) const { 83 | HANDLE token_handle; 84 | 85 | if( !OpenProcessToken( m_handle, desired_access, &token_handle ) ) 86 | return nullptr; 87 | 88 | return token_handle; 89 | } 90 | 91 | bool Process::set_privilege( LPCTSTR name, BOOL enable_privilege ) const { 92 | TOKEN_PRIVILEGES privilege = { 0, 0, 0, 0 }; 93 | LUID luid = { 0, 0 }; 94 | 95 | HANDLE token = Process::fetch_access_token( TOKEN_ADJUST_PRIVILEGES ); 96 | 97 | if( !LookupPrivilegeValueA( nullptr, name, &luid ) ) { 98 | CloseHandle( token ); 99 | return false; 100 | } 101 | 102 | privilege.PrivilegeCount = 1; 103 | privilege.Privileges[ 0 ].Luid = luid; 104 | privilege.Privileges[ 0 ].Attributes = enable_privilege ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED; 105 | 106 | if( !AdjustTokenPrivileges( token, FALSE, &privilege, 0, nullptr, nullptr ) ) { 107 | CloseHandle( token ); 108 | return false; 109 | } 110 | 111 | CloseHandle( token ); 112 | 113 | return true; 114 | } 115 | 116 | bool Process::load_library_external( const std::string &library_path ) const { 117 | LPVOID base_address = VirtualAllocEx( m_handle, nullptr, library_path.size() + 1, MEM_COMMIT, PAGE_READWRITE ); 118 | 119 | if( !WriteProcessMemory( m_handle, base_address, library_path.c_str(), library_path.size() + 1, nullptr ) ) { 120 | VirtualFreeEx( m_handle, base_address, 0, MEM_RELEASE ); 121 | return false; 122 | } 123 | 124 | HANDLE thread = CreateRemoteThread( m_handle, nullptr, 0, LPTHREAD_START_ROUTINE( GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "LoadLibraryA" ) ), base_address, 0, nullptr ); 125 | if( thread && thread != INVALID_HANDLE_VALUE ) { 126 | WaitForSingleObject( thread, 5000 ); 127 | CloseHandle( thread ); 128 | } 129 | else { 130 | VirtualFreeEx( m_handle, base_address, 0, MEM_RELEASE ); 131 | return false; 132 | } 133 | 134 | return true; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /zInjector/process.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | 3 | Copyright(c) 2017 (https://github.com/EternityX/) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files( the "Software" ), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions : 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | 22 | SOFTWARE. */ 23 | 24 | #pragma once 25 | 26 | #define WIN32_NO_STATUS 27 | #include 28 | #undef WIN32_NO_STATUS 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | 37 | #include 38 | 39 | #include "Shlwapi.h" 40 | #pragma comment(lib, "shlwapi") 41 | 42 | #include 43 | #pragma comment(lib, "psapi") 44 | 45 | namespace wpm { 46 | class Process { 47 | public: 48 | struct HANDLE_INFO { 49 | DWORD m_pid; 50 | HANDLE m_process; 51 | }; 52 | 53 | private: 54 | // SystemHandleInformation 55 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO { 56 | USHORT unique_pid; 57 | USHORT creator_backtrace_index; 58 | UCHAR object_type_index; 59 | UCHAR handle_attributes; 60 | USHORT handle_value; 61 | PVOID object; 62 | ULONG granted_access; 63 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO; 64 | 65 | typedef struct _SYSTEM_HANDLE_INFORMATION { 66 | ULONG number_of_handles; 67 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handles[ 1 ]; 68 | } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; 69 | 70 | // SystemExtendedHandleInformation 71 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX { 72 | PVOID object; 73 | ULONG_PTR unique_pid; 74 | ULONG_PTR handle_value; 75 | ULONG granted_access; 76 | USHORT creator_backtrace_index; 77 | USHORT object_type_index; 78 | ULONG handle_attributes; 79 | ULONG reserved; 80 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; 81 | 82 | typedef struct _SYSTEM_HANDLE_INFORMATION_EX { 83 | ULONG_PTR number_of_handles; 84 | ULONG_PTR reserved; 85 | SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handles[ 1 ]; 86 | } SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; 87 | 88 | public: 89 | /** 90 | * Constructor. 91 | * 92 | * @param process_id The process ID(PID). 93 | * @param desired_access The access to the process object. 94 | */ 95 | Process( DWORD process_id, DWORD desired_access ); 96 | 97 | /** 98 | * Constructor. 99 | * 100 | * @param process_name The process name. 101 | * @param desired_access The access to the process object. 102 | */ 103 | Process( const std::string &process_name, DWORD desired_access ); 104 | 105 | // Calls CloseOpenHandle. 106 | ~Process(); 107 | 108 | // Checks if the process is running/active. 109 | bool is_valid() const; 110 | 111 | // Wrapper function for IsHungAppWindow, returns true if the application is hanging. 112 | BOOL is_not_responding() const; 113 | 114 | /** 115 | * Sends the WM_NULL message to the primary window handle. 116 | * 117 | * @param timeout The duration of the time-out period, in milliseconds. 118 | */ 119 | LRESULT is_not_responding( UINT timeout ) const; 120 | 121 | /** 122 | * Set the access to the process object. This access right is checked against the security descriptor for the process. 123 | * You do not need to call this function if you need PROCESS_ALL_ACCESS as your desired access. 124 | * 125 | * @param desired_access The access to the process object. 126 | */ 127 | void set_desired_access( DWORD desired_access ) { 128 | m_desired_access = desired_access; 129 | } 130 | 131 | /** 132 | * Set the m_name member variable. 133 | * 134 | * @param module_name The process name. 135 | */ 136 | void set_module_name( std::string module_name ) { 137 | m_name = module_name; 138 | } 139 | 140 | /** 141 | * Set the m_hwnd member variable. 142 | * 143 | * @param window_handle The primary window handle. 144 | */ 145 | void set_primary_window_handle( HWND window_handle ) { 146 | m_handle = window_handle; 147 | } 148 | 149 | // Returns m_pid member. 150 | DWORD &get_pid() { 151 | return m_pid; 152 | } 153 | 154 | // Returns m_desired_access member. 155 | DWORD &get_desired_access() { 156 | return m_desired_access; 157 | } 158 | 159 | // Returns m_hwnd member. 160 | HWND &get_primary_window_handle() { 161 | return m_hwnd; 162 | } 163 | 164 | // Returns m_handle member. 165 | HANDLE &get_handle() { 166 | return m_handle; 167 | } 168 | 169 | // Returns m_name member. 170 | std::string &get_module_name() { 171 | return m_name; 172 | } 173 | 174 | /** 175 | * Wrapper function for OpenProcess. 176 | * 177 | * @param inherit_handle If this value is TRUE, processes created by this process will inherit the handle. 178 | */ 179 | bool open( BOOL inherit_handle ); 180 | 181 | /** 182 | * Wrapper function for CloseHandle. 183 | */ 184 | bool close_open_handle() const; 185 | 186 | /** 187 | * Returns process ID. -1 on failure. 188 | * 189 | * @param process_name The target process name. 190 | */ 191 | static DWORD fetch_process_by_name( const std::string &process_name ); 192 | 193 | /** 194 | * Wrapper function for GetProcessImageFileName. 195 | */ 196 | std::string fetch_process_image_file_name() const; 197 | 198 | /** 199 | * Wrapper function for GetModuleFileName. 200 | */ 201 | std::string fetch_module_file_name() const; 202 | 203 | /** 204 | * Wrapper function for TerminateProcess. 205 | * 206 | * @param exit_code The exit code to be used by the process and threads terminated as a result of this call. 207 | */ 208 | bool terminate( UINT exit_code = EXIT_SUCCESS ) const; 209 | 210 | /** 211 | * Returns a handle for every thread within the process. 212 | */ 213 | std::vector fetch_threads() const; 214 | 215 | /** 216 | * Resumes the process by enumerating all threads and calling ResumeThread. 217 | */ 218 | bool resume() const; 219 | 220 | /** 221 | * EXPERIMENTAL: Resumes the process via the undocumented NtResumeProcess function. 222 | */ 223 | bool nt_resume() const; 224 | 225 | /** 226 | * Suspends the process by enumerating all threads and calling SuspendThread. 227 | */ 228 | bool suspend() const; 229 | 230 | /** 231 | * EXPERIMENTAL: Suspends the process via the undocumented NtSuspendProcess function. 232 | */ 233 | bool nt_suspend() const; 234 | 235 | // TODO: doc 236 | std::vector fetch_handles() const; 237 | 238 | /** 239 | * Opens the access token associated with the process. 240 | * 241 | * @param desired_access Specifies an access mask that specifies the requested types of access to the access token. 242 | */ 243 | HANDLE fetch_access_token( DWORD desired_access ) const; 244 | 245 | /** 246 | * Wrapper function for AdjustTokenPrivileges. 247 | * 248 | * @param name A pointer to a null-terminated string that specifies the name of the privilege, as defined in the Winnt.h header file 249 | * @param enable_privilege Enables or disables the privilege. 250 | */ 251 | bool set_privilege( LPCTSTR name, BOOL enable_privilege ) const; 252 | 253 | /** 254 | * EXPERIMENTAL: Enables or disables a privilege from the calling thread or process. 255 | * 256 | * @param privilege Privilege index to change. 257 | * @param enable If TRUE, then enable the privilege otherwise disable. 258 | * @param current_thread If TRUE, then enable in calling thread, otherwise process. 259 | * @param enabled Whether privilege was previously enabled or disabled. 260 | */ 261 | static bool rtl_adjust_privileges( ULONG privilege, BOOLEAN enable, BOOLEAN current_thread, PBOOLEAN enabled ); 262 | 263 | /** 264 | * Load a dynamic link library into the target process. 265 | * 266 | * @param library_path Full path to library. 267 | */ 268 | bool load_library_external( const std::string &library_path ) const; 269 | 270 | protected: 271 | DWORD m_pid; // Process ID 272 | DWORD m_desired_access; // Desired access 273 | HWND m_hwnd; // Window handle 274 | HANDLE m_handle; // Handle to process 275 | std::string m_name; // Module name 276 | 277 | private: 278 | // Calls GetWindowThreadProcessId to return the primary window handle. 279 | HWND fetch_primary_window_handle(); 280 | 281 | // Run-time dynamic linking. 282 | using NtSuspendProcess = NTSTATUS( __stdcall * )( HANDLE ); 283 | using NtResumeProcess = NTSTATUS( __stdcall * )( HANDLE ); 284 | using NtQuerySystemInformation = NTSTATUS( __stdcall * )( ULONG, PVOID, ULONG, PULONG ); 285 | using NtQueryObject = NTSTATUS( __stdcall * )( ULONG, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG ); 286 | 287 | using RtlSetProcessIsCritical = NTSTATUS( __stdcall * )( BOOLEAN, BOOLEAN, BOOLEAN ); 288 | using RtlAdjustPrivilege = NTSTATUS( __stdcall * )( ULONG, BOOLEAN, BOOLEAN, PBOOLEAN ); 289 | 290 | enum _SYSTEM_INFORMATION_CLASS { 291 | SystemProcessInformation = 0x0005, 292 | SystemHandleInformation = 0x0010, 293 | SystemExtendedProcessInformation = 0x0039, 294 | SystemExtendedHandleInformation = 0x0040 // SystemExtendedHandleInformation isn't stuck with 16bit process IDs. 295 | }; 296 | }; 297 | } -------------------------------------------------------------------------------- /zInjector/utilities.cpp: -------------------------------------------------------------------------------- 1 | #include "utilities.h" 2 | #include "main.h" 3 | 4 | void utilities::raise_error() { 5 | DWORD last_error = GetLastError(); 6 | if( last_error == ERROR_SUCCESS ) 7 | return; 8 | 9 | nullptr_t format_buffer; 10 | auto format_flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS; 11 | DWORD size = FormatMessageA( format_flags, nullptr, last_error, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), reinterpret_cast( &format_buffer ), 0, nullptr ); 12 | 13 | std::string text{ format_buffer, size }; 14 | std::cout << text << "\n"; 15 | std::cout << "Press ENTER to continue . . ."; 16 | std::cin.get(); 17 | } 18 | 19 | PIMAGE_NT_HEADERS utilities::retrieve_image_header( const std::string &dll_path ) { 20 | // note: https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files 21 | 22 | // the handle to our module 23 | HANDLE file = CreateFileA( dll_path.c_str( ), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ); 24 | if( file == INVALID_HANDLE_VALUE ) 25 | return nullptr; 26 | 27 | // create a mapping object for our module 28 | HANDLE map = CreateFileMappingA( file, nullptr, PAGE_READONLY, 0, 0, nullptr ); 29 | if( !map ) 30 | return nullptr; 31 | 32 | // map the file with the handle to the mapping object we created 33 | HANDLE map_view = MapViewOfFile( map, FILE_MAP_READ, 0, 0, 0 ); 34 | if( !map_view ) 35 | return nullptr; 36 | 37 | // grab the ms-dos header with our file map 38 | // https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#MS-DOS_header 39 | auto dos_header = static_cast< PIMAGE_DOS_HEADER >( map_view ); 40 | 41 | // make sure the ms-dos header is actually valid 42 | if( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) 43 | return nullptr; 44 | 45 | // grab the nt header 46 | auto image_nt_headers = reinterpret_cast( reinterpret_cast( dos_header ) + dos_header->e_lfanew ); 47 | 48 | // make sure it's valid 49 | if( image_nt_headers->Signature != IMAGE_NT_SIGNATURE ) 50 | return nullptr; 51 | 52 | if( !CloseHandle( file ) ) 53 | return nullptr; 54 | 55 | return image_nt_headers; 56 | } 57 | 58 | bool utilities::is_valid_library( wpm::PortableExecutable pe, const std::string &dll_path ) { 59 | auto image_nt_headers = retrieve_image_header( dll_path ); 60 | if( !image_nt_headers ) 61 | return false; 62 | 63 | if( !( image_nt_headers->FileHeader.Characteristics & IMAGE_FILE_DLL ) ) { 64 | std::cout << "The selected payload is not a valid DLL.\n"; 65 | return false; 66 | } 67 | if( !image_nt_headers->FileHeader.Machine == pe.fetch_image_header()->FileHeader.Machine ) { 68 | std::cout << "The selected payload's architecture must match the target's\n"; 69 | return false; 70 | } 71 | 72 | if( !image_nt_headers->OptionalHeader.AddressOfEntryPoint ) 73 | std::cout << "No entry point found!\n"; 74 | 75 | return true; 76 | } -------------------------------------------------------------------------------- /zInjector/utilities.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "includes.h" 4 | 5 | namespace utilities { 6 | void raise_error(); 7 | 8 | /** 9 | * Retrieves the portable executable(PE) header of the passed DLL. 10 | * 11 | * @param dll_path Absolute path to the DLL. 12 | */ 13 | PIMAGE_NT_HEADERS retrieve_image_header( const std::string &dll_path ); 14 | 15 | /** 16 | * Verifies the file exists and is a valid DLL. 17 | * 18 | * @param dll_path Absolute path to the DLL. 19 | */ 20 | bool is_valid_library( wpm::PortableExecutable pe, const std::string &dll_path ); 21 | } 22 | -------------------------------------------------------------------------------- /zInjector/zInjector.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {396176A5-FD67-4326-9B57-1B2090455EFD} 23 | Win32Proj 24 | zInjector 25 | 10.0.16299.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | $(SourcePath) 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | 93 | 94 | 95 | 96 | Console 97 | true 98 | RequireAdministrator 99 | 100 | 101 | 102 | 103 | 104 | 105 | Level3 106 | Disabled 107 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | 118 | 119 | MaxSpeed 120 | true 121 | true 122 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | 124 | 125 | 126 | 127 | Console 128 | true 129 | true 130 | true 131 | RequireAdministrator 132 | 133 | 134 | 135 | 136 | Level3 137 | 138 | 139 | MaxSpeed 140 | true 141 | true 142 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | 144 | 145 | Console 146 | true 147 | true 148 | true 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | --------------------------------------------------------------------------------