├── .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
--------------------------------------------------------------------------------