├── .gitattributes ├── .gitignore ├── be-shellcode-tester.sln ├── be-shellcode-tester ├── battleye │ ├── battleye.hpp │ ├── handlers │ │ ├── beclient_encrypted.cpp │ │ ├── driver_presence.cpp │ │ ├── encrypted.cpp │ │ ├── general_info.cpp │ │ ├── memory_anomaly.cpp │ │ ├── memory_region.cpp │ │ ├── memory_signature.cpp │ │ ├── mono_assets.cpp │ │ ├── veh.cpp │ │ └── window_title.cpp │ ├── reports.cpp │ ├── reports.hpp │ └── resources │ │ └── beclient_x64.hpp ├── be-shellcode-tester.vcxproj ├── be-shellcode-tester.vcxproj.filters ├── be-shellcode-tester.vcxproj.user ├── bootstrap │ ├── bootstrap.cpp │ └── bootstrap.hpp ├── entry.cpp ├── hooks │ ├── battleye │ │ └── send_report.cpp │ ├── hooks.hpp │ └── winapi │ │ ├── GetModuleHandle.cpp │ │ ├── GetProcAddress.cpp │ │ ├── IsBadReadPtr.cpp │ │ ├── LoadLibraryA.cpp │ │ └── WideCharToMultiByte.cpp ├── loader │ ├── loader.cpp │ └── loader.hpp └── util │ ├── io │ ├── io.cpp │ └── io.hpp │ ├── logger.hpp │ ├── mem │ ├── mem.cpp │ └── mem.hpp │ ├── pe │ ├── pe.cpp │ └── pe.hpp │ ├── util.cpp │ └── util.hpp └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | # *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | intermediates/* 34 | output/* 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # StyleCop 67 | StyleCopReport.xml 68 | 69 | # Files built by Visual Studio 70 | *_i.c 71 | *_p.c 72 | *_h.h 73 | *.ilk 74 | *.meta 75 | *.obj 76 | *.iobj 77 | *.pch 78 | *.pdb 79 | *.ipdb 80 | *.pgc 81 | *.pgd 82 | *.rsp 83 | *.sbr 84 | *.tlb 85 | *.tli 86 | *.tlh 87 | *.tmp 88 | *.tmp_proj 89 | *_wpftmp.csproj 90 | *.log 91 | *.vspscc 92 | *.vssscc 93 | .builds 94 | *.pidb 95 | *.svclog 96 | *.scc 97 | 98 | # Chutzpah Test files 99 | _Chutzpah* 100 | 101 | # Visual C++ cache files 102 | ipch/ 103 | *.aps 104 | *.ncb 105 | *.opendb 106 | *.opensdf 107 | *.sdf 108 | *.cachefile 109 | *.VC.db 110 | *.VC.VC.opendb 111 | 112 | # Visual Studio profiler 113 | *.psess 114 | *.vsp 115 | *.vspx 116 | *.sap 117 | 118 | # Visual Studio Trace Files 119 | *.e2e 120 | 121 | # TFS 2012 Local Workspace 122 | $tf/ 123 | 124 | # Guidance Automation Toolkit 125 | *.gpState 126 | 127 | # ReSharper is a .NET coding add-in 128 | _ReSharper*/ 129 | *.[Rr]e[Ss]harper 130 | *.DotSettings.user 131 | 132 | # TeamCity is a build add-in 133 | _TeamCity* 134 | 135 | # DotCover is a Code Coverage Tool 136 | *.dotCover 137 | 138 | # AxoCover is a Code Coverage Tool 139 | .axoCover/* 140 | !.axoCover/settings.json 141 | 142 | # Visual Studio code coverage results 143 | *.coverage 144 | *.coveragexml 145 | 146 | # NCrunch 147 | _NCrunch_* 148 | .*crunch*.local.xml 149 | nCrunchTemp_* 150 | 151 | # MightyMoose 152 | *.mm.* 153 | AutoTest.Net/ 154 | 155 | # Web workbench (sass) 156 | .sass-cache/ 157 | 158 | # Installshield output folder 159 | [Ee]xpress/ 160 | 161 | # DocProject is a documentation generator add-in 162 | DocProject/buildhelp/ 163 | DocProject/Help/*.HxT 164 | DocProject/Help/*.HxC 165 | DocProject/Help/*.hhc 166 | DocProject/Help/*.hhk 167 | DocProject/Help/*.hhp 168 | DocProject/Help/Html2 169 | DocProject/Help/html 170 | 171 | # Click-Once directory 172 | publish/ 173 | 174 | # Publish Web Output 175 | *.[Pp]ublish.xml 176 | *.azurePubxml 177 | # Note: Comment the next line if you want to checkin your web deploy settings, 178 | # but database connection strings (with potential passwords) will be unencrypted 179 | *.pubxml 180 | *.publishproj 181 | 182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 183 | # checkin your Azure Web App publish settings, but sensitive information contained 184 | # in these scripts will be unencrypted 185 | PublishScripts/ 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # NuGet Symbol Packages 190 | *.snupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/[Pp]ackages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/[Pp]ackages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/[Pp]ackages/repositories.config 197 | # NuGet v3's project.json files produces more ignorable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | *.appx 215 | *.appxbundle 216 | *.appxupload 217 | 218 | # Visual Studio cache files 219 | # files ending in .cache can be ignored 220 | *.[Cc]ache 221 | # but keep track of directories ending in .cache 222 | !?*.[Cc]ache/ 223 | 224 | # Others 225 | ClientBin/ 226 | ~$* 227 | *~ 228 | *.dbmdl 229 | *.dbproj.schemaview 230 | *.jfm 231 | *.pfx 232 | *.publishsettings 233 | orleans.codegen.cs 234 | 235 | # Including strong name files can present a security risk 236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 237 | #*.snk 238 | 239 | # Since there are multiple workflows, uncomment next line to ignore bower_components 240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 241 | #bower_components/ 242 | 243 | # RIA/Silverlight projects 244 | Generated_Code/ 245 | 246 | # Backup & report files from converting an old project file 247 | # to a newer Visual Studio version. Backup files are not needed, 248 | # because we have git ;-) 249 | _UpgradeReport_Files/ 250 | Backup*/ 251 | UpgradeLog*.XML 252 | UpgradeLog*.htm 253 | ServiceFabricBackup/ 254 | *.rptproj.bak 255 | 256 | # SQL Server files 257 | *.mdf 258 | *.ldf 259 | *.ndf 260 | 261 | # Business Intelligence projects 262 | *.rdl.data 263 | *.bim.layout 264 | *.bim_*.settings 265 | *.rptproj.rsuser 266 | *- [Bb]ackup.rdl 267 | *- [Bb]ackup ([0-9]).rdl 268 | *- [Bb]ackup ([0-9][0-9]).rdl 269 | 270 | # Microsoft Fakes 271 | FakesAssemblies/ 272 | 273 | # GhostDoc plugin setting file 274 | *.GhostDoc.xml 275 | 276 | # Node.js Tools for Visual Studio 277 | .ntvs_analysis.dat 278 | node_modules/ 279 | 280 | # Visual Studio 6 build log 281 | *.plg 282 | 283 | # Visual Studio 6 workspace options file 284 | *.opt 285 | 286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 287 | *.vbw 288 | 289 | # Visual Studio LightSwitch build output 290 | **/*.HTMLClient/GeneratedArtifacts 291 | **/*.DesktopClient/GeneratedArtifacts 292 | **/*.DesktopClient/ModelManifest.xml 293 | **/*.Server/GeneratedArtifacts 294 | **/*.Server/ModelManifest.xml 295 | _Pvt_Extensions 296 | 297 | # Paket dependency manager 298 | .paket/paket.exe 299 | paket-files/ 300 | 301 | # FAKE - F# Make 302 | .fake/ 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb 347 | 348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 349 | MigrationBackup/ 350 | 351 | # Ionide (cross platform F# VS Code tools) working folder 352 | .ionide/ 353 | -------------------------------------------------------------------------------- /be-shellcode-tester.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31515.178 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "be-shellcode-tester", "be-shellcode-tester\be-shellcode-tester.vcxproj", "{D867B1EA-3C81-4EC2-A081-C3015D944B75}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug [dll]|x64 = Debug [dll]|x64 11 | Debug [dll]|x86 = Debug [dll]|x86 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release [dll]|x64 = Release [dll]|x64 15 | Release [dll]|x86 = Release [dll]|x86 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Debug [dll]|x64.ActiveCfg = Debug [dll]|x64 21 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Debug [dll]|x64.Build.0 = Debug [dll]|x64 22 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Debug [dll]|x86.ActiveCfg = Debug [dll]|Win32 23 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Debug [dll]|x86.Build.0 = Debug [dll]|Win32 24 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Debug|x64.ActiveCfg = Debug|x64 25 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Debug|x64.Build.0 = Debug|x64 26 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Debug|x86.ActiveCfg = Debug|Win32 27 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Debug|x86.Build.0 = Debug|Win32 28 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Release [dll]|x64.ActiveCfg = Release [dll]|x64 29 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Release [dll]|x64.Build.0 = Release [dll]|x64 30 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Release [dll]|x86.ActiveCfg = Release [dll]|Win32 31 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Release [dll]|x86.Build.0 = Release [dll]|Win32 32 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Release|x64.ActiveCfg = Release|x64 33 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Release|x64.Build.0 = Release|x64 34 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Release|x86.ActiveCfg = Release|Win32 35 | {D867B1EA-3C81-4EC2-A081-C3015D944B75}.Release|x86.Build.0 = Release|Win32 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {39E3FD5C-18F1-4A9E-81DA-97DDD2DA0261} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/battleye.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "resources/beclient_x64.hpp" 3 | 4 | #include 5 | #include 6 | 7 | 8 | namespace battleye { 9 | namespace typedefs { 10 | using shellcode_startup_t = void( * )( uintptr_t a1 /* it should be base addr but idk */, void* send_report_fn, void* get_module_handle_fn, void* get_proc_address_fn, void* a5 /* unknown :shrug: */ ); 11 | }; 12 | 13 | namespace enums { 14 | enum class e_report_id : uint8_t { 15 | REPORT_UNKNOWN = 0x0, 16 | REPORT_ENCRYPTED = 0x4B, 17 | REPORT_GENERAL_INFO = 0x3C, 18 | REPORT_VEH = 0x31, 19 | REPORT_MEMORY_ANOMALY = 0x2F, 20 | REPORT_WINDOW_TITLE = 0x33, 21 | REPORT_MEMORY_SIGNATURE = 0x35, 22 | REPORT_DRIVER_PRESENCE_BEEP = 0x3E, 23 | REPORT_DRIVER_PRESENCE_NULL = 0x3F, 24 | REPORT_MEMORY_REGION = 0x21, 25 | REPORT_BECLIENT_ENCRYPTED = 0x39, 26 | REPORT_MONO_ASSETS = 0x49 27 | }; 28 | 29 | inline const char* report_id_to_string( e_report_id id ) { 30 | switch ( id ) { 31 | case e_report_id::REPORT_BECLIENT_ENCRYPTED: 32 | case e_report_id::REPORT_ENCRYPTED: 33 | return "ENCRYPTED"; 34 | case e_report_id::REPORT_GENERAL_INFO: 35 | return "GENERAL_INFO"; 36 | case e_report_id::REPORT_VEH: 37 | return "VEH"; 38 | case e_report_id::REPORT_MEMORY_ANOMALY: 39 | return "MEMORY_ANOMALY"; 40 | case e_report_id::REPORT_WINDOW_TITLE: 41 | return "WINDOW_TITLE"; 42 | case e_report_id::REPORT_MEMORY_SIGNATURE: 43 | return "MEMORY_SIGNATURE"; 44 | case e_report_id::REPORT_DRIVER_PRESENCE_NULL: 45 | case e_report_id::REPORT_DRIVER_PRESENCE_BEEP: 46 | return "DRIVER_PRESENCE"; 47 | case e_report_id::REPORT_MEMORY_REGION: 48 | return "MEMORY_REGION"; 49 | case e_report_id::REPORT_MONO_ASSETS: 50 | return "MONO_ASSETS"; 51 | default: 52 | return "UNKNOWN"; 53 | } 54 | } 55 | }; 56 | 57 | inline std::unordered_map resources_list = { 58 | { "BEClient_x64.dll", resources::beclient_x64 } 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/beclient_encrypted.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void beclient_encrypted( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | util::hexdump( "", reader.get_buffer( ), reader.get_size( ) ); 7 | reader.skip( reader.get_size( ) ); 8 | 9 | // @todo: @es3n1n: decryption 10 | /* 11 | snippet from beclient: 12 | 13 | LABEL_53: 14 | LOWORD(_EAX) = v236 ^ inputParam ^ 0x5979; 15 | encryption_key = v236 ^ inputParam ^ 0x378E5979; 16 | LABEL_90: 17 | for ( m = 2; m < 505; ++m ) 18 | { 19 | *(int *)((char *)v230 + m) ^= encryption_key; 20 | _CL = m % 32; 21 | if ( ((encryption_key >> _CL) & 1) != 0 ) 22 | { 23 | __asm { rcr cl, 3 } 24 | encryption_key *= ~encryption_key; 25 | } 26 | LABEL_117: 27 | v115 = (*((_BYTE *)&encryption_key + m % 4) & 3) + 4; 28 | _ECX = 512 - v115; 29 | _EAX = v115 & ~(1 << (char)v113); 30 | LOWORD(_EAX) = __ROL2__(_EAX, 2); 31 | __asm { rcl eax, cl } 32 | v142 = m == _ECX; 33 | if ( m < _ECX ) 34 | { 35 | LOWORD(_ECX) = __ROR2__(_ECX + 1, _ECX + 1); 36 | __asm { rcr ecx, 9 } 37 | LOWORD(_ECX) = _ECX ^ 0x8F07; 38 | LOBYTE(_ECX) = BYTE1(v111) | _ECX; 39 | _ECX = -_ECX; 40 | LOBYTE(_ECX) = BYTE1(v111) | _ECX; 41 | BYTE1(_ECX) = -BYTE1(_ECX); 42 | LOWORD(_ECX) = v112 | _ECX; 43 | BYTE1(_ECX) <<= 6; 44 | v23 = m % 4; 45 | LABEL_94: 46 | __asm { rcr ch, cl } 47 | v24 = *((_BYTE *)&encryption_key + v23) & 3; 48 | v142 = v24 + m == 0; 49 | LOBYTE(_ECX) = v24 + m; 50 | m += v24; 51 | } 52 | while ( !v142 ) 53 | { 54 | _EAX = ++m; 55 | if ( _EAX >= 505 ) 56 | goto LABEL_324; 57 | _DH = 117; 58 | __asm { rcl dh, 2 } 59 | *(int *)((char *)v230 + _EAX) ^= encryption_key; 60 | _RDX = (_EAX >> 31) & 0x1F; 61 | _CL = -57; 62 | __asm { rcr cl, 4 } 63 | if ( !((encryption_key >> (_EAX % 32)) & 1) ) 64 | goto LABEL_117; 65 | __asm { rcr rdx, 2Bh } 66 | encryption_key *= ~encryption_key; 67 | _ECX = 512 - ((*((_BYTE *)&encryption_key + m % 4) & 3) + 4); 68 | v142 = m == _ECX; 69 | if ( m < _ECX ) 70 | { 71 | v23 = m % 4; 72 | goto LABEL_94; 73 | } 74 | } 75 | LOWORD(_EAX) = m + 1; 76 | } 77 | */ 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/driver_presence.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void driver_presence( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | util::logger::info( "\tDriver: %s", id == enums::e_report_id::REPORT_DRIVER_PRESENCE_BEEP ? "\\\\.\\Beep" : "\\\\.\\Null" ); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/encrypted.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void encrypted( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | // @note: user344: This decryption is really bad coded, but it works 7 | // and i dont want to spend any more time on it so shall it stay. 8 | auto v90 = ( uint8_t )reader.read( ); 9 | for ( auto i = reader.get_start_size( ) - 1; i >= 5; --i ) { 10 | auto v408 = i != 0 ? *( uint8_t* )( reader.get_start_buffer( ) + i - 1 ) : v90; 11 | *( uint8_t* )( reader.get_start_buffer( ) + i ) ^= v408; 12 | } 13 | 14 | // @note: user344: Since our decryption is not proper and we dont decrypt last byte 15 | // we cant do a proper "if (report_size == 0xFFFF) break;" check inside loop 16 | // thus im forced to do this ugly "while (bf.get_size() > 2)" check for now. 17 | // CHANGE WHEN DECRYPTION IS FIXED!!! 18 | int iteration = 0; 19 | while ( reader.get_size( ) > 4 ) { 20 | const auto report_size = reader.read( ); 21 | if ( ( iteration > 0 && report_size > reader.get_size( ) ) || !report_size ) // @note: es3n1n: otherwise it will fail cz of inproper decryption 22 | continue; 23 | 24 | battleye::reports::execute_handler( reader.get_buffer( ), report_size ); 25 | 26 | reader.skip( report_size ); 27 | iteration += 1; 28 | } 29 | 30 | // @note: user344: skip remaining bytes due to improper decryption 31 | reader.skip( reader.get_size( ) ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/general_info.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void general_info( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | char buffer[ 256 ] = { '\0' }; 7 | 8 | util::logger::info( "\twindows:" ); 9 | 10 | auto windows_end = reader.read( ) + reader.get_buffer( ); 11 | while ( reader.get_buffer( ) < windows_end ) { 12 | auto window_title_len = reader.read( ); 13 | if ( window_title_len ) { 14 | reader.read_to( buffer, window_title_len ); 15 | buffer[ window_title_len ] = '\0'; 16 | util::logger::info( "\t\ttitle: %s", buffer ); 17 | } 18 | 19 | auto window_class_len = reader.read( ); 20 | if ( window_class_len ) { 21 | reader.read_to( buffer, window_class_len ); 22 | buffer[ window_class_len ] = '\0'; 23 | util::logger::info( "\t\tclass: %s", buffer ); 24 | } 25 | 26 | auto window_path_len = reader.read( ); 27 | if ( window_path_len ) { 28 | reader.read_to( buffer, window_path_len ); 29 | buffer[ window_path_len ] = '\0'; 30 | util::logger::info( "\t\tpath: %s", buffer ); 31 | } 32 | 33 | util::logger::info( "\t\tfile_size: %d", reader.read( ) ); 34 | util::logger::info( "\t\twindow_style: %x", reader.read( ) ); 35 | util::logger::info( "\t\twindow_ex_style: %x", reader.read( ) ); 36 | 37 | auto window_rect = reader.read( ); 38 | util::logger::info( "\t\twindow_rect.left: %d", window_rect.left ); 39 | util::logger::info( "\t\twindow_rect.top: %d", window_rect.top ); 40 | util::logger::info( "\t\twindow_rect.right: %d", window_rect.right ); 41 | util::logger::info( "\t\twindow_rect.bottom: %d", window_rect.bottom ); 42 | util::logger::info( "\t\t================================" ); 43 | } 44 | 45 | util::logger::info( "\thandles:" ); 46 | auto handles_end = reader.read( ) + reader.get_buffer( ); 47 | while (reader.get_buffer() < handles_end) { 48 | auto len = reader.read( ); 49 | if ( len ) { 50 | reader.read_to( buffer, len ); 51 | buffer[ len ] = '\0'; 52 | util::logger::info( "\t\tpath: %s", buffer ); 53 | } 54 | util::logger::info( "\t\tfile_size: %d", reader.read( ) ); 55 | util::logger::info( "\t\taccess_mask: %x", reader.read( ) ); 56 | util::logger::info( "\t\t================================" ); 57 | } 58 | 59 | // @fixme: unknown zeroes? 60 | reader.skip( sizeof( uint32_t ) * 4 ); 61 | 62 | uint64_t hooked_addr = reader.read( ); 63 | if ( hooked_addr ) { 64 | //util::logger::info("\thooked function:\n"); 65 | //util::logger::info("\t\taddress: %p\n", hooked_addr); 66 | reader.skip( sizeof( uint64_t ) * 3 ); 67 | } 68 | 69 | util::logger::info( "\tsystem:" ); 70 | util::logger::info( "\t\tstartup_time: %d", reader.read( ) ); 71 | 72 | util::logger::info( "\tbootmgfw.efi:" ); 73 | util::logger::info( "\t\tcreated_at: %d", reader.read( ) ); 74 | util::logger::info( "\t\tlast_access_time: %d", reader.read( ) ); 75 | util::logger::info( "\t\tlast_write_time: %d", reader.read( ) ); 76 | util::logger::info( "\t\tchange_time: %d", reader.read( ) ); 77 | util::logger::info( "\t\tfile_attributes: %d", reader.read( ) ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/memory_anomaly.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void memory_anomaly( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | util::logger::info( "\tbase_address: 0x%p", reader.read( ) ); 7 | util::logger::info( "\tregion_size: 0x%x", reader.read( ) ); 8 | util::logger::info( "\tmemory_info: %x", reader.read( ) ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/memory_region.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void memory_region( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | util::logger::info( "\tunk_mem_type: %d", reader.read( ) ); 7 | util::logger::info( "\tbase_addr: 0x%p", reader.read( ) ); 8 | util::logger::info( "\tregion_size: 0x%x", reader.read( ) ); 9 | util::logger::info( "\tregion_flags: %x", reader.read( ) ); 10 | 11 | //size_t sz = reader.get_size( ); 12 | //uint8_t* dump = ( uint8_t* )( malloc( sz ) ); 13 | //reader.read_to( dump, sz ); 14 | //util::logger::info( "\thexdump:" ); 15 | //util::hexdump( "\t\t", dump, sz ); 16 | //free( dump ); 17 | reader.skip( reader.get_size( ) ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/memory_signature.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void memory_signature( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | const auto type = reader.read( ); 7 | const auto data = reader.read( ); 8 | const auto base_address = reader.read( ); 9 | const auto region_size = reader.read( ); 10 | const auto memory_info = reader.read( ); 11 | const auto len = strnlen( ( char* )data, 256 ); 12 | 13 | util::logger::info( "\ttype: %hx", type ); 14 | util::logger::info( "\tdata: 0x%p", data ); 15 | util::logger::info( "\tbase_address: 0x%p", base_address ); 16 | util::logger::info( "\tregion_size: 0x%x", region_size ); 17 | util::logger::info( "\tmemory_info: %x", memory_info ); 18 | util::logger::info( "\thexdump:" ); 19 | util::hexdump( "\t\t", reinterpret_cast< void* >( data ), ( len != 0 && len != 256 ) ? len : 10 ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/mono_assets.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void mono_assets( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | util::logger::info( "\tassets:" ); 7 | 8 | while ( reader.get_size( ) > 1 ) { 9 | char buf[ 256 ]; 10 | 11 | // @note: es3n1n: 12 | //**buffer_ptr = strlen; 13 | //for ( off = 0; off < **buffer_ptr; ++off ) 14 | // ( *buffer_ptr )[ off + 1 ] = *( ( _BYTE* )file_name + 2 * off );// write file name to buffer 15 | auto len = reader.read( ); 16 | reader.read_to( buf, len ); 17 | buf[ len ] = '\0'; 18 | util::logger::info( "\tname: %s", buf ); 19 | 20 | // @note: es3n1n: 21 | // if ( getfileattributesexw(full_path, 0i64, v27) ) 22 | // *( _DWORD* )*buffer_ptr = v28; // write attributes 23 | auto file_attributes = reader.read( ); 24 | util::logger::info( "\t\tfile_attributes: 0x%x", file_attributes ); 25 | 26 | // @note: es3n1n: 27 | // *((_DWORD *)*buffer_ptr + 1) = 0; 28 | // memset( read_buf, 0, sizeof( read_buf ) ); 29 | // while ( readfile( v26, read_buf, 256i64, &v25, 0i64 ) && v25 ) 30 | // *( ( _DWORD* )*buffer_ptr + 1 ) += read_buf[ 3 ] + read_buf[ 2 ] + read_buf[ 1 ] + read_buf[ 0 ]; 31 | auto checksum = reader.read( ); 32 | util::logger::info( "\t\tchecksum: 0x%x", checksum ); 33 | 34 | util::logger::info( "\t================================" ); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/veh.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void veh( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | util::logger::info( "\thook_id: %d", reader.read( ) ); 7 | util::logger::info( "\tcalled_by: 0x%p", reader.read( ) ); 8 | 9 | uint8_t dump[ 32 ]; 10 | reader.read_to( dump, 32 ); 11 | 12 | util::logger::info( "\tallocation_base: 0x%p", reader.read( ) ); 13 | util::logger::info( "\tbase_address: 0x%p", reader.read( ) ); 14 | util::logger::info( "\tregion_size: 0x%x", reader.read( ) ); 15 | util::logger::info( "\tstate: 0x%x", reader.read( ) ); 16 | 17 | util::logger::info( "\thexdump:" ); 18 | util::hexdump( "\t\t", dump, 32 ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/handlers/window_title.cpp: -------------------------------------------------------------------------------- 1 | #include "battleye/reports.hpp" 2 | 3 | 4 | namespace battleye::reports::handlers { 5 | void window_title( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 6 | char buf[ 128 ] = { '\0' }; 7 | reader.read_to( buf, reader.read( ) ); 8 | util::logger::info( "\ttitle: %s", buf ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/reports.cpp: -------------------------------------------------------------------------------- 1 | #include "reports.hpp" 2 | #include 3 | 4 | 5 | namespace battleye::reports { 6 | void register_handlers( ) { 7 | registered_handlers[ battleye::enums::e_report_id::REPORT_UNKNOWN ] = handlers::unknown; 8 | registered_handlers[ battleye::enums::e_report_id::REPORT_ENCRYPTED ] = handlers::encrypted; 9 | registered_handlers[ battleye::enums::e_report_id::REPORT_GENERAL_INFO ] = handlers::general_info; 10 | registered_handlers[ battleye::enums::e_report_id::REPORT_VEH ] = handlers::veh; 11 | registered_handlers[ battleye::enums::e_report_id::REPORT_MEMORY_ANOMALY ] = handlers::memory_anomaly; 12 | registered_handlers[ battleye::enums::e_report_id::REPORT_WINDOW_TITLE ] = handlers::window_title; 13 | registered_handlers[ battleye::enums::e_report_id::REPORT_MEMORY_SIGNATURE ] = handlers::memory_signature; 14 | registered_handlers[ battleye::enums::e_report_id::REPORT_DRIVER_PRESENCE_BEEP ] = handlers::driver_presence; 15 | registered_handlers[ battleye::enums::e_report_id::REPORT_DRIVER_PRESENCE_NULL ] = handlers::driver_presence; 16 | registered_handlers[ battleye::enums::e_report_id::REPORT_MEMORY_REGION ] = handlers::memory_region; 17 | registered_handlers[ battleye::enums::e_report_id::REPORT_BECLIENT_ENCRYPTED ] = handlers::beclient_encrypted; 18 | registered_handlers[ battleye::enums::e_report_id::REPORT_MONO_ASSETS ] = handlers::mono_assets; 19 | } 20 | 21 | void execute_handler( battleye::enums::e_report_id id, util::io::reader_t& reader ) { 22 | auto handler = registered_handlers.find( id ); 23 | if ( handler == registered_handlers.end( ) ) 24 | handler = registered_handlers.find( battleye::enums::e_report_id::REPORT_UNKNOWN ); 25 | if ( id != battleye::enums::e_report_id::REPORT_ENCRYPTED ) 26 | util::logger::info( "[0x%x] Report(%s):", id, enums::report_id_to_string( id ) ); 27 | handler->second( id, reader ); 28 | if ( id != battleye::enums::e_report_id::REPORT_ENCRYPTED ) 29 | util::logger::info( "" ); 30 | } 31 | 32 | void execute_handler( const uint8_t* buffer, size_t size ) { 33 | auto reader = util::io::reader_t( buffer, size ); 34 | auto id = reader.read( ); 35 | if ( id == 0x0 ) { 36 | util::logger::error( "Got invalid report 0x0" ); 37 | return; 38 | } 39 | execute_handler( static_cast< enums::e_report_id >( id ), reader ); 40 | assert( reader.get_size( ) == 0 ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/reports.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "util/util.hpp" 3 | #include "battleye/battleye.hpp" 4 | 5 | 6 | namespace battleye::reports { 7 | using report_handler_t = void( * )( battleye::enums::e_report_id, util::io::reader_t& ); 8 | 9 | namespace handlers { 10 | void encrypted( battleye::enums::e_report_id, util::io::reader_t& reader ); 11 | void general_info( battleye::enums::e_report_id, util::io::reader_t& reader ); 12 | void veh( battleye::enums::e_report_id, util::io::reader_t& reader ); 13 | void memory_anomaly( battleye::enums::e_report_id, util::io::reader_t& reader ); 14 | void window_title( battleye::enums::e_report_id, util::io::reader_t& reader ); 15 | void memory_signature( battleye::enums::e_report_id, util::io::reader_t& reader ); 16 | void driver_presence( battleye::enums::e_report_id, util::io::reader_t& reader ); 17 | void memory_region( battleye::enums::e_report_id, util::io::reader_t& reader ); 18 | void beclient_encrypted( battleye::enums::e_report_id, util::io::reader_t& reader ); 19 | void mono_assets( battleye::enums::e_report_id, util::io::reader_t& reader ); 20 | 21 | inline void unknown( battleye::enums::e_report_id, util::io::reader_t& reader ) { 22 | util::hexdump( "", reader.get_buffer( ), reader.get_size( ) ); 23 | reader.skip( reader.get_size( ) ); 24 | } 25 | } 26 | 27 | inline std::unordered_map registered_handlers; 28 | 29 | void register_handlers( ); 30 | void execute_handler( battleye::enums::e_report_id id, util::io::reader_t& reader ); 31 | void execute_handler( const uint8_t* buffer, size_t size ); 32 | } 33 | -------------------------------------------------------------------------------- /be-shellcode-tester/battleye/resources/beclient_x64.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace battleye::resources { 5 | inline unsigned char beclient_x64[ 1024 ] = { 6 | 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 7 | 0xFF, 0xFF, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 9 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 10 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11 | 0xE0, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 12 | 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 13 | 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 14 | 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 15 | 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, 16 | 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xB8, 0xD8, 0xCD, 17 | 0xFD, 0xD9, 0xB6, 0x9E, 0xFD, 0xD9, 0xB6, 0x9E, 0xFD, 0xD9, 0xB6, 0x9E, 18 | 0x91, 0xAD, 0xB5, 0x9F, 0xFC, 0xD9, 0xB6, 0x9E, 0xA6, 0xB1, 0xB7, 0x9F, 19 | 0xFE, 0xD9, 0xB6, 0x9E, 0xFD, 0xD9, 0xB7, 0x9E, 0xFF, 0xD9, 0xB6, 0x9E, 20 | 0x24, 0xAD, 0xBF, 0x9F, 0xFE, 0xD9, 0xB6, 0x9E, 0x24, 0xAD, 0xB6, 0x9F, 21 | 0xFC, 0xD9, 0xB6, 0x9E, 0x24, 0xAD, 0xB4, 0x9F, 0xFC, 0xD9, 0xB6, 0x9E, 22 | 0x52, 0x69, 0x63, 0x68, 0xFD, 0xD9, 0xB6, 0x9E, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 25 | 0x64, 0x86, 0x00, 0x00, 0xAF, 0xA2, 0x7A, 0x5D, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x22, 0x20, 0x0B, 0x02, 0x0E, 0x1C, 27 | 0x00, 0x7C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 28 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 29 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 30 | 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, 0x10, 0x00, 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 76 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 91 | 0x00, 0x00, 0x00, 0x00 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /be-shellcode-tester/be-shellcode-tester.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug [dll] 6 | Win32 7 | 8 | 9 | Debug [dll] 10 | x64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Release [dll] 18 | Win32 19 | 20 | 21 | Release [dll] 22 | x64 23 | 24 | 25 | Release 26 | Win32 27 | 28 | 29 | Debug 30 | x64 31 | 32 | 33 | Release 34 | x64 35 | 36 | 37 | 38 | 16.0 39 | Win32Proj 40 | {d867b1ea-3c81-4ec2-a081-c3015d944b75} 41 | beshellcodetester 42 | 10.0 43 | 44 | 45 | 46 | Application 47 | true 48 | v142 49 | Unicode 50 | 51 | 52 | DynamicLibrary 53 | true 54 | v142 55 | Unicode 56 | 57 | 58 | Application 59 | false 60 | v142 61 | true 62 | Unicode 63 | 64 | 65 | DynamicLibrary 66 | false 67 | v142 68 | true 69 | Unicode 70 | 71 | 72 | Application 73 | true 74 | v142 75 | Unicode 76 | 77 | 78 | DynamicLibrary 79 | true 80 | v142 81 | Unicode 82 | 83 | 84 | Application 85 | false 86 | v142 87 | true 88 | Unicode 89 | 90 | 91 | DynamicLibrary 92 | false 93 | v142 94 | true 95 | Unicode 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | true 129 | $(SolutionDir)output\$(Configuration)\ 130 | $(SolutionDir)intermediates\$(Configuration)\$(MSBuildProjectName)\ 131 | false 132 | 133 | 134 | true 135 | $(SolutionDir)output\$(Configuration)\ 136 | $(SolutionDir)intermediates\$(Configuration)\$(MSBuildProjectName)\ 137 | false 138 | 139 | 140 | false 141 | $(SolutionDir)output\$(Configuration)\ 142 | $(SolutionDir)intermediates\$(Configuration)\$(MSBuildProjectName)\ 143 | false 144 | 145 | 146 | false 147 | $(SolutionDir)output\$(Configuration)\ 148 | $(SolutionDir)intermediates\$(Configuration)\$(MSBuildProjectName)\ 149 | false 150 | 151 | 152 | true 153 | $(SolutionDir)output\$(Configuration)\ 154 | $(SolutionDir)intermediates\$(Configuration)\$(MSBuildProjectName)\ 155 | false 156 | 157 | 158 | true 159 | $(SolutionDir)output\$(Configuration)\ 160 | $(SolutionDir)intermediates\$(Configuration)\$(MSBuildProjectName)\ 161 | false 162 | 163 | 164 | false 165 | $(SolutionDir)output\$(Configuration)\ 166 | $(SolutionDir)intermediates\$(Configuration)\$(MSBuildProjectName)\ 167 | false 168 | 169 | 170 | false 171 | $(SolutionDir)output\$(Configuration)\ 172 | $(SolutionDir)intermediates\$(Configuration)\$(MSBuildProjectName)\ 173 | false 174 | 175 | 176 | 177 | Level3 178 | true 179 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 180 | true 181 | stdcpplatest 182 | stdc17 183 | true 184 | MultiThreadedDebug 185 | $(SolutionDir)$(ProjectName)\;%(AdditionalIncludeDirectories) 186 | 187 | 188 | Console 189 | true 190 | 191 | 192 | 193 | 194 | Level3 195 | true 196 | DLL;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 197 | true 198 | stdcpplatest 199 | stdc17 200 | true 201 | MultiThreadedDebug 202 | $(SolutionDir)$(ProjectName)\;%(AdditionalIncludeDirectories) 203 | 204 | 205 | Console 206 | true 207 | 208 | 209 | 210 | 211 | Level3 212 | true 213 | true 214 | true 215 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 216 | true 217 | stdcpplatest 218 | stdc17 219 | true 220 | MultiThreaded 221 | $(SolutionDir)$(ProjectName)\;%(AdditionalIncludeDirectories) 222 | 223 | 224 | Console 225 | true 226 | true 227 | true 228 | 229 | 230 | 231 | 232 | Level3 233 | true 234 | true 235 | true 236 | DLL;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 237 | true 238 | stdcpplatest 239 | stdc17 240 | true 241 | MultiThreaded 242 | $(SolutionDir)$(ProjectName)\;%(AdditionalIncludeDirectories) 243 | 244 | 245 | Console 246 | true 247 | true 248 | true 249 | 250 | 251 | 252 | 253 | Level3 254 | true 255 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 256 | true 257 | stdcpplatest 258 | stdc17 259 | true 260 | MultiThreadedDebug 261 | $(SolutionDir)$(ProjectName)\;%(AdditionalIncludeDirectories) 262 | 263 | 264 | Console 265 | true 266 | 267 | 268 | 269 | 270 | Level3 271 | true 272 | DLL;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 273 | true 274 | stdcpplatest 275 | stdc17 276 | true 277 | MultiThreadedDebug 278 | $(SolutionDir)$(ProjectName)\;%(AdditionalIncludeDirectories) 279 | 280 | 281 | Console 282 | true 283 | 284 | 285 | 286 | 287 | Level3 288 | true 289 | true 290 | true 291 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 292 | true 293 | stdcpplatest 294 | stdc17 295 | true 296 | MultiThreaded 297 | $(SolutionDir)$(ProjectName)\;%(AdditionalIncludeDirectories) 298 | 299 | 300 | Console 301 | true 302 | true 303 | true 304 | 305 | 306 | 307 | 308 | Level3 309 | true 310 | true 311 | true 312 | DLL;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 313 | true 314 | stdcpplatest 315 | stdc17 316 | true 317 | MultiThreaded 318 | $(SolutionDir)$(ProjectName)\;%(AdditionalIncludeDirectories) 319 | 320 | 321 | Console 322 | true 323 | true 324 | true 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | -------------------------------------------------------------------------------- /be-shellcode-tester/be-shellcode-tester.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | Source Files 71 | 72 | 73 | Source Files 74 | 75 | 76 | Source Files 77 | 78 | 79 | Source Files 80 | 81 | 82 | Source Files 83 | 84 | 85 | Source Files 86 | 87 | 88 | Source Files 89 | 90 | 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files 109 | 110 | 111 | Header Files 112 | 113 | 114 | Header Files 115 | 116 | 117 | Header Files 118 | 119 | 120 | Header Files 121 | 122 | 123 | Header Files 124 | 125 | 126 | -------------------------------------------------------------------------------- /be-shellcode-tester/be-shellcode-tester.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | -------------------------------------------------------------------------------- /be-shellcode-tester/bootstrap/bootstrap.cpp: -------------------------------------------------------------------------------- 1 | #include "bootstrap.hpp" 2 | #include "battleye/reports.hpp" 3 | #include "hooks/hooks.hpp" 4 | #include 5 | 6 | 7 | namespace bootstrap { 8 | namespace detail { 9 | void init( ) { 10 | static std::once_flag fl; 11 | std::call_once( fl, [ ] ( ) -> void { 12 | util::logger::info( "Registering handlers" ); 13 | battleye::reports::register_handlers( ); 14 | } ); 15 | } 16 | } 17 | 18 | void run_file( const std::wstring& path, const std::wstring& name ) { 19 | detail::init( ); 20 | 21 | util::logger::info( "Loading %ws", name.c_str( ) ); 22 | loader::load_shellcode( util::io::open_file( path.c_str( ) ) ); 23 | } 24 | 25 | void run_dir( const std::string& dir ) { 26 | detail::init( ); 27 | 28 | util::logger::info( "Iterating dir %s", dir.c_str( ) ); 29 | 30 | for ( const auto& entry : std::filesystem::directory_iterator( dir ) ) { 31 | const auto& path = entry.path( ); 32 | const auto& name = path.filename( ); 33 | 34 | // run only .bin files 35 | if ( name.extension( ) != L".bin" ) 36 | continue; 37 | 38 | run_file( path, name ); 39 | } 40 | 41 | util::logger::info( "Finished" ); 42 | } 43 | } -------------------------------------------------------------------------------- /be-shellcode-tester/bootstrap/bootstrap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "util/util.hpp" 3 | #include "loader/loader.hpp" 4 | 5 | 6 | namespace bootstrap { 7 | void run_file( const std::wstring& path, const std::wstring& name ); 8 | void run_dir( const std::string& dir ); 9 | } -------------------------------------------------------------------------------- /be-shellcode-tester/entry.cpp: -------------------------------------------------------------------------------- 1 | #include "bootstrap/bootstrap.hpp" 2 | 3 | 4 | #ifndef DLL 5 | int main( int argc, char* argv[ ] ) { 6 | util::logger::info( "Starting..." ); 7 | bootstrap::run_dir( 8 | argc >= 2 ? argv[ 1 ] : "C:\\shellcodes\\" 9 | ); 10 | return EXIT_SUCCESS; 11 | } 12 | #else 13 | DWORD __stdcall th( LPVOID h ) { 14 | util::logger::attach( ); 15 | util::logger::info( "Starting..." ); 16 | bootstrap::run_dir( 17 | "C:\\shellcodes\\" 18 | ); 19 | if ( h ) 20 | FreeLibraryAndExitThread( static_cast< HMODULE >( h ), 0x1 ); 21 | return 1; 22 | } 23 | 24 | BOOL __stdcall DllMain( HANDLE h, uint32_t call_reason, uintptr_t reserved ) { 25 | if ( call_reason != DLL_PROCESS_ATTACH ) return TRUE; 26 | 27 | CreateThread( 0, 0, th, h, 0, 0 ); 28 | 29 | return TRUE; 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /be-shellcode-tester/hooks/battleye/send_report.cpp: -------------------------------------------------------------------------------- 1 | #include "hooks/hooks.hpp" 2 | #include "battleye/reports.hpp" 3 | 4 | 5 | namespace hooks { 6 | void send_report( uint8_t* buffer, size_t size, bool unk ) { 7 | std::vector report( size - 1 ); 8 | memcpy( report.data( ), buffer + 1, size - 1 ); 9 | 10 | util::logger::info( "Got %d size report", report.size( ) ); 11 | //__debugbreak( ); 12 | battleye::reports::execute_handler( report.data( ), report.size( ) ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /be-shellcode-tester/hooks/hooks.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "util/util.hpp" 3 | 4 | 5 | namespace hooks { 6 | // winapi funcs 7 | HMODULE GetModuleHandleA( const char* module_name ); 8 | FARPROC GetProcAddress( HMODULE mod, const char* proc ); 9 | BOOL IsBadReadPtr( const void* lp, uintptr_t ucb ); 10 | HMODULE LoadLibraryA( const char* file_name ); 11 | int WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar ); 12 | 13 | // battleye funcs 14 | void send_report( uint8_t* buffer, size_t size, bool unk ); 15 | 16 | inline std::unordered_map hooked_functions = { 17 | { "GetModuleHandleA", ::hooks::GetModuleHandleA }, 18 | { "GetProcAddress", ::hooks::GetProcAddress }, 19 | { "IsBadReadPtr", ::hooks::IsBadReadPtr }, 20 | { "LoadLibraryA", ::hooks::LoadLibraryA }, 21 | { "WideCharToMultiByte", hooks::WideCharToMultiByte } 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /be-shellcode-tester/hooks/winapi/GetModuleHandle.cpp: -------------------------------------------------------------------------------- 1 | #include "hooks/hooks.hpp" 2 | #include "battleye/battleye.hpp" 3 | #include 4 | 5 | 6 | namespace hooks { 7 | namespace detail { 8 | static std::vector allowed_modules_to_load = { 9 | "msvcrt.dll", "USER32.dll", "shell32.dll", "mmres.dll" 10 | }; 11 | } 12 | 13 | HMODULE GetModuleHandleA( const char* module_name ) { 14 | util::logger::info( "%s%s%s%s%s", __FUNCTION__, module_name ? "(\"" : "", module_name, module_name ? "\"" : "", module_name ? ")" : "" ); 15 | 16 | if ( !module_name ) { // @note: es3n1n: if battleye asks for game handle, then we'll fake it 17 | static void* fake = nullptr; 18 | if ( !fake ) { 19 | fake = malloc( 0xFFFFFF ); 20 | 21 | const auto mod = reinterpret_cast< uint8_t* >( ::GetModuleHandleA( NULL ) ); 22 | auto pe = util::c_pe( mod ); 23 | memcpy( fake, mod, pe.get_headers_size( ) ); 24 | // @note: es3n1n: copy only headers and leave everything as it is 25 | } 26 | return reinterpret_cast< HMODULE >( fake ); 27 | } 28 | 29 | auto res = battleye::resources_list.find( module_name ); 30 | if ( res != battleye::resources_list.end( ) ) 31 | return reinterpret_cast< HMODULE >( res->second ); 32 | 33 | HMODULE ret = ::GetModuleHandleA( module_name ); 34 | if ( !ret ) { 35 | if ( std::find( detail::allowed_modules_to_load.begin( ), detail::allowed_modules_to_load.end( ), module_name ) != detail::allowed_modules_to_load.end( ) ) 36 | ret = ::LoadLibraryA( module_name ); 37 | } 38 | 39 | //if ( !ret ) 40 | // util::logger::error( "Module %s not found!", module_name ); 41 | 42 | return ret; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /be-shellcode-tester/hooks/winapi/GetProcAddress.cpp: -------------------------------------------------------------------------------- 1 | #include "hooks/hooks.hpp" 2 | 3 | 4 | namespace hooks { 5 | FARPROC GetProcAddress( HMODULE mod, const char* proc ) { 6 | util::logger::info( "%s(0x%p, \"%s\")", __FUNCTION__, mod, proc ); 7 | 8 | auto hk = hooks::hooked_functions.find( proc ); 9 | if ( hk != hooks::hooked_functions.end( ) ) 10 | return static_cast< FARPROC >( hk->second ); 11 | 12 | return ::GetProcAddress( mod, proc ); 13 | } 14 | } -------------------------------------------------------------------------------- /be-shellcode-tester/hooks/winapi/IsBadReadPtr.cpp: -------------------------------------------------------------------------------- 1 | #include "hooks/hooks.hpp" 2 | 3 | 4 | namespace hooks { 5 | BOOL IsBadReadPtr( const void* lp, uintptr_t ucb ) { // @note: es3n1n: I've made this hook cz i'm tired of unhandled errors 6 | MEMORY_BASIC_INFORMATION mbi = { 0 }; 7 | VirtualQuery( lp, &mbi, sizeof( mbi ) ); 8 | return !!GetLastError( ) || !( 9 | mbi.Protect & PAGE_EXECUTE_READ || 10 | mbi.Protect & PAGE_EXECUTE_READWRITE 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /be-shellcode-tester/hooks/winapi/LoadLibraryA.cpp: -------------------------------------------------------------------------------- 1 | #include "hooks/hooks.hpp" 2 | 3 | 4 | namespace hooks { 5 | HMODULE LoadLibraryA( const char* file_name ) { 6 | util::logger::info( "%s(\"%s\")", __FUNCTION__, file_name ); 7 | 8 | HMODULE ret = ::LoadLibraryA( file_name ); 9 | if ( !ret ) { 10 | util::logger::error( "Failed to load %s", file_name ); 11 | } 12 | 13 | if ( ret && util::str_ends_with( file_name, "BEClient2.dll" ) ) { 14 | // @note: es3n1n: the trick is that we'll iterate through IAT(Import Address Table) and replace original fn addr with our hk 15 | auto pe = util::c_pe( reinterpret_cast< uint8_t* >( ret ) ); 16 | 17 | for ( auto& [mod, imports] : pe.get_imports( ) ) { 18 | for ( auto& import_data : imports ) { 19 | auto hk = hooks::hooked_functions.find( import_data.name ); 20 | if ( hk == hooks::hooked_functions.end( ) ) continue; 21 | 22 | // @note: es3n1n: change protection, and we'll able to write our hooks there 23 | DWORD old_protection; 24 | VirtualProtect( reinterpret_cast< void* >( uintptr_t( ret ) + import_data.function_rva ), sizeof( uintptr_t ) * 3, PAGE_EXECUTE_READWRITE, &old_protection ); 25 | 26 | // @note: es3n1n: write hook address 27 | *reinterpret_cast< uintptr_t* >( uintptr_t( ret ) + import_data.function_rva ) = uintptr_t( hk->second ); 28 | 29 | // @fixme: es3n1n: GetModuleHandleA import doesn't present in iat idk lol 30 | if ( !strcmp( import_data.name.c_str( ), "GetProcAddress" ) ) 31 | *reinterpret_cast< uintptr_t* >( uintptr_t( ret ) + import_data.function_rva + sizeof( uintptr_t ) ) = uintptr_t( hooks::hooked_functions[ "GetModuleHandleA" ] ); 32 | 33 | // @note: es3n1n: restore protection 34 | VirtualProtect( reinterpret_cast< void* >( uintptr_t( ret ) + import_data.function_rva ), sizeof( uintptr_t ) * 3, old_protection, &old_protection ); 35 | } 36 | } 37 | } 38 | 39 | return ret; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /be-shellcode-tester/hooks/winapi/WideCharToMultiByte.cpp: -------------------------------------------------------------------------------- 1 | #include "hooks/hooks.hpp" 2 | 3 | 4 | namespace hooks { 5 | int WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar ) { 6 | // @note: es3n1n: stupid bastian cannot handle it properly 7 | // 000001CA0FE58896 | 81BC04 221D0000 64776D2E | cmp dword ptr ss:[rsp+rax+1D22],2E6D7764 | 8 | return ::WideCharToMultiByte( CodePage, dwFlags, lpWideCharStr, lstrlenW( lpWideCharStr ), lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /be-shellcode-tester/loader/loader.cpp: -------------------------------------------------------------------------------- 1 | #include "loader.hpp" 2 | 3 | 4 | namespace loader { 5 | bool load_shellcode( util::io::handle_t file_handle ) { 6 | // @note: es3n1n: assert file 7 | if ( file_handle == INVALID_HANDLE_VALUE ) { 8 | util::logger::error( "Got invalid file_handle" ); 9 | util::io::close_file( file_handle ); 10 | return false; 11 | } 12 | 13 | // @note: es3n1n: read file size, assert it then 14 | size_t file_size = util::io::get_file_size( file_handle ); 15 | if ( !file_size ) { 16 | util::logger::error( "Got empty file to load" ); 17 | util::io::close_file( file_handle ); 18 | return false; 19 | } 20 | 21 | // @note: es3n1n: allocating region for mapped shellcode 22 | uint8_t* shellcode_region = static_cast< uint8_t* >( VirtualAlloc( NULL, file_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ) ); 23 | if ( !shellcode_region ) { 24 | util::logger::error( "Failed to allocate memory" ); 25 | util::io::close_file( file_handle ); 26 | return false; 27 | } 28 | 29 | // @note: es3n1n: reading from file to allocated memory 30 | if ( !util::io::read_file( file_handle, shellcode_region, file_size ) ) { 31 | util::logger::error( "Failed to allocate memory" ); 32 | util::io::close_file( file_handle ); 33 | return false; 34 | } 35 | util::io::close_file( file_handle ); 36 | 37 | // @note: es3n1n: fix some weird check 38 | uint32_t* report_end = reinterpret_cast< uint32_t* >( reinterpret_cast< uint8_t* >( hooks::send_report ) + 5 ); 39 | if ( *report_end == 0xCCCCCCCC ) { 40 | DWORD old_protect; 41 | VirtualProtect( report_end, sizeof( uint32_t ), PAGE_EXECUTE_READWRITE, &old_protect ); 42 | *report_end = 0xCCCC90CC; 43 | VirtualProtect( report_end, sizeof( uint32_t ), old_protect, &old_protect ); 44 | } 45 | 46 | // @note: es3n1n: searching for shellcode ep 47 | auto ep_rva = util::mem::sig( shellcode_region, file_size, "4C 89 4C 24 ? 4C 89 44 24 ? 48 89 54 24 ? 89 4C 24 08" ); // @note: es3n1n: if this sig has failed, it will return 0 48 | util::logger::info( "Found EP at 0x%p [rva]", ep_rva ); 49 | 50 | // @note: es3n1n: checking if the returned rva is valid 51 | if ( *reinterpret_cast< uint8_t* >( shellcode_region + ep_rva ) != 0x4C ) { 52 | util::logger::warn( "It seems like EP rva is invalid, continue?" ); 53 | util::logger::pause( ); 54 | } 55 | 56 | // @note: es3n1n: ready to run 57 | util::logger::info( "Ready to run" ); 58 | #ifdef _DEBUG 59 | util::logger::pause( ); 60 | #endif 61 | 62 | // @note: es3n1n: running 63 | bool unk = true; 64 | reinterpret_cast< battleye::typedefs::shellcode_startup_t >( shellcode_region + ep_rva )( 65 | 0, hooks::send_report, hooks::GetModuleHandleA, hooks::GetProcAddress, &unk 66 | ); 67 | 68 | // @note: es3n1n: cleaning up 69 | VirtualFree( shellcode_region, 0, MEM_RELEASE ); 70 | 71 | return true; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /be-shellcode-tester/loader/loader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "util/util.hpp" 3 | #include "battleye/battleye.hpp" 4 | #include "hooks/hooks.hpp" 5 | 6 | 7 | namespace loader { 8 | bool load_shellcode( util::io::handle_t file_handle ); 9 | } 10 | -------------------------------------------------------------------------------- /be-shellcode-tester/util/io/io.cpp: -------------------------------------------------------------------------------- 1 | #include "io.hpp" 2 | 3 | 4 | namespace util::io { 5 | handle_t create_file( const char* path ) { 6 | return CreateFileA( path, 7 | GENERIC_READ, 8 | FILE_SHARE_READ, 9 | NULL, 10 | CREATE_NEW, 11 | FILE_ATTRIBUTE_NORMAL, 12 | NULL 13 | ); 14 | } 15 | 16 | handle_t create_file( const wchar_t* path ) { 17 | return CreateFileW( path, 18 | GENERIC_READ, 19 | FILE_SHARE_READ, 20 | NULL, 21 | CREATE_NEW, 22 | FILE_ATTRIBUTE_NORMAL, 23 | NULL 24 | ); 25 | } 26 | 27 | handle_t open_file( const char* path ) { 28 | return CreateFileA( path, 29 | GENERIC_READ, 30 | FILE_SHARE_READ, 31 | NULL, 32 | OPEN_EXISTING, 33 | FILE_ATTRIBUTE_NORMAL, 34 | NULL 35 | ); 36 | } 37 | 38 | handle_t open_file( const wchar_t* path ) { 39 | return CreateFileW( path, 40 | GENERIC_READ, 41 | FILE_SHARE_READ, 42 | NULL, 43 | OPEN_EXISTING, 44 | FILE_ATTRIBUTE_NORMAL, 45 | NULL 46 | ); 47 | } 48 | 49 | size_t get_file_size( handle_t handle ) { 50 | LARGE_INTEGER i = {}; 51 | if ( GetFileSizeEx( handle, &i ) ) 52 | return i.QuadPart; 53 | 54 | return 0; 55 | } 56 | 57 | bool read_file( handle_t handle, uint8_t* buffer, size_t size ) { 58 | const auto file_size = get_file_size( handle ); 59 | 60 | DWORD bytes_read = 0; 61 | return ReadFile( handle, buffer, static_cast< DWORD >( size ), &bytes_read, NULL ); 62 | } 63 | 64 | bool write_file( handle_t handle, uint8_t* buffer, size_t size ) { 65 | return WriteFile( handle, buffer, static_cast< DWORD >( size ), NULL, NULL ); 66 | } 67 | 68 | void close_file( handle_t handle ) { 69 | CloseHandle( handle ); 70 | } 71 | } -------------------------------------------------------------------------------- /be-shellcode-tester/util/io/io.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | namespace util::io { 8 | using handle_t = HANDLE; 9 | 10 | handle_t create_file( const char* path ); 11 | handle_t create_file( const wchar_t* path ); 12 | handle_t open_file( const char* path ); 13 | handle_t open_file( const wchar_t* path ); 14 | size_t get_file_size( handle_t handle ); 15 | bool read_file( handle_t handle, uint8_t* buffer, size_t size ); 16 | bool write_file( handle_t handle, uint8_t* buffer, size_t size ); 17 | void close_file( handle_t handle ); 18 | 19 | struct reader_t { 20 | private: 21 | const uint8_t* m_buffer; 22 | const uint8_t* m_start_buffer; 23 | size_t m_size; // @note: es3n1n: isn't const cz we'll change it skip function obv 24 | const size_t m_start_size; 25 | public: // ctor/etc 26 | reader_t( ) = default; 27 | ~reader_t( ) = default; 28 | reader_t( const uint8_t* buffer, size_t size ) : m_buffer( buffer ), m_size( size ), m_start_size( size ), m_start_buffer( buffer ) { } 29 | public: // getters 30 | __forceinline const uint8_t* get_buffer( ) { return m_buffer; } 31 | __forceinline size_t get_size( ) { return m_size; } 32 | __forceinline size_t get_start_size( ) { return m_start_size; } 33 | __forceinline const uint8_t* get_start_buffer( ) { return m_start_buffer; } 34 | public: // r/w funcs 35 | template 36 | __forceinline t read( ) { 37 | t ret = *( t* )m_buffer; 38 | skip( sizeof( t ) ); 39 | return ret; 40 | } 41 | template 42 | __forceinline void read_to( t* buf, size_t size ) { 43 | memcpy( buf, m_buffer, size ); 44 | skip( size ); 45 | } 46 | __forceinline void skip( size_t size ) { 47 | m_buffer += size; 48 | m_size -= size; 49 | } 50 | }; 51 | } -------------------------------------------------------------------------------- /be-shellcode-tester/util/logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | #define L_ERROR(...) util::logger::error(__FUNCTION__ "(): " __VA_ARGS__); 9 | #define TRACE_FN util::logger::debug( "%s()", __FUNCTION__ ); 10 | 11 | #define LOGGER_PARSE_FMT char buf[1024]; va_list va; va_start( va, fmt ); _vsnprintf_s( buf, 1024, fmt, va ); va_end( va ); 12 | #define CREATE_LOGGER_METHOD(n) inline void n(const char* fmt, ...) { LOGGER_PARSE_FMT; log( #n, e_level_color::level_color_ ##n, buf ); } 13 | 14 | 15 | namespace util { 16 | namespace logger { 17 | enum class e_level_color : uint32_t { 18 | level_color_none = 15, // black bg and white fg 19 | level_color_debug = 8, 20 | level_color_info = 10, 21 | level_color_warn = 14, 22 | level_color_error = 12 23 | }; 24 | 25 | namespace _colors { 26 | inline void* m_console_handle = nullptr; 27 | 28 | inline bool ensure_handle( ) { 29 | if ( !m_console_handle ) 30 | m_console_handle = GetStdHandle( STD_OUTPUT_HANDLE ); 31 | return static_cast< bool >( m_console_handle ); 32 | } 33 | 34 | inline void apply( uint32_t clr ) { 35 | if ( !ensure_handle( ) ) return; 36 | SetConsoleTextAttribute( m_console_handle, clr ); 37 | } 38 | 39 | inline void reset( ) { 40 | apply( static_cast< uint32_t >( e_level_color::level_color_none ) ); 41 | } 42 | 43 | inline void colorify( uint32_t clr, std::function cb ) { 44 | apply( clr ); 45 | cb( ); 46 | reset( ); 47 | } 48 | } 49 | 50 | inline void log( const char* prefix, e_level_color level, const char* message ) { 51 | _colors::colorify( static_cast< uint32_t >( level ), [ prefix ] ( ) -> void { 52 | printf( "%s >> ", prefix ); 53 | } ); 54 | 55 | printf( "%s\n", message ); 56 | } 57 | 58 | #ifdef _DEBUG 59 | CREATE_LOGGER_METHOD( debug ); 60 | #else 61 | __forceinline void debug( const char* fmt, ... ) { } 62 | #endif 63 | CREATE_LOGGER_METHOD( info ); 64 | CREATE_LOGGER_METHOD( warn ); 65 | CREATE_LOGGER_METHOD( error ); 66 | inline void fatal( const char* fmt, ... ) { 67 | LOGGER_PARSE_FMT; 68 | error( "Fatal error: %s", buf ); 69 | MessageBoxA( NULL, buf, "Fatal error", MB_OK ); 70 | ExitProcess( -1 ); 71 | } 72 | 73 | inline void pause( ) { 74 | _colors::colorify( static_cast< uint32_t >( e_level_color::level_color_warn ), [ ] ( ) -> void { 75 | printf( "warn >> " ); 76 | } ); 77 | printf( "Press any key to continue..." ); 78 | _getwch( ); 79 | printf( "\n" ); 80 | } 81 | 82 | __forceinline void attach( ) { 83 | ::AllocConsole( ); 84 | freopen_s( reinterpret_cast< FILE** >( stdin ), "CONIN$", "r", stdin ); 85 | freopen_s( reinterpret_cast< FILE** >( stdout ), "CONOUT$", "w", stdout ); 86 | } 87 | 88 | __forceinline void detach( ) { 89 | ::ShowWindow( ::GetConsoleWindow( ), SW_HIDE ); 90 | ::FreeConsole( ); 91 | } 92 | } 93 | } 94 | 95 | #undef CREATE_LOGGER_METHOD -------------------------------------------------------------------------------- /be-shellcode-tester/util/mem/mem.cpp: -------------------------------------------------------------------------------- 1 | #include "util/mem/mem.hpp" 2 | 3 | 4 | namespace { 5 | std::vector pattern_to_byte( std::string_view pattern ) { 6 | auto bytes = std::vector {}; 7 | auto start = const_cast< char* >( pattern.data( ) ); 8 | auto len = pattern.length( ); 9 | auto end = const_cast< char* >( start ) + len; 10 | bytes.reserve( len / 3 + 5 ); 11 | 12 | for ( auto current = start; current < end; ++current ) { 13 | if ( *current == '?' ) { 14 | ++current; 15 | 16 | if ( *current == '?' ) 17 | ++current; 18 | 19 | bytes.emplace_back( -1 ); 20 | } else 21 | bytes.emplace_back( strtoul( current, ¤t, 16 ) ); 22 | } 23 | return bytes; 24 | } 25 | } 26 | 27 | namespace util::mem { 28 | uintptr_t sig( uint8_t* buffer, size_t size, std::string_view pattern ) { 29 | const auto pattern_bytes = pattern_to_byte( pattern.data( ) ); 30 | 31 | const std::size_t pattern_size = pattern_bytes.size( ); 32 | const int* pattern_data = pattern_bytes.data( ); 33 | 34 | for ( std::uint32_t i = 0ul; i < size - pattern_size; ++i ) { 35 | bool found = true; 36 | 37 | for ( std::uint32_t j = 0ul; j < pattern_size; ++j ) { 38 | if ( buffer[ i + j ] == pattern_data[ j ] || pattern_data[ j ] == -1 ) 39 | continue; 40 | 41 | found = false; 42 | break; 43 | } 44 | 45 | if ( !found ) 46 | continue; 47 | 48 | return i; 49 | } 50 | 51 | return 0; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /be-shellcode-tester/util/mem/mem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | namespace util::mem { 8 | uintptr_t sig( uint8_t* buffer, size_t size, std::string_view pattern ); // @note: es3n1n: it returns RVA 9 | } -------------------------------------------------------------------------------- /be-shellcode-tester/util/pe/pe.cpp: -------------------------------------------------------------------------------- 1 | #include "pe.hpp" 2 | 3 | 4 | namespace util { 5 | c_pe::import_list c_pe::get_imports( ) { 6 | c_pe::import_list import_modules; 7 | 8 | auto import_dir = this->get_dir( IMAGE_DIRECTORY_ENTRY_IMPORT ); 9 | if ( import_dir.VirtualAddress == 0 || import_dir.Size == 0 ) 10 | return import_modules; 11 | 12 | auto import_table = reinterpret_cast< ::PIMAGE_IMPORT_DESCRIPTOR >( this->get_image_base( ) + import_dir.VirtualAddress ); 13 | 14 | for ( std::uint32_t previous_name = 0; 15 | previous_name < import_table->Name; 16 | previous_name = import_table->Name, ++import_table ) { 17 | auto module_name = std::string( reinterpret_cast< char* >( uintptr_t( m_base ) + import_table->Name ) ); 18 | 19 | if ( module_name.empty( ) ) // probably shoud be handled somehow ? 20 | continue; 21 | 22 | auto entry = reinterpret_cast< ::PIMAGE_THUNK_DATA32 >( uintptr_t( m_base ) + import_table->OriginalFirstThunk ); 23 | for ( std::uintptr_t index = 0; entry->u1.AddressOfData; index += sizeof( std::uint32_t ), ++entry ) { 24 | auto import_by_name = reinterpret_cast< ::PIMAGE_IMPORT_BY_NAME >( uintptr_t( m_base ) + entry->u1.AddressOfData ); 25 | 26 | auto& data = import_modules[ module_name ].emplace_back( ); 27 | data.function_rva = import_table->FirstThunk + index; 28 | 29 | if ( entry->u1.Ordinal < IMAGE_ORDINAL_FLAG32 && import_by_name->Name[ 0 ] ) { 30 | data.name = reinterpret_cast< const char* >( import_by_name->Name ); // IMPORT BY NAME 31 | } else { 32 | data.ordinal = IMAGE_ORDINAL32( entry->u1.AddressOfData ); // IMPORT BY ORDINAL 33 | } 34 | } 35 | } 36 | 37 | return import_modules; 38 | } 39 | } -------------------------------------------------------------------------------- /be-shellcode-tester/util/pe/pe.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace util { 9 | class c_pe { 10 | public: // ctors/etc 11 | c_pe( ) = default; 12 | ~c_pe( ) = default; 13 | c_pe( uint8_t* base ) : m_base( base ) { 14 | m_dos_headers = reinterpret_cast< IMAGE_DOS_HEADER* >( m_base ); 15 | m_nt_headers = reinterpret_cast< IMAGE_NT_HEADERS* >( m_base + m_dos_headers->e_lfanew ); 16 | } 17 | public: // getters 18 | __forceinline uintptr_t get_image_base( ) { return m_nt_headers->OptionalHeader.ImageBase; } 19 | __forceinline size_t get_image_size( ) { return m_nt_headers->OptionalHeader.SizeOfImage; } 20 | __forceinline size_t get_headers_size( ) { return m_nt_headers->OptionalHeader.SizeOfHeaders; } 21 | __forceinline IMAGE_DATA_DIRECTORY get_dir( size_t i ) { return m_nt_headers->OptionalHeader.DataDirectory[ i ]; } 22 | public: // imports stuff 23 | struct import_data_t { 24 | std::string name; 25 | uintptr_t function_rva; 26 | uintptr_t ordinal = 0; 27 | }; 28 | using import_list = std::unordered_map>; 29 | public: // imports stuff 30 | import_list get_imports( ); 31 | private: // fields 32 | uint8_t* m_base; 33 | IMAGE_DOS_HEADER* m_dos_headers; 34 | IMAGE_NT_HEADERS* m_nt_headers; 35 | }; 36 | } -------------------------------------------------------------------------------- /be-shellcode-tester/util/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.hpp" 2 | 3 | 4 | namespace util { 5 | void hexdump( const char* prefix, const void* ptr, size_t buflen ) { 6 | unsigned char* buf = ( unsigned char* )ptr; 7 | int i, j; 8 | for ( i = 0; i < buflen; i += 16 ) { 9 | printf( "%s%06x: ", prefix, i ); 10 | for ( j = 0; j < 16; j++ ) 11 | if ( i + j < buflen ) 12 | printf( "%02x ", buf[ i + j ] ); 13 | else 14 | printf( " " ); 15 | printf( " " ); 16 | for ( j = 0; j < 16; j++ ) 17 | if ( i + j < buflen ) 18 | printf( "%c", isprint( buf[ i + j ] ) ? buf[ i + j ] : '.' ); 19 | printf( "\n" ); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /be-shellcode-tester/util/util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "io/io.hpp" 6 | #include "logger.hpp" 7 | #include "mem/mem.hpp" 8 | #include "pe/pe.hpp" 9 | 10 | 11 | namespace util { 12 | void hexdump( const char* prefix, const void* ptr, size_t buflen ); 13 | __forceinline bool str_ends_with( const char* str, const char* suffix ) { 14 | if ( !str || !suffix ) 15 | return 0; 16 | size_t lenstr = strlen( str ); 17 | size_t lensuffix = strlen( suffix ); 18 | if ( lensuffix > lenstr ) 19 | return 0; 20 | return !strncmp( str + lenstr - lensuffix, suffix, lensuffix ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## be-shellcode-tester 2 | 3 | ### What is this? 4 | As you may know battleye loads custom shellcodes for detecting some stuff. \ 5 | Well this software is running those shellcodes and dumps every report that was sent. 6 | 7 | ### How's this works? 8 | - Iterating dir with previously dumped shellcodes and maps it to self mem. 9 | - Passes 'hooked' GetProcAddress/GetModuleHandleA/send_report functions to shellcode. 10 | - Reads report and prints info about it. 11 | 12 | ### How's it useful for me? 13 | Imagine your p2c is detected in be-protected game, all you need to do is dump their shellcodes and check your cheat with this tool. 14 | 15 | ### Features: 16 | - [x] Hookless 17 | - [x] Parses 9/10 reports(tested only on eft/r6 tho) 18 | - [x] Both .dll and .exe versions are available 19 | - [x] Decrypts encrypted reports from shellcodes 20 | - [ ] Decrypts encrypted reports from BEClient2.dll 21 | 22 | ### How can i dump shellcode from game? 23 | Hook GetProcAddress, get mbi of return address and check if it's not a legit module. 24 | 25 | ### Screenshot: 26 | ![img](https://i.imgur.com/9qbQ6JZ.png) 27 | 28 | ### Contributing 29 | Any contributions you make are **greatly appreciated**. 30 | 31 | 1. Fork the Project 32 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 33 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 34 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 35 | 5. Open a Pull Request 36 | 37 | ### Credits: 38 | [@es3n1n](https://github.com/es3n1n/) \ 39 | [@user344](https://github.com/user344/) 40 | 41 | --------------------------------------------------------------------------------