├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── rust-toolchain.toml ├── scripts └── find_funcs.py └── src ├── detour.rs ├── error.rs └── lib.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: 3 | workflow_dispatch: 4 | push: 5 | 6 | jobs: 7 | artifact: 8 | name: artifact - ${{ matrix.platform.target }} 9 | runs-on: ${{ matrix.platform.os }} 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | platform: 14 | - target: i686-unknown-linux-gnu 15 | os: ubuntu-latest 16 | - target: x86_64-unknown-linux-gnu 17 | os: ubuntu-latest 18 | - target: i686-pc-windows-msvc 19 | os: windows-latest 20 | - target: x86_64-pc-windows-msvc 21 | os: windows-latest 22 | toolchain: 23 | - nightly 24 | 25 | steps: 26 | - name: checkout 27 | uses: actions/checkout@v3 28 | - name: install build dependencies 29 | run: | 30 | sudo dpkg --add-architecture i386 31 | sudo apt-get update 32 | sudo apt-get install -y gcc-multilib g++-multilib libgcc-s1:i386 libssl-dev:i386 33 | if: contains(matrix.platform.target, 'i686-unknown-linux') 34 | - name: setup cache 35 | uses: Swatinem/rust-cache@v2 36 | - name: build binary 37 | uses: houseabsolute/actions-rust-cross@v0 38 | with: 39 | command: "build" 40 | target: ${{ matrix.platform.target }} 41 | toolchain: ${{ matrix.toolchain }} 42 | args: "--locked --release" 43 | env: 44 | PKG_CONFIG_SYSROOT_DIR: "/" 45 | PKG_CONFIG_PATH: "/" 46 | - name: package 47 | shell: bash 48 | run: | 49 | TARGET="${{ matrix.platform.target }}" 50 | ARCH=$(echo "$TARGET" | cut -d- -f 1 ) 51 | echo "$ARCH" 52 | if [ "$ARCH" == "x86_64" ]; then 53 | ARCH_SHORT="64" 54 | else 55 | ARCH_SHORT="32" 56 | fi 57 | 58 | PLATFORM=$(echo "$TARGET" | cut -d- -f 3 ) 59 | echo "$PLATFORM" 60 | if [ "$PLATFORM" == "windows" ]; then 61 | PLATFORM_SHORT="win" 62 | else 63 | PLATFORM_SHORT="linux" 64 | fi 65 | 66 | NAME="gmsv_accelerator_$PLATFORM_SHORT$ARCH_SHORT.dll" 67 | 68 | cd target/${{ matrix.platform.target }}/release 69 | [ -f libaccelerator.so ] && mv libaccelerator.so accelerator.dll 70 | 71 | mv accelerator.dll "../../../$NAME" 72 | cd - 73 | - name: Publish release artifacts 74 | uses: actions/upload-artifact@v3 75 | with: 76 | name: ${{ matrix.platform.target }} 77 | path: "gmsv_accelerator_*.dll" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | /scripts/__pycache__ 4 | /scripts/bin/* 5 | /scripts/sigs.txt -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "accelerator" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "anyhow", 10 | "bzip2", 11 | "gmod", 12 | "rglua", 13 | "thiserror", 14 | "toml", 15 | "ureq", 16 | ] 17 | 18 | [[package]] 19 | name = "adler" 20 | version = "1.0.2" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 23 | 24 | [[package]] 25 | name = "anyhow" 26 | version = "1.0.79" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" 29 | 30 | [[package]] 31 | name = "base64" 32 | version = "0.21.6" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" 35 | 36 | [[package]] 37 | name = "bitflags" 38 | version = "1.3.2" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 41 | 42 | [[package]] 43 | name = "bzip2" 44 | version = "0.4.4" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" 47 | dependencies = [ 48 | "bzip2-sys", 49 | "libc", 50 | ] 51 | 52 | [[package]] 53 | name = "bzip2-sys" 54 | version = "0.1.11+1.0.8" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" 57 | dependencies = [ 58 | "cc", 59 | "libc", 60 | "pkg-config", 61 | ] 62 | 63 | [[package]] 64 | name = "cc" 65 | version = "1.0.83" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 68 | dependencies = [ 69 | "libc", 70 | ] 71 | 72 | [[package]] 73 | name = "cfg-if" 74 | version = "1.0.0" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 77 | 78 | [[package]] 79 | name = "cfg_table" 80 | version = "1.0.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "78518bef4e5cc70a69a0bd1905594f8033b2f7492c9d7c0f173208c0945c30a2" 83 | 84 | [[package]] 85 | name = "convert_case" 86 | version = "0.4.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 89 | 90 | [[package]] 91 | name = "crc32fast" 92 | version = "1.3.2" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 95 | dependencies = [ 96 | "cfg-if", 97 | ] 98 | 99 | [[package]] 100 | name = "cstr" 101 | version = "0.2.11" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "8aa998c33a6d3271e3678950a22134cd7dd27cef86dee1b611b5b14207d1d90b" 104 | dependencies = [ 105 | "proc-macro2", 106 | "quote", 107 | ] 108 | 109 | [[package]] 110 | name = "ctor" 111 | version = "0.2.6" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" 114 | dependencies = [ 115 | "quote", 116 | "syn 2.0.48", 117 | ] 118 | 119 | [[package]] 120 | name = "derive_more" 121 | version = "0.99.17" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" 124 | dependencies = [ 125 | "convert_case", 126 | "proc-macro2", 127 | "quote", 128 | "rustc_version", 129 | "syn 1.0.109", 130 | ] 131 | 132 | [[package]] 133 | name = "equivalent" 134 | version = "1.0.1" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 137 | 138 | [[package]] 139 | name = "flate2" 140 | version = "1.0.28" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" 143 | dependencies = [ 144 | "crc32fast", 145 | "miniz_oxide", 146 | ] 147 | 148 | [[package]] 149 | name = "fn_abi" 150 | version = "2.0.1" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "451b828bd3c5f19949222834f58b38c3670604dcaa5f2b7aec50c0cd58f34900" 153 | dependencies = [ 154 | "proc-macro2", 155 | "quote", 156 | "syn 1.0.109", 157 | "syn_squash", 158 | ] 159 | 160 | [[package]] 161 | name = "fn_has_this" 162 | version = "0.1.1" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "eb93938067213676967092012a53515e926de7c813afccd9b075ba0ec78dbba9" 165 | dependencies = [ 166 | "proc-macro2", 167 | "quote", 168 | "syn 1.0.109", 169 | "syn_squash", 170 | ] 171 | 172 | [[package]] 173 | name = "fn_type_alias" 174 | version = "0.1.0" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "809e807f01217f1f89959fbeebd10c6471b5ef3971fce1b02a70fb7212cc6c1f" 177 | dependencies = [ 178 | "proc-macro2", 179 | "quote", 180 | "syn 1.0.109", 181 | ] 182 | 183 | [[package]] 184 | name = "form_urlencoded" 185 | version = "1.2.1" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 188 | dependencies = [ 189 | "percent-encoding", 190 | ] 191 | 192 | [[package]] 193 | name = "generic-array" 194 | version = "0.14.7" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 197 | dependencies = [ 198 | "typenum", 199 | "version_check", 200 | ] 201 | 202 | [[package]] 203 | name = "getrandom" 204 | version = "0.2.12" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" 207 | dependencies = [ 208 | "cfg-if", 209 | "libc", 210 | "wasi", 211 | ] 212 | 213 | [[package]] 214 | name = "gmod" 215 | version = "17.0.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "fba999064c8149319a285441ab101b47ded87bfbd6f58c3127a3f289e4d728c2" 218 | dependencies = [ 219 | "cfg_table", 220 | "cstr", 221 | "ctor", 222 | "fn_abi", 223 | "fn_has_this", 224 | "fn_type_alias", 225 | "gmod-macros", 226 | "lazy_static", 227 | "libloading 0.8.1", 228 | "null_fn", 229 | "retour", 230 | "skidscan", 231 | ] 232 | 233 | [[package]] 234 | name = "gmod-macros" 235 | version = "2.0.1" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "4f379e64e2b37dc89becb8ac4e1a67211a1a8989b866a71d8365dc16459224a8" 238 | dependencies = [ 239 | "proc-macro2", 240 | "quote", 241 | "syn 1.0.109", 242 | ] 243 | 244 | [[package]] 245 | name = "hashbrown" 246 | version = "0.14.3" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 249 | 250 | [[package]] 251 | name = "idna" 252 | version = "0.5.0" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 255 | dependencies = [ 256 | "unicode-bidi", 257 | "unicode-normalization", 258 | ] 259 | 260 | [[package]] 261 | name = "indexmap" 262 | version = "2.1.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" 265 | dependencies = [ 266 | "equivalent", 267 | "hashbrown", 268 | ] 269 | 270 | [[package]] 271 | name = "lazy_static" 272 | version = "1.4.0" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 275 | 276 | [[package]] 277 | name = "libc" 278 | version = "0.2.152" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" 281 | 282 | [[package]] 283 | name = "libloading" 284 | version = "0.7.4" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 287 | dependencies = [ 288 | "cfg-if", 289 | "winapi", 290 | ] 291 | 292 | [[package]] 293 | name = "libloading" 294 | version = "0.8.1" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" 297 | dependencies = [ 298 | "cfg-if", 299 | "windows-sys", 300 | ] 301 | 302 | [[package]] 303 | name = "libudis86-sys" 304 | version = "0.2.1" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "139bbf9ddb1bfc90c1ac64dd2923d9c957cd433cee7315c018125d72ab08a6b0" 307 | dependencies = [ 308 | "cc", 309 | "libc", 310 | ] 311 | 312 | [[package]] 313 | name = "log" 314 | version = "0.4.20" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 317 | 318 | [[package]] 319 | name = "mach" 320 | version = "0.3.2" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" 323 | dependencies = [ 324 | "libc", 325 | ] 326 | 327 | [[package]] 328 | name = "memchr" 329 | version = "2.7.1" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" 332 | 333 | [[package]] 334 | name = "miniz_oxide" 335 | version = "0.7.1" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 338 | dependencies = [ 339 | "adler", 340 | ] 341 | 342 | [[package]] 343 | name = "mmap-fixed-fixed" 344 | version = "0.1.3" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "0681853891801e4763dc252e843672faf32bcfee27a0aa3b19733902af450acc" 347 | dependencies = [ 348 | "libc", 349 | "winapi", 350 | ] 351 | 352 | [[package]] 353 | name = "null_fn" 354 | version = "0.1.1" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "345919cfb52d0d8da7efc21aea56046ca96d9e3a8adfdbdb27ef1172829976c1" 357 | dependencies = [ 358 | "proc-macro2", 359 | "quote", 360 | "syn 1.0.109", 361 | ] 362 | 363 | [[package]] 364 | name = "once_cell" 365 | version = "1.19.0" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 368 | 369 | [[package]] 370 | name = "percent-encoding" 371 | version = "2.3.1" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 374 | 375 | [[package]] 376 | name = "pkg-config" 377 | version = "0.3.28" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" 380 | 381 | [[package]] 382 | name = "proc-macro-crate" 383 | version = "1.3.1" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" 386 | dependencies = [ 387 | "once_cell", 388 | "toml_edit 0.19.15", 389 | ] 390 | 391 | [[package]] 392 | name = "proc-macro2" 393 | version = "1.0.76" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" 396 | dependencies = [ 397 | "unicode-ident", 398 | ] 399 | 400 | [[package]] 401 | name = "quote" 402 | version = "1.0.35" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 405 | dependencies = [ 406 | "proc-macro2", 407 | ] 408 | 409 | [[package]] 410 | name = "region" 411 | version = "3.0.0" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" 414 | dependencies = [ 415 | "bitflags", 416 | "libc", 417 | "mach", 418 | "winapi", 419 | ] 420 | 421 | [[package]] 422 | name = "retour" 423 | version = "0.3.1" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "a9af44d40e2400b44d491bfaf8eae111b09f23ac4de6e92728e79d93e699c527" 426 | dependencies = [ 427 | "cfg-if", 428 | "generic-array", 429 | "libc", 430 | "libudis86-sys", 431 | "mmap-fixed-fixed", 432 | "once_cell", 433 | "region", 434 | "slice-pool2", 435 | ] 436 | 437 | [[package]] 438 | name = "rglua" 439 | version = "2.1.0" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "c1ef00fee6e71eaafdc0ff0844f93348e4d6615d9e6c68bb047872a0803e49bc" 442 | dependencies = [ 443 | "derive_more", 444 | "libloading 0.7.4", 445 | "once_cell", 446 | "rglua-macros", 447 | "thiserror", 448 | "vtables", 449 | "vtables_derive", 450 | ] 451 | 452 | [[package]] 453 | name = "rglua-macros" 454 | version = "0.2.0" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "74f3c746ea354577a62bb8d2ad860ced2fa9c35f7a99a5a64f79059a7f11165e" 457 | dependencies = [ 458 | "proc-macro2", 459 | "quote", 460 | "syn 1.0.109", 461 | ] 462 | 463 | [[package]] 464 | name = "ring" 465 | version = "0.17.7" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" 468 | dependencies = [ 469 | "cc", 470 | "getrandom", 471 | "libc", 472 | "spin", 473 | "untrusted", 474 | "windows-sys", 475 | ] 476 | 477 | [[package]] 478 | name = "rustc_version" 479 | version = "0.4.0" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 482 | dependencies = [ 483 | "semver", 484 | ] 485 | 486 | [[package]] 487 | name = "rustls" 488 | version = "0.21.10" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" 491 | dependencies = [ 492 | "log", 493 | "ring", 494 | "rustls-webpki", 495 | "sct", 496 | ] 497 | 498 | [[package]] 499 | name = "rustls-webpki" 500 | version = "0.101.7" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" 503 | dependencies = [ 504 | "ring", 505 | "untrusted", 506 | ] 507 | 508 | [[package]] 509 | name = "sct" 510 | version = "0.7.1" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" 513 | dependencies = [ 514 | "ring", 515 | "untrusted", 516 | ] 517 | 518 | [[package]] 519 | name = "semver" 520 | version = "1.0.21" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" 523 | 524 | [[package]] 525 | name = "serde" 526 | version = "1.0.195" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" 529 | dependencies = [ 530 | "serde_derive", 531 | ] 532 | 533 | [[package]] 534 | name = "serde_derive" 535 | version = "1.0.195" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" 538 | dependencies = [ 539 | "proc-macro2", 540 | "quote", 541 | "syn 2.0.48", 542 | ] 543 | 544 | [[package]] 545 | name = "serde_spanned" 546 | version = "0.6.5" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" 549 | dependencies = [ 550 | "serde", 551 | ] 552 | 553 | [[package]] 554 | name = "skidscan" 555 | version = "2.0.1" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "d3c2ec2f6baba2d1d58590fee1627bc6899fdc0ccb9006521d5f87ac78e375b9" 558 | dependencies = [ 559 | "libc", 560 | "skidscan-macros", 561 | "winapi", 562 | ] 563 | 564 | [[package]] 565 | name = "skidscan-macros" 566 | version = "0.1.2" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "881ef2150f0e4e2a855bb661a3ecd621ab1b6aa07b34aef941d1bd37b4267e8d" 569 | dependencies = [ 570 | "proc-macro-crate", 571 | "syn 1.0.109", 572 | ] 573 | 574 | [[package]] 575 | name = "slice-pool2" 576 | version = "0.4.3" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "7a3d689654af89bdfeba29a914ab6ac0236d382eb3b764f7454dde052f2821f8" 579 | 580 | [[package]] 581 | name = "spin" 582 | version = "0.9.8" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 585 | 586 | [[package]] 587 | name = "syn" 588 | version = "1.0.109" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 591 | dependencies = [ 592 | "proc-macro2", 593 | "quote", 594 | "unicode-ident", 595 | ] 596 | 597 | [[package]] 598 | name = "syn" 599 | version = "2.0.48" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" 602 | dependencies = [ 603 | "proc-macro2", 604 | "quote", 605 | "unicode-ident", 606 | ] 607 | 608 | [[package]] 609 | name = "syn_squash" 610 | version = "0.1.0" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "134b985708d02b2569ab2b9e27c8758ca4baaaf725341a572d59bc2d174b9bb5" 613 | 614 | [[package]] 615 | name = "thiserror" 616 | version = "1.0.56" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" 619 | dependencies = [ 620 | "thiserror-impl", 621 | ] 622 | 623 | [[package]] 624 | name = "thiserror-impl" 625 | version = "1.0.56" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" 628 | dependencies = [ 629 | "proc-macro2", 630 | "quote", 631 | "syn 2.0.48", 632 | ] 633 | 634 | [[package]] 635 | name = "tinyvec" 636 | version = "1.6.0" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 639 | dependencies = [ 640 | "tinyvec_macros", 641 | ] 642 | 643 | [[package]] 644 | name = "tinyvec_macros" 645 | version = "0.1.1" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 648 | 649 | [[package]] 650 | name = "toml" 651 | version = "0.8.8" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" 654 | dependencies = [ 655 | "serde", 656 | "serde_spanned", 657 | "toml_datetime", 658 | "toml_edit 0.21.0", 659 | ] 660 | 661 | [[package]] 662 | name = "toml_datetime" 663 | version = "0.6.5" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" 666 | dependencies = [ 667 | "serde", 668 | ] 669 | 670 | [[package]] 671 | name = "toml_edit" 672 | version = "0.19.15" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" 675 | dependencies = [ 676 | "indexmap", 677 | "toml_datetime", 678 | "winnow", 679 | ] 680 | 681 | [[package]] 682 | name = "toml_edit" 683 | version = "0.21.0" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" 686 | dependencies = [ 687 | "indexmap", 688 | "serde", 689 | "serde_spanned", 690 | "toml_datetime", 691 | "winnow", 692 | ] 693 | 694 | [[package]] 695 | name = "typenum" 696 | version = "1.17.0" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 699 | 700 | [[package]] 701 | name = "unicode-bidi" 702 | version = "0.3.14" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" 705 | 706 | [[package]] 707 | name = "unicode-ident" 708 | version = "1.0.12" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 711 | 712 | [[package]] 713 | name = "unicode-normalization" 714 | version = "0.1.22" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 717 | dependencies = [ 718 | "tinyvec", 719 | ] 720 | 721 | [[package]] 722 | name = "untrusted" 723 | version = "0.9.0" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 726 | 727 | [[package]] 728 | name = "ureq" 729 | version = "2.9.1" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" 732 | dependencies = [ 733 | "base64", 734 | "flate2", 735 | "log", 736 | "once_cell", 737 | "rustls", 738 | "rustls-webpki", 739 | "url", 740 | "webpki-roots", 741 | ] 742 | 743 | [[package]] 744 | name = "url" 745 | version = "2.5.0" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 748 | dependencies = [ 749 | "form_urlencoded", 750 | "idna", 751 | "percent-encoding", 752 | ] 753 | 754 | [[package]] 755 | name = "version_check" 756 | version = "0.9.4" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 759 | 760 | [[package]] 761 | name = "vtables" 762 | version = "0.1.0" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "f5588453c4f7af8bb03be89540d7bb204aa8e0e56f2b010e547cc73cba4cd5f9" 765 | 766 | [[package]] 767 | name = "vtables_derive" 768 | version = "0.1.0" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "a048e7ec096bec258f2d32ff336217de2ee3947f0af04777a972c2c264659b44" 771 | dependencies = [ 772 | "proc-macro2", 773 | "quote", 774 | "syn 1.0.109", 775 | ] 776 | 777 | [[package]] 778 | name = "wasi" 779 | version = "0.11.0+wasi-snapshot-preview1" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 782 | 783 | [[package]] 784 | name = "webpki-roots" 785 | version = "0.25.3" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" 788 | 789 | [[package]] 790 | name = "winapi" 791 | version = "0.3.9" 792 | source = "registry+https://github.com/rust-lang/crates.io-index" 793 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 794 | dependencies = [ 795 | "winapi-i686-pc-windows-gnu", 796 | "winapi-x86_64-pc-windows-gnu", 797 | ] 798 | 799 | [[package]] 800 | name = "winapi-i686-pc-windows-gnu" 801 | version = "0.4.0" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 804 | 805 | [[package]] 806 | name = "winapi-x86_64-pc-windows-gnu" 807 | version = "0.4.0" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 810 | 811 | [[package]] 812 | name = "windows-sys" 813 | version = "0.48.0" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 816 | dependencies = [ 817 | "windows-targets", 818 | ] 819 | 820 | [[package]] 821 | name = "windows-targets" 822 | version = "0.48.5" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 825 | dependencies = [ 826 | "windows_aarch64_gnullvm", 827 | "windows_aarch64_msvc", 828 | "windows_i686_gnu", 829 | "windows_i686_msvc", 830 | "windows_x86_64_gnu", 831 | "windows_x86_64_gnullvm", 832 | "windows_x86_64_msvc", 833 | ] 834 | 835 | [[package]] 836 | name = "windows_aarch64_gnullvm" 837 | version = "0.48.5" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 840 | 841 | [[package]] 842 | name = "windows_aarch64_msvc" 843 | version = "0.48.5" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 846 | 847 | [[package]] 848 | name = "windows_i686_gnu" 849 | version = "0.48.5" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 852 | 853 | [[package]] 854 | name = "windows_i686_msvc" 855 | version = "0.48.5" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 858 | 859 | [[package]] 860 | name = "windows_x86_64_gnu" 861 | version = "0.48.5" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 864 | 865 | [[package]] 866 | name = "windows_x86_64_gnullvm" 867 | version = "0.48.5" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 870 | 871 | [[package]] 872 | name = "windows_x86_64_msvc" 873 | version = "0.48.5" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 876 | 877 | [[package]] 878 | name = "winnow" 879 | version = "0.5.33" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" 882 | dependencies = [ 883 | "memchr", 884 | ] 885 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "accelerator" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | anyhow = "1.0.71" 12 | bzip2 = "0.4.4" 13 | gmod = { version = "17", features = [ "gmcl" ] } 14 | rglua = "2.1.0" 15 | thiserror = "1.0" 16 | toml = "0.8" 17 | ureq = "2.9.1" 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

3 | ~kusabana/accelerator 4 |

5 | multithreads source engine http downloads 6 |
7 | 8 | ## Installation 9 | 1. download the latest artifact or compile it yourself 10 | 2. move the binary module (.dll file) to `garrysmod/lua/bin` 11 | 3. add `require'accelerator'` to `garrysmod/lua/menu/menu.lua` in order to load the module on launch 12 | ## Building 13 | ```sh 14 | git clone https://github.com/kusabana/accelerator 15 | cd accelerator 16 | cargo +nightly build --release --target= 17 | ``` 18 | 19 | target triples: 20 | ```sh 21 | x86_64-unknown-linux-gnu # linux 64-bit 22 | x86_64-pc-windows-msvc # windows 64-bit 23 | i686-unknown-linux-gnu # linux 32-bit 24 | i686-pc-windows-msvc # windows 32-bit 25 | ``` 26 | ## Todo 27 | ``` 28 | - check hash instead of giving up when file exists 29 | ``` -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" -------------------------------------------------------------------------------- /scripts/find_funcs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import binaryninja 3 | from glob import glob 4 | import re 5 | from multiprocessing import Pool, cpu_count, set_start_method 6 | 7 | 8 | # this doesn't handle types correctly, but it works 9 | # for what i need it to so problem for later. 10 | def hlil_to_expression(hlil_instruction): 11 | if isinstance(hlil_instruction, binaryninja.HighLevelILInstruction): 12 | operands = [] 13 | for operand in hlil_instruction.operands: 14 | if isinstance(operand, list): 15 | operands.append( 16 | "(" 17 | + ", ".join(hlil_to_expression(inner) for inner in operand) 18 | + ")" 19 | ) 20 | else: 21 | operands.append(hlil_to_expression(operand)) 22 | expr = "{}({})".format(hlil_instruction.operation.name, ", ".join(operands)) 23 | else: 24 | expr = str(hlil_instruction) 25 | return expr 26 | 27 | 28 | # ?? => capture wildcard 29 | # .. => non-captured wildcard 30 | # (supports multiline expressions) 31 | def expression_extract_wildcard(hlil, expressions): 32 | for expression in expressions: 33 | pattern = expression.replace("(", "\\(").replace(")", "\\)") 34 | pattern = pattern.replace("..", "\\w+").replace("??", "(\\w+)") 35 | match = re.search(pattern, hlil) 36 | if match: 37 | return (expression, match.group(1)) 38 | return (None, None) 39 | 40 | 41 | def extract_wildcards(hlil, expressions): 42 | values = [ 43 | (name, expression_extract_wildcard(hlil, expr)) 44 | for name, expr in expressions.items() 45 | ] 46 | values = [ 47 | (name, (pattern, int(val))) 48 | for name, (pattern, val) in values 49 | if val is not None 50 | ] 51 | return values 52 | 53 | 54 | markers = { 55 | "CheckUpdatingSteamResources": { 56 | "CL_GetDownloadQueueSize": ( 57 | "HLIL_IF(HLIL_CMP_E(HLIL_CALL(HLIL_CONST_PTR(??), ()), HLIL_CONST(0)))", # universal 58 | ), 59 | "CL_DownloadUpdate": ( 60 | "HLIL_IF(HLIL_AND(HLIL_CMP_NE(HLIL_VAR(..), HLIL_CONST(0)), HLIL_CMP_E(HLIL_CALL(HLIL_CONST_PTR(??), ()), HLIL_CONST(0)))", # linux 61 | "HLIL_ASSIGN(HLIL_VAR(..), HLIL_CALL(HLIL_CONST_PTR(??), ()))", # windows 62 | ), 63 | }, 64 | "Multiple download search paths?": {}, 65 | } 66 | 67 | 68 | def spawn(binary): 69 | binaryninja.set_worker_thread_count(1) 70 | # print(binary) 71 | with binaryninja.open_view(binary) as bv: 72 | for marker, expressions in markers.items(): 73 | matches = list(bv.find_all_text(bv.start, bv.end, marker)) 74 | text = matches[0] 75 | func = bv.get_functions_containing(text[0])[0] 76 | print("~ %s:%s => %s (0x%x)" % (binary, marker, func, func.start)) 77 | 78 | if expressions: 79 | instructions = func.hlil.instructions 80 | hlil = "\n".join([hlil_to_expression(instr) for instr in instructions]) 81 | values = extract_wildcards(hlil, expressions) 82 | 83 | for name, (pattern, addr) in values: 84 | print("~ %s:%s => 0x%x" % (binary, name, addr)) 85 | func = bv.get_function_at(addr) 86 | 87 | 88 | if __name__ == "__main__": 89 | print( 90 | "~ NOTE: this script takes a while to run due to binaryninja's analysis process." 91 | ) 92 | set_start_method("spawn") 93 | processes = cpu_count() - 1 if cpu_count() > 1 else 1 94 | pool = Pool(processes=processes) 95 | results = [] 96 | for binary in glob("./bin/*.so") + glob("./bin/*.dll"): 97 | results.append(pool.apply_async(spawn, (binary,))) 98 | 99 | for result in results: 100 | result.get() 101 | pool.close() 102 | -------------------------------------------------------------------------------- /src/detour.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_char, c_void, CStr, OsString}; 2 | use std::fs::File; 3 | use std::io::{copy, Read}; 4 | use std::path::{Path, PathBuf}; 5 | use std::str::FromStr; 6 | use std::time::Instant; 7 | 8 | use std::sync::Mutex; 9 | use std::thread::{self, JoinHandle}; 10 | 11 | use anyhow::Result; 12 | use gmod::detour::GenericDetour; 13 | use rglua::prelude::*; 14 | 15 | use crate::error::AcceleratorError; 16 | use crate::log; 17 | 18 | static VALVE_USER_AGENT: &str = "Half-Life 2"; 19 | static VALVE_REFERER: &str = "hl2://accelerator"; 20 | 21 | static mut GET_DOWNLOAD_QUEUE_SIZE_DETOUR: Option> = None; 22 | static mut QUEUE_DOWNLOAD_DETOUR: Option> = None; 23 | static mut DOWNLOAD_UPDATE_DETOUR: Option> = None; 24 | 25 | struct DownloadState { 26 | lua: LuaState, 27 | handles: Vec>>, 28 | timestamp: Option, 29 | } 30 | 31 | impl DownloadState { 32 | pub const fn new(state: LuaState) -> Self { 33 | Self { 34 | lua: state, 35 | handles: Vec::new(), 36 | timestamp: None, 37 | } 38 | } 39 | } 40 | 41 | static mut STATE: Option> = None; 42 | 43 | #[gmod::type_alias(GetDownloadQueueSize)] 44 | unsafe extern "cdecl" fn get_download_queue_size() -> i64 { 45 | let binding = STATE.as_ref().unwrap(); 46 | let state = &mut binding.lock().unwrap(); 47 | let res: i64 = GET_DOWNLOAD_QUEUE_SIZE_DETOUR.as_ref().unwrap().call(); 48 | 49 | res + >::try_into(state.handles.len()).unwrap() 50 | } 51 | 52 | #[gmod::type_alias(QueueDownload)] 53 | unsafe extern "cdecl" fn queue_download( 54 | this: *mut c_void, 55 | c_url: *const c_char, 56 | unk0: i32, 57 | c_path: *const c_char, 58 | as_http: bool, 59 | compressed: bool, 60 | unk3: i32, 61 | ) { 62 | let binding = STATE.as_ref().unwrap(); 63 | let state = &mut binding.lock().unwrap(); 64 | 65 | if state.timestamp.is_none() { 66 | state.timestamp = Some(Instant::now()); 67 | } 68 | 69 | let mut url = CStr::from_ptr(c_url) 70 | .to_str() 71 | .unwrap_or_default() 72 | .to_string(); 73 | 74 | if url.ends_with('/') { 75 | url.pop(); 76 | } 77 | 78 | // dispatch to netchan if no url or as_http is false 79 | if url.is_empty() || !as_http { 80 | log!( 81 | state.lua, 82 | "calling original... URL.IS_EMPTY={:?} !AS_HTTP={:?}", 83 | url.is_empty(), 84 | !as_http 85 | ); 86 | 87 | return QUEUE_DOWNLOAD_DETOUR 88 | .as_ref() 89 | .unwrap() 90 | .call(this, c_url, unk0, c_path, as_http, compressed, unk3); 91 | } 92 | 93 | let game_path = CStr::from_ptr(c_path) 94 | .to_str() 95 | .unwrap_or_default() 96 | .replace('\\', "/"); 97 | 98 | let mut path = PathBuf::from_str(&game_path).unwrap(); 99 | if compressed { 100 | let mut os: OsString = path.into(); 101 | os.push(".bz2"); 102 | path = os.into(); 103 | } 104 | 105 | log!(state.lua, "dispatching `{}`", path.display()); 106 | let handle: JoinHandle> = thread::spawn(move || { 107 | let url = format!("{}/{}", url, path.to_str().unwrap_or_default()); 108 | let mut content = ureq::get(&url) 109 | .set("User-Agent", VALVE_USER_AGENT) 110 | .set("Referer", VALVE_REFERER) 111 | .call()? 112 | .into_reader(); 113 | 114 | let file_path = Path::new("garrysmod/download").join(path.with_extension("")); 115 | std::fs::create_dir_all(file_path.parent().unwrap_or_else(|| return Path::new("")))?; 116 | let mut dest = File::create_new(file_path)?; 117 | 118 | let mut reader: Box = if compressed { 119 | use bzip2::read::BzDecoder; 120 | Box::new(BzDecoder::new(&mut content)) 121 | } else { 122 | Box::new(content) 123 | }; 124 | 125 | copy(&mut reader, &mut dest)?; 126 | Ok(path.to_str().unwrap().to_string()) 127 | }); 128 | 129 | state.handles.push(handle); 130 | } 131 | 132 | #[gmod::type_alias(DownloadUpdate)] 133 | unsafe extern "cdecl" fn download_update() -> bool { 134 | let binding = STATE.as_ref().unwrap(); 135 | let mut state = binding.lock().unwrap(); 136 | 137 | if !state.handles.is_empty() { 138 | while let Some(handle) = state.handles.pop() { 139 | let file = handle.join().unwrap(); 140 | 141 | match file { 142 | Ok(file) => log!(state.lua, "download finished: `{}`", file), 143 | Err(e) => log!(state.lua, "download failed: {}", e), 144 | } 145 | } 146 | 147 | log!(state.lua, "finished!"); 148 | if let Some(timestamp) = state.timestamp { 149 | log!(state.lua, "elapsed: `{:?}`", timestamp.elapsed()); 150 | state.timestamp = None; 151 | drop(state); 152 | } 153 | } 154 | 155 | return DOWNLOAD_UPDATE_DETOUR.as_ref().unwrap().call(); 156 | } 157 | 158 | pub unsafe fn apply(lua: LuaState) -> Result<()> { 159 | log!(lua, "applying detours"); 160 | 161 | let state = DownloadState::new(lua); 162 | 163 | let (_lib, path) = if cfg!(all(target_os = "linux", target_pointer_width = "64")) { 164 | gmod::open_library!("engine_client")? 165 | } else { 166 | gmod::open_library!("engine")? 167 | }; 168 | 169 | macro_rules! detour_fn { 170 | ($func:ident, $type_alias:ty, ($library:ident, $path:ident) -> $pattern:tt) => { 171 | let $func = { 172 | let addr = gmod::find_gmod_signature!(($library, $path) -> $pattern) 173 | .ok_or(AcceleratorError::SigNotFound(stringify!($type_alias).to_string()))?; 174 | 175 | let detour = GenericDetour::new::<$type_alias>(addr, $func)?; 176 | detour.enable()?; 177 | detour 178 | }; 179 | } 180 | } 181 | 182 | detour_fn!(get_download_queue_size, GetDownloadQueueSize, (_lib, path) -> { 183 | win64_x86_64: [@SIG = "48 83 ec 28 48 8b 0d ?? ?? ?? ?? 48 8b 01 ff 50 58 48 8b c8 48 8b 10 ff 52 10"], 184 | win32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself 185 | 186 | linux64_x86_64: [@SIG = "55 48 89 e5 53 48 83 ec 08 48 8b 05 ?? ?? ?? ?? 8b 1d"], 187 | linux32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself 188 | 189 | win32: [@SIG = "8b 0d ?? ?? ?? ?? 56 8b 01 ff 50 2c 8b 35 ?? ?? ?? ?? 8b c8 8b 10 ff 52 08 03 c6 5e c3"], // untested 190 | linux32: [@SIG = "55 89 e5 53 83 ec 14 8b 15 60 ?? ?? ?? 8b 1d"], 191 | }); 192 | 193 | detour_fn!(download_update, DownloadUpdate, (_lib, path) -> { 194 | win64_x86_64: [@SIG = "48 83 ec 28 48 8b 0d ?? ?? ?? ?? 48 8b 01 ff 50 58 48 8b c8 48 8b 10 ff 52 08"], 195 | win32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself 196 | 197 | linux64_x86_64: [@SIG = "55 48 8d 3d ?? ?? ?? ?? 48 89 e5 5d e9 9f ff ff ff 90 90 90"], 198 | linux32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself 199 | 200 | win32: [@SIG = "55 8b ec 5d e9 87 05 00 00"], // untested 201 | linux32: [@SIG = "55 89 e5 83 ec 18 c7 04 24 ?? ?? ?? ?? e8 9e ff ff ff c9 c3"], 202 | }); 203 | 204 | detour_fn!(queue_download, QueueDownload, (_lib, path) -> { 205 | win64_x86_64: [@SIG = "40 53 55 56 57 41 54 41 55 41 56 41 57 48 81 ec 78 02 00 00"], 206 | win32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself 207 | 208 | linux64_x86_64: [@SIG = "55 48 89 e5 41 57 49 89 cf 41 56 41 55 45 89 cd"], 209 | linux32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself 210 | 211 | win32: [@SIG = "55 8b ec 51 83 3d ?? ?? ?? ?? 01 0f 8e 8f 01 00 00 8b 0d ?? ?? ?? ?? 53 8b 01 ff 50 2c 8b 5d"], // untested 212 | linux32: [@SIG = "55 89 e5 57 56 53 81 ec 5c 02 00 00 8b 45 0c 8b 5d 08 8b 7d 1c"], 213 | }); 214 | 215 | GET_DOWNLOAD_QUEUE_SIZE_DETOUR = Some(get_download_queue_size); 216 | QUEUE_DOWNLOAD_DETOUR = Some(queue_download); 217 | DOWNLOAD_UPDATE_DETOUR = Some(download_update); 218 | 219 | STATE = Some(Mutex::new(state)); 220 | 221 | Ok(()) 222 | } 223 | 224 | pub unsafe fn revert(lua: LuaState) { 225 | log!(lua, "reverting detours"); 226 | 227 | GET_DOWNLOAD_QUEUE_SIZE_DETOUR.take(); 228 | QUEUE_DOWNLOAD_DETOUR.take(); 229 | DOWNLOAD_UPDATE_DETOUR.take(); 230 | 231 | STATE.take(); 232 | } 233 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | pub enum AcceleratorError { 5 | #[error("signature not found ({0})")] 6 | SigNotFound(String), 7 | } 8 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use rglua::prelude::*; 3 | 4 | mod detour; 5 | mod error; 6 | 7 | #[macro_export] 8 | macro_rules! log { 9 | ($state:expr, $fmt:expr, $( $arg:expr ),*) => { 10 | printgm!($state, concat!("accelerator: ", $fmt), $( $arg ),*) 11 | }; 12 | ($state:expr, $fmt:expr) => { 13 | printgm!($state, concat!("accelerator: ", $fmt)) 14 | }; 15 | } 16 | 17 | #[gmod_open] 18 | fn open(l: LuaState) -> Result { 19 | log!(l, "loading..."); 20 | 21 | unsafe { 22 | detour::apply(l)?; 23 | } 24 | 25 | Ok(0) 26 | } 27 | 28 | #[gmod_close] 29 | fn close(l: LuaState) -> Result { 30 | log!(l, "unloading..."); 31 | 32 | unsafe { 33 | detour::revert(l); 34 | } 35 | 36 | Ok(0) 37 | } 38 | --------------------------------------------------------------------------------