From 63962c95cce6c01f2e9bb2c3435398860e12e87f Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sun, 7 May 2023 21:36:20 +0200 Subject: [PATCH] add Rust ScrapHacks prototype and network sniffer/parser --- tools/remaster/scrap_net/.gitignore | 2 + tools/remaster/scrap_net/Cargo.lock | 1015 +++++++++++ tools/remaster/scrap_net/Cargo.toml | 28 + tools/remaster/scrap_net/get_app.py | 22 + tools/remaster/scrap_net/src/hex_ii.rs | 93 + tools/remaster/scrap_net/src/main.rs | 640 +++++++ tools/remaster/scrap_net/src/parser.rs | 151 ++ .../remaster/scraphacks_rs/.cargo/config.toml | 2 + tools/remaster/scraphacks_rs/Cargo.lock | 1624 +++++++++++++++++ tools/remaster/scraphacks_rs/Cargo.toml | 45 + tools/remaster/scraphacks_rs/Pipfile | 11 + tools/remaster/scraphacks_rs/Save0.sav.json | 242 +++ tools/remaster/scraphacks_rs/build.rs | 3 + tools/remaster/scraphacks_rs/build.sh | 4 + tools/remaster/scraphacks_rs/notes.md | 16 + tools/remaster/scraphacks_rs/run.py | 34 + tools/remaster/scraphacks_rs/scrap.hpp | 16 + tools/remaster/scraphacks_rs/src/config.rs | 7 + tools/remaster/scraphacks_rs/src/discord.rs | 94 + tools/remaster/scraphacks_rs/src/lib.rs | 96 + tools/remaster/scraphacks_rs/src/lua.rs | 204 +++ tools/remaster/scraphacks_rs/src/mem.rs | 94 + tools/remaster/scraphacks_rs/src/parser.rs | 177 ++ tools/remaster/scraphacks_rs/src/scrap.rs | 381 ++++ .../scraphacks_rs/target/.rustc_info.json | 1 + .../scraphacks_rs/target/CACHEDIR.TAG | 3 + .../target/i686-pc-windows-msvc/CACHEDIR.TAG | 3 + 27 files changed, 5008 insertions(+) create mode 100644 tools/remaster/scrap_net/.gitignore create mode 100644 tools/remaster/scrap_net/Cargo.lock create mode 100644 tools/remaster/scrap_net/Cargo.toml create mode 100644 tools/remaster/scrap_net/get_app.py create mode 100644 tools/remaster/scrap_net/src/hex_ii.rs create mode 100644 tools/remaster/scrap_net/src/main.rs create mode 100644 tools/remaster/scrap_net/src/parser.rs create mode 100644 tools/remaster/scraphacks_rs/.cargo/config.toml create mode 100644 tools/remaster/scraphacks_rs/Cargo.lock create mode 100644 tools/remaster/scraphacks_rs/Cargo.toml create mode 100644 tools/remaster/scraphacks_rs/Pipfile create mode 100644 tools/remaster/scraphacks_rs/Save0.sav.json create mode 100644 tools/remaster/scraphacks_rs/build.rs create mode 100644 tools/remaster/scraphacks_rs/build.sh create mode 100644 tools/remaster/scraphacks_rs/notes.md create mode 100644 tools/remaster/scraphacks_rs/run.py create mode 100644 tools/remaster/scraphacks_rs/scrap.hpp create mode 100644 tools/remaster/scraphacks_rs/src/config.rs create mode 100644 tools/remaster/scraphacks_rs/src/discord.rs create mode 100644 tools/remaster/scraphacks_rs/src/lib.rs create mode 100644 tools/remaster/scraphacks_rs/src/lua.rs create mode 100644 tools/remaster/scraphacks_rs/src/mem.rs create mode 100644 tools/remaster/scraphacks_rs/src/parser.rs create mode 100644 tools/remaster/scraphacks_rs/src/scrap.rs create mode 100644 tools/remaster/scraphacks_rs/target/.rustc_info.json create mode 100644 tools/remaster/scraphacks_rs/target/CACHEDIR.TAG create mode 100644 tools/remaster/scraphacks_rs/target/i686-pc-windows-msvc/CACHEDIR.TAG diff --git a/tools/remaster/scrap_net/.gitignore b/tools/remaster/scrap_net/.gitignore new file mode 100644 index 0000000..9623fa0 --- /dev/null +++ b/tools/remaster/scrap_net/.gitignore @@ -0,0 +1,2 @@ +/target +/.history \ No newline at end of file diff --git a/tools/remaster/scrap_net/Cargo.lock b/tools/remaster/scrap_net/Cargo.lock new file mode 100644 index 0000000..11f08a4 --- /dev/null +++ b/tools/remaster/scrap_net/Cargo.lock @@ -0,0 +1,1015 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" + +[[package]] +name = "array-init" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb6d71005dc22a708c7496eee5c8dc0300ee47355de6256c3b35b12b5fef596" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "binrw" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "272caaf6e0bfb7d508c0606e541e2c68f85c0d6352b62d0b299924eed59fe384" +dependencies = [ + "array-init", + "binrw_derive", + "bytemuck", +] + +[[package]] +name = "binrw_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4b28c1e534d96213c8966bb9240095757aa0909128985f97d16afd2e7257a8" +dependencies = [ + "either", + "owo-colors", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-padding" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a90ec2df9600c28a01c56c4784c9207a96d2451833aeceb8cc97e4c9548bb78" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bytemuck" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha20" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9484ccdc4cb8e7b117cbd0eb150c7c0f04464854e4679aeb50ef03b32d003" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca689d7434ce44517a12a89456b2be4d1ea1cafcd8f581978c03d45f5a5c12a7" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "console" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "unicode-width", + "winapi", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags", + "crossterm_winapi", + "futures-core", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dialoguer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1" +dependencies = [ + "console", + "tempfile", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "futures" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" + +[[package]] +name = "futures-executor" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" + +[[package]] +name = "futures-macro" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" + +[[package]] +name = "futures-task" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" + +[[package]] +name = "futures-util" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "os_str_bytes" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rhexdump" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e9af64574935e39f24d1c0313a997c8b880ca0e087c888bc6af8af31579847" + +[[package]] +name = "rustyline-async" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e1a02d2c727fac4c73a019de82183d990af0e13d6bed2e3a6f37a525ff591d" +dependencies = [ + "crossterm", + "futures", + "pin-project", + "thingbuf", + "thiserror", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scrap_net" +version = "0.1.0" +dependencies = [ + "anyhow", + "binrw", + "chacha20", + "clap", + "dialoguer", + "futures-util", + "hex", + "itertools", + "lazy_static", + "modular-bitfield", + "poly1305", + "rand", + "rhexdump", + "rustyline-async", + "tokio", +] + +[[package]] +name = "signal-hook" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "thingbuf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee2d290fe0db0225026350bc1f0bd02b2daad43b09b56780e29e549effcd54a" +dependencies = [ + "parking_lot", + "pin-project", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" + +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "universal-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/tools/remaster/scrap_net/Cargo.toml b/tools/remaster/scrap_net/Cargo.toml new file mode 100644 index 0000000..0c17ba6 --- /dev/null +++ b/tools/remaster/scrap_net/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "scrap_net" +version = "0.1.0" +edition = "2021" +authors = ["Daniel Seiller "] +description = "Scrapland Remastered network sniffer, proxy (and soon hopefully parser)" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +chacha20 = { version = "0.9", features = ["std"] } +poly1305 = { version = "0.8", features = ["std"] } +rhexdump = "0.1" +tokio = { version = "1.21", features = ["full"] } +clap = {version = "4.0", features = ["derive"]} +rand = "0.8" +dialoguer = "0.10" +binrw = "0.11" +modular-bitfield = "0.11" +hex = "0.4" +lazy_static = "1.4.0" +rustyline-async = "0.3" +futures-util = "0.3.24" +itertools = "0.10.5" +anyhow = "1.0.68" + +[profile.release] +lto="fat" +opt-level = 3 diff --git a/tools/remaster/scrap_net/get_app.py b/tools/remaster/scrap_net/get_app.py new file mode 100644 index 0000000..2c0cada --- /dev/null +++ b/tools/remaster/scrap_net/get_app.py @@ -0,0 +1,22 @@ +from distutils.command.install_data import install_data +import winreg as reg +import vdf +from pathlib import Path +import pefile +app_id="897610" +try: + key = reg.OpenKey(reg.HKEY_LOCAL_MACHINE,"SOFTWARE\\Valve\\Steam") +except FileNotFoundError: + key = reg.OpenKey(reg.HKEY_LOCAL_MACHINE,"SOFTWARE\\Wow6432Node\\Valve\\Steam") +path=Path(reg.QueryValueEx(key,"InstallPath")[0]) +libraryfolders=vdf.load((path/"steamapps"/"libraryfolders.vdf").open("r"))['libraryfolders'] +for folder in libraryfolders.values(): + path=Path(folder['path']) + if app_id in folder['apps']: + install_dir = vdf.load((path/"steamapps"/f"appmanifest_{app_id}.acf").open("r"))['AppState']['installdir'] + install_dir=path/"steamapps"/"common"/install_dir + for file in install_dir.glob("**/*.exe"): + pe = pefile.PE(file, fast_load=True) + entry = pe.OPTIONAL_HEADER.AddressOfEntryPoint + if pe.get_dword_at_rva(entry) == 0xE8: + print(file) \ No newline at end of file diff --git a/tools/remaster/scrap_net/src/hex_ii.rs b/tools/remaster/scrap_net/src/hex_ii.rs new file mode 100644 index 0000000..70ddc47 --- /dev/null +++ b/tools/remaster/scrap_net/src/hex_ii.rs @@ -0,0 +1,93 @@ +use itertools::Itertools; +use std::fmt::Display; +use std::ops::{Deref, DerefMut}; + +#[derive(Debug, PartialEq, Eq)] +enum HexII { + Ascii(char), + Byte(u8), + Null, + Full, + Eof, +} + +impl From<&u8> for HexII { + fn from(v: &u8) -> Self { + match v { + 0x00 => Self::Null, + 0xFF => Self::Full, + c if c.is_ascii_graphic() => Self::Ascii(*c as char), + v => Self::Byte(*v), + } + } +} + +impl Display for HexII { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + HexII::Ascii(v) => write!(f, ".{}", v)?, + HexII::Byte(v) => write!(f, "{:02x}", v)?, + HexII::Null => write!(f, " ")?, + HexII::Full => write!(f, "##")?, + HexII::Eof => write!(f, " ]")?, + } + Ok(()) + } +} + +struct HexIILine(Vec); + +impl Display for HexIILine { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, v) in self.0.iter().enumerate() { + if i != 0 { + write!(f, " ")?; + } + write!(f, "{}", v)?; + } + Ok(()) + } +} + +impl From<&[u8]> for HexIILine { + fn from(l: &[u8]) -> Self { + Self(l.iter().map(HexII::from).collect()) + } +} + +impl Deref for HexIILine { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for HexIILine { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +pub fn hex_ii_dump>(data: T, base_offset: usize, total: usize) { + const CHUNK_SIZE: usize = 0x10; + let mut num_digits = (std::mem::size_of_val(&total) * 8) - (total.leading_zeros() as usize); + if (num_digits % 8) != 0 { + num_digits += 8 - (num_digits % 8) + } + num_digits >>= 2; + for (mut offset, line) in data.chunks(CHUNK_SIZE).into_iter().enumerate() { + offset += base_offset; + let mut line = HexIILine::from(line.collect::>().as_slice()); + if line.len() < CHUNK_SIZE { + line.push(HexII::Eof); + } + while line.len() < CHUNK_SIZE { + line.push(HexII::Null); + } + if line.iter().all(|v| v == &HexII::Null) { + continue; + } + let offset = format!("{:digits$x}", offset * CHUNK_SIZE, digits = num_digits); + println!("{} | {:<16} |", offset, line); + } +} diff --git a/tools/remaster/scrap_net/src/main.rs b/tools/remaster/scrap_net/src/main.rs new file mode 100644 index 0000000..0b8cbd0 --- /dev/null +++ b/tools/remaster/scrap_net/src/main.rs @@ -0,0 +1,640 @@ +use anyhow::{bail, ensure, Result}; +use binrw::BinReaderExt; +use binrw::{BinRead, NullString}; +use chacha20::cipher::KeyInit; +use chacha20::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}; +use chacha20::ChaCha20; +use clap::Parser; +use dialoguer::theme::ColorfulTheme; +use dialoguer::Select; +use futures_util::FutureExt; +use poly1305::Poly1305; +use rand::{thread_rng, Rng}; +use rhexdump::hexdump; +use rustyline_async::{Readline, ReadlineError, SharedWriter}; +use std::collections::BTreeMap; +use std::error::Error; +use std::fmt::Display; +use std::io::Cursor; +use std::io::Write; +use std::iter; +use std::net::SocketAddr; +use std::net::ToSocketAddrs; +use std::net::{IpAddr, Ipv4Addr}; +use std::path::PathBuf; +use std::time::{Duration, Instant}; +use tokio::io::AsyncBufReadExt; +use tokio::net::UdpSocket; +use tokio::time; + +mod hex_ii; +mod parser; + +const KEY: &[u8; 32] = b"\x02\x04\x06\x08\x0a\x0c\x0e\x10\x12\x14\x16\x18\x1a\x1c\x1e\x20\x22\x24\x26\x28\x2a\x2c\x2e\x30\x32\x34\x36\x38\x3a\x3c\x3e\x40"; +const INFO_PACKET: &[u8] = b"\x7f\x01\x00\x00\x07"; + +#[derive(Debug, Clone)] +struct ServerFlags { + dedicated: bool, + force_vehicle: bool, + _rest: u8, +} + +impl Display for ServerFlags { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let force_vehicle = if self.force_vehicle { "F" } else { " " }; + let dedicated = if self.dedicated { "D" } else { " " }; + write!(f, "{}{}", force_vehicle, dedicated)?; + Ok(()) + } +} + +impl From for ServerFlags { + fn from(v: u8) -> Self { + ServerFlags { + dedicated: v & 0b1 != 0, + force_vehicle: v & 0b10 != 0, + _rest: (v & 0b11111100) >> 2, + } + } +} + +#[derive(Debug, Clone, BinRead)] +#[br(little, magic = b"\xba\xce", import(rtt: Duration, addr: SocketAddr))] +pub struct Server { + #[br(calc=addr)] + addr: SocketAddr, + #[br(calc=rtt)] + rtt: Duration, + #[br(map = |v: (u8,u8)| format!("{}.{}",v.0,v.1))] + version: String, + port: u16, + max_players: u16, + cur_players: u16, + #[br(map = u8::into)] + flags: ServerFlags, + #[br(pad_size_to(0x20), map = |s :NullString| s.to_string())] + name: String, + #[br(pad_size_to(0x10), map = |s :NullString| s.to_string())] + mode: String, + #[br(pad_size_to(0x20), map = |s :NullString| s.to_string())] + map: String, + _pad: u8, +} + +fn pad_copy(d: &[u8], l: usize) -> Vec { + let diff = d.len() % l; + if diff != 0 { + d.iter() + .copied() + .chain(iter::repeat(0).take(l - diff)) + .collect() + } else { + d.to_vec() + } +} + +fn pad(d: &mut Vec, l: usize) { + let diff = d.len() % l; + if diff != 0 { + d.extend(iter::repeat(0).take(l - diff)) + } +} + +struct Packet { + nonce: Vec, + data: Vec, +} + +impl Packet { + fn encrypt(data: &[u8]) -> Packet { + let mut data: Vec = data.to_vec(); + let mut rng = thread_rng(); + let mut nonce = vec![0u8; 12]; + rng.fill(nonce.as_mut_slice()); + let mut cipher = ChaCha20::new(KEY.into(), nonce.as_slice().into()); + cipher.seek(KEY.len() + 32); + cipher.apply_keystream(&mut data); + Packet { nonce, data } + } + + fn get_tag(&self) -> Vec { + let mut sign_data = vec![]; + sign_data.extend(pad_copy(&self.nonce, 16).iter()); + sign_data.extend(pad_copy(&self.data, 16).iter()); + sign_data.extend((self.nonce.len() as u64).to_le_bytes().iter()); + sign_data.extend((self.data.len() as u64).to_le_bytes().iter()); + let mut cipher = ChaCha20::new(KEY.into(), self.nonce.as_slice().into()); + let mut poly_key = *KEY; + cipher.apply_keystream(&mut poly_key); + let signer = Poly1305::new(&poly_key.into()); + signer.compute_unpadded(&sign_data).into_iter().collect() + } + + fn bytes(&self) -> Vec { + let mut data = vec![]; + data.extend(pad_copy(&self.nonce, 16).iter()); + data.extend(pad_copy(&self.data, 16).iter()); + data.extend((self.nonce.len() as u64).to_le_bytes().iter()); + data.extend((self.data.len() as u64).to_le_bytes().iter()); + data.extend(self.get_tag().iter()); + data + } + + fn decrypt(&self) -> Result> { + let mut data = self.data.clone(); + let mut sign_data = data.clone(); + pad(&mut sign_data, 16); + let mut nonce = self.nonce.clone(); + pad(&mut nonce, 16); + let sign_data = nonce + .iter() + .chain(sign_data.iter()) + .chain((self.nonce.len() as u64).to_le_bytes().iter()) + .chain((self.data.len() as u64).to_le_bytes().iter()) + .copied() + .collect::>(); + let mut poly_key = *KEY; + let mut cipher = ChaCha20::new(KEY.into(), self.nonce.as_slice().into()); + cipher.apply_keystream(&mut poly_key); + let signer = Poly1305::new(&poly_key.into()); + let signature: Vec = signer.compute_unpadded(&sign_data).into_iter().collect(); + + if signature != self.get_tag() { + bail!("Invalid signature!"); + }; + cipher.seek(poly_key.len() + 32); + cipher.apply_keystream(&mut data); + Ok(data) + } +} + +impl TryFrom<&[u8]> for Packet { + type Error = anyhow::Error; + fn try_from(data: &[u8]) -> Result { + let (mut nonce, data) = data.split_at(16); + let (mut data, tag) = data.split_at(data.len() - 16); + let nonce_len = u64::from_le_bytes(data[data.len() - 16..][..8].try_into()?) as usize; + let data_len = u64::from_le_bytes(data[data.len() - 8..].try_into()?) as usize; + data = &data[..data_len]; + nonce = &nonce[..nonce_len]; + let pkt = Packet { + nonce: nonce.into(), + data: data.into(), + }; + if pkt.get_tag() != tag { + bail!("Invalid signature!"); + } + Ok(pkt) + } +} + +#[derive(Debug, Clone)] +pub enum ServerEntry { + Alive(Server), + Dead { addr: SocketAddr, reason: String }, +} + +impl Display for ServerEntry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ServerEntry::Alive(srv) => write!( + f, + "[{}] {} ({} {}/{} Players on {}) version {} [{}] RTT: {:?}", + srv.addr, + srv.name, + srv.mode, + srv.cur_players, + srv.max_players, + srv.map, + srv.version, + srv.flags, + srv.rtt + ), + ServerEntry::Dead { addr, reason } => write!(f, "[{}] (error: {})", addr, reason), + } + } +} + +fn encrypt(data: &[u8]) -> Vec { + Packet::encrypt(data).bytes() +} + +fn decrypt(data: &[u8]) -> Result> { + Packet::try_from(data)?.decrypt() +} + +async fn recv_from_timeout( + sock: &UdpSocket, + buf: &mut [u8], + timeout: f64, +) -> Result<(usize, SocketAddr)> { + Ok(time::timeout(Duration::from_secs_f64(timeout), sock.recv_from(buf)).await??) +} + +async fn query_server<'a>(addr: SocketAddr) -> Result { + let mut buf = [0; 32 * 1024]; + let socket = UdpSocket::bind("0.0.0.0:0").await?; + socket.connect(addr).await?; + let msg = encrypt(INFO_PACKET); + let t_start = Instant::now(); + socket.send(&msg).await?; + let size = recv_from_timeout(&socket, &mut buf, 5.0).await?.0; + let rtt = t_start.elapsed(); + let data = decrypt(&buf[..size])?; + if !data.starts_with(&[0xba, 0xce]) { + // Server Info + bail!("Invalid response"); + } + let mut cur = Cursor::new(&data); + let info: Server = cur.read_le_args((rtt, addr))?; + if info.port != addr.port() { + eprint!("[WARN] Port differs for {}: {}", addr, info.port); + } + if cur.position() != (data.len() as u64) { + bail!("Leftover data"); + } + Ok(info) +} + +async fn get_servers(master_addr: &str) -> Result<(Duration, Vec)> { + let master_addr: SocketAddr = master_addr.to_socket_addrs()?.next().unwrap(); + let mut rtt = std::time::Duration::from_secs_f32(0.0); + let mut servers = vec![]; + let mut buf = [0; 32 * 1024]; + let master = UdpSocket::bind("0.0.0.0:0").await?; + master.connect(master_addr).await?; + for n in 0..(256 / 32) { + let data = format!("Brw={},{}\0", n * 32, (n + 1) * 32); + let data = &encrypt(data.as_bytes()); + let t_start = Instant::now(); + master.send(data).await?; + let size = master.recv(&mut buf).await?; + rtt += t_start.elapsed(); + let data = decrypt(&buf[..size])?; + if data.starts_with(b"\0\0\0\0}") { + for chunk in data[5..].chunks(6) { + if chunk.iter().all(|v| *v == 0) { + break; + } + let port = u16::from_le_bytes(chunk[chunk.len() - 2..].try_into()?); + let addr = SocketAddr::from(([chunk[0], chunk[1], chunk[2], chunk[3]], port)); + let server = match query_server(addr).await { + Ok(server) => ServerEntry::Alive(server), + Err(err) => ServerEntry::Dead { + addr, + reason: err.to_string(), + }, + }; + servers.push(server); + } + } + } + rtt = Duration::from_secs_f64(rtt.as_secs_f64() / ((256 / 32) as f64)); + Ok((rtt, servers)) +} + +fn indent_hexdump(data: &[u8], indentation: usize, label: &str) -> String { + let mut out = String::new(); + let indent = " ".repeat(indentation); + out.push_str(&indent); + out.push_str(label); + out.push('\n'); + for line in rhexdump::hexdump(data).lines() { + out.push_str(&indent); + out.push_str(line); + out.push('\n'); + } + out.trim_end().to_owned() +} + +#[derive(Default, Debug)] +struct State { + client: BTreeMap>, + server: BTreeMap>, +} + +impl State { + fn update_client(&mut self, data: &[u8]) { + data.iter().enumerate().for_each(|(pos, b)| { + *self.client.entry(pos).or_default().entry(*b).or_default() += 1; + }); + } + fn update_server(&mut self, data: &[u8]) { + data.iter().enumerate().for_each(|(pos, b)| { + *self.server.entry(pos).or_default().entry(*b).or_default() += 1; + }); + } +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +enum Direction { + Client, + Server, + Both, +} + +#[derive(Debug)] +enum CmdResult { + Exit, + Packet { + data: Vec, + direction: Direction, + }, + Fuzz { + direction: Direction, + start: usize, + end: usize, + chance: (u32, u32), + }, + NoFuzz, + Log(bool), +} + +async fn handle_line( + line: &str, + state: &State, + stdout: &mut SharedWriter, +) -> Result> { + use CmdResult::*; + let cmd: Vec<&str> = line.trim().split_ascii_whitespace().collect(); + match cmd[..] { + ["log", "off"] => Ok(Some(Log(false))), + ["log", "on"] => Ok(Some(Log(true))), + ["state", pos] => { + let pos = pos.parse()?; + writeln!(stdout, "Client: {:?}", state.client.get(&pos))?; + writeln!(stdout, "Server: {:?}", state.server.get(&pos))?; + Ok(None) + } + [dir @ ("client" | "server"), ref args @ ..] => { + let mut data: Vec = vec![]; + for args in args.iter() { + let args = hex::decode(args)?; + data.extend(args); + } + Ok(Some(CmdResult::Packet { + data, + direction: match dir { + "client" => Direction::Client, + "server" => Direction::Server, + _ => unreachable!(), + }, + })) + } + ["fuzz", dir @ ("client" | "server" | "both"), start, end, chance_num, chance_den] => { + let direction = match dir { + "client" => Direction::Client, + "server" => Direction::Server, + "both" => Direction::Both, + _ => unreachable!(), + }; + let start = start.parse()?; + let end = end.parse()?; + if start > end { + bail!("Fuzz start>end"); + } + let res = CmdResult::Fuzz { + direction, + start, + end, + chance: (chance_num.parse()?, chance_den.parse()?), + }; + Ok(Some(res)) + } + ["fuzz", "off"] => Ok(Some(CmdResult::NoFuzz)), + ["exit"] => Ok(Some(CmdResult::Exit)), + [""] => Ok(None), + _ => bail!("Unknown command: {:?}", line), + } +} + +async fn run_proxy( + remote_addr: &SocketAddr, + local_addr: &SocketAddr, + logfile: &Option, +) -> Result<()> { + let mut print_log = false; + let mut state = State::default(); + let mut logfile = match logfile { + Some(path) => Some(std::fs::File::create(path)?), + None => None, + }; + let mut fuzz = None; + let mut rng = thread_rng(); + let mut client_addr: Option = None; + let local = UdpSocket::bind(local_addr).await?; + let remote = UdpSocket::bind("0.0.0.0:0").await?; + remote.connect(remote_addr).await?; + let mut local_buf = vec![0; 32 * 1024]; + let mut remote_buf = vec![0; 32 * 1024]; + println!("Proxy listening on {}", local_addr); + let (mut rl, mut stdout) = Readline::new(format!("{}> ", remote_addr)).unwrap(); + loop { + tokio::select! { + line = rl.readline().fuse() => { + match line { + Ok(line) => { + let line=line.trim(); + rl.add_history_entry(line.to_owned()); + match handle_line(line, &state, &mut stdout).await { + Ok(Some(result)) => { + match result { + CmdResult::Packet{data,direction} => { + let data=encrypt(&data); + match direction { + Direction::Client => { + if client_addr.is_some() { + local + .send_to(&data, client_addr.unwrap()) + .await?; + } else { + writeln!(stdout,"Error: No client address")?; + } + }, + Direction::Server => { + remote.send(&data).await?; + } + Direction::Both => unreachable!() + }; + } + CmdResult::Log(log) => { + print_log=log; + } + CmdResult::Exit => break Ok(()), + CmdResult::NoFuzz => { + fuzz=None; + } + CmdResult::Fuzz { .. } => { + fuzz=Some(result) + }, + } + }, + Ok(None) => (), + Err(msg) => { + writeln!(stdout, "Error: {}", msg)?; + } + } + }, + Err(ReadlineError::Eof) =>{ writeln!(stdout, "Exiting...")?; break Ok(()) }, + Err(ReadlineError::Interrupted) => { + writeln!(stdout, "^C")?; + break Ok(()); + }, + Err(err) => { + writeln!(stdout, "Received err: {:?}", err)?; + writeln!(stdout, "Exiting...")?; + break Ok(()); + } + } + } + local_res = local.recv_from(&mut local_buf) => { + let (size, addr) = local_res?; + client_addr.get_or_insert(addr); + let mut data = Packet::try_from(&local_buf[..size])?.decrypt()?; + state.update_client(&data); + if print_log { + writeln!(stdout,"{}", indent_hexdump(&data, 0, &format!("OUT: {}", addr)))?; + } + if let Some(lf) = logfile.as_mut() { + writeln!(lf, ">{:?} {} {}", addr, data.len(), hex::encode(&data))?; + }; + if let Some(CmdResult::Fuzz{direction,start,end,chance}) = fuzz { + if (direction==Direction::Server || direction==Direction::Both) && rng.gen_ratio(chance.0,chance.1) { + rng.fill(&mut data[start..end]); + } + } + remote.send(&encrypt(&data)).await?; + } + remote_res = remote.recv_from(&mut remote_buf) => { + let (size, addr) = remote_res?; + let mut data = Packet::try_from(&remote_buf[..size])?.decrypt()?; + state.update_server(&data); + if print_log { + writeln!(stdout,"\r{}", indent_hexdump(&data, 5, &format!("IN: {}", addr)))?; + } + if let Some(lf) = logfile.as_mut() { + writeln!(lf, "<{:?} {} {}", addr, data.len(), hex::encode(&data))?; + }; + if client_addr.is_some() { + if let Some(CmdResult::Fuzz{direction,start,end,chance}) = &fuzz { + if (*direction==Direction::Client || *direction==Direction::Both) && rng.gen_ratio(chance.0,chance.1) { + rng.fill(&mut data[*start..*end]); + } + } + local + .send_to(&encrypt(&data), client_addr.unwrap()) + .await?; + } + } + } + } +} + +async fn send_master_cmd(sock: &UdpSocket, cmd: &str) -> Result> { + let mut buf = [0; 32 * 1024]; + let mut data: Vec = cmd.as_bytes().to_vec(); + data.push(0); + let data = &encrypt(&data); + sock.send(data).await?; + let size = recv_from_timeout(sock, &mut buf, 5.0).await?.0; + decrypt(&buf[..size]) +} + +async fn run_master_shell(master_addr: &str) -> Result<()> { + let master = UdpSocket::bind("0.0.0.0:0").await?; + master.connect(master_addr).await?; + let (mut rl, mut stdout) = Readline::new(format!("{}> ", master_addr)).unwrap(); + loop { + tokio::select! { + line = rl.readline().fuse() => { + match line { + Ok(line) => { + let line=line.trim(); + rl.add_history_entry(line.to_owned()); + writeln!(stdout,"[CMD] {line}")?; + match send_master_cmd(&master,line).await { + Ok(data) => writeln!(stdout,"{}",hexdump(&data))?, + Err(e) => writeln!(stdout,"Error: {e}")? + } + } + Err(ReadlineError::Eof) =>{ writeln!(stdout, "Exiting...")?; break Ok(()) }, + Err(ReadlineError::Interrupted) => { + writeln!(stdout, "^C")?; + break Ok(()); + }, + Err(err) => { + writeln!(stdout, "Receive error: {err}")?; + break Err(err.into()); + } + } + } + } + } +} + +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Args { + /// Server to connect to (if unspecified will query the master server) + server: Option, + /// Only list servers without starting proxy + #[clap(short, long, action)] + list: bool, + /// Local Address to bind to + #[clap(short,long, default_value_t = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 28086))] + addr: SocketAddr, + /// Master server to query for running games + #[clap(short, long, default_value = "scrapland.mercurysteam.com:5000")] + master: String, + /// Path of file to log decrypted packets to + #[clap(short = 'f', long)] + logfile: Option, +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Args::parse(); + if args.list && args.server.is_some() { + let addr = args.server.unwrap(); + let server = match query_server(addr).await { + Ok(server) => ServerEntry::Alive(server), + Err(msg) => ServerEntry::Dead { + addr, + reason: msg.to_string(), + }, + }; + println!("{}", server); + return Ok(()); + } + if let Some(server) = args.server { + run_proxy(&server, &args.addr, &args.logfile).await?; + return Ok(()); + } + loop { + let (rtt, servers) = get_servers(&args.master).await?; + println!("Master RTT: {:?}", rtt); + if args.list { + for server in servers { + println!("{}", server); + } + return Ok(()); + } + let selection = Select::with_theme(&ColorfulTheme::default()) + .items(&servers) + .with_prompt("Select server (press Esc to drop into master server command shell)") + .interact_opt()? + .map(|v| &servers[v]); + match selection { + Some(ServerEntry::Dead { addr, reason }) => { + eprintln!("{:?} returned an error: {}", addr, reason) + } + Some(ServerEntry::Alive(srv)) => { + return run_proxy(&srv.addr, &args.addr, &args.logfile).await; + } + None => { + return run_master_shell(&args.master).await; + } + } + } +} diff --git a/tools/remaster/scrap_net/src/parser.rs b/tools/remaster/scrap_net/src/parser.rs new file mode 100644 index 0000000..e8cbcd4 --- /dev/null +++ b/tools/remaster/scrap_net/src/parser.rs @@ -0,0 +1,151 @@ +use std::collections::HashMap; +use std::error::Error; + +use crate::hex_ii::hex_ii_dump; +use crate::ServerFlags; +use binrw::BinReaderExt; +use binrw::{binread, BinRead, NullString}; + +/* +00000000: 7f 4c 00 00 06 ba ce 01 01 06 63 61 63 6f 74 61 | .L........cacota +00000010: 10 5b 42 4a 5a 5d 20 45 61 72 74 68 6e 75 6b 65 | .[BJZ].Earthnuke +00000020: 72 06 53 50 6f 6c 69 31 37 00 08 50 5f 50 6f 6c | r.SPoli17..P_Pol +00000030: 69 63 65 06 4d 50 4f 4c 49 31 00 00 00 0d 30 2c | ice.MPOLI1....0, +00000040: 30 2c 30 2c 31 2c 30 2c 30 2c 31 00 00 00 00 | 0,0,1,0,0,1.... + +00000000: 7f 49 00 00 06 ba ce 01 01 06 63 61 63 6f 74 61 | .I........cacota +00000010: 0e 55 6e 6e 61 6d 65 64 20 50 6c 61 79 65 72 07 | .Unnamed.Player. +00000020: 53 42 65 74 74 79 31 50 00 07 50 5f 42 65 74 74 | SBetty1P..P_Bett +00000030: 79 07 4d 42 65 74 74 79 31 00 00 00 0b 31 2c 31 | y.MBetty1....1,1 +00000040: 2c 30 2c 31 2c 33 2c 30 00 00 00 00 | ,0,1,3,0.... +*/ + +#[derive(Debug, Clone, BinRead)] +#[br(big)] +#[br(magic = b"\xba\xce")] +struct ServerInfoJoin { + #[br(map = |v: (u8,u8)| format!("{}.{}",v.0,v.1))] + version: String, +} + +struct Data { + player_id: u32, + num_vals: u32, + pos: [f32; 3], + player_index: u32, + rtt: u32, +} + +#[binread] +#[br(big)] +#[derive(Debug, Clone)] +enum PacketData { + #[br(magic = b"\x7f")] + PlayerJoin { + data_len: u8, + _1: u8, + cur_players: u8, + max_players: u8, + info: ServerInfoJoin, + #[br(temp)] + pw_len: u8, + #[br(count = pw_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + password: String, + #[br(temp)] + player_name_len: u8, + #[br(count = player_name_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + player_name: String, + #[br(temp)] + ship_model_len: u8, + #[br(count = ship_model_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + ship_model: String, + #[br(little)] + max_health: u16, + #[br(temp)] + pilot_model_len: u8, + #[br(count = pilot_model_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + pilot_model: String, + #[br(temp)] + engine_model_r_len: u8, + #[br(count = engine_model_r_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + engine_model_r: String, + #[br(temp)] + engine_model_l_len: u8, + #[br(count = engine_model_r_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + engine_model_l: String, + _2: u16, + #[br(temp)] + loadout_len: u8, + #[br(count = loadout_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + loadout: String, + team_number: u16, + padding: [u8; 2], + }, + #[br(magic = b"\x80\x15")] + MapInfo { + #[br(temp)] + map_len: u32, + #[br(count = map_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + map: String, + #[br(temp)] + mode_len: u8, + #[br(count = mode_len, map = |bytes: Vec| String::from_utf8_lossy(&bytes).into_owned())] + mode: String, + _2: u16, + item_count: u8, + // _3: u32, + // #[br(count = item_count)] + // items: Vec<[u8;0x11]> + }, + #[br(magic = b"\xba\xce")] + ServerInfo { + #[br(map = |v: (u8,u8)| format!("{}.{}",v.1,v.0))] + version: String, + port: u16, + max_players: u16, + cur_players: u16, + #[br(map = u8::into)] + flags: ServerFlags, + #[br(pad_size_to(0x20), map=|s: NullString| s.to_string())] + name: String, + #[br(pad_size_to(0x10), map=|s: NullString| s.to_string())] + mode: String, + #[br(pad_size_to(0x20), map=|s: NullString| s.to_string())] + map: String, + _pad: u8, + }, +} + +fn parse(data: &[u8]) -> Result<(PacketData, Vec), Box> { + use std::io::Cursor; + let mut rdr = Cursor::new(data); + let pkt: PacketData = rdr.read_le()?; + let rest = data[rdr.position() as usize..].to_vec(); + println!("{}", rhexdump::hexdump(data)); + Ok((pkt, rest)) +} + +#[test] +fn test_parser() { + let log = include_str!("../test_.log").lines(); + let mut hm = HashMap::new(); + for line in log { + let data = line.split_ascii_whitespace().nth(1).unwrap(); + let data = hex::decode(data).unwrap(); + *hm.entry(data[0..1].to_vec()).or_insert(0usize) += 1; + match parse(&data) { + Ok((pkt, rest)) => { + println!("{:#x?}", pkt); + } + Err(e) => (), + } + } + let mut hm: Vec<(_, _)> = hm.iter().collect(); + hm.sort_by_key(|(_, v)| *v); + for (k, v) in hm { + let k = k.iter().map(|v| format!("{:02x}", v)).collect::(); + println!("{} {}", k, v); + } + // println!("{:#x?}",parse("8015000000094c6576656c732f465a08466c616748756e7400000100000000000000000000000000000000000004105feb0006003e1125f3bc1300000019007e9dfa0404d5f9003f00000000000000000000")); + // println!("{:#x?}",parse("8015000000094c6576656c732f465a08466c616748756e7400002000000000000000000000000000000000000004105feb0006003e1125f3bc1300000019007e9dfa0404d5f9003f000000000000000000001f020b0376a8e2475b6e5b467c1e99461e020903982d14c5ec79cb45b2ee96471d020e03b29dbc46caa433464a28a0c71c020603aa80514658b8ab458db025c71b020803ce492f4658b8ab4514d320c71a02070344532f4658b8ab4587cf16c7190205031b3a0d4658b8ab459eaf25c7180206030ac34c4669e1fd469891ca47170208032e8c2a4669e1fd465500cd4716020703a4952a4669e1fd461b02d247150205037b7c084669e1fd460f92ca4714020603da6b7ec714aa3746b77c5a4713020803c87c83c714aa3746305a5f47120207039a7b83c714aa3746bd5d694711020503bfbe87c714aa3746a67d5a4710020803c5c719474ad5d445a7b3d2c60f0206037c5522474ad5d4459a6edcc60e02070323ca19474ad5d4458dacbec60d020503d84311474ad5d445bb6cdcc60c020603a9b16b47d52d974602dd15470b020803f2236347d52d97467bba1a470a02070350266347d52d974608be24470902050305a05a47d52d9746f1dd1547080206031f4066c6384b9c46955bd345070208037e3b84c6384b9c466147fa4506020703c33684c6384b9c46e431254605020503574395c6384b9c461063d34504020603ba349bc77a60294640f387c103020803957b9fc77a602946658f994402020703677a9fc77a60294680006d45010205038cbda3c77a602946807880c1")); +} diff --git a/tools/remaster/scraphacks_rs/.cargo/config.toml b/tools/remaster/scraphacks_rs/.cargo/config.toml new file mode 100644 index 0000000..bf040d8 --- /dev/null +++ b/tools/remaster/scraphacks_rs/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "i686-pc-windows-msvc" \ No newline at end of file diff --git a/tools/remaster/scraphacks_rs/Cargo.lock b/tools/remaster/scraphacks_rs/Cargo.lock new file mode 100644 index 0000000..b636b23 --- /dev/null +++ b/tools/remaster/scraphacks_rs/Cargo.lock @@ -0,0 +1,1624 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" + +[[package]] +name = "app_dirs2" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a8d2d8dbda5fca0a522259fb88e4f55d2b10ad39f5f03adeebf85031eba501" +dependencies = [ + "jni", + "ndk-context", + "winapi", + "xdg", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-trait" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "brownstone" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5839ee4f953e811bfdcf223f509cb2c6a3e1447959b0bff459405575bc17f22" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "memchr", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bytecount" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + +[[package]] +name = "cc" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "comma" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" + +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + +[[package]] +name = "const_format" +version = "0.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7309d9b4d3d2c0641e018d449232f2e28f1b22933c137f157d3dbc14228b8c0e" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f47bf7270cf70d370f8f98c1abb6d2d4cf60a6845d30e05bfb90c6568650" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "custom-print" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb50a9067f6b0c4ecdac7986070032d9d299f69078ed69d6131bb5ede3345bd2" + +[[package]] +name = "cxx" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dataview" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50eb3a329e19d78c3a3dfa4ec5a51ecb84fa3a20c06edad04be25356018218f9" +dependencies = [ + "derive_pod", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_pod" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ea6706d74fca54e15f1d40b5cf7fe7f764aaec61352a9fcec58fe27e042fc8" + +[[package]] +name = "detour3" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0246383803197ff0315ef865f2daf6611f43b5782562e49f08bfa9de8a125ee" +dependencies = [ + "cfg-if", + "generic-array", + "lazy_static", + "libc", + "libudis86-sys", + "mmap-fixed-fixed", + "region", + "slice-pool", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "discord-sdk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0df260a6baf1d63a08dc38a7b75f30d4722a9eb2bf6d1172d33e0221bd72ae" +dependencies = [ + "anyhow", + "app_dirs2", + "async-trait", + "base64", + "bitflags", + "crossbeam-channel", + "num-traits", + "parking_lot", + "serde", + "serde_json", + "serde_repr", + "thiserror", + "time", + "tokio", + "tracing", + "url", + "winreg", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "erased-serde" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ca605381c017ec7a5fef5e548f1cfaa419ed0f6df6367339300db74c92aa7d" +dependencies = [ + "serde", +] + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "git2" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "iced-x86" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indent_write" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" + +[[package]] +name = "is_debug" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06d198e9919d9822d5f7083ba8530e04de87841eaf21ead9af8f2304efd57c89" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "joinery" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "libgit2-sys" +version = "0.14.2+1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libudis86-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139bbf9ddb1bfc90c1ac64dd2923d9c957cd433cee7315c018125d72ab08a6b0" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lua-src" +version = "544.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "708ba3c844d5e9d38def4a09dd871c17c370f519b3c4b7261fbabe4a613a814c" +dependencies = [ + "cc", +] + +[[package]] +name = "luajit-src" +version = "210.4.5+resty2cf5186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b7992a40e602786272d84c6f2beca44a588ededcfd57b48ec6f82008a7cb97" +dependencies = [ + "cc", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "mlua" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee2ad7a9aa69056b148d9d590344bc155d3ce0d2200e3b2838f7034f6ba33c1" +dependencies = [ + "bstr", + "cc", + "erased-serde", + "lua-src", + "luajit-src", + "mlua_derive", + "num-traits", + "once_cell", + "pkg-config", + "rustc-hash", + "serde", +] + +[[package]] +name = "mlua_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9214e60d3cf1643013b107330fcd374ccec1e4ba1eef76e7e5da5e8202e71c0" +dependencies = [ + "itertools", + "once_cell", + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "mmap-fixed-fixed" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0681853891801e4763dc252e843672faf32bcfee27a0aa3b19733902af450acc" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom-greedyerror" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f359007d505b20cd6e4974ff0d5c8e4565f0f9e15823937238221ccb74b516" +dependencies = [ + "nom", + "nom_locate", +] + +[[package]] +name = "nom-supreme" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd3ae6c901f1959588759ff51c95d24b491ecb9ff91aa9c2ef4acc5b1dcab27" +dependencies = [ + "brownstone", + "indent_write", + "joinery", + "memchr", + "nom", +] + +[[package]] +name = "nom_locate" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e299bf5ea7b212e811e71174c5d1a5d065c4c0ad0c8691ecb1f97e3e66025e" +dependencies = [ + "bytecount", + "memchr", + "nom", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "parse_int" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d695b79916a2c08bcff7be7647ab60d1402885265005a6658ffe6d763553c5a" +dependencies = [ + "num-traits", +] + +[[package]] +name = "pelite" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88dccf4bd32294364aeb7bd55d749604450e9db54605887551f21baea7617685" +dependencies = [ + "dataview", + "libc", + "no-std-compat", + "pelite-macros", + "winapi", +] + +[[package]] +name = "pelite-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a7cf3f8ecebb0f4895f4892a8be0a0dc81b498f9d56735cb769dc31bf00815b" + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "region" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + +[[package]] +name = "rhexdump" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e9af64574935e39f24d1c0313a997c8b880ca0e087c888bc6af8af31579847" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scraphacks_rs" +version = "0.1.0" +dependencies = [ + "anyhow", + "comma", + "custom-print", + "derivative", + "detour3", + "discord-sdk", + "futures", + "hex", + "iced-x86", + "mlua", + "nom", + "nom-greedyerror", + "nom-supreme", + "nom_locate", + "num-traits", + "once_cell", + "parse_int", + "pelite", + "region", + "rhexdump", + "rustc-hash", + "shadow-rs", + "struct_layout", + "tokio", + "viable", + "winsafe", +] + +[[package]] +name = "scratch" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shadow-rs" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427f07ab5f873000cf55324882e12a88c0a7ea7025df4fc1e7e35e688877a583" +dependencies = [ + "const_format", + "git2", + "is_debug", + "time", + "tzdb", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-pool" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733fc6e5f1bd3a8136f842c9bdea4e5f17c910c2fcc98c90c3aa7604ef5e2e7a" + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "struct_layout" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d806456ba83a5a07a5c09f984c7b5339c576d38d9656d464956ec4a74e5d7" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "itoa", + "libc", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" +dependencies = [ + "autocfg", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys", +] + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "tz-rs" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33851b15c848fad2cf4b105c6bb66eb9512b6f6c44a4b13f57c53c73c707e2b4" +dependencies = [ + "const_fn", +] + +[[package]] +name = "tzdb" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b882d864be6a5d7c3c916719944458b1e03c85f86dbc825ec98155117c4408" +dependencies = [ + "iana-time-zone", + "tz-rs", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "viable" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7746c1a6e7b03a755198414f4a364d8515f688f5f2e5fdd1db323891d299cb60" +dependencies = [ + "viable-impl", +] + +[[package]] +name = "viable-impl" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55bccf43d6bb2790e856edc1f250e25d8eeca72b2e6dd659386c85f794d53a6f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "winsafe" +version = "0.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62a4f20d0e60f34bfbb2624564d0bfda0a6eaee8f7f4494e5c3c883c3a62fdd2" + +[[package]] +name = "xdg" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" +dependencies = [ + "dirs", +] diff --git a/tools/remaster/scraphacks_rs/Cargo.toml b/tools/remaster/scraphacks_rs/Cargo.toml new file mode 100644 index 0000000..a4bf58c --- /dev/null +++ b/tools/remaster/scraphacks_rs/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "scraphacks_rs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[profile.release] +debug = 0 + +[lib] +crate-type = ["dylib"] + +[features] +console=[] + +[dependencies] +anyhow = "1.0.68" +comma = "1.0.0" +custom-print = "0.1.0" +derivative = "2.2.0" +detour3 = "0.1.0" +discord-sdk = "0.3.2" +futures = "0.3.25" +hex = "0.4.3" +iced-x86 = "1.18.0" +mlua = { version = "0.8.7", features = ["luajit", "vendored", "macros", "serialize", "mlua_derive"] } +nom = "7.1.3" +nom-greedyerror = "0.5.0" +nom-supreme = "0.8.0" +nom_locate = "4.1.0" +num-traits = "0.2.15" +once_cell = "1.17.0" +parse_int = "0.6.0" +pelite = "0.10.0" +region = "3.0.0" +rhexdump = "0.1.1" +rustc-hash = "1.1.0" +shadow-rs = "0.21.0" +struct_layout = "0.1.0" +tokio = "1.24.2" +viable = "0.2.0" +winsafe = { version = "0.0.15", features = ["kernel", "user", "dshow"] } + +[build-dependencies] +shadow-rs = "0.21.0" diff --git a/tools/remaster/scraphacks_rs/Pipfile b/tools/remaster/scraphacks_rs/Pipfile new file mode 100644 index 0000000..71e4f7c --- /dev/null +++ b/tools/remaster/scraphacks_rs/Pipfile @@ -0,0 +1,11 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +[requires] +python_version = "3.9" diff --git a/tools/remaster/scraphacks_rs/Save0.sav.json b/tools/remaster/scraphacks_rs/Save0.sav.json new file mode 100644 index 0000000..f7d1504 --- /dev/null +++ b/tools/remaster/scraphacks_rs/Save0.sav.json @@ -0,0 +1,242 @@ +{ + "id": "Outskirts - 07:41:13", + "title": "Scrapland savegame", + "data": { + "CTFFinishPlayerLoosesTextCad": "Mission_CTFAgainstBankers_RemoteMessage3", + "CTFFinishPlayerWinsTextCad": "Mission_CTFAgainstBankers_RemoteMessage2", + "CTFStartTextCad": "Mission_CTFAgainstBankers_RemoteMessage1", + "CTFOnDeathSpawnTime": "5.0", + "CTFFriendProfile": "BankersCTFFriends", + "CTFEnemyProfile": "BankersCTFEnemies", + "CTFFriendHead": "Functionary", + "CTFFriendType": "Functionary", + "CTFEnemyType": "BankDirector", + "CTFNumFriends": "5", + "CTFNumEnemies": "5", + "CTFFlags": "5", + "CombatFriendProfile": "ArrangeBankersCombatFriends", + "CombatFriendType": "Police", + "CombatNumFriends": "4", + "CombatNumEnemies": "5", + "PlayerWinsCombat": "1", + "OnVictory": "import SaveGame; SaveGame.QWayPoint();import MissionsFuncs; MissionsFuncs.SetNextMission(\"Mission_BackFromMortalRace\", \"GamblinDen\");Scrap.SetSaveVar(\"Map\", \"Levels/GamblinDen\");import SaveGame; SaveGame.QLoad(\"Levels/GamblinDen\");Scrap.SetSaveVar('MapPress_BureauExists','1')", + "OnAbort": "import MissionsFuncs; MissionsFuncs.EndOfSuperDeal('SuperDeal_Faliure_SystemMessage1')", + "CombatFinishPlayerLoosesTextCad": "SuperDeal_First_RemoteMessage3", + "CombatFinishPlayerWinsTextCad": "SuperDeal_First_RemoteMessage2", + "CombatStartTextCad": "SuperDeal_First_RemoteMessage1", + "CombatEnemyProfile": "SuperDealFirstElite", + "CombatEnemyTypeHead": "CrazyGambler", + "CombatEnemyType": "BankDirector", + "CombatDeaths": "5", + "SuperDealType": "", + "IgorFirstContactMissionState": "TalkToMercenaries", + "Stats.MadHunter": "10", + "Stats.Nurse.Dazed": "2", + "Stats.BankMaster": "6758", + "Bank.Circuit.36": "0", + "Bank.Circuit.35": "0", + "Bank.Circuit.34": "0", + "Bank.Circuit.33": "0", + "Bank.Circuit.32": "0", + "Bank.Circuit.31": "0", + "Bank.Circuit.30": "0", + "Bank.Circuit.29": "0", + "Bank.Circuit.28": "0", + "Bank.Circuit.27": "0", + "Bank.Circuit.26": "0", + "Bank.Circuit.25": "0", + "Bank.Circuit.24": "0", + "Bank.Circuit.23": "0", + "Bank.Circuit.22": "0", + "Bank.Circuit.21": "0", + "Bank.Circuit.20": "0", + "Bank.Circuit.19": "0", + "Bank.Circuit.18": "0", + "Bank.Circuit.17": "0", + "Bank.Circuit.16": "0", + "Bank.Circuit.15": "0", + "Bank.Circuit.14": "0", + "Bank.Circuit.13": "0", + "Bank.Circuit.12": "0", + "Bank.Circuit.11": "0", + "Bank.Circuit.10": "0", + "Bank.Circuit.9": "0", + "Bank.Circuit.8": "0", + "Bank.Circuit.7": "0", + "Bank.Circuit.6": "0", + "Bank.Circuit.5": "0", + "Bank.Circuit.4": "0", + "Bank.Circuit.3": "0", + "Bank.Circuit.2": "0", + "Bank.Circuit.1": "0", + "Bank.Circuit.0": "0", + "Stats.Mosquito": "116", + "PoliceBossAtTownHall": "0", + "Stats.Parking": "18", + "Police.FicusDeath": "1", + "CostumeAtPolice": "0", + "Hangar.HangarShip10": "SLifeBoat<-<-<-<-<-0,0,0,0,0,0,1<-30<-0,0,0,0,0,0", + "Hangar.iHangarShips": "8", + "AutoSaveGameOnLoad": "0", + "GameAct": "3rdMurder", + "BankDebt": "0", + "Map": "Levels/Outskirts", + "Mission.Library": "Mission_DestroyBadDebtors", + "EnergyBarActive": "1", + "SpecialActionActive": "2", + "CrazyWing.Status": "1", + "Conversor.ActiveConversors": "1", + "Hangar.iHangarShip": "0", + "Player.NumLives": "100", + "Hangar.shipsToEditList": "['SPoli1', 'SPoli2', 'SPoli3', 'SPoli4', 'SPoli5', 'SPoliBoss1', 'SMerc1', 'SMerc2', 'SMerc3', 'SMayor1', 'SBanker1', 'SBankMaster1', 'SBishop1', 'SArchbishop1', 'SFunc1', 'SBerto1', 'SBetty1', 'SHump1', 'SBoss1', 'SPoli4']", + "Hangar.availableEnginesList": "['MPOLI4', 'MPOLI5', 'MPOLIBOSS1', 'MPOLI2', 'MBERTO1', 'MBETTY1', 'MPOLI1', 'MMERC1', 'MMERC2', 'MPOLI3', 'MMAYOR1', 'MFUNC1', 'MBANKER1', 'MBANKMASTER1', 'MBISHOP1', 'MARCHBISHOP1', 'MHUMP1', 'MBOSS1', 'MMERC3']", + "Hangar.availableWeaponsList": "['Vulcan', 'Devastator', 'Swarm', 'Inferno', 'Tesla', 'ATPC', 'Swarm', 'Devastator']", + "Hangar.availableUpgradesList": "[\"VulcanUpgrade1\", \"VulcanUpgrade2\", \"DevastatorUpgrade1\", \"DevastatorUpgrade2\", \"SwarmUpgrade1\", \"SwarmUpgrade2\", \"InfernoUpgrade1\", \"InfernoUpgrade2\", \"TeslaUpgrade1\", \"TeslaUpgrade2\", \"ATPCUpgrade1\", \"ATPCUpgrade2\"]", + "JackInTheBox.Active": "1", + "Parked.Police": "['SPOLI1', 'SPOLI2', 'SPOLI3', 'SPOLI4']", + "Parked.Mercs": "['SMERC1', 'SMERC2']", + "Parked.TownHall": "['SFUNC1']", + "Parked.Bank": "['SBANKER1']", + "Parked.Press": "['SBERTO1', 'SBETTY1', 'SHUMP1']", + "Parked.Temple": "['SBISHOP1']", + "PoliceBlueprints.Ships": "['SPoli2', 'SPoli3', 'SPoli5', 'SPoliBoss1']", + "PoliceBlueprints.Engines": "['MPoli2', 'MPoli3', 'MPoli4', 'MPoli5', 'MPoliBoss1']", + "PressBlueprints.Ships": "['SBerto1', 'SBetty1', 'SHump1']", + "PressBlueprints.Engines": "['MBerto1', 'MBetty1', 'MHump1']", + "MayorAtGambinDen": "0", + "PolicesAtGambinDen": "1", + "PoliceBossAtPolice": "0", + "CrazyGamblerAtGambinDen": "1", + "FunctionaryTwinsAtGambinDen": "1", + "BankersAtGambinDen": "0", + "BishopsAtGambinDen": "0", + "GameSkill": "0", + "CreateBertos": "0", + "MercsHelpDtritus": "0", + "RobotsControlledByBoss": "0", + "Player.InfiniteLives": "0", + "PrevMap": "Levels/GamblinDen", + "Spawn": "DM_Player_Spawn_GamblinDen", + "Char": "Dtritus", + "ComeFrom": "DoorElevator", + "AlarmActive": "0", + "AlarmStatus": "0.0", + "Money": "2147483647", + "Challenge": "1", + "Challenge.Type": "", + "Challenge.Foe": "", + "Challenge.NumEnemies": "", + "Challenge.Money": "0", + "Revenge.Type": "", + "Revenge.Foe": "", + "Revenge.NumEnemies": "", + "Revenge.LastWinner": "", + "Mission.Map": "Outskirts", + "BadReputation": "3", + "GameplayTime": "27673.5857997", + "LonelyMercInGamblinDen": "0", + "LonelyMercLairActive": "1", + "LonelyMercDataActive": "0", + "ComSatsMissionsMapsFinished": "[]", + "Conversor.AvailableChars": "['Police', 'Nurse', 'BankDirector', 'Desktop', 'Sentinel', 'Gear', 'Bishop', 'Messenger', 'Functionary', 'Betty', 'Berto', 'BankMaster', 'Dtritus']", + "Batteries": "5", + "AcBatteries": "2", + "PrimaryMissionDesc": "Ich muss den Bankdirektor besuchen. Er treibt gerade ausstehende Kreditzahlungen mit seinem Kampfraumschiff ein. Ich sehe mal, ob ich ihm helfen kann.", + "SecondaryMissionDesc": "", + "TakePhotoMsg": "0", + "Race.Num": "3", + "Race.FirstTime": "0", + "Race.Profile": "Pilot", + "Combat.FirstTime": "1", + "Combat.Profile": "Rookie", + "Traffic.AcShips": "[\"SPoli6\", \"SMerc1\",\"SMerc2\",\"SBanker1\"]", + "IsSecondMission": "0", + "CrazyDeal.1.Var": "Stats.Dtritus", + "CrazyDeal.1.Tgt": "5", + "CrazyDeal.2.Var": "Stats.Parking", + "CrazyDeal.2.Tgt": "3", + "CrazyDeal.3.Var": "Stats.Battery", + "CrazyDeal.3.Tgt": "5", + "SuperDeal.Map": "FZ", + "SuperDeal.Library": "SuperDeal_Second", + "SuperDeal.Type": "MortalRace", + "CrazyWing.List": "['Sentinel', 'Betty', 'CrazyGambler', 'Functionary', 'Bishop']", + "Journalist.Humphrey_Defaut": "NoPlace", + "Journalist.Betty_Defaut": "NoPlace", + "Journalist.Berto_Defaut": "Press", + "Conversor.FirstConversion": "0", + "Conversor.FirstPossession": "0", + "WindowsError": "0", + "Orbit.Decontaminated": "yes", + "MercFriends.MercenaryA_Smartie": "0", + "MercFriends.MercenaryC_Brutus": "0", + "MercFriends.MercenaryB_Dumber": "0", + "StdShipAIProfile": "Elite", + "usrShip.Ammo00": "1000.0", + "usrShip.Ammo01": "500.0", + "usrShip.Ammo02": "1500.0", + "usrShip.AcWeap": "6", + "Parking.Desolate": "0", + "Hangar.HangarShip1": "SBoss1<-MBOSS1<-MBOSS1<-<-<-15,15,15,15,15,15,1<-187<-1,8,6,9,11,3", + "Hangar.HangarShip2": "", + "Hangar.HangarShip3": "", + "Hangar.HangarShip4": "", + "Hangar.HangarShip5": "", + "Hangar.HangarShip6": "", + "Hangar.HangarShip7": "", + "Hangar.HangarShip8": "", + "Hangar.HangarShip9": "", + "Hangar.HangarShipAux": "SLifeBoat<-<-<-<-<-0,0,0,0,0,0,1<-50<-0,0,0,0,0,0", + "Hangar.DestroyedShips": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", + "NewBluePrintAvaliable": "11", + "DebugSave": "1", + "OutMusicRelax": "141", + "MayorAtTownHall": "1", + "GamblinMusic": "1", + "OutMusicAction": "122", + "Stats.Traffic": "767", + "Stats.OutPolice": "110", + "MapPress_HiAlarm": "0", + "MapPress_BureauExists": "1", + "Stats.PossessBerto": "1", + "Stats.ConvertIntoDtritus": "1", + "Stats.WinHumphreyRace": "1", + "Stats.Possession": "57", + "Stats.Betty": "49", + "Stats.Killer": "119", + "Stats.Jump": "1", + "Stats.Jump.Police": "1", + "Stats.Bishop": "10", + "Stats.Battery": "0", + "Stats.Dtritus": "0", + "Stats.Race.Press": "1", + "Stats.TotalRaces.Press": "1", + "BankMasterAtBank": "1", + "DM_ExtraLife_00": "-60", + "DM_ExtraLife_01": "-60", + "DM_ExtraLife_02": "-60", + "DM_ExtraLife_03": "-60", + "DM_ExtraLife_04": "16294.7919922", + "Stats.TempleLife": "4", + "Mission_CatchTrurl_Data": "[]", + "Mission_CatchTrurl_MapsPos": "[]", + "Mission_CatchTrurl_NumMapsDropped": "0", + "Mission_CatchTrurl_NumMapsTaken": "0", + "GDB.BishopsMsg": "1", + "Stats.GDB": "6", + "LonelyMercActive": "0", + "Stats.Messenger": "2", + "MortalRaceRace": "[((71611.59375, 18231.6992188, 93232.796875), 422.337219238), ((45388.4140625, 14599.3476563, 79622.6640625), 400.984222412), ((25194.9804688, 18783.4863281, 59759.296875), 404.390136719), ((-433.664245605, 26340.1289063, 34561.0898438), 409.718261719), ((-38229.3671875, 26457.5292969, 679.068054199), 449.472442627), ((-107464.132813, 19331.875, 3288.328125), 528.452758789), ((-113911.117188, 14331.4462891, 40812.9414063), 558.054199219), ((-102532.132813, 11236.1474609, 75072.375), 630.567077637), ((-58177.6289063, 6282.20654297, 74209.3515625), 673.615478516), ((-24157.5449219, 7054.30419922, 43223.1679688), 630.510681152), ((33550.1445313, 15480.2402344, 41122.5820313), -55.4565696716), ((56201.6054688, 15587.5126953, 24649.8496094), 23.7488441467), ((26343.9511719, 22077.8789063, -32317.0292969), 90.5086135864), ((-13835.4755859, 26276.8730469, -31975.1582031), 145.932754517), ((-29244.3652344, 26745.4667969, -2544.81738281), -892.995666504), ((-23808.9570313, 27246.9980469, 32018.1816406), -819.383483887), ((21584.3066406, 29452.4667969, 41221.6171875), -822.313781738), ((54026.796875, 24611.7421875, 42694.0898438), -802.188171387), ((95732.015625, 16516.8085938, 36323.546875), -872.699890137), ((113450.46875, 12325.5195313, 77796.75), -969.003662109)]", + "MortalRaceWaypoints": "20", + "MortalRaceRacers": "['ArchBishop', 'BankDirector', 'Functionary', 'MercenaryA', 'MercenaryB']", + "MortalRaceRacersProfile": "MortalRace", + "MortalRaceFightingFreezeControlAim": "4", + "MortalRaceRespawnTime": "5.0", + "MortalRaceStartTextCad": "Mission_WinMortalRace_RemoteMessage1", + "MortalRaceFinishPlayerLoosesTextCad": "Mission_WinMortalRace_RemoteMessage2", + "MortalRaceFinishPlayerLoosesTextFoe": "Messenger", + "MortalRaceFinishPlayerWinsTextCad": "Mission_WinMortalRace_RemoteMessage3", + "MortalRaceFinishPlayerWinsTextFoe": "Messenger", + "MortalRaceAutoRestart": "1" + } +} \ No newline at end of file diff --git a/tools/remaster/scraphacks_rs/build.rs b/tools/remaster/scraphacks_rs/build.rs new file mode 100644 index 0000000..4a0dfc4 --- /dev/null +++ b/tools/remaster/scraphacks_rs/build.rs @@ -0,0 +1,3 @@ +fn main() -> shadow_rs::SdResult<()> { + shadow_rs::new() +} diff --git a/tools/remaster/scraphacks_rs/build.sh b/tools/remaster/scraphacks_rs/build.sh new file mode 100644 index 0000000..cf4b138 --- /dev/null +++ b/tools/remaster/scraphacks_rs/build.sh @@ -0,0 +1,4 @@ +impo +cargo b -r +cp D:/devel/Git_Repos/Scrapland-RE/tools/remaster/scraphacks_rs/target/i686-pc-windows-msvc/release/scraphacks_rs.dll E:/Games/Steam/steamapps/common/Scrapland/lib/ScrapHack.pyd +# x32dbg E:/Games/Steam/steamapps/common/Scrapland/Bin/Scrap.unpacked.exe "-debug:10 -console" \ No newline at end of file diff --git a/tools/remaster/scraphacks_rs/notes.md b/tools/remaster/scraphacks_rs/notes.md new file mode 100644 index 0000000..705b494 --- /dev/null +++ b/tools/remaster/scraphacks_rs/notes.md @@ -0,0 +1,16 @@ +# Notes + +## Snippets + +Map name: `Scrap.GetLangStr("Station_" + Scrap.GetLevelPath()[7:])` + +## Run + +`steam://run/897610/` + +## Signatures + +- World pointer: `a3 *{'} e8 ? ? ? ? 6a 00 68 *"World initialized"` +- print: `6a0068 *{"Scrap engine"} 6a?e8 $'` +- console handler: `68 *{"import Viewer"} e8 $'` +- DirectX Device: `` \ No newline at end of file diff --git a/tools/remaster/scraphacks_rs/run.py b/tools/remaster/scraphacks_rs/run.py new file mode 100644 index 0000000..2cda825 --- /dev/null +++ b/tools/remaster/scraphacks_rs/run.py @@ -0,0 +1,34 @@ +import subprocess as SP +import shutil as sh +import json +from pathlib import Path +import psutil +import os +import sys +os.environ['DISCORD_INSTANCE_ID']='1' +SP.check_call(["cargo","b","-r"]) +info=[json.loads(line) for line in SP.check_output(["cargo","b", "-r" ,"-q","--message-format=json"]).splitlines()] +dll_path=None +for line in info: + if line.get('reason')=="compiler-artifact" and ("dylib" in line.get("target",{}).get("crate_types",[])): + dll_path=Path(line['filenames'][0]) + +sh.copy(dll_path,"E:/Games/Steam/steamapps/common/Scrapland/lib/ScrapHack.pyd") + +if "--run" not in sys.argv[1:]: + exit(0) + +os.startfile("steam://run/897610/") +pid=None +while pid is None: + for proc in psutil.process_iter(): + try: + if proc.name()=="Scrap.exe": + pid=proc.pid + except: + pass +print(f"PID: {pid:x}") +if "--dbg" in sys.argv[1:]: + SP.run(["x32dbg","-p",str(pid)]) +# cp D:/devel/Git_Repos/Scrapland-RE/tools/remaster/scraphacks_rs/target/i686-pc-windows-msvc/release/scraphacks_rs.dll E:/Games/Steam/steamapps/common/Scrapland/lib/ScrapHack.pyd +# x32dbg E:/Games/Steam/steamapps/common/Scrapland/Bin/Scrap.unpacked.exe "-debug:10 -console" \ No newline at end of file diff --git a/tools/remaster/scraphacks_rs/scrap.hpp b/tools/remaster/scraphacks_rs/scrap.hpp new file mode 100644 index 0000000..a6c95ee --- /dev/null +++ b/tools/remaster/scraphacks_rs/scrap.hpp @@ -0,0 +1,16 @@ +#include +struct HashTable { + uint32_t num_slots; + struct HashTableEntry **chains; +}; + +struct HashTableEntry { + void *data; + const char *name; + HashTableEntry *next; +}; + +struct World { + void** VMT; + HashTable *entities; +}; \ No newline at end of file diff --git a/tools/remaster/scraphacks_rs/src/config.rs b/tools/remaster/scraphacks_rs/src/config.rs new file mode 100644 index 0000000..95585b7 --- /dev/null +++ b/tools/remaster/scraphacks_rs/src/config.rs @@ -0,0 +1,7 @@ +enum FilePatch { + +} + +pub struct Config { + file_patches: FxHashMap +} \ No newline at end of file diff --git a/tools/remaster/scraphacks_rs/src/discord.rs b/tools/remaster/scraphacks_rs/src/discord.rs new file mode 100644 index 0000000..acc021b --- /dev/null +++ b/tools/remaster/scraphacks_rs/src/discord.rs @@ -0,0 +1,94 @@ +use std::{num::NonZeroU32, thread::JoinHandle, time::SystemTime}; + +use crate::{cdbg, ceprintln, cprint, cprintln}; +use anyhow::{bail, Result}; +use discord_sdk::{ + activity::{ActivityBuilder, Assets, PartyPrivacy, Secrets}, + registration::{register_app, Application, LaunchCommand}, + wheel::Wheel, + Discord, DiscordApp, Subscriptions, +}; +const APP_ID: discord_sdk::AppId = 1066820570097930342; +const STEAM_APP_ID: u32 = 897610; +pub struct Client { + pub discord: discord_sdk::Discord, + pub user: discord_sdk::user::User, + pub wheel: discord_sdk::wheel::Wheel, +} + +impl Client { + pub fn run() -> Result>> { + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build()?; + register_app(Application { + id: APP_ID, + name: Some("Scrapland Remastered".to_owned()), + command: LaunchCommand::Steam(STEAM_APP_ID), + })?; + Ok(std::thread::spawn(move || rt.block_on(Self::run_async()))) + } + async fn run_async() -> Result<()> { + let (wheel, handler) = Wheel::new(Box::new(|err| { + ceprintln!("Encountered an error: {}", err); + })); + let mut user = wheel.user(); + let discord = Discord::new( + DiscordApp::PlainId(APP_ID), + Subscriptions::ACTIVITY, + Box::new(handler), + )?; + user.0.changed().await?; + let user = match &*user.0.borrow() { + discord_sdk::wheel::UserState::Connected(user) => user.clone(), + discord_sdk::wheel::UserState::Disconnected(err) => { + ceprintln!("Failed to connect to Discord: {err}"); + bail!("{}", err); + } + }; + let uid = user.id; + cprintln!( + "Logged in as: {user}#{discriminator}", + user = user.username, + discriminator = user + .discriminator + .map(|d| d.to_string()) + .unwrap_or_else(|| "????".to_owned()) + ); + let mut activity = ActivityBuilder::new() + .state("Testing") + .assets(Assets::default().large("scrap_logo", Some("Testing"))) + .timestamps(Some(SystemTime::now()), Option::::None) + .details("Testing ScrapHack"); + if false { + // (SCRAP.is_server()||SCRAP.is_client()) + let players = 1; + let capacity = 32; + activity = activity + .instance(true) + .party( + "Testt", + NonZeroU32::new(players), + NonZeroU32::new(capacity), + if false { + PartyPrivacy::Private + } else { + PartyPrivacy::Public + } + ) + .secrets(Secrets { + r#match: Some("MATCH".to_owned()), // Use server_ip+port + join: Some("JOIN".to_owned()), // Use server_ip+port + spectate: Some("SPECTATE".to_owned()), // Use server_ip+port + }); + } + + discord.update_activity(activity).await?; + loop { + if let Ok(req) = wheel.activity().0.try_recv() { + cprintln!("Got Join request: {req:?}"); + } + } + Ok(()) + } +} diff --git a/tools/remaster/scraphacks_rs/src/lib.rs b/tools/remaster/scraphacks_rs/src/lib.rs new file mode 100644 index 0000000..c1bca1c --- /dev/null +++ b/tools/remaster/scraphacks_rs/src/lib.rs @@ -0,0 +1,96 @@ +#![feature(abi_thiscall)] +#![feature(c_variadic)] +mod discord; +mod lua; +mod mem; +mod parser; +mod scrap; +use std::ffi::{c_char, c_void, CString}; +use anyhow::Result; +use crate::mem::search; +use crate::scrap::SCRAP; +use shadow_rs::shadow; +use winsafe::{co::{MB, CS, WS}, prelude::*, HWND, WNDCLASSEX, RegisterClassEx, WString}; + +shadow!(build); + +custom_print::define_macros!({cprint, cprintln, cdbg}, fmt, |value: &str| {crate::scrap::SCRAP.print(value)}); +custom_print::define_macros!({ceprint, ceprintln}, fmt, |value: &str| {crate::scrap::SCRAP.print_c(0x800000,value)}); + +#[allow(clippy::single_component_path_imports)] +pub(crate) use {cdbg, cprint, cprintln}; +#[warn(clippy::single_component_path_imports)] +pub(crate) use {ceprint, ceprintln}; + +#[repr(C)] +#[derive(Debug)] +struct PyMethodDef { + name: *const c_char, + func: *const (*const c_void, *const c_void), + ml_flags: i32, + doc: *const c_char, +} + +#[repr(C)] +#[derive(Debug)] +struct PyModuleDef { + name: *const c_char, + methods: *const PyMethodDef, +} + +fn init_py_mod() { + let py_init_module: fn( + *const c_char, // name + *const PyMethodDef, // methods + *const c_char, // doc + *const (), // passthrough + i32, // module_api_version + ) -> *const () = + unsafe { std::mem::transmute(search("68 *{\"Scrap\" 00} e8 ${'}", 1, None).unwrap_or_default()) }; + let name = CString::new("ScrapHack").unwrap_or_default(); + let desc = CString::new("ScrapHack Rust version").unwrap_or_default(); + let methods: &[PyMethodDef] = &[PyMethodDef { + name: 0 as _, + func: 0 as _, + ml_flags: 0, + doc: 0 as _, + }]; + assert!( + !py_init_module(name.as_ptr(), methods.as_ptr(), desc.as_ptr(), 0 as _, 1007).is_null() + ); +} + +#[no_mangle] +pub extern "system" fn initScrapHack() { + #[cfg(feature = "console")] + unsafe { + AllocConsole(); + } + std::panic::set_hook(Box::new(|info| { + ceprintln!("ScrapHacks: {info}"); + HWND::DESKTOP + .MessageBox(&format!("{info}"), "ScrapHacks error", MB::ICONERROR) + .unwrap(); + std::process::exit(1); + })); + init_py_mod(); + print_version_info(); + cprintln!("{SCRAP:#x?}"); +} + +#[no_mangle] +pub extern "system" fn DllMain(_inst: isize, _reason: u32, _: *const u8) -> u32 { + 1 +} + +fn print_version_info() { + cprintln!( + "{} v{} ({} {}), built for {} by {}.", + build::PROJECT_NAME, + build::PKG_VERSION, + build::SHORT_COMMIT, + build::BUILD_TIME, + build::BUILD_TARGET, + build::RUST_VERSION + ); +} diff --git a/tools/remaster/scraphacks_rs/src/lua.rs b/tools/remaster/scraphacks_rs/src/lua.rs new file mode 100644 index 0000000..9442ece --- /dev/null +++ b/tools/remaster/scraphacks_rs/src/lua.rs @@ -0,0 +1,204 @@ +use std::{path::PathBuf, sync::Arc}; + +use crate::{ + cprintln, + mem::{get_module, get_modules}, + parser::Cmd, +}; +use anyhow::{anyhow, bail, Result}; +use detour3::GenericDetour; +use mlua::{prelude::*, Variadic}; +use pelite::pattern; +use pelite::pe32::{Pe, PeObject}; +use rustc_hash::FxHashMap; +use winsafe::{prelude::*, HINSTANCE}; + +struct Ptr(*const ()); + +impl LuaUserData for Ptr { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_meta_method(LuaMetaMethod::ToString, |_, this, _: ()| { + Ok(format!("{:p}", this.0)) + }); + methods.add_method("read", |_, this, (size,): (usize,)| { + let addr = this.0 as u32; + let ptr = this.0 as *const u8; + let info = region::query(ptr).map_err(mlua::Error::external)?; + let end = info.as_ptr_range::<()>().end as u32; + let size = ((end - addr) as usize).min(size); + if !info.is_readable() { + return Err(LuaError::external(anyhow!("No read permission on page"))); + } + let data = unsafe { std::slice::from_raw_parts(ptr, size) }; + Ok(data.to_vec()) + }); + methods.add_method("write", |_, this, data: Vec| { + let data = data.as_slice(); + let addr = this.0 as *const u8; + unsafe { + let handle = region::protect_with_handle( + addr, + data.len(), + region::Protection::READ_WRITE_EXECUTE, + ) + .map_err(mlua::Error::external)?; + std::ptr::copy(data.as_ptr(), addr as *mut u8, data.len()); + drop(handle); + }; + Ok(()) + }); + // methods.add_method("hook", |_, this, func: LuaFunction| -> LuaResult<()> { + // let addr = this.0; + // cprintln!("Hook: {func:?} @ {addr:p}"); + // let dt = unsafe { GenericDetour:: u32>::new(std::mem::transmute(addr), hook_func) }.unwrap(); + // Err(LuaError::external(anyhow!("TODO: hook"))) + // }); + } +} + +// extern "thiscall" fn hook_func(this: *const (), args: (u32,u32,u32)) -> u32 { +// return 0; +// } + +pub(crate) fn init() -> Result { + let lua = unsafe { Lua::unsafe_new() }; + { + let globals = lua.globals(); + globals.set("scan", lua.create_function(lua_scan)?)?; + globals.set("print", lua.create_function(lua_print)?)?; + globals.set("hook", lua.create_function(lua_hook)?)?; + globals.set("imports", lua.create_function(lua_imports)?)?; + globals.set( + "ptr", + lua.create_function(|_, addr: u32| Ok(Ptr(addr as _)))?, + )?; + globals.set( + "ptr", + lua.create_function(lua_alloc)?, + )?; + } + Ok(lua) +} + +fn lua_val_to_string(val: &LuaValue) -> LuaResult { + Ok(match val { + LuaNil => "Nil".to_owned(), + LuaValue::Boolean(b) => format!("{b}"), + LuaValue::LightUserData(u) => format!("{u:?}"), + LuaValue::Integer(i) => format!("{i}"), + LuaValue::Number(n) => format!("{n}"), + LuaValue::String(s) => (s.to_str()?).to_string(), + LuaValue::Table(t) => { + let mut vals = vec![]; + for res in t.clone().pairs() { + let (k, v): (LuaValue, LuaValue) = res?; + vals.push(format!( + "{k} = {v}", + k = lua_val_to_string(&k)?, + v = lua_val_to_string(&v)? + )); + } + format!("{{{vals}}}", vals = vals.join(", ")) + } + LuaValue::Function(f) => format!("{f:?}"), + LuaValue::Thread(t) => format!("{t:?}"), + LuaValue::UserData(u) => format!("{u:?}"), + LuaValue::Error(e) => format!("{e:?}"), + }) +} + +fn lua_alloc(lua: &Lua, size: usize) -> LuaResult { + let data = vec![0u8;size].into_boxed_slice(); + Ok(Ptr(Box::leak(data).as_ptr() as _)) +} + +fn lua_hook(lua: &Lua, (addr, func): (u32, LuaFunction)) -> LuaResult<()> { + cprintln!("Hook: {func:?} @ {addr:08x}"); + Err(LuaError::external(anyhow!("TODO: hook"))) +} + +fn lua_imports(lua: &Lua, (): ()) -> LuaResult<()> { + Err(LuaError::external(anyhow!("TODO: imports"))) +} + +fn lua_print(lua: &Lua, args: Variadic) -> LuaResult<()> { + let msg: Vec = args + .into_iter() + .map(|v| lua_val_to_string(&v)) + .collect::>>()?; + cprintln!("{}", msg.join(" ")); + Ok(()) +} + +#[derive(Debug)] +enum ScanMode { + MainModule, + Modules(Vec), + All, +} + +impl FromLua<'_> for ScanMode { + fn from_lua<'lua>(lua_value: LuaValue<'lua>, lua: &'lua Lua) -> LuaResult { + match &lua_value { + LuaValue::Nil => Ok(ScanMode::MainModule), + LuaValue::Boolean(true) => Ok(ScanMode::All), + LuaValue::Table(t) => Ok(ScanMode::Modules(FromLua::from_lua(lua_value, lua)?)), + _ => Err(LuaError::FromLuaConversionError { + from: lua_value.type_name(), + to: "scan_mode", + message: None, + }), + } + } +} + +fn lua_scan(lua: &Lua, (pattern, scan_mode): (String, ScanMode)) -> LuaResult { + let pat = pattern::parse(&pattern).map_err(mlua::Error::external)?; + let mut ret = FxHashMap::default(); + let modules = match scan_mode { + ScanMode::MainModule => vec![get_module(None).map_err(mlua::Error::external)?], + ScanMode::Modules(modules) => modules + .into_iter() + .map(|m| get_module(Some(m))) + .collect::>() + .map_err(mlua::Error::external)?, + ScanMode::All => get_modules().map_err(mlua::Error::external)?, + }; + 'outer: for module in modules { + let regions = region::query_range(module.image().as_ptr(), module.image().len()) + .map_err(mlua::Error::external)?; + for region in regions { + let Ok(region)=region else { + continue 'outer; + }; + if !region.is_readable() { + continue 'outer; + } + } + let h_module = unsafe { HINSTANCE::from_ptr(module.image().as_ptr() as _) }; + let module_name = PathBuf::from( + h_module + .GetModuleFileName() + .map_err(mlua::Error::external)?, + ) + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_owned(); + if let Ok(res) = crate::mem::scan(&pat, &module) { + if !res.is_empty() { + let res: Vec> = res + .into_iter() + .map(|res| res.into_iter().map(|a| Ptr(a as _)).collect()) + .collect(); + ret.insert(module_name, res); + } + }; + } + lua.create_table_from(ret.into_iter()) +} + +pub(crate) fn exec(chunk: &str) -> Result<()> { + Ok(init()?.load(chunk).set_name("ScrapLua")?.exec()?) +} diff --git a/tools/remaster/scraphacks_rs/src/mem.rs b/tools/remaster/scraphacks_rs/src/mem.rs new file mode 100644 index 0000000..87ccda5 --- /dev/null +++ b/tools/remaster/scraphacks_rs/src/mem.rs @@ -0,0 +1,94 @@ +use std::str::FromStr; + +use anyhow::anyhow; +use anyhow::bail; +use anyhow::Result; +use pelite::pattern::parse; +use pelite::pattern::save_len; +use pelite::pattern::Atom; +use pelite::pe32::{Pe, PeView}; +use winsafe::co::TH32CS; +use winsafe::prelude::*; +use winsafe::HINSTANCE; +use winsafe::HPROCESSLIST; +pub(crate) struct Pattern(Vec, usize); + +impl Pattern { + pub(crate) fn set_index(mut self, idx: usize) -> Self { + self.1 = idx; + self + } +} + +impl FromStr for Pattern { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + Ok(Self(parse(s)?, 0)) + } +} + +impl Pattern { + pub(crate) fn scan(&self, module: Option) -> Result { + let pe = get_module(module)?; + let scan = pe.scanner(); + let mut save = vec![0u32; save_len(&self.0)]; + if !scan.finds(&self.0, 0..u32::MAX, &mut save) { + bail!("Pattern not found"); + } + save.get(self.1) + .ok_or_else(|| anyhow!("Result index out of range")) + .and_then(|r| pe.rva_to_va(*r).map_err(|e| e.into())) + } +} + +pub(crate) fn get_modules() -> Result>> { + let mut res = vec![]; + let pid = std::process::id(); + let mut h_snap = HPROCESSLIST::CreateToolhelp32Snapshot(TH32CS::SNAPMODULE, Some(pid))?; + for module in h_snap.iter_modules() { + res.push(unsafe { PeView::module(module?.hModule.as_ptr() as *const u8) }); + } + Ok(res) +} + +pub(crate) fn get_module(module: Option) -> Result> { + let hmodule = HINSTANCE::GetModuleHandle(module.as_deref())?; + Ok(unsafe { PeView::module(hmodule.as_ptr() as *const u8) }) +} + +pub(crate) fn scan(pat: &[Atom], pe: &PeView) -> Result>> { + let mut ret = vec![]; + let scan = pe.scanner(); + let mut m = scan.matches(pat, 0..u32::MAX); + let mut save = vec![0u32; save_len(pat)]; + while m.next(&mut save) { + ret.push( + save.iter() + .map(|rva| pe.rva_to_va(*rva).map_err(|e| e.into())) + .collect::>>()?, + ); + } + Ok(ret) +} + +pub(crate) fn search(pat: &str, idx: usize, module: Option) -> Result { + pat.parse::()?.set_index(idx).scan(module) +} + +fn addr_info(addr: u32) -> Result<()> { + let pid = std::process::id(); + let mut h_snap = HPROCESSLIST::CreateToolhelp32Snapshot(TH32CS::SNAPMODULE, Some(pid))?; + for module in h_snap.iter_modules() { + let module = module?; + let module_name = module.szModule(); + if module_name.to_lowercase() == "kernel32.dll" { + continue; + } + let mod_range = + unsafe { module.modBaseAddr..module.modBaseAddr.offset(module.modBaseSize as isize) }; + println!("{module_name}: {mod_range:?}"); + // let module = unsafe { PeView::module(module.modBaseAddr as *const u8) }; + } + Ok(()) +} diff --git a/tools/remaster/scraphacks_rs/src/parser.rs b/tools/remaster/scraphacks_rs/src/parser.rs new file mode 100644 index 0000000..700c7b2 --- /dev/null +++ b/tools/remaster/scraphacks_rs/src/parser.rs @@ -0,0 +1,177 @@ +// use crate::{cdbg, ceprintln, cprint, cprintln}; +use std::path::PathBuf; +use std::str::FromStr; +use anyhow::{anyhow, Result}; +use nom::branch::alt; +use nom::bytes::complete::{take_till, take_while1}; +use nom::character::complete::{digit1, hex_digit1}; +use nom::character::streaming::char; +use nom::combinator::{eof, opt, rest}; +use nom::sequence::{separated_pair, tuple}; +use nom::{IResult, Parser}; +use nom_locate::LocatedSpan; +use nom_supreme::error::ErrorTree; +use nom_supreme::final_parser::final_parser; +use nom_supreme::tag::complete::{tag, tag_no_case}; +use nom_supreme::ParserExt; +use pelite::pattern::{self, Atom}; + +type Span<'a> = LocatedSpan<&'a str>; + +type ParseResult<'a, 'b, T> = IResult, T, ErrorTree>>; + +#[derive(Debug, Clone)] +pub enum Cmd { + Imports, + Read(u32, usize), + ReadPE(u32, usize), + Write(u32, Vec), + Disams(u32, usize), + Info(Option), + Script(PathBuf), + Unload, + ScanModule(Vec, Option), + Lua(String), +} + +impl FromStr for Cmd { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match parse(s) { + Ok(cmd) => Ok(cmd), + Err(err) => Err(anyhow!("{}", err)), + } + } +} + +fn ws(input: Span) -> ParseResult<()> { + take_while1(|c: char| c.is_whitespace()) + .value(()) + .context("Whitepace") + .parse(input) +} + +// + +/// Test + +fn hex_bytes(input: Span) -> ParseResult> { + hex_digit1 + .map_res_cut(hex::decode) + .context("Hex string") + .parse(input) +} + +fn num(input: Span) -> ParseResult { + digit1 + .map_res_cut(|n: Span| parse_int::parse(&n)) + .context("Number") + .parse(input) +} + +fn address(input: Span) -> ParseResult { + tag_no_case("0x") + .precedes(hex_digit1) + .recognize() + .map_res_cut(|addr: Span| parse_int::parse::(&addr)) + .context("Memory address") + .parse(input) +} + +fn parse_read_pe(input: Span) -> ParseResult { + tag("read_pe") + .precedes(ws) + .precedes(separated_pair(address, ws, num.opt())) + .map(|(addr, size)| Cmd::ReadPE(addr, size.unwrap_or(0x100))) + .parse(input) +} + +fn parse_read(input: Span) -> ParseResult { + tag("read") + .precedes(ws) + .precedes(separated_pair(address, ws, num.opt())) + .map(|(addr, size)| Cmd::Read(addr, size.unwrap_or(0x100))) + .parse(input) +} + +fn parse_disasm(input: Span) -> ParseResult { + tag("disasm") + .precedes(ws) + .precedes(separated_pair(address, ws, num.opt())) + .map(|(addr, size)| Cmd::Disams(addr, size.unwrap_or(50))) + .parse(input) +} + +fn parse_write(input: Span) -> ParseResult { + tag("write") + .precedes(ws) + .precedes(separated_pair(address, ws, hex_bytes)) + .map(|(addr, data)| Cmd::Write(addr, data)) + .parse(input) +} + +fn parse_info(input: Span) -> ParseResult { + tag("info") + .precedes(eof) + .value(Cmd::Info(None)) + .or(tag("info") + .precedes(ws) + .precedes(address) + .map(|addr| Cmd::Info(Some(addr)))) + .parse(input) +} + +fn parse_scan(input: Span) -> ParseResult { + let (input, _) = tag("scan").parse(input)?; + let (input, module) = + opt(tuple((char(':'), take_till(|c: char| c.is_whitespace())))).parse(input)?; + let module = module.map(|(_, module)| module.fragment().to_string()); + let (input, _) = ws.parse(input)?; + let (input, pattern) = rest + .map_res(|pat: Span| pattern::parse(&pat)) + .parse(input)?; + Ok((input, Cmd::ScanModule(pattern, module))) +} + +fn parse_unload(input: Span) -> ParseResult { + tag("unload").value(Cmd::Unload).parse(input) +} + +fn parse_imports(input: Span) -> ParseResult { + tag("imports").value(Cmd::Imports).parse(input) +} + +fn parse_lua(input: Span) -> ParseResult { + tag("lua") + .precedes(ws) + .precedes(rest) + .map(|s| Cmd::Lua(s.fragment().to_string())) + .parse(input) +} + +fn parse_script(input: Span) -> ParseResult { + tag("script") + .precedes(ws) + .precedes(rest) + .map(|s| Cmd::Script(PathBuf::from(s.fragment()))) + .parse(input) +} + +fn parse(input: &str) -> Result>> { + final_parser( + alt(( + parse_imports, + parse_unload, + parse_scan, + parse_info, + parse_write, + parse_read, + parse_read_pe, + parse_script, + parse_disasm, + parse_lua, + )) + .context("command"), + )(Span::new(input)) +} diff --git a/tools/remaster/scraphacks_rs/src/scrap.rs b/tools/remaster/scraphacks_rs/src/scrap.rs new file mode 100644 index 0000000..05790c1 --- /dev/null +++ b/tools/remaster/scraphacks_rs/src/scrap.rs @@ -0,0 +1,381 @@ +use crate::{ + cdbg, ceprintln, cprint, cprintln, lua, + mem::{get_module, scan, search}, + parser::Cmd, discord, +}; +use anyhow::{bail, Result}; +use derivative::Derivative; +use detour3::GenericDetour; +use futures::executor::block_on; +use iced_x86::{Decoder, DecoderOptions, Formatter, Instruction, NasmFormatter}; +use once_cell::sync::Lazy; +use pelite::{pe::PeView, pe32::Pe}; +use std::{ + collections::HashMap, + ffi::{c_char, CStr, CString}, + fmt::Debug, + ptr, + thread::JoinHandle, + time::Duration, +}; +use winsafe::HINSTANCE; +use winsafe::{co::TH32CS, prelude::*, HPROCESSLIST}; + +const POINTER_SIZE: usize = std::mem::size_of::<*const ()>(); + +#[repr(C)] +struct VirtualMethodTable(*const *const ()); + +impl Debug for VirtualMethodTable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut methods = vec![]; + for idx in 0.. { + let ptr = self.get::<()>(idx); + if ptr.is_null() + || !region::query(ptr) + .map(|r| r.is_executable()) + .unwrap_or(false) + { + break; + } + methods.push(ptr); + } + f.debug_tuple("VMT").field(&methods).finish() + } +} + +impl VirtualMethodTable { + fn get(&self, offset: usize) -> *const T { + unsafe { self.0.add(POINTER_SIZE * offset).read() as *const T } + } +} + +#[derive(Derivative)] +#[derivative(Debug)] +pub struct Scrap { + print: extern "C" fn(u32, *const c_char, u8), + console_detour: GenericDetour, + world: WorldPointer, + discord_thread_handle: JoinHandle>, +} + +#[repr(C)] +#[derive(Debug)] +struct Entity { + vmt: VirtualMethodTable, +} + +#[repr(C)] +#[derive(Debug)] +struct HashTableEntry { + data: *const T, + name: *const c_char, + next: *const Self, +} + +#[repr(C)] +struct HashTable { + num_slots: u32, + chains: *const *const HashTableEntry, +} + +fn try_read(ptr: *const T) -> Option { + (!ptr.is_null()).then(|| unsafe { ptr.read() }) +} + +impl std::fmt::Debug for HashTable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut entries: HashMap> = HashMap::default(); + for offset in 0..self.num_slots { + let offset = offset as _; + // let chain=vec![]; + let mut chain_ptr = unsafe { self.chains.offset(offset).read() }; + while !chain_ptr.is_null() { + let entry = unsafe { chain_ptr.read() }; + let data = try_read(entry.data); + let key = unsafe { CStr::from_ptr(entry.name) } + .to_str() + .unwrap() + .to_owned(); + chain_ptr = entry.next; + entries.insert(key, data); + } + } + f.debug_struct(&format!("HashTable @ {self:p} ")) + .field("num_slots", &self.num_slots) + .field("entries", &entries) + .finish() + } +} + +#[repr(C)] +struct World { + vmt: VirtualMethodTable, + entities: HashTable, +} + +impl Debug for World { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("World") + .field("vmt", &self.vmt) + .field("entities", &self.entities) + .finish() + } +} + +struct WorldPointer(u32); + +impl std::fmt::Debug for WorldPointer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let ptr = self.ptr(); + let world = unsafe { ptr.read() }; + f.debug_tuple(&format!("WorldPointer @ {ptr:p} ")) + .field(&world) + .finish() + } +} + +impl WorldPointer { + fn ptr(&self) -> *const World { + let ptr = self.0 as *const *const World; + unsafe { ptr.read() } + } + + fn get_hashtable(&self) { + // let ents = unsafe { self.ptr().read().entities.read() }; + // cprintln!("Ents: {ents:?}"); + } +} + +pub(crate) static SCRAP: Lazy = + Lazy::new(|| Scrap::init().expect("Failed to initialize Scrap data structure")); + +impl Scrap { + const PRINT_PATTERN: &str = r#"6a0068 *{"Scrap engine"} 6a?e8 $'"#; + const PY_EXEC: &str = r#"68 *{"import Viewer"} e8 $'"#; + const WORLD_PATTERN: &str = r#"8b 0d *{'} 68 *"CTFFriends""#; + fn init() -> Result { + let scrap = unsafe { + Self { + world: WorldPointer(search(Self::WORLD_PATTERN, 1, None)? as _), + print: std::mem::transmute(search(Self::PRINT_PATTERN, 1, None)?), + console_detour: GenericDetour::::new( + std::mem::transmute(search(Self::PY_EXEC, 1, None)?), + Self::console_input, + )?, + discord_thread_handle: discord::Client::run()?, + } + }; + unsafe { scrap.console_detour.enable()? } + Ok(scrap) + } + + extern "C" fn console_input(orig_line: *const c_char) { + let line = unsafe { CStr::from_ptr(orig_line) }.to_str(); + let Ok(line) = line else { + return SCRAP.console_detour.call(orig_line); + }; + if let Some(cmd) = line.strip_prefix('$') { + let res = cmd.parse().and_then(|cmd: Cmd| cmd.exec()); + if let Err(err) = res { + ceprintln!("Error: {err}"); + } + return; + }; + SCRAP.console_detour.call(orig_line) + } + + pub fn println(&self, msg: &str) { + self.println_c(0x008000, msg) + } + + pub fn print(&self, msg: &str) { + self.print_c(0x008000, msg) + } + + pub fn print_c(&self, col: u32, msg: &str) { + let col = (col & 0xffffff).swap_bytes() >> 8; // 0xRRGGBB -> 0xBBGGRR + let msg = CString::new(msg.to_string()).unwrap(); + (self.print)(col, msg.as_ptr(), 0); + } + + pub fn println_c(&self, col: u32, msg: &str) { + let msg = msg.to_owned() + "\n"; + self.print_c(col, &msg) + } +} + +impl Cmd { + pub(crate) fn exec(&self) -> Result<()> { + let pe = get_module(None)?; + match self { + Cmd::Imports => { + for import in pe.imports()? { + let iat = import.iat()?; + let int = import.int()?; + for (func, imp) in iat.zip(int) { + let imp = imp?; + cprintln!( + "{addr:p}: {name} {imp:?}", + name = import.dll_name()?, + addr = func + ); + } + } + } + Cmd::Read(addr, size) => { + let ptr = *addr as *const u8; + let info = region::query(ptr)?; + let end = info.as_ptr_range::<()>().end as u32; + let size = ((end - addr) as usize).min(*size); + if !info.is_readable() { + bail!("No read permission on page"); + } + let data = unsafe { std::slice::from_raw_parts(ptr, size) }; + cprintln!("{}", &rhexdump::hexdump_offset(data, *addr)); + } + Cmd::Disams(addr, size) => { + let ptr = *addr as *const u8; + let info = region::query(ptr)?; + let end = info.as_ptr_range::<()>().end as u32; + let size = ((end - addr) as usize).min(*size); + if !info.is_readable() { + bail!("No read permission on page"); + } + let data = unsafe { std::slice::from_raw_parts(ptr, size) }; + let mut decoder = Decoder::with_ip(32, data, *addr as u64, DecoderOptions::NONE); + let mut instruction = Instruction::default(); + let mut output = String::new(); + let mut formatter = NasmFormatter::new(); + while decoder.can_decode() { + decoder.decode_out(&mut instruction); + output.clear(); + formatter.format(&instruction, &mut output); + cprint!("{:016X} ", instruction.ip()); + let start_index = (instruction.ip() - (*addr as u64)) as usize; + let instr_bytes = &data[start_index..start_index + instruction.len()]; + for b in instr_bytes.iter() { + cprint!("{:02X}", b); + } + cprintln!(" {}", output); + } + } + Cmd::Write(addr, data) => { + let data = data.as_slice(); + let addr = *addr as *const u8; + unsafe { + let handle = region::protect_with_handle( + addr, + data.len(), + region::Protection::READ_WRITE_EXECUTE, + )?; + std::ptr::copy(data.as_ptr(), addr as *mut u8, data.len()); + drop(handle); + }; + } + Cmd::ReadPE(addr, size) => { + if !region::query(*addr as *const ())?.is_readable() { + bail!("No read permission for 0x{addr:x}"); + } + let data = pe.read_bytes(*addr)?; + cprintln!("{}", &rhexdump::hexdump_offset(&data[..*size], *addr)); + } + Cmd::Info(None) => { + let regions = region::query_range(ptr::null::<()>(), usize::MAX)?; + for region in regions.flatten() { + cprintln!( + "{:?}: {}", + region.as_ptr_range::<*const ()>(), + region.protection() + ); + } + } + Cmd::Info(Some(addr)) => { + let info = region::query(*addr as *const ())?; + cprintln!( + "{:?}: {}", + info.as_ptr_range::<*const ()>(), + info.protection() + ); + } + Cmd::ScanModule(pat, module) => { + cprintln!("{:?}", pat); + let mut total_hits = 0; + let mut modules = vec![]; + let is_wildcard = matches!(module.as_deref(), Some("*")); + if is_wildcard { + let pid = std::process::id(); + let mut h_snap = + HPROCESSLIST::CreateToolhelp32Snapshot(TH32CS::SNAPMODULE, Some(pid))?; + for module in h_snap.iter_modules() { + let module = module?; + let module_name = module.szModule(); + let module_addr = module.hModule.as_ptr() as *const u8; + let module = region::query_range(module_addr, module.modBaseSize as usize)? + .all(|m| m.ok().map(|m| m.is_readable()).unwrap_or(false)) + .then(|| unsafe { PeView::module(module_addr) }); + if let Some(module) = module { + modules.push((module_name, module)); + } + } + } else { + let module = HINSTANCE::GetModuleHandle(module.as_deref())?; + let module_name = module.GetModuleFileName()?; + let module_addr = module.as_ptr() as *const u8; + let module = region::query(module_addr) + .map(|m| m.is_readable()) + .unwrap_or(false) + .then(|| unsafe { PeView::module(module_addr) }); + if let Some(module) = module { + modules.push((module_name, module)); + }; + } + for (module_name, pe) in modules { + let res = scan(pat, &pe)?; + if res.is_empty() { + continue; + } + total_hits += res.len(); + cprintln!("Module: {module_name}"); + let sections = pe.section_headers(); + for hit in &res { + for (idx, addr) in hit.iter().enumerate() { + let mut section_name = String::from(""); + if let Ok(section_rva) = pe.va_to_rva(*addr) { + if let Some(section) = sections.by_rva(section_rva) { + section_name = match section.name() { + Ok(name) => name.to_string(), + Err(name_bytes) => format!("{name_bytes:?}"), + }; + } else { + section_name = String::from(""); + } + }; + if let Ok(region) = region::query(addr) { + cprintln!( + "\t{}: {:?} {} [{}] {:p}", + idx, + region.as_ptr_range::<()>(), + region.protection(), + section_name, + addr + ) + } + } + } + } + cprintln!("Results: {total_hits}"); + } + Cmd::Lua(code) => { + lua::exec(code)?; + } + Cmd::Script(path) => { + for line in std::fs::read_to_string(path)?.lines() { + line.parse().and_then(|cmd: Cmd| cmd.exec())?; + } + } + other => bail!("Not implemented: {other:?}"), + } + Ok(()) + } +} diff --git a/tools/remaster/scraphacks_rs/target/.rustc_info.json b/tools/remaster/scraphacks_rs/target/.rustc_info.json new file mode 100644 index 0000000..c0733dc --- /dev/null +++ b/tools/remaster/scraphacks_rs/target/.rustc_info.json @@ -0,0 +1 @@ +{"rustc_fingerprint":18143952876974389501,"outputs":{"16636649553340150347":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Earthnuker\\scoop\\persist\\rustup-msvc\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\nfeature=\"cargo-clippy\"\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"32\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.70.0-nightly (9df3a39fb 2023-04-11)\nbinary: rustc\ncommit-hash: 9df3a39fb30575d808e70800f9fad5362aac57a2\ncommit-date: 2023-04-11\nhost: x86_64-pc-windows-msvc\nrelease: 1.70.0-nightly\nLLVM version: 16.0.2\n","stderr":""},"1185988223601034215":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Earthnuker\\scoop\\persist\\rustup-msvc\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\nfeature=\"cargo-clippy\"\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}} \ No newline at end of file diff --git a/tools/remaster/scraphacks_rs/target/CACHEDIR.TAG b/tools/remaster/scraphacks_rs/target/CACHEDIR.TAG new file mode 100644 index 0000000..20d7c31 --- /dev/null +++ b/tools/remaster/scraphacks_rs/target/CACHEDIR.TAG @@ -0,0 +1,3 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by cargo. +# For information about cache directory tags see https://bford.info/cachedir/ diff --git a/tools/remaster/scraphacks_rs/target/i686-pc-windows-msvc/CACHEDIR.TAG b/tools/remaster/scraphacks_rs/target/i686-pc-windows-msvc/CACHEDIR.TAG new file mode 100644 index 0000000..20d7c31 --- /dev/null +++ b/tools/remaster/scraphacks_rs/target/i686-pc-windows-msvc/CACHEDIR.TAG @@ -0,0 +1,3 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by cargo. +# For information about cache directory tags see https://bford.info/cachedir/