├── MAIN.cpp └── README.md /MAIN.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | //#include 13 | //#include 14 | 15 | using namespace std; 16 | 17 | std::unordered_set usedTypeNames; 18 | 19 | std::string getRandomString( const int len ) { 20 | static const char alpha[] = 21 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 22 | "abcdefghijklmnopqrstuvwxyz"; 23 | 24 | static const char alphanum[] = 25 | "0123456789" 26 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 27 | "abcdefghijklmnopqrstuvwxyz"; 28 | 29 | string s; 30 | s.resize( len ); 31 | 32 | for ( auto i = 0; i < len; ++i ) { 33 | // we always want to start types with an alphabetical letter 34 | if ( 0 == i ) 35 | { 36 | s[i] = alpha[rand() % ( sizeof( alpha ) - 1 )]; 37 | 38 | } 39 | else 40 | { 41 | s[i] = alphanum[rand() % ( sizeof( alphanum ) - 1 )]; 42 | } 43 | } 44 | 45 | s[len] = 0; 46 | 47 | return s; 48 | } 49 | 50 | // really like that boost regexp callback idea! 51 | namespace std 52 | { 53 | template 54 | std::basic_string regex_replace( Iterator iterStart, Iterator iterFinish, const std::basic_regex& expressions, SingleArg sArg ) 56 | { 57 | std::basic_string sBuffer; 58 | 59 | typename std::match_results::difference_type lastPos = 0; 60 | auto lastPosEnd = iterStart; 61 | 62 | auto regexp_callback = [&]( const std::match_results& m ) 63 | { 64 | auto pos = m.position( 0 ); 65 | auto difference = pos - lastPos; 66 | 67 | auto start = lastPosEnd; 68 | std::advance( start, difference ); 69 | 70 | sBuffer.append( lastPosEnd, start ); 71 | sBuffer.append( sArg( m ) ); 72 | 73 | auto len = m.length( 0 ); 74 | 75 | lastPos = pos + len; 76 | 77 | lastPosEnd = start; 78 | std::advance( lastPosEnd, len ); 79 | }; 80 | 81 | std::sregex_iterator start( iterStart, iterFinish, expressions ), finish; 82 | std::for_each( start, finish, regexp_callback ); 83 | 84 | sBuffer.append( lastPosEnd, iterFinish ); 85 | 86 | return sBuffer; 87 | } 88 | 89 | template 90 | std::string regex_replace( const std::string& sBuffer, 91 | const std::basic_regex& expressions, SingleArg sArg ) 92 | { 93 | auto begin = sBuffer.cbegin(); 94 | auto end = sBuffer.cend(); 95 | return regex_replace( begin, end, expressions, sArg ); 96 | } 97 | } 98 | 99 | int main( int argc, char* argv[] ) 100 | { 101 | cout << "===== RTTI obfuscator by koemeet/rifk01 =====" << endl; 102 | 103 | srand( time( nullptr ) ); 104 | 105 | try 106 | { 107 | if ( argc < 2 ) 108 | { 109 | throw std::exception( "Please provide a path or drop a file into me." ); 110 | } 111 | 112 | // path to input binary 113 | string path = argv[1]; 114 | 115 | std::ifstream fs( path, std::fstream::binary ); 116 | if ( fs.fail() ) 117 | { 118 | throw std::exception( "Could not open source binary" ); 119 | } 120 | 121 | // read file contents 122 | std::stringstream ss; 123 | ss << fs.rdbuf(); 124 | auto contents = ss.str(); 125 | 126 | std::regex reg( "\\.(\\?AV|PEAV)(.+?)@@" ); 127 | //boost::regex reg( "\\.(\\?AV|PEAV)(.+?)@@" ); 128 | 129 | // replace RTTI types 130 | contents = std::regex_replace( contents, reg, []( const std::smatch& m ) 131 | { 132 | auto prefix = m[1].str(); 133 | auto typeName = m[2].str(); 134 | 135 | // generate the new type name for the current rtti entry 136 | auto newTypeName = getRandomString( typeName.size() ); 137 | 138 | // get a new random name untill we have one we never used before 139 | while ( usedTypeNames.find( newTypeName ) != usedTypeNames.end() ) 140 | { 141 | newTypeName = getRandomString( typeName.size() ); 142 | } 143 | 144 | usedTypeNames.emplace( newTypeName ); 145 | 146 | return "." + prefix + newTypeName + "@@"; 147 | } ); 148 | 149 | // generate output path 150 | //boost::filesystem::path p( path ); 151 | //auto outputPath = p.parent_path().string() + "\\" + p.stem().string() + ".tan" + p.extension().string(); 152 | 153 | string fileExtension = path.substr( path.length() - 3 ); 154 | path.erase( path.length() - 3 ); 155 | // write to file 156 | path += "tan."; 157 | path += fileExtension; 158 | 159 | std::ofstream os( path.c_str(), std::ofstream::trunc | std::ofstream::binary ); 160 | if ( !os.write( contents.data(), contents.size() ) ) 161 | { 162 | throw std::exception( ( std::string( "Unable to write to file " ) + path ).c_str() ); 163 | } 164 | else 165 | { 166 | cout << "Successfully obfuscated RTTI information. Output written to " << path << endl; 167 | system( "pause" ); 168 | } 169 | } 170 | 171 | catch ( std::exception &e ) 172 | { 173 | cout << e.what() << endl; 174 | system( "pause" ); 175 | return 1; 176 | } 177 | 178 | return 0; 179 | } 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ RTTI Obfuscator 2 | Obfuscates all RTTI (Run-time type information) inside a binary so AC's can't catch you on it. 3 | 4 | Credits to https://github.com/koemeet/rtti-obfuscator! 5 | I've just got rid of the annoying boost dependencies. :-) 6 | 7 | ### Usage 8 | You can simply drop any binary into it and it outputs the obfuscated binary in `/.tan.`. 9 | 10 | It can also be used on the command line by simply providing the path to the input binary as its first argument: 11 | ``` 12 | $ rtti-obfuscator 13 | ``` 14 | 15 | ### Preview 16 | 17 | RTTI (left pane) | Obfuscated RTTI (right pane) 18 | ![](http://i.imgur.com/DdhjIsv.jpg) 19 | 20 | This is how a binary would look without any RTTI obfuscation: 21 | ![](https://i.imgur.com/GDWNMNY.png) 22 | 23 | Now when ran through the obfuscator, it will turn into this: 24 | ![](https://i.imgur.com/02MnMbm.png) 25 | --------------------------------------------------------------------------------