├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── VmxHijack ├── VmxHijack.licenseheader ├── VmxHijack.sln ├── VmxHijack.vcxproj ├── VmxHijack.vcxproj.filters ├── VmxHijack.vcxproj.user ├── config.hpp ├── dllproxy.cpp ├── logger.hpp ├── main.cpp └── vmx.hpp ├── includes └── vmx.hpp ├── install.bat ├── uninstall.bat └── vmx.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | VmxHijack/build/VmxHijack.tlog/ 3 | 4 | *.log 5 | 6 | VmxHijack/build/ 7 | 8 | VmxHijack/.vs/VmxHijack/v16/ 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "linux-pe"] 2 | path = linux-pe 3 | url = https://github.com/can1357/linux-pe 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Can Bölük 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 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. 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 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

VmxHijack

3 |

4 | Header-only VMWare Backdoor API Implementation & Effortless VMX Patcher for Custom Guest-to-Host RPCs 5 |

6 |
7 |

8 | 9 | # Sample 10 | 11 | ```cpp 12 | 13 | // --- RPC Server Code (VmxHijack/vmx.hpp) 14 | // 15 | bool vmx_log_handler( 16 | uint64_t vcpuid, void* vcpuctx, 17 | const char* data, uint32_t length, 18 | const void** out, uint32_t* out_length ) 19 | { 20 | // Insert the message prefix. 21 | // 22 | std::string msg = "[vmx] vcpu-" + std::to_string( vcpuid ) + ": "; 23 | msg.insert( msg.end(), data, data + length ); 24 | 25 | // Print onto the host console and DebugView. 26 | // 27 | OutputDebugStringA( msg.c_str() ); 28 | logger::print( "%s\n", msg.c_str() ); 29 | 30 | // Write dummy output. 31 | // 32 | *out = "OK"; 33 | *out_length = 2; 34 | return true; 35 | } 36 | 37 | 38 | 39 | // --- RPC Client Code (Any guest application/driver/hypervisor) 40 | // 41 | extern "C" int32_t DriverEntry() 42 | { 43 | auto [success, reply] = vmx::send( "Hello from guest Ring0 to Host!" ); 44 | DbgPrint( "=> %s\n", reply.c_str() ); 45 | return -1; 46 | } 47 | ``` 48 | 49 | 50 | -------------------------------------------------------------------------------- /VmxHijack/VmxHijack.licenseheader: -------------------------------------------------------------------------------- 1 | extensions: .cpp .hpp 2 | // Copyright (c) 2020, Can Boluk 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, 12 | // this list of conditions and the following disclaimer in the documentation 13 | // and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // -------------------------------------------------------------------------------- /VmxHijack/VmxHijack.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30717.126 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VmxHijack", "VmxHijack.vcxproj", "{E0810C81-30B4-4C98-8136-0DB4D1776D06}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x64 = Release|x64 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {E0810C81-30B4-4C98-8136-0DB4D1776D06}.Release|x64.ActiveCfg = Release|x64 14 | {E0810C81-30B4-4C98-8136-0DB4D1776D06}.Release|x64.Build.0 = Release|x64 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | SolutionGuid = {B699368E-8562-4FEC-B849-A3EF3BA36E99} 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /VmxHijack/VmxHijack.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Release 6 | x64 7 | 8 | 9 | 10 | 16.0 11 | Win32Proj 12 | {e0810c81-30b4-4c98-8136-0db4d1776d06} 13 | VmxHijack 14 | 10.0 15 | 16 | 17 | 18 | DynamicLibrary 19 | false 20 | v142 21 | true 22 | Unicode 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | false 35 | $(SolutionDir)build\ 36 | build\ 37 | dsound 38 | $(ProjectDir)../linux-pe/includes;$(IncludePath) 39 | 40 | 41 | 42 | Level3 43 | true 44 | true 45 | true 46 | NOMINMAX;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 47 | true 48 | stdcpplatest 49 | MultiThreaded 50 | 51 | 52 | Console 53 | true 54 | true 55 | true 56 | 57 | 58 | $(ProjectDir)../uninstall.bat 59 | 60 | 61 | $(ProjectDir)../install.bat 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /VmxHijack/VmxHijack.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /VmxHijack/VmxHijack.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /VmxHijack/config.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Can Boluk 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | #pragma once 30 | 31 | // If set, disables the console usage, will messagebox on errors and outputdebugstring on logs. 32 | // 33 | #ifndef VMX_NO_CONSOLE 34 | #define VMX_NO_CONSOLE 0 35 | #endif 36 | 37 | // If set, enables verbose logging. 38 | // 39 | #ifndef VMX_VERBOSE 40 | #define VMX_VERBOSE 0 41 | #endif 42 | -------------------------------------------------------------------------------- /VmxHijack/dllproxy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Can Boluk 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "logger.hpp" 34 | 35 | // Quick and lazy wrapper around the real DSOUND.dll 36 | // 37 | extern "C" decltype( *std::declval() ) __ImageBase; 38 | extern "C" __declspec( dllexport ) uint64_t DirectSoundCreate( uint64_t a, uint64_t b, uint64_t c, uint64_t d ) 39 | { 40 | static void* real_func = [ ] () -> void* 41 | { 42 | std::wstring nt_path = ( const wchar_t* ) 0x7FFE0030; 43 | nt_path += L"system32\\dsound.dll"; 44 | 45 | if ( HMODULE lib = LoadLibraryW( nt_path.c_str() ); lib && lib != &__ImageBase ) 46 | { 47 | return GetProcAddress( lib, "DirectSoundCreate" ); 48 | } 49 | else 50 | { 51 | logger::warning( "Failed to load the real DSOUND.dll" ); 52 | return nullptr; 53 | } 54 | }( ); 55 | 56 | if ( !real_func ) return -1; 57 | else return ( ( uint64_t( __stdcall* )( ... ) )real_func )( a, b, c, d ); 58 | } 59 | -------------------------------------------------------------------------------- /VmxHijack/logger.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Can Boluk 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | #pragma once 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "config.hpp" 36 | 37 | enum console_color 38 | { 39 | CON_BRG = 15, 40 | CON_YLW = 14, 41 | CON_PRP = 13, 42 | CON_RED = 12, 43 | CON_CYN = 11, 44 | CON_GRN = 10, 45 | CON_BLU = 9, 46 | CON_DEF = 7, 47 | }; 48 | 49 | namespace logger 50 | { 51 | // Mutex guarding the console. 52 | // 53 | inline std::mutex mutex; 54 | 55 | // Simple interface to change the current text color. 56 | // 57 | inline void set_color( console_color col ) 58 | { 59 | #if !VMX_NO_CONSOLE 60 | static auto con_hnd = [ ] () 61 | { 62 | // Create the console. 63 | // 64 | AllocConsole(); 65 | freopen( "CONOUT$", "w", stdout ); 66 | HANDLE hnd = GetStdHandle( STD_OUTPUT_HANDLE ); 67 | 68 | // Print the banner. 69 | // 70 | static constexpr char banner[] = 71 | R"( )" "\n" 72 | R"( /$$ /$$ /$$ /$$ /$$ /$$ )" "\n" 73 | R"( | $$ | $$ | $$ | $$|__/ | $$ )" "\n" 74 | R"( | $$ | $$ /$$$$$$/$$$$ /$$ /$$| $$ | $$ /$$ /$$ /$$$$$$ /$$$$$$$| $$ /$$ )" "\n" 75 | R"( | $$ / $$/| $$_ $$_ $$| $$ /$$/| $$$$$$$$| $$|__/ |____ $$ /$$_____/| $$ /$$/ )" "\n" 76 | R"( \ $$ $$/ | $$ \ $$ \ $$ \ $$$$/ | $$__ $$| $$ /$$ /$$$$$$$| $$ | $$$$$$/ )" "\n" 77 | R"( \ $$$/ | $$ | $$ | $$ >$$ $$ | $$ | $$| $$| $$ /$$__ $$| $$ | $$_ $$ )" "\n" 78 | R"( \ $/ | $$ | $$ | $$ /$$/\ $$| $$ | $$| $$| $$| $$$$$$$| $$$$$$$| $$ \ $$ )" "\n" 79 | R"( \_/ |__/ |__/ |__/|__/ \__/|__/ |__/|__/| $$ \_______/ \_______/|__/ \__/ )" "\n" 80 | R"( /$$ | $$ )" "\n" 81 | R"( | $$$$$$/ )" "\n" 82 | R"( \______/ )" "\n" 83 | R"( -------------------------------------------------------------------------------------- )" "\n\n"; 84 | for ( char c : banner ) 85 | { 86 | if ( c == '$' ) 87 | SetConsoleTextAttribute( hnd, CON_BLU ); 88 | else 89 | SetConsoleTextAttribute( hnd, CON_CYN ); 90 | putchar( c ); 91 | } 92 | 93 | // Return the file handle: 94 | // 95 | return hnd; 96 | }(); 97 | SetConsoleTextAttribute( con_hnd, col ); 98 | #endif 99 | } 100 | 101 | // Wrappers acquiring the lock, setting the color and printing to the console. 102 | // 103 | template 104 | static void print( const char* fmt, Tx&&... args ) 105 | { 106 | std::lock_guard _g{ mutex }; 107 | set_color( c ); 108 | printf( fmt, std::forward( args )... ); 109 | } 110 | template 111 | static void error( const char* fmt, Tx&&... args ) 112 | { 113 | #if !VMX_NO_CONSOLE 114 | print( "[Error] " ); 115 | print( fmt, std::forward( args )... ); 116 | putchar( '\n' ); 117 | #else 118 | std::string buffer( 128, ' ' ); 119 | buffer.resize( snprintf( buffer.data(), buffer.size() + 1, fmt, args... ) ); 120 | if ( buffer.size() >= 128 ) 121 | snprintf( buffer.data(), buffer.size() + 1, fmt, args... ); 122 | MessageBoxA( 0, buffer.data(), "Failed to Initialize VmxHijack", MB_TOPMOST | MB_ICONERROR ); 123 | #endif 124 | } 125 | template 126 | static void warning( const char* fmt, Tx&&... args ) 127 | { 128 | print( "[Warning] " ); 129 | print( fmt, std::forward( args )... ); 130 | putchar( '\n' ); 131 | } 132 | }; -------------------------------------------------------------------------------- /VmxHijack/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Can Boluk 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "logger.hpp" 35 | #include "vmx.hpp" 36 | #include "config.hpp" 37 | 38 | // Finds the log GuestRPC handler and hooks it, the methods used to find it are very simplistic 39 | // but it should not be an issue given that it's tailored to the way this image is linked and compiled. 40 | // 41 | static void try_hook( win::image_x64_t* vmx ) 42 | { 43 | static constexpr char target_string[] = "Guest: %s%s"; 44 | static constexpr size_t target_string_align = 8; 45 | static constexpr uint8_t target_instruction[] = { 0x48, 0x8D, 0x0D }; // lea rcx, [rip + rel32] 46 | 47 | // Parse the image header. 48 | // 49 | if ( !vmx ) 50 | return logger::error( "Failed hooking the vmx image: image not found." ); 51 | win::nt_headers_x64_t* nt = vmx->get_nt_headers(); 52 | win::section_header_t* scns = nt->get_sections(); 53 | #if VMX_VERBOSE 54 | logger::print( "- Located 'vmware-vmx.exe' at [%p - %p]\n", vmx, vmx->raw_to_ptr( nt->optional_header.size_image ) ); 55 | #endif 56 | 57 | // Find "Guest: %s%s" in '.rdata'. 58 | // 59 | std::unordered_set string_entries; 60 | for ( size_t n = 0; n != nt->file_header.num_sections; n++ ) 61 | { 62 | win::section_header_t* scn = &scns[ n ]; 63 | if ( !memcmp( &scn->name, ".rdata", sizeof( ".rdata" ) ) ) 64 | { 65 | uint8_t* data = vmx->raw_to_ptr( scn->virtual_address ); 66 | for ( size_t n = 0; n < ( std::min( scn->virtual_size, scn->size_raw_data ) - ( sizeof( target_string ) - 1 ) ); n += target_string_align ) 67 | { 68 | if ( !memcmp( data + n, target_string, sizeof( target_string ) - 1 ) ) 69 | string_entries.emplace( uint64_t( data + n ) ); 70 | } 71 | } 72 | } 73 | 74 | #if VMX_VERBOSE 75 | logger::print( " - Found %d match(es) of the string '%s'%c\n", string_entries.size(), target_string, string_entries.empty() ? '.' : ':' ); 76 | for ( auto va : string_entries ) 77 | logger::print( " - .rdata:%p\n", va ); 78 | #endif 79 | if ( string_entries.empty() ) 80 | return logger::error( "Failed string search." ); 81 | 82 | // Find the referencing [lea rcx, [rip+x]] in '.text'. 83 | // 84 | std::unordered_set code_references; 85 | for ( size_t n = 0; n != nt->file_header.num_sections; n++ ) 86 | { 87 | win::section_header_t* scn = &scns[ n ]; 88 | if ( !memcmp( &scn->name, ".text", sizeof( ".text" ) ) ) 89 | { 90 | uint8_t* data = vmx->raw_to_ptr( scn->virtual_address ); 91 | for ( size_t n = 0; n < ( std::min( scn->virtual_size, scn->size_raw_data ) - ( sizeof( target_instruction ) + 4 ) ); n++ ) 92 | { 93 | // lea rcx, [rip+N]: 94 | if ( !memcmp( data + n, target_instruction, sizeof( target_instruction ) ) ) 95 | { 96 | uint64_t ref_ptr = ( uint64_t ) ( data + n + 3 + 4 + *( int32_t* ) ( data + n + 3 ) ); 97 | if ( string_entries.contains( ref_ptr ) ) 98 | code_references.insert( uint64_t( data + n ) ); 99 | } 100 | } 101 | } 102 | } 103 | 104 | #if VMX_VERBOSE 105 | logger::print( " - Found %d instruction(s) referencing the string%c\n", code_references.size(), code_references.empty() ? '.' : ':' ); 106 | for ( auto va : code_references ) 107 | logger::print( " - .text:%p\n", va ); 108 | #endif 109 | if ( code_references.size() != 1 ) 110 | return logger::error( "Failed instruction search." ); 111 | 112 | // Find the prologue. 113 | // 114 | uint8_t* instruction = (uint8_t*)*code_references.begin(); 115 | while ( instruction[ -1 ] != 0xCC ) --instruction; 116 | if ( *instruction != 0x48 ) 117 | return logger::error( "Failed prologue search." ); 118 | 119 | // Form the hook bytes beforehand so that we can swap with a single MOVAPS. 120 | // 121 | alignas( M128A ) uint8_t hook[ 16 ] = 122 | { 123 | // jmp [rip] 124 | 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 125 | }; 126 | *( void** ) ( hook + 2 + 4 ) = &vmx_log_handler; 127 | 128 | // Unprotect the code region. 129 | // 130 | DWORD old; 131 | if ( !VirtualProtect( instruction, sizeof( hook ), PAGE_EXECUTE_READWRITE, &old ) ) 132 | return logger::error( "Failed VirtualProtect." ); 133 | 134 | // Write the hook and protect the code again. 135 | // 136 | memcpy( instruction, hook, sizeof( hook ) ); 137 | VirtualProtect( instruction, sizeof( hook ), old, &old ); 138 | #if VMX_VERBOSE 139 | logger::print( " - Successfully hooked the 'log' vmx handler, initialization complete!\n\n" ); 140 | #endif 141 | } 142 | 143 | // Hook the vmx RPC handler on DLL initialization. 144 | // 145 | BOOL WINAPI DllMain( HINSTANCE, DWORD fwd_reason, LPVOID ) 146 | { 147 | if ( fwd_reason == DLL_PROCESS_ATTACH ) 148 | try_hook( ( win::image_x64_t* ) GetModuleHandleA( nullptr ) ); 149 | return true; 150 | } -------------------------------------------------------------------------------- /VmxHijack/vmx.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Can Boluk 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | #pragma once 30 | #include 31 | #include "logger.hpp" 32 | 33 | // // 34 | // <<< Edit this function as you wish >>> // 35 | // // 36 | bool vmx_log_handler( 37 | uint64_t vcpuid, void* vcpuctx, 38 | const char* data, uint32_t length, 39 | const void** out, uint32_t* out_length ) 40 | { 41 | // Normalize the string. 42 | // 43 | std::string_view str = { data, length }; 44 | if ( auto pos = str.find( '\x0' ); pos != std::string::npos ) 45 | str = str.substr( 0, pos ); 46 | if ( str.ends_with( '\n' ) ) 47 | str.remove_suffix( 1 ); 48 | 49 | // Insert a prefix. 50 | // 51 | std::string msg = "[vmx] vcpu-" + std::to_string( vcpuid ) + ": "; 52 | msg.insert( msg.end(), str.begin(), str.end() ); 53 | 54 | // Print onto the console and DebugView. 55 | // 56 | OutputDebugStringA( msg.c_str() ); 57 | logger::print( "%s\n", msg.c_str() ); 58 | 59 | // Write dummy output. 60 | // 61 | *out = ""; 62 | *out_length = 0; 63 | return true; 64 | } 65 | -------------------------------------------------------------------------------- /includes/vmx.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Can Boluk 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | #pragma once 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace vmx 39 | { 40 | // Magic numbers. 41 | // 42 | enum class bdoor_cmd : uint16_t 43 | { 44 | message = 30 45 | }; 46 | constexpr uint16_t bdoor_port = 0x5658; // 'VX' 47 | constexpr uint32_t bdoor_magic = 0x564D5868; // 'VMXh' 48 | constexpr uint32_t rpc_magic = 0x49435052; // 'RPCI' 49 | 50 | // Interface details for bdoor_cmd::message. 51 | // 52 | enum class message_type : uint16_t 53 | { 54 | open, 55 | send_size, 56 | send_payload, 57 | recv_size, 58 | recv_payload, 59 | recv_status, 60 | close 61 | }; 62 | union message_result 63 | { 64 | uint32_t raw; 65 | struct 66 | { 67 | uint32_t _pad : 16; 68 | uint32_t success : 1; 69 | uint32_t dorecv : 1; 70 | uint32_t closed : 1; 71 | uint32_t unsent : 1; 72 | uint32_t checkpoint : 1; 73 | uint32_t poweroff : 1; 74 | uint32_t timeout : 1; 75 | uint32_t high_bandwidth : 1; 76 | }; 77 | }; 78 | 79 | // Wrap simple I/O. 80 | // 81 | template 82 | inline std::array send_command( bdoor_cmd command, Tp parameter = {}, Ts subcommand = {}, uint16_t channel = {} ) 83 | { 84 | register uint32_t _a asm( "eax" ) = bdoor_magic; 85 | register uint32_t _b asm( "ebx" ) = uint32_t( parameter ); 86 | register uint32_t _c asm( "ecx" ) = ( uint32_t( command ) ) | ( uint32_t( subcommand ) << 16 ); 87 | register uint32_t _d asm( "edx" ) = ( uint32_t( bdoor_port ) ) | ( uint32_t( channel ) << 16 ); 88 | asm volatile( "in %%dx, %%eax" : "+r" ( _a ), "+r" ( _b ), "+r" ( _c ), "+r" ( _d ) :: "memory" ); 89 | return { _a, _b, _c, _d }; 90 | } 91 | 92 | // Channel wrapper. 93 | // 94 | struct channel 95 | { 96 | uint16_t channel_number = 0xFFFF; 97 | 98 | // Default constructor creates invalid channel, no copy allowed, swapping move. 99 | // 100 | channel() {} 101 | channel( const channel& ) = delete; 102 | channel& operator=( const channel& ) = delete; 103 | channel( channel&& o ) : channel_number( std::exchange( o.channel_number, 0xFFFF ) ) {} 104 | channel& operator=( channel&& o ) 105 | { 106 | std::swap( channel_number, o.channel_number ); 107 | return *this; 108 | } 109 | 110 | // Attempts to open a valid channel. 111 | // 112 | static channel open() 113 | { 114 | channel res; 115 | auto [_, __, raw_status, channel] = send_command( 116 | bdoor_cmd::message, 117 | rpc_magic, 118 | message_type::open 119 | ); 120 | message_result status{ .raw = raw_status }; 121 | if ( status.success ) 122 | res.channel_number = channel >> 16; 123 | return res; 124 | } 125 | 126 | // Validity check. 127 | // 128 | bool is_valid() const { return channel_number != 0xFFFF; } 129 | explicit operator bool() const { return is_valid(); } 130 | 131 | // Closes the channel. 132 | // 133 | void reset() 134 | { 135 | if ( is_valid() ) 136 | send_command( bdoor_cmd::message, {}, message_type::close, channel_number ); 137 | channel_number = 0xFFFF; 138 | } 139 | 140 | // Restarts the channel. 141 | // 142 | channel& restart() 143 | { 144 | reset(); 145 | return operator=( open() ); 146 | } 147 | 148 | // Internal send/recv functions. 149 | // 150 | bool send_msg( const std::initializer_list& segments ) 151 | { 152 | size_t total_msg_length = 0; 153 | for ( auto& n : segments ) 154 | total_msg_length += n.size(); 155 | auto read4 = [ & ] ( size_t it ) -> uint32_t 156 | { 157 | // Enumerate every segment: 158 | // 159 | uint32_t dword = 0; 160 | size_t pos = 0, epos = 0; 161 | for ( auto& msg : segments ) 162 | { 163 | pos = epos; 164 | 165 | // If beyond limit, break, we're done. 166 | // 167 | if ( pos >= ( it + 4 ) ) 168 | return dword; 169 | 170 | // If before limit, skip. 171 | // 172 | epos = pos + msg.size(); 173 | if ( epos <= it ) 174 | continue; 175 | 176 | // Copy the relevant part. 177 | // 178 | char* dbegin = ( char* ) &dword; 179 | const char* sbegin = msg.data(); 180 | if ( pos < it ) sbegin += it - pos; 181 | else dbegin += pos - it; 182 | memcpy( dbegin, sbegin, std::min( epos - it, 4 ) ); 183 | } 184 | return dword; 185 | }; 186 | 187 | while( true ) 188 | { 189 | message_result result = { .raw = 0 }; 190 | 191 | // Send the length. 192 | // 193 | result.raw = send_command( 194 | bdoor_cmd::message, 195 | total_msg_length, 196 | message_type::send_size, 197 | channel_number 198 | )[ 2 ]; 199 | if ( !result.success ) 200 | return false; 201 | 202 | // Iterate the message in u32 boundaries: 203 | // 204 | for ( size_t it = 0; it < total_msg_length; it += 4 ) 205 | { 206 | // Send the partial command, propagate failure. 207 | // 208 | result.raw = send_command( 209 | bdoor_cmd::message, 210 | read4( it ) , 211 | message_type::send_payload, 212 | channel_number 213 | )[ 2 ]; 214 | 215 | // If server reported a checkpoint, retry the entire operation. 216 | // 217 | if ( result.checkpoint ) 218 | break; 219 | 220 | // If server reported an error, fail. 221 | // 222 | if ( !result.success ) 223 | return false; 224 | } 225 | 226 | // If no retry required, quit. 227 | // 228 | if ( !result.checkpoint ) 229 | return true; 230 | } 231 | return false; 232 | } 233 | std::optional recv_reply() 234 | { 235 | std::string buffer; 236 | while ( true ) 237 | { 238 | message_result result = { .raw = 0 }; 239 | 240 | // Get the reply length. 241 | // 242 | auto [_, reply_length, reply_result, reply_id] = send_command( 243 | bdoor_cmd::message, 244 | {}, 245 | message_type::recv_size, 246 | channel_number 247 | ); 248 | result.raw = reply_result; 249 | reply_id >>= 16; 250 | if ( !result.success ) 251 | return std::nullopt; 252 | 253 | // If there is no reply, return empty string. 254 | // 255 | if( !result.dorecv ) 256 | return std::string{}; 257 | 258 | // Resize the buffer to 4-byte aligned reply length. 259 | // 260 | buffer.resize( ( reply_length + 3 ) & ~3 ); 261 | for ( size_t it = 0; it != buffer.size(); it += 4 ) 262 | { 263 | // Fetch the partial reply, propagate failure. 264 | // 265 | auto [_, data, recv_result, __] = send_command( 266 | bdoor_cmd::message, 267 | reply_id, 268 | message_type::recv_payload, 269 | channel_number 270 | ); 271 | result.raw = recv_result; 272 | 273 | // If server reported a checkpoint, retry the entire operation. 274 | // 275 | if ( result.checkpoint ) 276 | break; 277 | 278 | // If server reported an error, fail. 279 | // 280 | if ( !result.success ) 281 | return std::nullopt; 282 | 283 | // Otherwise write the partial reply. 284 | // 285 | *( uint32_t* ) ( buffer.data() + it ) = data; 286 | } 287 | 288 | // Handle checkpoints. 289 | // 290 | if ( result.checkpoint ) 291 | continue; 292 | 293 | // Resize to the real reply size. 294 | // 295 | buffer.resize( reply_length ); 296 | 297 | // Finish the reply and return the final message. 298 | // 299 | result.raw = send_command( 300 | bdoor_cmd::message, 301 | reply_id, 302 | message_type::recv_status, 303 | channel_number 304 | )[ 2 ]; 305 | if ( !result.success ) 306 | return std::nullopt; 307 | if ( result.checkpoint ) 308 | continue; 309 | return buffer; 310 | } 311 | return std::nullopt; 312 | } 313 | 314 | // Combined send. 315 | // 316 | std::optional send( const std::initializer_list& segments ) 317 | { 318 | if ( !send_msg( segments ) ) 319 | return std::nullopt; 320 | return recv_reply(); 321 | } 322 | 323 | // Destructor cleans up the host resources. 324 | // 325 | ~channel() { reset(); } 326 | }; 327 | 328 | // Global singleton channel and it's lazy getter. 329 | // 330 | inline channel g_channel = {}; 331 | inline channel& get_channel() 332 | { 333 | if ( !g_channel ) 334 | g_channel = channel::open(); 335 | return g_channel; 336 | } 337 | 338 | // Sends a message and ignores the reply. 339 | // 340 | template 341 | inline void send_n( std::string_view msg_0, Tx&&... msg_n ) 342 | { 343 | // If there is a valid channel: 344 | // 345 | if ( auto& channel = get_channel() ) 346 | { 347 | // Try sending the message, retry up to three times. 348 | // 349 | for ( size_t n = 0; n != 3; n++ ) 350 | { 351 | if ( channel.send_msg( { "log ", msg_0, ( std::string_view ) msg_n... } ) ) 352 | { 353 | channel.reset(); 354 | break; 355 | } 356 | channel.restart(); 357 | } 358 | } 359 | } 360 | 361 | // Sends a message and returns the reply. 362 | // 363 | template 364 | inline std::pair send( std::string_view msg_0, Tx&&... msg_n ) 365 | { 366 | bool success = false; 367 | std::string result = {}; 368 | 369 | // If there is a valid channel: 370 | // 371 | if ( auto& channel = get_channel() ) 372 | { 373 | // Try sending the message, retry up to three times. 374 | // 375 | for ( size_t n = 0; n != 3; n++ ) 376 | { 377 | if ( auto res = channel.send( { "log ", msg_0, ( std::string_view ) msg_n... } ) ) 378 | { 379 | success = true; 380 | result = std::move( res ).value(); 381 | break; 382 | } 383 | channel.restart(); 384 | } 385 | 386 | // If reply starts with standard VMWare header, parse it. 387 | // 388 | if ( result.starts_with( "0 " ) ) 389 | success = false, result.erase( result.begin(), result.begin() + 2 ); 390 | else if ( result.starts_with( "1 " ) ) 391 | success = true, result.erase( result.begin(), result.begin() + 2 ); 392 | } 393 | 394 | return std::pair{ success, std::move( result ) }; 395 | } 396 | }; -------------------------------------------------------------------------------- /install.bat: -------------------------------------------------------------------------------- 1 | set VmxPath=C:\Program Files (x86)\VMware\VMware Workstation\x64 2 | 3 | del "%VmxPath%\dsound.dll" 4 | mklink "%VmxPath%\dsound.dll" "%~dp0VmxHijack\build\dsound.dll" -------------------------------------------------------------------------------- /uninstall.bat: -------------------------------------------------------------------------------- 1 | set VmxPath=C:\Program Files (x86)\VMware\VMware Workstation\x64 2 | 3 | del "%VmxPath%\dsound.dll" -------------------------------------------------------------------------------- /vmx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rtyuiow/vmware-backdoor/fd84f1a216ca9f8b8da8f8fa854618d078d5cd5c/vmx.png --------------------------------------------------------------------------------