diff --git a/.gitignore b/.gitignore index c0b9891..5e7f336 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ *.sln.docstates sleuth/target/ +sleuth/old/ CMakeFiles Output diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/sleuth/CMakeLists.txt b/sleuth/CMakeLists.txt index 7413f3e..e33eccd 100644 --- a/sleuth/CMakeLists.txt +++ b/sleuth/CMakeLists.txt @@ -4,7 +4,7 @@ project(sleuthlib C) add_custom_command( OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/target/release/sleuthlib.lib - COMMAND cargo build --release + COMMAND cargo +nightly build --release WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS # ${CMAKE_CURRENT_SOURCE_DIR}/sleuthlib.rs @@ -27,18 +27,26 @@ target_link_libraries(${PROJECT_NAME}_interface INTERFACE # Native system libs required by Rust advapi32.lib + bcrypt.lib + secur32.lib cfgmgr32.lib + crypt32.lib + cryptnet.lib + dbghelp.lib gdi32.lib kernel32.lib + legacy_stdio_definitions.lib msimg32.lib msvcrtd.lib + ncrypt.lib ntdll.lib ole32.lib opengl32.lib + psapi.lib shell32.lib user32.lib userenv.lib winspool.lib + # windows.0.52.0.lib ws2_32.lib - psapi.lib ) diff --git a/sleuth/Cargo.lock b/sleuth/Cargo.lock index 33446b8..a6df69c 100644 --- a/sleuth/Cargo.lock +++ b/sleuth/Cargo.lock @@ -1,746 +1,5014 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +name = "a2s" +version = "0.5.2" +dependencies = [ + "byteorder", + "bzip2", + "crc", + "thiserror", +] [[package]] -name = "anyhow" -version = "1.0.98" +name = "ab_glyph" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] [[package]] -name = "autocfg" -version = "1.4.0" +name = "ab_glyph_rasterizer" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] -name = "bitflags" -version = "2.9.1" +name = "accesskit" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "74a4b14f3d99c1255dcba8f45621ab1a2e7540a0009652d33989005a4d0bfc6b" [[package]] -name = "byteorder" -version = "1.5.0" +name = "accesskit_consumer" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "8c17cca53c09fbd7288667b22a201274b9becaa27f0b91bf52a526db95de45e6" +dependencies = [ + "accesskit", +] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "accesskit_macos" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "cd3b6ae1eabbfbced10e840fd3fce8a93ae84f174b3e4ba892ab7bcb42e477a7" +dependencies = [ + "accesskit", + "accesskit_consumer", + "objc2 0.3.0-beta.3.patch-leaks.3", + "once_cell", +] [[package]] -name = "crc32fast" -version = "1.4.2" +name = "accesskit_unix" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "09f46c18d99ba61ad7123dd13eeb0c104436ab6af1df6a1cd8c11054ed394a08" dependencies = [ - "cfg-if", + "accesskit", + "accesskit_consumer", + "async-channel 2.3.1", + "async-once-cell", + "atspi", + "futures-lite 1.13.0", + "once_cell", + "serde", + "zbus", ] [[package]] -name = "crossbeam-channel" -version = "0.5.15" +name = "accesskit_windows" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "afcae27ec0974fc7c3b0b318783be89fd1b2e66dd702179fe600166a38ff4a0b" dependencies = [ - "crossbeam-utils", + "accesskit", + "accesskit_consumer", + "once_cell", + "paste", + "static_assertions", + "windows 0.48.0", ] [[package]] -name = "crossbeam-deque" -version = "0.8.6" +name = "accesskit_winit" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "88e39fcec2e10971e188730b7a76bab60647dacc973d4591855ebebcadfaa738" dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", + "accesskit", + "accesskit_macos", + "accesskit_unix", + "accesskit_windows", + "winit", ] [[package]] -name = "crossbeam-epoch" -version = "0.9.18" +name = "addr2line" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ - "crossbeam-utils", + "gimli", ] [[package]] -name = "crossbeam-utils" -version = "0.8.21" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "dashmap" -version = "5.5.3" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "hashbrown", - "lock_api", "once_cell", - "parking_lot_core", + "version_check", + "zerocopy", ] [[package]] -name = "derive_more" -version = "0.99.20" +name = "aho-corasick" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ - "proc-macro2", - "quote", - "syn", + "memchr", ] [[package]] -name = "either" -version = "1.15.0" +name = "android-activity" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "64529721f27c2314ced0890ce45e469574a73e5e6fdd6e9da1860eb29285f5e0" +dependencies = [ + "android-properties", + "bitflags 1.3.2", + "cc", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum 0.6.1", +] [[package]] -name = "erased-serde" -version = "0.4.6" +name = "android-properties" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" -dependencies = [ - "serde", - "typeid", -] +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" [[package]] -name = "flate2" -version = "1.1.1" +name = "android-tzdata" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" -dependencies = [ - "crc32fast", - "miniz_oxide", -] +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] -name = "futures" -version = "0.3.31" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "libc", ] [[package]] -name = "futures-channel" -version = "0.3.31" +name = "anstream" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ - "futures-core", - "futures-sink", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", ] [[package]] -name = "futures-core" -version = "0.3.31" +name = "anstyle" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] -name = "futures-executor" -version = "0.3.31" +name = "anstyle-parse" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "utf8parse", ] [[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" +name = "anstyle-query" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows-sys 0.52.0", ] [[package]] -name = "futures-scopes" -version = "0.2.0" +name = "anstyle-wincon" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdcf32827e803f1a3cd04c4319feb99156cb5968a3b393f8541efefa1e3b24c" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ - "crossbeam-channel", - "dashmap", - "futures", - "pin-project", + "anstyle", + "windows-sys 0.52.0", ] [[package]] -name = "futures-sink" -version = "0.3.31" +name = "anyhow" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] -name = "futures-task" -version = "0.3.31" +name = "arboard" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "c1df21f715862ede32a0c525ce2ca4d52626bb0007f8c18b87a384503ac33e70" +dependencies = [ + "clipboard-win", + "log", + "objc2 0.6.1", + "objc2-app-kit", + "objc2-foundation", + "parking_lot", + "percent-encoding", + "x11rb", +] [[package]] -name = "futures-util" -version = "0.3.31" +name = "arc-swap" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] -name = "hashbrown" -version = "0.14.5" +name = "arrayref" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] -name = "heck" -version = "0.4.1" +name = "arrayvec" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "iced-x86" -version = "1.21.0" +name = "async-broadcast" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" dependencies = [ - "lazy_static", + "event-listener 2.5.3", + "futures-core", ] [[package]] -name = "inventory" -version = "0.3.20" +name = "async-channel" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab08d7cd2c5897f2c949e5383ea7c7db03fb19130ffcfbf7eda795137ae3cb83" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ - "rustversion", + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", ] [[package]] -name = "itertools" -version = "0.12.1" +name = "async-channel" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ - "either", + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", ] [[package]] -name = "itoa" -version = "1.0.15" +name = "async-executor" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.3.0", + "futures-lite 2.6.0", + "pin-project-lite", + "slab", +] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "async-fs" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "blocking", + "futures-lite 1.13.0", +] [[package]] -name = "libc" -version = "0.2.172" +name = "async-global-executor" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io 2.3.3", + "async-lock 3.4.0", + "blocking", + "futures-lite 2.6.0", + "once_cell", +] [[package]] -name = "lock_api" -version = "0.4.13" +name = "async-io" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ + "async-lock 2.8.0", "autocfg", - "scopeguard", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.28", + "slab", + "socket2 0.4.10", + "waker-fn", ] [[package]] -name = "memchr" -version = "2.7.4" +name = "async-io" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock 3.4.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.6.0", + "parking", + "polling 3.7.2", + "rustix 0.38.44", + "slab", + "tracing", + "windows-sys 0.52.0", +] [[package]] -name = "miniz_oxide" -version = "0.8.8" +name = "async-lock" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "adler2", + "event-listener 2.5.3", ] [[package]] -name = "object" -version = "0.32.2" +name = "async-lock" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "flate2", - "memchr", - "ruzstd", + "event-listener 5.4.0", + "event-listener-strategy", + "pin-project-lite", ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "async-once-cell" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "4288f83726785267c6f2ef073a3d83dc3f9b81464e9f99898240cced85fce35a" [[package]] -name = "parking_lot_core" -version = "0.9.11" +name = "async-process" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", + "blocking", "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.44", + "windows-sys 0.48.0", ] [[package]] -name = "paste" -version = "1.0.15" +name = "async-recursion" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] [[package]] -name = "patternsleuth" -version = "0.1.0" -source = "git+https://github.com/trumank/patternsleuth.git?rev=5786164#5786164189604fd55f647aa38ef0bfd6f23f7d58" +name = "async-signal" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" dependencies = [ - "anyhow", - "futures", - "futures-scopes", - "iced-x86", - "inventory", - "itertools", - "libc", - "memchr", - "object", - "paste", - "patternsleuth_scanner", - "rayon", - "serde", - "strum", - "tracing", - "typetag", - "windows", + "async-io 2.3.3", + "async-lock 3.4.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.44", + "signal-hook-registry", + "slab", + "windows-sys 0.52.0", ] [[package]] -name = "patternsleuth_scanner" -version = "0.1.0" -source = "git+https://github.com/trumank/patternsleuth.git?rev=5786164#5786164189604fd55f647aa38ef0bfd6f23f7d58" +name = "async-std" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730294c1c08c2e0f85759590518f6333f0d5a0a766a27d519c1b244c3dfd8a24" dependencies = [ - "anyhow", + "async-channel 1.9.0", + "async-global-executor", + "async-io 2.3.3", + "async-lock 3.4.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 2.6.0", + "gloo-timers", + "kv-log-macro", + "log", "memchr", - "rayon", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", ] [[package]] -name = "pin-project" -version = "1.1.10" +name = "async-task" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] -name = "pin-project-internal" -version = "1.1.10" +name = "async-trait" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.101", ] [[package]] -name = "pin-project-lite" -version = "0.2.16" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "atspi" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "6059f350ab6f593ea00727b334265c4dfc7fd442ee32d264794bd9bdc68e87ca" +dependencies = [ + "atspi-common", + "atspi-connection", + "atspi-proxies", +] [[package]] -name = "proc-macro2" -version = "1.0.95" +name = "atspi-common" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "92af95f966d2431f962bc632c2e68eda7777330158bf640c4af4249349b2cdf5" dependencies = [ - "unicode-ident", + "enumflags2", + "serde", + "static_assertions", + "zbus", + "zbus_names", + "zvariant", ] [[package]] -name = "quote" -version = "1.0.40" +name = "atspi-connection" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a0c65e7d70f86d4c0e3b2d585d9bf3f979f0b19d635a336725a88d279f76b939" dependencies = [ - "proc-macro2", + "atspi-common", + "atspi-proxies", + "futures-lite 1.13.0", + "zbus", ] [[package]] -name = "rayon" -version = "1.10.0" +name = "atspi-proxies" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "6495661273703e7a229356dcbe8c8f38223d697aacfaf0e13590a9ac9977bb52" dependencies = [ - "either", - "rayon-core", + "atspi-common", + "serde", + "zbus", ] [[package]] -name = "rayon-core" -version = "1.12.1" +name = "autocfg" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] -name = "redox_syscall" -version = "0.5.12" +name = "backtrace" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ - "bitflags", + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.7.4", + "object 0.36.7", + "rustc-demangle", ] [[package]] -name = "rustversion" -version = "1.0.21" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "ruzstd" -version = "0.5.0" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" -dependencies = [ - "byteorder", - "derive_more", - "twox-hash", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "ryu" -version = "1.0.20" +name = "bitflags" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] -name = "scopeguard" -version = "1.2.0" +name = "block" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] -name = "serde" -version = "1.0.219" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "serde_derive", + "generic-array", ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "block-sys" +version = "0.1.0-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" dependencies = [ - "proc-macro2", - "quote", - "syn", + "objc-sys", ] [[package]] -name = "serde_json" -version = "1.0.140" +name = "block2" +version = "0.2.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", + "block-sys", + "objc2-encode 2.0.0-pre.2", ] [[package]] -name = "slab" -version = "0.4.9" +name = "blocking" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "sleuthlib" -version = "0.1.0" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ - "anyhow", - "futures", - "once_cell", - "paste", - "patternsleuth", - "serde", - "serde_json", - "tracing", + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite 2.6.0", + "piper", ] [[package]] -name = "smallvec" -version = "1.15.0" +name = "build_const" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] -name = "static_assertions" -version = "1.1.0" +name = "bumpalo" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] -name = "strum" -version = "0.25.0" +name = "bytemuck" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ - "strum_macros", + "bytemuck_derive", ] [[package]] -name = "strum_macros" -version = "0.25.3" +name = "bytemuck_derive" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ - "heck", "proc-macro2", "quote", - "rustversion", - "syn", + "syn 2.0.101", ] [[package]] -name = "syn" -version = "2.0.101" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "bzip2-sys", + "libc", ] [[package]] -name = "tracing" -version = "0.1.41" +name = "bzip2-sys" +version = "0.1.13+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", + "cc", + "pkg-config", ] [[package]] -name = "tracing-attributes" -version = "0.1.28" +name = "calloop" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" dependencies = [ - "proc-macro2", - "quote", - "syn", + "bitflags 1.3.2", + "log", + "nix 0.25.1", + "slotmap", + "thiserror", + "vec_map", ] [[package]] -name = "tracing-core" -version = "0.1.33" +name = "cc" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ - "once_cell", + "jobserver", + "libc", + "shlex", ] [[package]] -name = "twox-hash" -version = "1.6.3" +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" dependencies = [ - "cfg-if", - "static_assertions", + "libc", ] [[package]] -name = "typeid" -version = "1.0.3" +name = "chrono" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] [[package]] -name = "typetag" -version = "0.2.20" +name = "clap" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f22b40dd7bfe8c14230cf9702081366421890435b2d625fa92b4acc4c3de6f" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ - "erased-serde", - "inventory", - "once_cell", - "serde", - "typetag-impl", + "clap_builder", + "clap_derive", ] [[package]] -name = "typetag-impl" -version = "0.2.20" +name = "clap_builder" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35f5380909ffc31b4de4f4bdf96b877175a016aa2ca98cee39fcfd8c4d53d952" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ + "heck 0.5.0", "proc-macro2", "quote", - "syn", + "syn 2.0.101", ] [[package]] -name = "unicode-ident" -version = "1.0.18" +name = "clap_lex" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] -name = "windows" -version = "0.52.0" +name = "clipboard-win" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ - "windows-core", - "windows-targets", + "error-code", ] [[package]] -name = "windows-core" -version = "0.52.0" +name = "cocoa" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "windows-targets", + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", ] [[package]] -name = "windows-targets" -version = "0.52.0" +name = "cocoa-foundation" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" 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", + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" +name = "colorchoice" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] -name = "windows_i686_gnu" -version = "0.52.6" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] [[package]] -name = "windows_i686_msvc" -version = "0.52.6" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] [[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +dependencies = [ + "build_const", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[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 = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "destructure_traitobject" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.8", +] + +[[package]] +name = "dll_hook" +version = "0.1.0" +source = "git+https://github.com/Knutschbert/patternsleuth.git?rev=644f980#644f9804e5247fe40e4d7a1e470639601254cd70" +dependencies = [ + "anyhow", + "backtrace", + "bitflags 2.9.1", + "eframe", + "egui-winit", + "indexmap", + "itertools", + "parking_lot", + "patternsleuth", + "regex", + "retour 0.4.0-alpha.3", + "serde", + "simple-log", + "thread_local", + "widestring", + "windows 0.52.0", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "ecolor" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7637fc2e74d17e52931bac90ff4fc061ac776ada9c7fa272f24cdca5991972" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "eframe" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd73918a828c35a7efb4d7188ea973df4bffc589178ed95f521c917b03ddcfa" +dependencies = [ + "bytemuck", + "cocoa", + "egui", + "egui-winit", + "egui_glow", + "glow", + "glutin", + "glutin-winit", + "image", + "js-sys", + "log", + "objc", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "static_assertions", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winapi", + "winit", +] + +[[package]] +name = "egui" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c55bcb864b764eb889515a38b8924757657a250738ad15126637ee2df291ee6b" +dependencies = [ + "accesskit", + "ahash", + "epaint", + "log", + "nohash-hasher", +] + +[[package]] +name = "egui-winit" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b673606b6606b12b95e3a3194d7882bf5cff302db36a520b8144c7c342e4e84" +dependencies = [ + "accesskit_winit", + "arboard", + "egui", + "log", + "raw-window-handle", + "smithay-clipboard", + "web-time", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_glow" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262151f9d57c557c02a40a46f27b9e050a6eb0b006b94dced9c6f4519a04d489" +dependencies = [ + "bytemuck", + "egui", + "glow", + "log", + "memoffset 0.7.1", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "emath" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a045c6c0b44b35e98513fc1e9d183ab42881ac27caccb9fa345465601f56cce4" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enumflags2" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "epaint" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1b9e000d21bab9b535ce78f9f7745be28b3f777f6c7223936561c5c7fefab8" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "log", + "nohash-hasher", + "parking_lot", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +dependencies = [ + "serde", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener 5.4.0", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.8", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand 2.3.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "futures-scopes" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcf32827e803f1a3cd04c4319feb99156cb5968a3b393f8541efefa1e3b24c" +dependencies = [ + "crossbeam-channel", + "dashmap", + "futures", + "pin-project", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "glow" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc93b03242719b8ad39fb26ed2b01737144ce7bd4bfc7adadcef806596760fe" +dependencies = [ + "bitflags 1.3.2", + "cfg_aliases", + "cgl", + "core-foundation", + "dispatch", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading 0.7.4", + "objc2 0.3.0-beta.3.patch-leaks.3", + "once_cell", + "raw-window-handle", + "wayland-sys 0.30.1", + "windows-sys 0.45.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629a873fc04062830bfe8f97c03773bcd7b371e23bcc465d0a61448cd1588fa4" +dependencies = [ + "cfg_aliases", + "glutin", + "raw-window-handle", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af784eb26c5a68ec85391268e074f0aa618c096eadb5d6330b0911cf34fe57c5" +dependencies = [ + "gl_generator", + "windows-sys 0.45.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b53cb5fe568964aa066a3ba91eac5ecbac869fb0842cd0dc9e412434f1a1494" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef89398e90033fc6bc65e9bd42fd29bbbfd483bda5b56dc5562f455550618165" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "h2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "humantime" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.5.10", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.61.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "iced-x86" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-traits", + "png", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.4", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "inventory" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab08d7cd2c5897f2c949e5383ea7c7db03fb19130ffcfbf7eda795137ae3cb83" +dependencies = [ + "rustversion", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[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.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.52.0", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.9.1", + "libc", + "redox_syscall 0.5.12", +] + +[[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 = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +dependencies = [ + "serde", + "value-bag", +] + +[[package]] +name = "log-mdc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" + +[[package]] +name = "log4rs" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6" +dependencies = [ + "anyhow", + "arc-swap", + "chrono", + "derivative", + "flate2", + "fnv", + "humantime", + "libc", + "log", + "log-mdc", + "once_cell", + "parking_lot", + "rand 0.8.5", + "serde", + "serde-value", + "serde_json", + "serde_yaml", + "thiserror", + "thread-id", + "typemap-ors", + "winapi", +] + +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[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 = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags 1.3.2", + "jni-sys", + "ndk-sys", + "num_enum 0.5.11", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.4.1+23.1.7779620" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.2.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" + +[[package]] +name = "objc2" +version = "0.3.0-beta.3.patch-leaks.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" +dependencies = [ + "block2", + "objc-sys", + "objc2-encode 2.0.0-pre.2", +] + +[[package]] +name = "objc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +dependencies = [ + "objc2-encode 4.1.0", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-core-graphics", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.9.1", + "dispatch2", + "objc2 0.6.1", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +dependencies = [ + "bitflags 2.9.1", + "dispatch2", + "objc2 0.6.1", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-encode" +version = "2.0.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-core-foundation", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "flate2", + "memchr", + "ruzstd", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "orbclient" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +dependencies = [ + "libredox", +] + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.12", + "smallvec", + "windows-targets 0.52.0", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "patternsleuth" +version = "0.1.0" +source = "git+https://github.com/Knutschbert/patternsleuth.git?rev=644f980#644f9804e5247fe40e4d7a1e470639601254cd70" +dependencies = [ + "anyhow", + "futures", + "futures-scopes", + "iced-x86", + "inventory", + "itertools", + "libc", + "memchr", + "object 0.32.2", + "paste", + "patternsleuth_scanner", + "rayon", + "serde", + "strum", + "tracing", + "typetag", + "windows 0.52.0", +] + +[[package]] +name = "patternsleuth_scanner" +version = "0.1.0" +source = "git+https://github.com/Knutschbert/patternsleuth.git?rev=644f980#644f9804e5247fe40e4d7a1e470639601254cd70" +dependencies = [ + "anyhow", + "memchr", + "rayon", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.3.0", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.8", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.44", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[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 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "region" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" +dependencies = [ + "bitflags 1.3.2", + "libc", + "mach2", + "windows-sys 0.52.0", +] + +[[package]] +name = "reqwest" +version = "0.12.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "retour" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9af44d40e2400b44d491bfaf8eae111b09f23ac4de6e92728e79d93e699c527" +dependencies = [ + "cfg-if", + "generic-array", + "libc", + "libudis86-sys", + "mmap-fixed-fixed", + "once_cell", + "region", + "slice-pool2", +] + +[[package]] +name = "retour" +version = "0.4.0-alpha.3" +source = "git+https://github.com/Hpmason/retour-rs#02c7c4c18cf87651b30b684ac9944dd47d2593ec" +dependencies = [ + "cfg-if", + "generic-array", + "iced-x86", + "libc", + "mmap-fixed-fixed", + "once_cell", + "region", + "slice-pool2", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.37.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "ruzstd" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +dependencies = [ + "byteorder", + "derive_more", + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[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 = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.1", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simple-log" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94263a9019c994147d7dc572aa1b3bce100bbdf5b5e3a8a446a025c80ecba169" +dependencies = [ + "log", + "log4rs", + "once_cell", + "serde", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "sleuthlib" +version = "0.1.0" +dependencies = [ + "a2s", + "anyhow", + "async-std", + "bitflags 2.9.1", + "chrono", + "clap", + "dll_hook", + "futures", + "indexmap", + "log", + "log4rs", + "once_cell", + "parking_lot", + "paste", + "patternsleuth", + "rand 0.9.1", + "regex", + "reqwest", + "retour 0.3.1", + "serde", + "serde_json", + "serde_urlencoded", + "shell-words", + "simple-log", + "tracing", + "widestring", + "winapi", + "windows 0.52.0", +] + +[[package]] +name = "slice-pool2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3d689654af89bdfeba29a914ab6ac0236d382eb3b764f7454dde052f2821f8" + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "smithay-client-toolkit" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9" +dependencies = [ + "bitflags 1.3.2", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.24.3", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8" +dependencies = [ + "smithay-client-toolkit", + "wayland-client", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.101", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.1", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand 2.3.0", + "getrandom 0.3.3", + "once_cell", + "rustix 1.0.7", + "windows-sys 0.52.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "thread-id" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-skia" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adbfb5d3f3dd57a0e11d12f4f13d4ebbbc1b5c15b7ab0a156d030b21da5f677c" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio 1.0.3", + "pin-project-lite", + "socket2 0.5.10", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typemap-ors" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" +dependencies = [ + "unsafe-any-ors", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "typetag" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f22b40dd7bfe8c14230cf9702081366421890435b2d625fa92b4acc4c3de6f" +dependencies = [ + "erased-serde", + "inventory", + "once_cell", + "serde", + "typetag-impl", +] + +[[package]] +name = "typetag-impl" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35f5380909ffc31b4de4f4bdf96b877175a016aa2ca98cee39fcfd8c4d53d952" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset 0.9.1", + "tempfile", + "winapi", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unsafe-any-ors" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" +dependencies = [ + "destructure_traitobject", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "value-bag" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wayland-client" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +dependencies = [ + "bitflags 1.3.2", + "downcast-rs", + "libc", + "nix 0.24.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys 0.29.5", +] + +[[package]] +name = "wayland-commons" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +dependencies = [ + "nix 0.24.3", + "once_cell", + "smallvec", + "wayland-sys 0.29.5", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +dependencies = [ + "nix 0.24.3", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +dependencies = [ + "bitflags 1.3.2", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "wayland-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" +dependencies = [ + "dlib", + "lazy_static", + "log", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" +dependencies = [ + "core-foundation", + "home", + "jni", + "log", + "ndk-context", + "objc", + "raw-window-handle", + "url", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.52.0", +] + +[[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" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-implement 0.48.0", + "windows-interface 0.48.0", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core 0.52.0", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winit" +version = "0.28.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9596d90b45384f5281384ab204224876e8e8bf7d58366d9b795ad99aa9894b94" +dependencies = [ + "android-activity", + "bitflags 1.3.2", + "cfg_aliases", + "core-foundation", + "core-graphics", + "dispatch", + "instant", + "libc", + "log", + "mio 0.8.11", + "ndk", + "objc2 0.3.0-beta.3.patch-leaks.3", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.5", + "sctk-adwaita", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "wayland-commons", + "wayland-protocols", + "wayland-scanner", + "web-sys", + "windows-sys 0.45.0", + "x11-dl", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "gethostname", + "rustix 0.38.44", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + +[[package]] +name = "xcursor" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" + +[[package]] +name = "xdg-home" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "xml-rs" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zbus" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder", + "derivative", + "enumflags2", + "event-listener 2.5.3", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.26.4", + "once_cell", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zvariant" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] diff --git a/sleuth/Cargo.toml b/sleuth/Cargo.toml index 7a9c86b..8584e24 100644 --- a/sleuth/Cargo.toml +++ b/sleuth/Cargo.toml @@ -4,14 +4,123 @@ version = "0.1.0" edition = "2021" [lib] -crate-type = ["staticlib"] +crate-type = ["staticlib", "cdylib", "rlib"] [dependencies] -patternsleuth = { git = "https://github.com/trumank/patternsleuth.git", rev = "5786164", features = ["process-internal", "serde-resolvers", "image-pe"] } +winapi = { version = "0.3.9", features = ["winnt", "wincrypt", "winuser"] } + +patternsleuth = { git = "https://github.com/Knutschbert/patternsleuth.git", rev = "644f980", features = ["process-internal", "serde-resolvers", "image-pe"] } +dll_hook = { git = "https://github.com/Knutschbert/patternsleuth.git", rev = "644f980", package = "dll_hook" } +# patternsleuth = { path = "../../patternsleuth/patternsleuth", features = ["process-internal", "symbols", "serde-resolvers", "image-pe", "image-elf"] } +# dll_hook = { path = "../../patternsleuth/examples/dll_hook"} anyhow = "1.0.79" -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0" +# typetag = "0.2.20" tracing = "0.1.40" futures = "0.3.31" once_cell = "1.19" -paste = "1.0" \ No newline at end of file +paste = "1.0.15" +widestring = "1.0.2" +# backtrace = "0.3.69" +bitflags = "2.4.1" +# eframe = "0.24.0" +# egui-winit = { version = "0.24.0", default-features = false } +indexmap = "2.1.0" +parking_lot = "0.12.1" +simple-log = "1.6.0" +# thread_local = "1.1.7" +regex = "1.11" +chrono = "0.4.0" +log = "0.4" +log4rs = "1.3.0" +clap = { version = "4.5.0", features = ["derive"] } # cli arg parsing +shell-words = "1.1" + +retour = { version = "0.3.1", features = ["static-detour"]} +windows = { version = "0.52.0", features = ["Win32_Foundation", + "Win32_System_Console", + "Win32_System_LibraryLoader", + "Win32_System_SystemServices", + "Win32_Graphics_Gdi", + "Win32_Graphics_Direct3D", + "Win32_Graphics_Direct3D11", + "Win32_Graphics_Dxgi", + "Win32_Graphics_Dxgi_Common", + "Win32_UI_WindowsAndMessaging", + "Win32_System_Threading", + + "Win32_Security", + "Win32_System_Kernel", + "Win32_System_Memory", + "Win32_System_ProcessStatus", + ]} +rand = "0.9.1" +async-std = "1.13.1" +serde_urlencoded = "0.7" + +# Server registration +# a2s = { version = "0.5.2", optional = true } +a2s = { path = "../../a2s-rs", optional = true } +reqwest = { version = "0.12.19", optional = true, features = ["blocking", "json"] } + + +# [target."cfg(windows)".dev-dependencies.windows] +# version = "0.48" +# features = ["Win32_Foundation", +# "Win32_System_Console", "Win32_System_LibraryLoader", "Win32_System_SystemServices", +# "Win32_Graphics_Gdi", "Win32_Graphics_Direct3D", "Win32_Graphics_Direct3D11", +# "Win32_Graphics_Dxgi", "Win32_Graphics_Dxgi_Common", +# "Win32_UI_WindowsAndMessaging", +# ] + +# [target.'cfg(windows)'.dependencies] +# winapi = { version = "0.3.9", features = ["winnt", "wincrypt", "winuser"] } + +[features] +default = [ + "serde-resolvers", + "chat-commands", + "cli-commands", + "kismet-log", + "chat-log", + "chiv2", + "mirage", + #"demo", + #"syslog-client", + "rcon", + "dev", + "server-registration", + #"dev-joindata", + "object-lookup", + ] +serde-resolvers = [] +image-elf = [] +dev = [] + +# UE generic +cli-commands = [] +rcon = [] +syslog-client = [] +kismet-log = [] +demo = [] + +# Client specific +server-registration = ["dep:a2s", "dep:reqwest"] +chiv2 = [] +chat-commands = [] +chat-log = [] +mirage = [] + +# WIP +rpc-debug = [] +object-lookup = [] +dev-joindata = [] + +server = [ +# "chat-commands", + "cli-commands", +# "kismet-log", + "chat-log", + "chiv2", +] diff --git a/sleuth/src/chiv2.rs b/sleuth/src/chiv2.rs new file mode 100644 index 0000000..21249bf --- /dev/null +++ b/sleuth/src/chiv2.rs @@ -0,0 +1,76 @@ + + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[allow(clippy::upper_case_acronyms)] +pub enum EChatType { + AllSay, + TeamSay, + Whisper, + Admin, + Objective, + System, + ServerSay, + Debug, + CrosshairMsg, + Backend, + Party, + Spectator, + ClosedCaption, + ClosedCaptionMason, + ClosedCaptionAgatha, + MAX, +} + +use std::str::FromStr; + +impl FromStr for EChatType { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "AllSay" => Ok(EChatType::AllSay), + "TeamSay" => Ok(EChatType::TeamSay), + "Whisper" => Ok(EChatType::Whisper), + "Admin" => Ok(EChatType::Admin), + "Objective" => Ok(EChatType::Objective), + "System" => Ok(EChatType::System), + "ServerSay" => Ok(EChatType::ServerSay), + "Debug" => Ok(EChatType::Debug), + "CrosshairMsg" => Ok(EChatType::CrosshairMsg), + "Backend" => Ok(EChatType::Backend), + "Party" => Ok(EChatType::Party), + "Spectator" => Ok(EChatType::Spectator), + "ClosedCaption" => Ok(EChatType::ClosedCaption), + "ClosedCaptionMason" => Ok(EChatType::ClosedCaptionMason), + "ClosedCaptionAgatha" => Ok(EChatType::ClosedCaptionAgatha), + "MAX" => Ok(EChatType::MAX), + _ => Err(()), + } + } +} + +impl TryFrom for EChatType { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(EChatType::AllSay), + 1 => Ok(EChatType::TeamSay), + 2 => Ok(EChatType::Whisper), + 3 => Ok(EChatType::Admin), + 4 => Ok(EChatType::Objective), + 5 => Ok(EChatType::System), + 6 => Ok(EChatType::ServerSay), + 7 => Ok(EChatType::Debug), + 8 => Ok(EChatType::CrosshairMsg), + 9 => Ok(EChatType::Backend), + 10 => Ok(EChatType::Party), + 11 => Ok(EChatType::Spectator), + 12 => Ok(EChatType::ClosedCaption), + 13 => Ok(EChatType::ClosedCaptionMason), + 14 => Ok(EChatType::ClosedCaptionAgatha), + 15 => Ok(EChatType::MAX), + _ => Err(()), + } + } +} \ No newline at end of file diff --git a/sleuth/src/lib.rs b/sleuth/src/lib.rs index f616ece..78e404e 100644 --- a/sleuth/src/lib.rs +++ b/sleuth/src/lib.rs @@ -2,18 +2,188 @@ mod resolvers; mod scan; - -use std::env; +use std::sync::Arc; +use std::time::Duration; +use std::{env, thread}; use std::fs::File; use std::io::{BufReader, Read}; use std::io::{BufWriter, Write}; -use std::collections::HashMap; -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; +mod ue; +mod tools; +mod chiv2; use anyhow::Result; +use patternsleuth::resolvers::unreal::blueprint_library::UFunctionBind; +use patternsleuth::resolvers::unreal::*; +// use dll_hook::ue::*; +use patternsleuth::resolvers::unreal::game_loop::FEngineLoopInit; +use patternsleuth::resolvers::unreal::kismet::{FFrameStep, FFrameStepExplicitProperty, FFrameStepViaExec}; +use patternsleuth::resolvers::unreal::KismetSystemLibrary; +use patternsleuth::resolvers::unreal::{fname::FNameToString, + game_loop::UGameEngineTick, + gmalloc::GMalloc, + guobject_array::{FUObjectArrayAllocateUObjectIndex, FUObjectArrayFreeUObjectIndex, GUObjectArray} + }; +use resolvers::asset_registry::*; +use resolvers::admin_control::*; +#[cfg(feature="kismet-log")] +use resolvers::kismet_dev::*; use serde::Serialize; use serde_json::to_writer_pretty; -use self::resolvers::{PLATFORM, PlatformType}; +use tools::logger::init_syslog; +#[cfg(feature="server-registration")] +use tools::registration::Registration; +// use tools::server_registration::Registration; +use windows::core::PCSTR; +use windows::Win32::System::Console::SetConsoleTitleA; +use self::resolvers::{PLATFORM, BASE_ADDR, PlatformType}; + +use log::info; +use clap::{command, CommandFactory, Parser, Subcommand}; + +pub static TEST_INTRO: &str = "\x1b[38;5;228m\ +\ +▄████████ ▄█ █▄ ▄█ ▄█ █▄ ▄████████ ▄█ ▄████████ ▄██ ▄ ▄█ ▄█ \r\n\ +███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ██▄ ███ ███ \r\n\ +███ █▀ ███ ███ ███▌ ███ ███ ███ ███ ███ ███ ███ ███▄▄▄███ ███▌ ███▌\r\n\ +███ ▄███▄▄▄▄███▄▄ ███▌ ███ ███ ███ ███ ███ ▄███▄▄▄▄██▀ ▀▀▀▀▀▀███ ███▌ ███▌\r\n\ +███ ▀▀███▀▀▀▀███▀ ███▌ ███ ███ ▀███████████ ███ ▀▀███▀▀▀▀▀ ▄██ ███ ███▌ ███▌\r\n\ +███ █▄ ███ ███ ███ ███ ███ ███ ███ ███ ▀███████████ ███ ███ ███ ███ \r\n\ +███ ███ ███ ███ ███ ███ ███ ███ ███ ███▌ ▄ ███ ███ ███ ███ ███ ███ \r\n\ +████████▀ ███ █▀ █▀ ▀██████▀ ███ █▀ █████▄▄██ ███ ███ ▀█████▀ █▀ █▀ \r\n\ + ▀ ███ ███ \r\n\ +\x1b[38;5;1m███ █▄ ███▄▄▄▄ ▄████████ ▄█ █▄ ▄████████ ▄█ ███▄▄▄▄ ▄████████ ████████▄ \r\n\ +███ ███ ███▀▀▀██▄ ███ ███ ███ ███ ███ ███ ███ ███▀▀▀██▄ ███ ███ ███ ▀███ \r\n\ +███ ███ ███ ███ ███ █▀ ███ ███ ███ ███ ███▌ ███ ███ ███ █▀ ███ ███ \r\n\ +███ ███ ███ ███ ███ ▄███▄▄▄▄███▄▄ ███ ███ ███▌ ███ ███ ▄███▄▄▄ ███ ███ \r\n\ +███ ███ ███ ███ ███ ▀▀███▀▀▀▀███▀ ▀███████████ ███▌ ███ ███ ▀▀███▀▀▀ ███ ███ \r\n\ +███ ███ ███ ███ ███ █▄ ███ ███ ███ ███ ███ ███ ███ ███ █▄ ███ ███ \r\n\ +███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ▄███ \r\n\ +████████▀ ▀█ █▀ ████████▀ ███ █▀ ███ █▀ █▀ ▀█ █▀ ██████████ ████████▀ \r\n\ +\x1b[38;5;255m \r\n\ + "; + +pub static TEST_INTRO3: &str = "\ +| █ \r\n\ +| ███████ \r\n\ +| ██ ███ \r\n\ +| ███ █████ ██ \r\n\ +| █████ █ █████ \r\n\ +| ████████ ███████ \r\n\ +| ███████████ ███ ██ \r\n\ +| █████████████ ███ ███\r\n\ +| ██ ███ █████ \r\n\ +| ██ ████ █ \r\n\ +| ███ ████████ ██ \r\n\ +| ██████████ █████████ \r\n\ +| ██████ ████████ \r\n\ +| █████ █████ \r\n\ +| ███████████ \r\n\ +| ███████ ██ \r\n\ +| ██ █ █ \r\n\ +"; + +// pub static test: &str = "\x1b[38;5;196m▄\x1b[0m\x1b[38;5;202m█\x1b[0m\x1b[38;5;226m█\x1b[0m\x1b[38;5;46m█\x1b[0m\x1b[38;5;21m█\x1b[0m\x1b[38;5;93m█\x1b[0m\x1b[38;5;201m█\x1b[0m\x1b[38;5;196m█\x1b[0m\x1b[38;5;202m█\x1b[0m \x1b[38;5;226m▄\x1b[0m\x1b[38;5;46m█\x1b[0m \x1b[38;5;21m█\x1b[0m\x1b[38;5;93m▄\x1b[0m \x1b[38;5;201m▄\x1b[0m\x1b[38;5;196m█\x1b[0m \x1b[38;5;202m▄\x1b[0m\x1b[38;5;226m█\x1b[0m \x1b[38;5;46m█\x1b[0m\x1b[38;5;21m▄\x1b[0m \x1b[38;5;93m▄\x1b[0m\x1b[38;5;201m█\x1b[0m\x1b[38;5;196m█\x1b[0m\x1b[38;5;202m█\x1b[0m\x1b[38;5;226m█\x1b[0m\x1b[38;5;46m█\x1b[0m\x1b[38;5;21m█\x1b[0m\x1b[38;5;93m█\x1b[0m\x1b[38;5;201m█\x1b[0m \x1b[38;5;196m▄\x1b[0m\x1b[38;5;202m█\x1b[0m \x1b[38;5;226m▄\x1b[0m\x1b[38;5;46m█\x1b[0m\x1b[38;5;21m█\x1b[0m\x1b[38;5;93m█\x1b[0m\x1b[38;5;201m█\x1b[0m\x1b[38;5;196m█\x1b[0m\x1b[38;5;202m█\x1b[0m\x1b[38;5;226m█\x1b[0m\x1b[38;5;46m█\x1b[0m \x1b[38;5;21m▄\x1b[0m\x1b[38;5;93m█\x1b[0m\x1b[38;5;201m█\x1b[0m \x1b[38;5;196m▄\x1b[0m \x1b[38;5;202m▄\x1b[0m\x1b[38;5;226m█\x1b[0m \x1b[38;5;46m▄\x1b[0m\x1b[38;5;21m█\x1b[0m\n\x1b[38;5;93m█\x1b[0m\x1b[38;5;201m█\x1b[0m\x1b[38;5;196m█\x1b[0m \x1b[38;5;202m█\x1b[0m\x1b[38;5;226m█\x1b[0m\x1b[38;5;46m█\x1b[0m \x1b[38;5;21m█\x1b[0m\x1b[38;5;93m█\x1b[0m\x1b[38;5;201m█\x1b[0m \x1b[38;5;196m█\x1b[0m\x1b[38;5;202m█\x1b[0m\x1b[38;5;226m█\x1b[0m \x1b[38;5;46m█\x1b"; + + +// CLI args +#[derive(Debug, Subcommand)] +enum Commands { + #[allow(clippy::upper_case_acronyms)] + TBL, + #[allow(clippy::upper_case_acronyms)] + NONE, +} +// #[derive(Parser, Debug)] +// #[command(name = "Chivalry 2 Unchained", version = "1.0", author = "Unchained Team")] +#[derive(Parser, Debug)] +#[command(name = "Chivalry 2 Unchained", author = "Unchained Team", version, about, long_about = None)] +// FIXME: possible to skip unhandled args? +struct CLIArgs { + // #[arg()] + // positional_args: Vec, + // #[arg()] + // game_id: String, + + #[arg(long = "next-map-mod-actors", value_delimiter = ',', required = false)] + next_mod_actors: Option>, + + #[arg(long = "all-mod-actors", value_delimiter = ',', required = false)] + mod_paks: Option>, + + #[arg(long = "unchained")] + is_unchained: bool, + // + #[arg(long = "rcon")] + rcon_port: Option, + // // + #[arg(long = "desync-patch")] + apply_desync_patch: bool, + // + #[arg(long = "use-backend-banlist")] + use_backend_banlist: bool, + // + #[arg(long = "nullrhi")] + is_headless: bool, + // + #[arg(long = "next-map-name")] + next_map: Option, + // + #[arg(long = "launched-profile")] + launched_profile: Option, + // + #[arg(long = "playable-listen")] + playable_listen: bool, + // + #[arg(long = "register")] + register: bool, + // // + #[arg(long = "server-browser-backend", default_value="https://servers.polehammer.net")] + server_browser_backend: Option, + // // + #[arg(long = "server-password")] + server_password: Option, + // s + #[arg(long = "platform")] + platform: Option, + + #[arg(long = "GameServerPingPort", default_value="3075")] + game_server_ping_port: Option, + + #[arg(long = "GameServerQueryPort", default_value="7071")] + game_server_query_port: Option, + + #[arg(long = "Port", default_value="7777")] + game_port: Option, + + + // UNHANDLED START + // #[arg(long = "AUTH_LOGIN")] + // auth_login: Option, + // #[arg(long = "AUTH_PASSWORD")] + // auth_password: Option, + // #[arg(long = "AUTH_TYPE")] + // auth_type: Option, + // #[arg(long = "epicapp")] + // epicapp: Option, + // #[arg(long = "epicenv")] + // epicenv: Option, + // #[arg(long = "EpicPortal")] + // epic_portal: bool, + // #[arg(long = "epicusername")] + // epicusername: Option, + // #[arg(long = "epicuserid")] + // epicuserid: Option, + // #[arg(long = "epiclocale")] + // epiclocale: Option, + // #[arg(long = "epicsandboxid")] + // epicsandboxid: Option, + // UNHANDLED END + + #[arg(trailing_var_arg = true)] + pub extra_args: Vec, +} // IEEE use std::arch::x86_64::_mm_crc32_u8; @@ -47,7 +217,7 @@ struct BuildInfo { name: String, platform: String, path: String, - offsets: HashMap, + offsets: HashMap, } fn expand_env_path(path: &str) -> Option { @@ -59,23 +229,32 @@ fn expand_env_path(path: &str) -> Option { None } -pub fn dump_builds(offsets: HashMap) -> Result<()> { +pub fn dump_builds() -> Result<()> { let builds_path = expand_env_path(r"%LOCALAPPDATA%\Chivalry 2\Saved\Config\c2uc.builds.json").unwrap().to_path_buf(); - println!("JSON PATH {}", builds_path.to_string_lossy()); + // println!("JSON PATH {}", builds_path.to_string_lossy()); let file = File::create(builds_path)?; let mut writer = BufWriter::new(file); let mut data = HashMap::new(); - let mut file_path = String::new(); + // let mut file_path = String::new(); - match env::current_exe() { - Ok(path) => file_path = path.to_string_lossy().into(), - Err(e) => eprintln!("Failed to get path: {}", e), - } - println!("Current executable path: {:?}", file_path); + let offsets = crate::scan::OFFSETS.get().unwrap(); + let base_addr = BASE_ADDR.get().unwrap(); + + let file_path: String = env::current_exe().unwrap().to_string_lossy().into(); + + // match env::current_exe() { + // Ok(path) => file_path = path.to_string_lossy().into(), + // Err(e) => eprintln!("Failed to get path: {}", e), + // } + // println!("Current executable path: {:?}", file_path); let crc32 = unsafe { crc32_from_file(&file_path) }.expect("Failed to compute CRC"); + let base_offsets: HashMap = offsets + .iter() + .map(|(k, v)| (k.clone(), v - base_addr)) + .collect(); let build_info = BuildInfo { build: 0, @@ -83,7 +262,7 @@ pub fn dump_builds(offsets: HashMap) -> Result<()> { name: "".to_string(), platform: PLATFORM.get().ok_or("OTHER").unwrap().to_string(),//platform.to_string(), path: file_path.to_string(), - offsets, + offsets: base_offsets, }; data.insert(crc32.to_string(), build_info); @@ -93,19 +272,479 @@ pub fn dump_builds(offsets: HashMap) -> Result<()> { Ok(()) } -#[no_mangle] -pub extern "C" fn generate_json() -> u8 { - println!("test asd"); + + + + +pub unsafe fn attach_hooks(base_address: usize, offsets: HashMap) -> Result<(), Box> { + + // attach_GameEngineTick(base_address, offsets).unwrap(); + info!("Attaching hooks:"); + + let mut hooks_new = attach_hooks_list![[ + UGameEngineTick, + ExecuteConsoleCommand, + #[cfg(feature="engine_loop")] + FEngineLoopInit, + ClientMessage, + StaticFindObjectSafe, + #[cfg(feature="kismet-log")] + KismetExecutionMessage, + ]]; + + // Misc hooks + #[cfg(feature="dev")] + hooks_new.extend(attach_hooks_list![[ + ClientTravelToSession, + ClientTravelInternal, + #[cfg(feature="rpc-debug")] + LogReliableRPC, + #[cfg(feature="rpc-debug")] + LogReliableRPCFailed, + #[cfg(feature="demo")] + SomeRandomFunction, + #[cfg(feature = "dev-joindata")] + JoinData, + JoinDataTwo, + MatchUpdate, + // GetStageTimeRemaining, + SetMatchState, + LogFImpl, + Log2, + GetAssetRegistry, + Conv_InterfaceToObject, + GetAssetsByClass, + GetAssetRegistry_Helper, + FNamePool, + FNameCtorWchar, + GetAsset, + // LogFImpl2, + // ShowSusMessage, + // JoinDataFour + ]]); + + // use crate::resolvers::macros; + hooks_new.iter().for_each(|(s, f)| { + match (f)(base_address, offsets.clone()) { + Ok(_) => { + sinfo![f; "☑ {} ", s] + }, + Err(e) => { + // sdebug!(file, f;"☐ {}: {}", s.to_uppercase(), e); + // strace!(file, f, line;"☐ {}: {}", s.to_uppercase(), e); + // swarn!(file, f, line;"☐ {}: {}", s.to_uppercase(), e); + // sinfo!(file, func, line, mod;"☐ {}: {}", s.to_uppercase(), e); + // serror!(file, func, line, column;"☐ {}: {}", s.to_uppercase(), e); + // debug_where!(); +// console -> [23:54:45 ERROR] [attach_hooks] ☐ SOMERANDOMFUNCTION: No address found. +// file -> [2025-06-09 23:54:45 13116 ERROR | function ] [attach_hooks] ☐ SOMERANDOMFUNCTION: No address found. + +// console -> [23:54:45 ERROR] [src\lib.rs|sleuthlib::attach_hooks::{{closure}}|L317|C17] ☐ SOMERANDOMFUNCTION: No address found. +// file -> [2025-06-09 23:54:45 13116 ERROR | function ] [src\lib.rs|sleuthlib::attach_hooks::{{closure}}|L317|C17] ☐ SOMERANDOMFUNCTION: No address found. + + // error!("☐ {}: {}", s.to_uppercase(), e); + serror!(f; "☐ {}: {}", s.to_uppercase(), e); + // serror!(file, func, line, column;"☐ {}: {}", s.to_uppercase(), e); + }, + } + }); + + // resolvers::admin_control::attach_UGameEngineTick(base_address, offsets.clone()).unwrap(); + // resolvers::admin_control::attach_ExecuteConsoleCommand(base_address, offsets.clone()).unwrap(); + // resolvers::admin_control::attach_FEngineLoopInit(base_address, offsets.clone()).unwrap(); + // resolvers::admin_control::attach_ClientMessage(base_address, offsets.clone()).unwrap(); + Ok(()) + } + +// We're using a mix of cli arg types, normalize them to --key value(s) +// e.g. -rcon 9001, -epicsomething=blablabla, Port=7777 +// This function converts all of those to --convention. It also drops game_identifier +// To parse it all with clap, it checks against entries in CLIArgs and filters out unhandled ones +fn normalize_and_filter_args>(args: I) -> Vec { + let mut args = args.into_iter(); + let bin_name = args.next().unwrap_or_else(|| "app".to_string()); + + let known_flags: Vec = CLIArgs::command() + .get_arguments() + .filter_map(|a| a.get_long().map(|s| format!("--{s}"))) + .collect(); + + let mut result = vec![bin_name]; + let mut args = args.peekable(); + let mut last_flag: Option = None; + let mut last_opt: Option = None; + + + while let Some(arg) = args.next() { + // println!("-- LINE: {arg}"); + // Normalize `key=value` and `-flag` → `--flag` + let (flag, value_opt): (String, Option) = + if let Some((k, v)) = arg.split_once('=') { + // println!("{} Split by =", arg); + println!("k '{}' , v '{}' ", k, v); + (format!("--{}", k.trim_start_matches('-')), Some(v.to_string())) + } else if arg.starts_with('-') && !arg.starts_with("--") && arg.len() > 2 { + // println!("{} Split by -", arg); + (format!("--{}", &arg[1..]), None) + } else { + // println!("{} Split by else", arg); + (arg.clone(), None) + }; + + // println!("cur: '{flag}'"); + let cur_flag = flag.clone(); + if known_flags.contains(&flag) { + result.push(flag.trim().to_string()); + if let Some(v) = value_opt { + // println!("option: '{v}'"); + last_opt = Some(v.clone()); + result.push(v.trim().to_string()); + } + else if let Some(peek) = args.peek() { + if !peek.starts_with('-') { + let var = args.next().unwrap(); + // print!("pushing '{var}'"); + result.push(var.trim().to_string()); + } + } + } + // args can split an option (e.g. --name Not Sure) + else if !result.is_empty() && !flag.starts_with('-') { + let last_valid = result.last().unwrap(); + if last_flag.is_some() { + // println!("Last '{last}' last valid '{last_valid}'"); + if let Some(o) = &last_opt { + // println!("Last '{}' last valid {} last option '{}' equal: {}", last, last_valid, o, o == last_valid); + // println!("Res: {} Trailing string {}, last flag {}, last result {}",result.len(), flag, last, last_valid); + if o == last_valid { + if let Some(last_mut) = result.last_mut() { + if (cur_flag.len() > 0) + { + // println!("Trailing '{cur_flag}'"); + last_mut.push(' '); + last_mut.push_str(&cur_flag.trim().to_string()); + + } + // last_mut = last_mut.trim().to_string(); + } + } + } + } + } + last_flag = Some(cur_flag); + } + + println!("Res: {:?}", result); + result +} + +unsafe fn load_cli() -> Result { + let args = std::env::args(); + let parsed = normalize_and_filter_args(args); + println!("Pre-Parsed CLI: {:#?}", parsed); + let cli = CLIArgs::try_parse_from(parsed).expect("Failed to parse CLI atgs"); + Ok(cli) +} +unsafe fn init_globals() -> Result<(), clap::error::Error>{ let platform = match env::args().any(|arg| arg == "-epicapp=Peppermint") { true => PlatformType::EGS, false => PlatformType::STEAM }; - + + let exe = patternsleuth::process::internal::read_image().map_err(|e| e.to_string()).expect("failed to read image"); + // FIXME: replace old references PLATFORM.set(platform).expect("Platform already set"); + BASE_ADDR.set(exe.base_address).expect("BASE_ADDR already set"); + // debug!("Platform: {} base_addr: '0x{:x?}'", platform, exe.base_address); + + // Load CLI ARGS + let args = load_cli().expect("Failed to load CLI ARGS"); + let resolution = exe.resolve(DllHookResolution::resolver()).unwrap(); + + // println!("results: {:?}", resolution); + let guobject_array: &'static ue::FUObjectArray = + &*(resolution.guobject_array.0 as *const ue::FUObjectArray); + + + GLOBALS = Some(Globals { + guobject_array: guobject_array.into(), + resolution, + main_thread_id: std::thread::current().id(), + // last_command: None, + base_address: exe.base_address, + is_server: false, + cli_args: args, + platform + }); + sdebug!(f; "{GLOBALS:#?}"); + Ok(()) +} + + - let offsets = scan::scan().expect("Failed to scan"); +// █: 743 +// ▀: 67 +// ▄: 66 +// r: 18 +// n: 18 +// ▌: 13 +#[allow(dead_code)] +fn intro() { + let mut color_index = 16; + let max_color = 231; + for line in TEST_INTRO.lines() { + for ch in line.chars() { + let color = format!("\x1b[38;5;{color_index}m"); + print!("{color}{ch}\x1b[0m"); + + color_index += 1; + if color_index > max_color { + color_index = 16; + } + thread::sleep(Duration::from_micros(20)); + } + println!(); // new line + } +} + +// https://stackoverflow.com/questions/38088067/equivalent-of-func-or-function-in-rust +// https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=df5975cd589ae7286a769e1c70e7715d +// #[allow(unused_macros)] +// macro_rules! function { +// () => {{ +// fn f() {} +// fn type_name_of(_: T) -> &'static str { +// std::any::type_name::() +// } +// let name = type_name_of(f); +// &name[..name.len() - 3] +// }} +// } +// define_pocess! +use tools::memtools::*; +#[no_mangle] +pub extern "C" fn generate_json() -> u8 { + // intro(); + // thread::sleep(Duration::from_secs(10)); + print!("{TEST_INTRO}"); + println!(); + init_syslog().expect("Failed to init syslog"); + unsafe { + match init_globals() { + Ok(_) => { + // swarn!("{:#?}", globals().cli_args) + }, + Err(e) => serror!(f; "No globals: {}", e), + } + }; + + + unsafe { + let mut title_pcstr = PCSTR("Chivalry 2 Unchained\0".to_string().as_ptr() as _); + + if let Some(profile_name) = &globals().cli_args.launched_profile { + let title = format!("Chivalry 2 Unchained - {}\0", profile_name); + title_pcstr = PCSTR(title.as_ptr() as _); + } + + match SetConsoleTitleA(title_pcstr) { + Ok(_) => {}, + Err(e) => serror!(f; "Failed to set title {e}"), + } + } + + #[cfg(feature="rcon")] + std::thread::spawn(|| { + resolvers::rcon::handle_rcon(); + }); + + // (|| { + // mod module { + // pub trait Trait { + // fn function(&self) { + // println!("{} (in {} [{}:{}:{}])", + // function!(), module_path!(), file!(), line!(), column!() + // ); + // } + // } + // impl Trait for () {} + // } + // module::Trait::function(&()); + // })(); + + // Init syslog + // info!("Info blabla"); + // warn!("Warning! ‼"); + // debug!("DEBUG MESSAGE"); + // error!("ERRROR "); + + // PLATFORM.set(platform).expect("Platform already set"); + let exe = patternsleuth::process::internal::read_image().map_err(|e| e.to_string()).expect("failed to read image"); + + let mut offsets = scan::scan().expect("Failed to scan"); let len_u8 = offsets.len() as u8; - dump_builds(offsets).expect("Failed to dump builds JSON"); + let addr_temp = *globals().resolution.kismet_system_library.0.get("Conv_InterfaceToObject").unwrap() - exe.base_address; + offsets.insert("Conv_InterfaceToObject".to_string(), addr_temp as u64); + // FIXME: Nihi: ? + unsafe { + attach_hooks(exe.base_address, offsets.clone()).unwrap(); + } + dump_builds().expect("Failed to dump builds JSON"); + + sinfo!("trying to patch"); + // 19626AE + 0xF = 19626BD + // #[cfg(feature="skip_msg")] + match offsets.get("ShowSusMessage") { + Some(a) => { //FIXME: Nihi: <- usize or u64 or *mut u8 + + // let addr = exe.base_address + 0x19626BD; // *a as usize;// + 0xF; + let extra = match globals().get_platform() { + PlatformType::EGS => 0xE, + PlatformType::STEAM => 0xF, + PlatformType::XBOX => todo!(), + PlatformType::OTHER => todo!(), + }; + swarn!(f; "Offset: 0x{:X?}", extra); + let addr = exe.base_address + *a as usize + extra;// + 0xF; + swarn!(f; "sus: {:X?} {:X?}", a-exe.base_address as u64, a, ); + swarn!(f; "an addr: {:X?}", *a as usize ); + swarn!(f; "a base: {:X?}", *a as usize + extra); + unsafe { nop(addr as *mut u8, 5) }; + // unsafe { nop(addr as *mut u8, 5) }; + swarn!(f; "Patched the function {:X?} {:X?}", addr, addr - exe.base_address); + swarn!(f; "Patchessthe function {:X?} {:X?}", a, a - exe.base_address as u64); + }, + None => serror!(f; "No address to patch"), + } + + #[cfg(feature="cli-commands")] + std::thread::spawn(|| { + resolvers::rcon::handle_cmd(); + }); + + + #[cfg(feature="server-registration")] + if globals().cli_args.rcon_port.is_some() || + globals().cli_args.register { // FIXME: Nihi: better way than checking for rcon port. Listen? + let cli = globals().args(); + // sinfo!(f; "cli: {cli:?}"); + + let backend = cli.server_browser_backend.clone().unwrap(); + let reg = Arc::new(Registration::new( + "127.0.0.1", + globals().cli_args.game_server_query_port.unwrap() + )); + + // let last_info = std::sync::Arc::clone(&tools::server_registration::REGISTRATION); + // *last_info.lock().unwrap() = Some(reg); + sinfo!(f; "Started server registration"); + // (&backend); + reg.start(); + // let registration = std::sync::Arc::new(reg); + // registration.start_heartbeat(&backend, "Some Server", ""); + info!("Backend: {backend}"); + // std::thread::spawn(|| { + // }); + + } + sinfo!("Generate_json done"); len_u8 } + +patternsleuth::_impl_try_collector! { + #[derive(Debug, PartialEq, Clone)] + struct DllHookResolution { + gmalloc: GMalloc, + guobject_array: GUObjectArray, + fnametostring: FNameToString, + allocate_uobject: FUObjectArrayAllocateUObjectIndex, + free_uobject: FUObjectArrayFreeUObjectIndex, + game_tick: UGameEngineTick, + engine_loop_init: FEngineLoopInit, + kismet_system_library: KismetSystemLibrary, + fframe_step_via_exec: FFrameStepViaExec, + fframe_step: FFrameStep, + fframe_step_explicit_property: FFrameStepExplicitProperty, + // fframe_kismet_execution_message: FFrameKismetExecutionMessage, + ufunction_bind: UFunctionBind, + uobject_base_utility_get_path_name: UObjectBaseUtilityGetPathName, + } +} + + +use serde::{Serializer, Deserialize, Deserializer}; + +// Stubs to disable unimplemented err +impl Serialize for DllHookResolution { + fn serialize(&self, _serializer: S) -> Result + where S: Serializer, { todo!("Serialization not implemented") } +} +impl<'de> Deserialize<'de> for DllHookResolution { + fn deserialize(_deserializer: D) -> Result + where D: Deserializer<'de>, { todo!("Deserialization not implemented") } +} + + +// Globals impl from dll_hook example +// used by ue.rs + +static mut GLOBALS: Option = None; +#[derive(Debug)] +pub struct Globals { + resolution: DllHookResolution, + guobject_array: parking_lot::FairMutex<&'static ue::FUObjectArray>, + #[allow(dead_code)] + main_thread_id: std::thread::ThreadId, + // last_command: Option, + platform: PlatformType, + base_address: usize, + is_server: bool, + cli_args: CLIArgs, +} + +impl Globals { + pub fn gmalloc(&self) -> &ue::FMalloc { + unsafe { &**(self.resolution.gmalloc.0 as *const *const ue::FMalloc) } + } + pub fn fframe_step(&self) -> ue::FnFFrameStep { + unsafe { std::mem::transmute(self.resolution.fframe_step.0) } + } + pub fn fframe_step_explicit_property(&self) -> ue::FnFFrameStepExplicitProperty { + unsafe { std::mem::transmute(self.resolution.fframe_step_explicit_property.0) } + } + pub fn fname_to_string(&self) -> ue::FnFNameToString { + unsafe { std::mem::transmute(self.resolution.fnametostring.0) } + } + pub fn uobject_base_utility_get_path_name(&self) -> ue::FnUObjectBaseUtilityGetPathName { + unsafe { std::mem::transmute(self.resolution.uobject_base_utility_get_path_name.0) } + } + pub fn guobject_array(&self) -> parking_lot::FairMutexGuard<'static, &ue::FUObjectArray> { + self.guobject_array.lock() + } + pub unsafe fn guobject_array_unchecked(&self) -> &ue::FUObjectArray { + *self.guobject_array.data_ptr() + } + + pub fn get_platform(&self) -> PlatformType { + self.platform + } + + pub fn get_base_address(&self) -> usize { + self.base_address + } + + pub fn is_server(&self) -> bool { + self.is_server + } + + fn args(&self) -> &CLIArgs { + &self.cli_args + } +} + +// FIXME: Nihi: ? +#[allow(static_mut_refs)] +pub fn globals() -> &'static Globals { + unsafe { GLOBALS.as_ref().unwrap() } +} \ No newline at end of file diff --git a/sleuth/src/resolvers/admin_control.rs b/sleuth/src/resolvers/admin_control.rs index 5fbe97a..34aa5b6 100644 --- a/sleuth/src/resolvers/admin_control.rs +++ b/sleuth/src/resolvers/admin_control.rs @@ -1,5 +1,14 @@ +use client_message::parse_chat_line; +use log::{debug, info, warn}; +use std::sync::Arc; +use std::os::raw::c_void; +use crate::resolvers::rcon::LAST_COMMAND; +use crate::chiv2::*; +use crate::serror; +use crate::ue::*; + define_pattern_resolver![UTBLLocalPlayer_Exec, { // "75 18 ?? ?? ?? ?? 75 12 4d 85 f6 74 0d 41 38 be ?? ?? ?? ?? 74 04 32 db eb 9b 48 8b 5d 7f 49 8b d5 4c 8b 45 77 4c 8b cb 49 8b cf", // EGS - latest // "75 17 45 84 ED", // STEAM @@ -13,6 +22,39 @@ define_pattern_resolver!(ExecuteConsoleCommand, [ "40 53 48 83 EC 30 48 8B 05 ?? ?? ?? ?? 48 8B D9 48 8B 90 58 0C 00 00" ]); +// FIXME: Nihi: stub +CREATE_HOOK!(ExecuteConsoleCommand, (string:*mut FString), { + println!("ExecuteConsoleCommand: {}", unsafe { &*string }); +}); + +#[cfg(feature="demo")] +CREATE_HOOK!(SomeRandomFunction, c_void, (string:*mut FString), { + println!("SomeRandomFunction: {}", unsafe { &*string }); +}); + +// Executes pending RCON command +CREATE_HOOK!(UGameEngineTick, (engine:*mut c_void, delta:f32, state:u8), { + let lock = Arc::clone(&crate::resolvers::rcon::LAST_COMMAND); + let mut fstring = FString::default(); + if let Some(cmd) = crate::resolvers::rcon::LAST_COMMAND.lock().unwrap().as_ref() { + fstring = FString::from( + widestring::U16CString::from_str(cmd.as_str()) + .unwrap() + .as_slice_with_nul()); + } + + if fstring.len() > 1 { + warn!("Executing Command: {fstring}"); + *lock.lock().unwrap() = None; + unsafe { o_ExecuteConsoleCommand.call(&mut fstring); } + } +}); + +// FIXME: Nihi: stub +CREATE_HOOK!(FEngineLoopInit, (engine_loop:*mut c_void), { +// println!("Engine Loop initialized!!"); +}); + // FText* __cdecl FText::AsCultureInvariant(FText* __return_storage_ptr__, FString* param_1) define_pattern_resolver![FText_AsCultureInvariant, First, { EGS: ["48 89 5C 24 18 48 89 74 24 20 41 56 48 83 EC 60 33 C0 48 89 7C 24 78 48 63"], @@ -42,6 +84,340 @@ define_pattern_resolver![GetTBLGameMode, { OTHER : ["40 53 48 83 EC 20 48 8B D9 48 85 C9 74 60 48 8B 01 FF 90 ?? ?? ?? ?? 48 85 C0 75 23 0F 1F 40 00 48 8B 5B 20 48 85 DB 74 11 48 8B 03 48 8B CB FF 90 ?? ?? ?? ?? 48 85 C0 74 E6 48 85 C0 74 2F 48 8B 98 28"] }]; + +// https://github.com/trumank/unrealsdk/blob/d121ba258e6751d5fa522aa9b803aaa0ea59fec7/src/unrealsdk/game/bl3/object.cpp#L122 +// "48 89 5C 24 ??" // mov [rsp+08], rbx +// "48 89 6C 24 ??" // mov [rsp+10], rbp +// "48 89 74 24 ??" // mov [rsp+18], rsi +// "57" // push rdi +// "48 83 EC 30" // sub rsp, 30 +// "80 3D ???????? 00" // cmp byte ptr [Borderlands3.exe+69EAA10], 00 +// Handle Game chat: commands, chat log, system messages +#[cfg(feature="object-lookup")] +define_pattern_resolver!(StaticFindObjectSafe, [ + "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 80 3D ?? ?? ?? ?? 00 41 0F B6 D9 49 8B F8 48 8B", + // "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 80 3D ?? ?? ?? ?? 00" +]); +// UObject * __cdecl StaticFindObjectSafe(UClass.conflict *param_1,UObject *param_2,wchar_t *param_3,bool param_4) +// UObject* StaticFindObjectSafe( UClass* ObjectClass, UObject* ObjectParent, const TCHAR* InName, bool bExactClass ) +#[cfg(feature="object-lookup")] +CREATE_HOOK!(StaticFindObjectSafe, *mut UObject, (ObjectClass:*mut UClass, ObjectParent:*mut UObject, InName:*mut u16, bExactClass: bool), { + if !InName.is_null() { + unsafe { + let reference = &*InName; + // Now you can use `reference` safely + let mut class_str = "".to_string(); + let mut parent_str = "".to_string(); + // FIXME: Oh god + if !ObjectClass.is_null() { + // crate::sinfo!(f; "ObjectClass {}", (&*ObjectClass).ustruct.ufield.uobject.uobject_base_utility.uobject_base.name_private); + class_str = (&*ObjectClass).ustruct.ufield.uobject.uobject_base_utility.uobject_base.name_private.to_string(); + } + if !ObjectParent.is_null() { + // crate::sinfo!(f; "ObjectParent {}", (&*ObjectParent).uobject_base_utility.uobject_base.name_private); + parent_str = (&*ObjectParent).uobject_base_utility.uobject_base.name_private.to_string(); + } + + crate::sinfo!(f; "Exact? {} '{}' '{}' '{}'", + // (&*ObjectClass).ustruct.ufield.uobject.uobject_base_utility.uobject_base.name_private, + // (&*ObjectParent).uobject_base_utility.uobject_base.name_private, + bExactClass, + class_str, + parent_str, + widestring::U16CString::from_ptr_str(InName).display(), + ); + } + } +}); + + +mod client_message { + + use regex::Regex; + + use crate::chiv2::EChatType; + + + #[derive(Debug)] + pub struct ChatMessage<'a> { + pub name: &'a str, + pub channel: u32, + pub message: &'a str, + } + + pub fn parse_chat_line(line: &str) -> Option { + static RE: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| { + Regex::new(r"^(\w+)\s+\w+\s+<(\d+)>:\s+(.*)$").unwrap() + }); + + RE.captures(line).map(|caps| ChatMessage { + name: caps.get(1).unwrap().as_str(), + channel: caps.get(2).unwrap().as_str().parse().ok().unwrap(), + message: caps.get(3).unwrap().as_str(), + }) + } + + pub fn parse_msg_line(line: &str) -> Option<(EChatType, &str)> { + // "<8>: FACTION NOT VALID" + // warn!("LINE: '{line}'"); + let re = Regex::new(r#"<(\d+)>: (.+)"#).unwrap(); + // warn!("TEST: '{test}'"); + + if let Some(caps) = re.captures(line) { + let msg_type_str: u8 = caps.get(1)?.as_str().parse().ok()?; + let msg_type = EChatType::try_from(msg_type_str).expect("Failed to parse EChatType"); + let message = caps.get(2)?.as_str(); + Some((msg_type, message)) + } else { + None + } + // let mut parts = line.splitn(2, ": "); + // warn!["parts: {:?}", parts]; + // let msg_type_str = parts.next()?; + // let msg = parts.next()?; + // let msg_type = EChatType::from_str(msg_type_str).ok()?; + // Some((msg_type, msg)) + } +} + + + +// Handle Game chat: commands, chat log, system messages define_pattern_resolver!(ClientMessage, [ "4C 8B DC 48 83 EC 58 33 C0 49 89 5B 08 49 89 73 18 49 8B D8 49 89 43 C8 48 8B F1 49 89 43 D0 49 89 43 D8 49 8D 43" -]); \ No newline at end of file +]); + +// void __thiscall APlayerController::ClientMessage(APlayerController *this,FString *S,FName Type,float MsgLifeTime) +CREATE_HOOK!(ClientMessage, (this:*mut c_void, S:*mut FString, Type:FName, MsgLifeTime: f32), { + #[cfg(feature="chat-commands")] + let cmd_store = Arc::clone(&LAST_COMMAND); + // FIXME: Nihi: better way to access it? + let string_ref: &FString = unsafe{ &*S }; + let message = string_ref.to_string(); + // TODO: Does this need to handle lines separately? + // info!("[ClientMessages] S: \'{:?}\', Type: \'{}\'({}), MsgLifeTime: \'{}\' ", message.replace("\r\n", " "), Type, Type.number, MsgLifeTime); + let message_repl = match message.contains('\n') { + true => format!("\n{message}"),//.replace("\r\n", " "), + false => message, + }; + + // info!(target: "client", " \'{:?}\'", message_repl); + + // Chat commands + // TODO: handle commands tranformed by ChatHooks + // e.g. ".hello" -> '<7>: Console Command: hello', Type: 'None'(0), MsgLifeTime: '0' + // this needs to provide the playfabid somehow + { + let cmd_filter = |c| ['/', '.'].contains(&c); + match client_message::parse_chat_line(message_repl.as_str()) { + Some(chat) => { + match chat.message.starts_with(cmd_filter) { + true => { + #[cfg(feature="chat-commands")] + { + let cmd_trimmed = chat.message.trim_start_matches(cmd_filter); + debug!("-> Got console command from \'{}\' ch{}: {}", + chat.name, + chat.channel, + cmd_trimmed); + // Set pending console command + // FIXME: Nihi: Add auth or allow only offline + *cmd_store.lock().unwrap() = Some(cmd_trimmed.trim().to_string()); + debug!("Pending: {:?}", Some(cmd_trimmed.trim().to_string())); + // TODO: save command to log + } + } + false => { + // debug!("-> User message: {:?}", chat); + let msg_type = EChatType::try_from(chat.channel as u8).expect("Failed to parse EChatType"); + info!(target: "game_chat", "\x1b[38;5;214m[ {:10?} ] \x1b[38;5;251m[ {} ]\x1b[38;5;255m: \x1b[38;5;251m{}\x1b[38;5;255m", msg_type, chat.name, chat.message); + // TODO: save user message + } + }; + } + _ => { + // debug!("System message"); + // "<8>: FACTION NOT VALID" + if let Some((chat_type, message)) = client_message::parse_msg_line(message_repl.as_str()) { + if let Some(msg) = parse_chat_line(message_repl.as_str()) { + info!("Chat: channel {}, name {}, message {}, ", msg.channel, msg.name, msg.message); + } + else { + info!(target: "system_chat", "\x1b[38;5;214m[ {chat_type:10?} ] \x1b[38;5;251m{message}\x1b[38;5;255m"); + } + } + else { + println!("something went wrong"); + } + // if let Some(msg) = parse_chat_line(message_repl.as_str()) { + // warn!("Chat: channel {}, name {}, message {}, ", msg.channel, msg.name, msg.message); + // if let Some(chat_mnsg) = client_message::parse_msg_line(msg.message) { + // warn!("Text: {:?} {}", chat_mnsg.0, chat_mnsg.1); + // } + // } + // TODO: Write message to logfile + } + } + } +}); + +// Match state change +// void __thiscall UTBLMatchesSubsystem::MatchUpdate(UTBLMatchesSubsystem *this) +#[cfg(feature = "dev")] +define_pattern_resolver!(MatchUpdate,[ + "48 89 5C 24 08 57 48 83 EC 20 48 8B D9 ?? ?? ?? ?? ?? 48 8B F8 48 85 C0 ?? ?? ?? ?? ?? ?? 48 8D 54 24 38 48 8B C8 ?? ?? ?? ?? ?? 48 8B", + "48 89 5C 24 ?? 57 48 83 EC 20 48 8B D9 E8 ?? ?? ?? ?? 48 8B F8 48 85 C0 0F 84 ?? ?? ?? ??" + ]); + +#[cfg(feature = "dev")] +CREATE_HOOK!(MatchUpdate,(arg0: *mut u8),{ + crate::sinfo![f; "Triggered!"]; +}); + +// // float __thiscall ATBLGameState::GetStageTimeRemaining(ATBLGameState *this) +#[cfg(feature = "dev")] +define_pattern_resolver![GetStageTimeRemaining,[ + "40 53 48 83 EC 40 48 8B 01 48 8B D9 0F 29 7C 24 ?? 0F 57 FF FF 90 ?? ?? ?? ?? 48 85 C0 74 ?? 48 8B 03 48 8B CB 0F 29 74 24 ?? F3 0F 10 B3 ?? ?? ?? ?? FF 90 ?? ?? ?? ?? F3 0F 5C F0 F3 0F 5F F7 0F 28 C6 0F 28 74 24 ?? 0F 28 7C 24 ?? 48 83 C4 40 5B C3 0F 28 7C 24 ?? 0F 57 C0 48 83 C4 40 5B C3" + ] +,|ctx, patterns| { + let futures = ::patternsleuth::resolvers::futures::future::join_all( + patterns.iter() + .map(|p| ctx.scan(::patternsleuth::scanner::Pattern::new(p).unwrap())) + ).await; + + // FIXME (2 of 3) + futures.into_iter().flatten().collect::>()[1] +} +]; + +#[cfg(feature = "dev")] +// CREATE_HOOK!(GetStageTimeRemaining, f32, (arg0: *mut u8), { +// // serror!("RETVAL: {}", ret_val); +// // crate::sinfo![f; "Triggered!"]; +// // ret_val +// }); +// CREATE_HOOK!(GetStageTimeRemaining, POST, f32, (arg0: *mut u8), |ret_val| { +// serror!("RETVAL: {}", ret_val); +// crate::sinfo![f; "Triggered!"]; +// ret_val +// }); + +// void __thiscall AGameMode::SetMatchState(AGameMode *this,FName param_1) +#[cfg(feature = "dev")] +define_pattern_resolver!(SetMatchState,[ + "48 89 5C 24 ?? 56 48 83 EC 20 48 8B DA 48 8B F1 48 39 91 ?? ?? ?? ??" + ]); +#[cfg(feature = "dev")] +CREATE_HOOK!(SetMatchState,(this_ptr: *mut u8, new_state: FName),{ + info![target: "server", "Changed! {}", new_state]; + // unsafe { + // let time_rem = o_GetStageTimeRemaining.call(this_ptr); + // if time_rem != 0.0 { + // crate::sinfo!(f; "Time: {}", time_rem); + // } + // } +}); + +enum UELogType { + NoLogging = 0, + Fatal = 1, + Error = 2, + Warning = 3, + Display = 4, + Log = 5, + Verbose = 6, + All = 7, + // VeryVerbose = 7, + NumVerbosity = 8, + VerbosityMask = 15, + SetColor = 64, + BreakOnLog = 128, +} + +// void __thiscall FOutputDevice::LogfImpl(FOutputDevice *this,Type param_1,wchar_t *param_2) +// longlong * FUN_14352dec0(longlong *param_1,longlong *param_2,short **param_3,char param_4) +#[cfg(feature = "dev")] +define_pattern_resolver!(LogFImpl,[ + // "4C 89 44 24 ?? 4C 89 4C 24 ?? 53 55 56 57 41 54 41 55 41 56 41 57 48 81 EC 58 04 00 00 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 49 8B F8", + "44 88 4C 24 ?? 48 89 54 24 ?? 55 53 56 57 41 54 41 55" + ]); +#[cfg(feature = "dev")] +// CREATE_HOOK!(LogFImpl,(this_ptr: *mut c_void, Type: u8, Text: *mut u8),{ +CREATE_HOOK!(LogFImpl, POST, *mut i64, ( + param_1: *mut i64, + param_2: *mut i64, + param_3: *mut *mut i16, + param_4: i8,), |ret_val: *mut i64| { +// CREATE_HOOK!(LogFImpl,(this_ptr: *mut c_void, Type: u8, Text: *const u16),{ + + // crate::sinfo![f; "TEXT"]; + unsafe { + if param_3.is_null() || (*param_3).is_null() { + // Handle null pointer safely + // return std::ptr::null_mut(); + } else { + + let raw_u16_ptr: *const u16 = *param_3 as *const u16; + let u16_cstr = widestring::U16CStr::from_ptr_str(raw_u16_ptr); + if !u16_cstr.to_string_lossy().contains("RCON_INTERCEPT") { + crate::sinfo![f; "{}", u16_cstr.display()]; + } + } + + } + + // if !Text.is_null() { + // unsafe { + // let msg = widestring::U16CStr::from_ptr_str(Text); + // // let string = FString::from(msg.as_slice_with_nul()); + // let mut message = msg.to_string_lossy(); + // message = match message.contains('\n') { + // true => format!("\n{message}"),//.replace("\r\n", " "), + // false => message, + // }; + // crate::sinfo![f; "{}", message]; + + // } + // } + ret_val +}); + +// void __thiscall FOutputDevice::LogfImpl(FOutputDevice *this,wchar_t *param_1) +#[cfg(feature = "dev")] +define_pattern_resolver!(LogFImpl2,[ + "48 89 54 24 ?? 4C 89 44 24 ?? 4C 89 4C 24 ?? 53 55 56 57 41 54 41 55" + ]); +#[cfg(feature = "dev")] +// CREATE_HOOK!(LogFImpl2, POST, *mut u16, (this_ptr: *mut c_void, Text: *const u16), |ret_val: *mut u16|{ +CREATE_HOOK!(LogFImpl2, POST, *mut u16, ( + param_1: *mut i64, + param_2: *mut i64, + param_3: *mut *mut i16, + param_4: i8,), |ret_val: *mut u16|{ +// CREATE_HOOK!(LogFImpl2,(this_ptr: *mut c_void, Text: *const u16),{ + + crate::sinfo![f; "TEXT2"]; + // if !ret_val.is_null() { + // unsafe { + // let msg = widestring::U16CStr::from_ptr_str(ret_val.clone()); + // // let string = FString::from(msg.as_slice_with_nul()); + // let mut message = msg.to_string_lossy(); + // message = match message.contains('\n') { + // true => format!("\n{message}"),//.replace("\r\n", " "), + // false => message, + // }; + // crate::sinfo![f; "{}", message]; + + // } + // } + ret_val +}); + +// never triggers +// void __thiscall FOutputDevice::Log(FOutputDevice *this,wchar_t *param_1) +#[cfg(feature = "dev")] +define_pattern_resolver!(Log2,["48 89 5C 24 ?? 57 48 83 EC 20 48 8B DA 48 8B F9 E8 ?? ?? ?? ?? 4C 8B 17"]); +#[cfg(feature = "dev")] +CREATE_HOOK!(Log2, (this_ptr: *mut c_void, Text: *mut *mut i16),{ + crate::sinfo![f; "Triggered!"]; +}); \ No newline at end of file diff --git a/sleuth/src/resolvers/backend_hooks.rs b/sleuth/src/resolvers/backend_hooks.rs index e85f3c9..8754d83 100644 --- a/sleuth/src/resolvers/backend_hooks.rs +++ b/sleuth/src/resolvers/backend_hooks.rs @@ -1,4 +1,14 @@ +// use futures::future::join_all; +// use patternsleuth::resolvers::AsyncContext; +// use patternsleuth::resolvers::ensure_one; +// use crate::resolvers::macros::Simple_signature; + +// use super::macros::DefaultResult; +// use patternsleuth::resolvers::ResolveError; + +// use std::future::Future; +// use std::pin::Pin; define_pattern_resolver!(FString_AppendChars, [ "45 85 C0 0F 84 89 00 00 00 48 89 5C 24 18 48 89 6C 24 20 56 48 83 EC 20 48 89 7C 24 30 48 8B EA 48 63 79 08 48 8B D9 4C 89 74 24 38 45 33 F6 85 FF 49 63 F0 41 8B C6 0F 94 C0 03 C7 03 C6 89 41 08 3B 41 0C 7E 07 8B D7 E8 ?? ?? ?? ?? 85 FF 49 8B C6 48 8B CF 48 8B D5 0F 95 C0 48 2B C8 48 8B 03 48 8D 1C 36 4C 8B C3 48 8D 3C 48 48 8B CF E8 ?? ?? ?? ?? 48 8B 6C 24 48 66 44 89 34 3B 4C 8B 74 24 38 48 8B 7C 24 30 48 8B 5C 24 40 48 83 C4 20 5E C3" // Universal @@ -27,4 +37,72 @@ define_pattern_resolver!(GetCurrentGames, Call, [ define_pattern_resolver!(SendRequest, [ "48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 55 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 40 48 8B D9 49 8B F9" -]); \ No newline at end of file +]); + +// define_signature_fn!(function_first_signature, +// | ctx, patterns | { +// let futures = ::patternsleuth::resolvers::futures::future::join_all( +// patterns.iter() +// .map(|p| ctx.scan(::patternsleuth::scanner::Pattern::new(p).unwrap())) +// ).await; + +// // FIXME +// Ok(DefaultResult(futures.into_iter().flatten().collect::>()[0])) +// } +// ); + +// define_pattern_resolver!(GetMotdTwo, { +// EGS: [ +// // function_signature("4C 89 4C 24 20 4C 89 44 24 18 48 89 4C 24 08 55 56 57 41 54 48 8D 6C 24 C1 48 81 EC D8 00 00 00 83 79 08 01 4C 8B E2 48 8B F9 7F 19 33 F6 48 8B C2 48 89 32 48 89 72 08 48 81 C4 D8 00 00 00 41 5C 5F 5E 5D C3 48 89 9C 24 08 01 00 00 48 8D 55 B7 4C 89 AC 24 D0 00 00 00 4C 89 B4 24 C8 00 00 00 4C 89 BC 24 C0 00 00 00 E8 ?? ?? ?? ?? 4C 8B 6D B7 48 8D 4D 97 33 F6 48 89 75 97 48 89 75 9F 49 8B 45 00 8D 56 09"), +// function_first_signature("4C 89 4C 24 20 4C 89 44 24 18 48 89 4C 24 08 55 56 57 41 54 48 8D 6C 24 C1 48 81 EC D8 00 00 00 83 79 08 01 4C 8B E2 48 8B F9 7F 19 33 F6 48 8B C2 48 89 32 48 89 72 08 48 81 C4 D8 00 00 00 41 5C 5F 5E 5D C3 48 89 9C 24 08 01 00 00 48 8D 55 B7 4C 89 AC 24 D0 00 00 00 4C 89 B4 24 C8 00 00 00 4C 89 BC 24 C0 00 00 00 E8 ?? ?? ?? ?? 4C 8B 6D B7 48 8D 4D 97 33 F6 48 89 75 97 48 89 75 9F 49 8B 45 00 8D 56 09") +// ], +// STEAM: [call_signature("4C 89 4C 24 20 4C 89 44 24 18 48 89 4C 24 08 55 56 57 41 54 48 8D 6C 24 C1 48 81 EC E8 00 00 00 83 79 08 01 4C 8B E2 48 8B F9 7F 19 33 F6 48 8B C2 48 89 32 48 89 72 08 48 81 C4 E8 00 00 00 41 5C 5F 5E 5D C3 48 89 9C 24 18 01 00 00 48 8D 55 B7 4C 89 AC 24 E0 00 00 00 4C 89 B4 24 D8 00 00 00 4C 89 BC 24 D0 00 00 00 E8 ?? ?? ?? ?? 4C 8B 6D B7 48 8D 4C 24 20 33 F6 BA 09")] +// }, +// |ctx, patterns| { +// let mut results = Vec::new(); +// // FIXME: Nihi: group sigs by type, run Signature func on multiple +// for pat in patterns { +// // match pat.kind { +// // SignatureKind::Call => println!("call"), +// // SignatureKind::Function => println!("function"), +// // _ => print!("NO MATCH") +// // } +// let offset = pat.calculate_offset(ctx).await.map(|r| r.offset()); +// // print!("PART RESULT: {:?}", offset); +// results.push(offset); +// } +// ensure_one(results.into_iter().flatten())? +// }); + +// define_pattern_resolver!(GetMotdTwo2, MultiCall, { +// EGS: [ +// Simple_signature("4C 89"), +// function_first_signature("4C 89") +// ], +// STEAM: [call_signature("4C 89 | ?? ?? ?? ?? BE EF")] +// }); + +// define_pattern_resolver!(GetMotdTwoS, { +// EGS: [ +// Simple_signature("4C 89"), +// function_first_signature("4C 89") +// ], +// STEAM: [call_signature("4C 89 | ?? ?? ?? ?? BE EF")] +// }); + +// define_pattern_resolver![GetMotdTwoS2, [ +// Simple_signature("4C 89"), +// function_first_signature("4C 89") +// ]]; + +// define_pattern_resolver![GetMotdTwoS3, MultiCall, [ +// Simple_signature("4C 89"), +// function_first_signature("4C 89") +// ]]; + + +// define_pattern_resolver!(GetMotdTwo3, MultiCall, [ +// function_signature("4C 89 4C 24 20 4C 89 44 24 18 48 89 4C 24 08 55 56 57 41 54 48 8D 6C 24 C1 48 81 EC D8 00 00 00 83 79 08 01 4C 8B E2 48 8B F9 7F 19 33 F6 48 8B C2 48 89 32 48 89 72 08 48 81 C4 D8 00 00 00 41 5C 5F 5E 5D C3 48 89 9C 24 08 01 00 00 48 8D 55 B7 4C 89 AC 24 D0 00 00 00 4C 89 B4 24 C8 00 00 00 4C 89 BC 24 C0 00 00 00 E8 ?? ?? ?? ?? 4C 8B 6D B7 48 8D 4D 97 33 F6 48 89 75 97 48 89 75 9F 49 8B 45 00 8D 56 09"), +// function_signature("4C 89 4C 24 20 4C 89 44 24 18 48 89 4C 24 08 55 56 57 41 54 48 8D 6C 24 C1 48 81 EC E8 00 00 00 83 79 08 01 4C 8B E2 48 8B F9 7F 19 33 F6 48 8B C2 48 89 32 48 89 72 08 48 81 C4 E8 00 00 00 41 5C 5F 5E 5D C3 48 89 9C 24 18 01 00 00 48 8D 55 B7 4C 89 AC 24 E0 00 00 00 4C 89 B4 24 D8 00 00 00 4C 89 BC 24 D0 00 00 00 E8 ?? ?? ?? ?? 4C 8B 6D B7 48 8D 4C 24 20 33 F6 BA 09") +// ]); + diff --git a/sleuth/src/resolvers/hook_retour.rs b/sleuth/src/resolvers/hook_retour.rs new file mode 100644 index 0000000..a22617d --- /dev/null +++ b/sleuth/src/resolvers/hook_retour.rs @@ -0,0 +1,61 @@ +// use retour::static_detour; +// use std::collections::HashMap; +// use std::error::Error; +// use std::os::raw::c_void; +// use std::mem; + + +// CREATE_HOOK!(TESTFKT, (engine:*mut c_void, delta:f32, state:u8), { +// println!("rust UGameEngineTick delta: {}", delta); +// }); + +// use once_cell::sync::Lazy; + +// fn get_base_address +// fn get_offsets() -> HashMap { +// HashMap() +// } + +// static _GAME_ENGINE_TICK_HOOK: Lazy>> = Lazy::new(|| { +// // Provide the actual base address and offsets here +// let base_address = get_base_address(); // <-- define this globally +// let offsets = get_offsets(); // <-- define this globally +// unsafe { attach_TESTFKT(base_address, offsets) } +// }); + +// // Force initialization at compile time (optional, ensures it runs) +// #[used] +// static _FORCE_GAME_ENGINE_TICK_HOOK: &Lazy>> = &_GAME_ENGINE_TICK_HOOK; + + +// CREATE_HOOK!(UGameEngineTick, HOOK_ATTACH, c_void, (engine:c_void, delta:f32, state:u8)); + +// unsafe fn attach_GameEngineTick(base_address: usize, offsets: HashMap) -> Result<(), Box>{ + +// let address = base_address + offsets["UGameEngineTick"] as usize; +// let target: FnUGameEngineTick = mem::transmute(address); + +// type FnUGameEngineTick = unsafe extern "C" fn(*mut c_void, f32, u8); + +// static_detour! { +// static UGameEngineTick: unsafe extern "C" fn(*mut c_void, f32, u8); +// } + +// fn detour_fkt(engine:*mut c_void, delta:f32, state:u8) { +// println!("rust UGameEngineTick delta: {}", delta); +// unsafe { UGameEngineTick.call( engine, delta, state) } +// } + +// UGameEngineTick +// .initialize(target, detour_fkt)? +// .enable()?; + +// Ok(()) +// } + +// pub unsafe fn attach_hooks(base_address: usize, offsets: HashMap) -> Result<(), Box> { + +// // attach_GameEngineTick(base_address, offsets).unwrap(); +// attach_TESTFKT(base_address, offsets).unwrap(); +// Ok(()) +// } diff --git a/sleuth/src/resolvers/kismet_dev.rs b/sleuth/src/resolvers/kismet_dev.rs new file mode 100644 index 0000000..594c5e1 --- /dev/null +++ b/sleuth/src/resolvers/kismet_dev.rs @@ -0,0 +1,343 @@ + + +use std::{ffi::c_void, os::raw::{c_char, c_longlong}}; + + +/*KismetExecutionMessage*/ + +use crate::{globals, resolvers::macros::First_signature, sinfo, ue::*}; +static LIST_OF_SHAME: [&str; 4] = [ + "/Game/Maps/Frontend/CIT/FE_Citadel_Atmospherics.FE_Citadel_Atmospherics_C", + "Divide by zero: ProjectVectorOnToVector with zero Target vector", + "A null object was passed as a world context object to UEngine::GetWorldFromContextObject().", + "/Game/Maps/Frontend/Blueprints/Customization_Rotation.Customization_Rotation_C", +]; + +define_pattern_resolver!(KismetExecutionMessage, [ + "48 89 5C 24 08 57 48 83 EC 30 0F B6 DA 48 8B F9 80 FA 01 ?? ?? ?? ?? ?? ?? ?? ?? ?? BA", +]); + +// void __cdecl FFrame::KismetExecutionMessage(wchar_t *param_1,Type param_2,FName param_3) + +#[cfg(feature="kismet-log")] +CREATE_HOOK!(KismetExecutionMessage, *mut UObject, (Message:*const u16, Type: u8, fname: FName), { + + if !Message.is_null() { + unsafe { + let msg = widestring::U16CStr::from_ptr_str(Message); + // let string = FString::from(msg.as_slice_with_nul()); + let mut message = msg.to_string_lossy(); + message = match message.contains('\n') { + true => format!("\n{message}"),//.replace("\r\n", " "), + false => message, + }; + + match LIST_OF_SHAME.iter().any(|x| message.contains(x)) { + true => {} // filtered out + false => log::debug!(target: "kismet", "{message}"), + } + } + } + +}); +#[cfg(feature = "dev")] +define_pattern_resolver!(ClientTravelInternal,["4C 8B DC 48 83 EC 58 33 C0 49 89 5B 08 49 89 6B 10 41 0F B6 E9 49 89 73 18 48"]); +#[cfg(feature = "dev")] +// void __thiscall +// APlayerController::ClientTravelInternal +// (APlayerController *this,FString *param_1,ETravelType param_2,bool param_3,FGuid *param_4) +CREATE_HOOK!(ClientTravelInternal, c_void, (PC: *mut c_void, arg1: *mut FString, TravelType: u8, arg3: bool, guid: *mut c_void),{ + + #[derive(Debug, serde::Deserialize)] + #[allow(dead_code)] + struct ConnectionInfo { + Address: String, + PartyId: Option, + PartySize: Option, + PlayFabId: Option, + UnofficialTicket: Option, + } + + //127.0.0.1:7777&PartyId=1231231&PartySize=1&PlayFabId=123123&UnofficialTicket=12323 + fn parse_connection_info(raw: &str) -> Result> { + let query_str = raw.replace('?', "&"); + let query_with_address = format!("Address={}", query_str); + let info: ConnectionInfo = serde_urlencoded::from_str(&query_with_address)?; + Ok(info) + } + + let string_ref: &FString = unsafe{ &*arg1 }; + + match parse_connection_info(string_ref.to_string().as_str()) { + Ok(info) => { + sinfo!(f; "info: {:#?}", info); + } + Err(e) => eprintln!("Error: {}", e), + } +}); + + +#[cfg(feature = "dev-joindata")] +use { + futures::future::join_all, + patternsleuth::{resolvers::ensure_one, scanner::Pattern}, +}; + +// 48 8d 55 97 48 8d 4d d7 e8 ?? ?? ?? ?? +// This is actually something else than I was looking for +// [20:09:50 INFO ] [JoinData_detour_fkt] Triggered! /Client/GetTitleData +// [20:09:50 INFO ] [JoinData_detour_fkt] Triggered! /Client/GetCatalogItems +// [20:09:50 INFO ] [JoinData_detour_fkt] Triggered! /Client/GetUserInventory +// [20:09:50 INFO ] [JoinData_detour_fkt] Triggered! /Authentication/GetEntityToken +// [20:09:50 INFO ] [JoinData_detour_fkt] Triggered! /Client/GetCatalogItems +// [20:09:50 INFO ] [JoinData_detour_fkt] Triggered! /Match/CancelAllMatchmakingTicketsForPlayer +// [20:09:50 INFO ] [JoinData_detour_fkt] Triggered! /MultiplayerServer/ListQosServersForTitle +#[cfg(feature = "dev-joindata")] +define_pattern_resolver!(JoinData, [ + "48 8d 55 97 48 8d 4d d7 e8 | ?? ?? ?? ??", + ], +|ctx, patterns| { + let res = futures::future::join_all(patterns.iter().map(|p| ctx.scan(patternsleuth::scanner::Pattern::new(p).unwrap()))).await; + + let temp_res = res.iter() + .flatten() + .map(|a| -> patternsleuth::resolvers::Result { Ok(patternsleuth::MemoryTrait::rip4(&ctx.image().memory, *a)?) }); + let len = temp_res.clone().count(); + let lvec: Vec> = temp_res.clone().collect(); + println!("JoinData: {:#?}", lvec); + // patternsleuth::resolvers::try_ensure_one(lvec.get(1).unwrap())? + *lvec.get(3).unwrap().as_ref().unwrap() // 2 and 3 point to the correct one +}); + +#[cfg(feature = "dev-joindata")] +CREATE_HOOK!(JoinData, *mut u8, (arg0: *mut u8, arg1: *mut FString),{ + let string_ref: &FString = unsafe{ &*arg1 }; + crate::sinfo![f; "Triggered! {string_ref}"]; +}); +// // INVALID +// #[cfg(feature = "dev")] +// define_pattern_resolver!(JoinDataTwo,{ +// OTHER: [ +// "48 89 5C 24 08 48 89 6C 24 18 48 89 74 24 20 57 48 83 EC 70 49 8B F0 48 8B DA 48 8B E9 ?? ?? ?? ?? ?? 48 8B F8 48 8D 4C 24 30 33", +// // "48 89 5C 24 08 48 89 6C 24 18 48 89 74 24 20 57 48 83 EC 70 49 8B F0 48 8B DA 48 8B E9 ? ? ? ? ? 48 8B F8 48 8D 4C 24 30 33" +// ] + +// }); +// #[cfg(feature = "dev")] +// CREATE_HOOK!(JoinDataTwo, c_void, (arg0: c_void, arg1: *mut c_void, arg3: c_void),{ +// crate::sinfo![f; "Triggered!"]; +// }); + + + +#[cfg(feature = "dev")] +define_pattern_resolver!(JoinDataTwo,{ + OTHER: [ + // "24 48 48 8B 07 48 8B CF 48 8B 15", + "4C 8B DC 48 83 EC 38 33 C0 49 89 5B 08 49 89 43 E8 49 89 43 F0 49 8D 43 E8 49 89 7B F8 48" + //"4C 8B DC 48 83 EC 38 33 C0 49 89 5B 08 49 89 43 E8 49 89 43 F0 49 8D 43 E8 49 89 7B F8 48 8B F9 48 3B C2 ? ? 48 63 5A 08 49 89 73 10 48 8B 32 89 5C 24 28 85 DB ? ? 45 33 C0 49 8D 4B E8 8B D3 ? ? ? ? ? 48 8B 4C 24 20 4C 8B C3 48 8B D6 ? ? ? ? ? 48 8B 74 24 48 48 8B 07 48 8B CF 48 8B 15 90 77" + // "48 89 5C 24 08 48 89 6C 24 18 48 89 74 24 20 57 48 83 EC 70 49 8B F0 48 8B DA 48 8B E9 ? ? ? ? ? 48 8B F8 48 8D 4C 24 30 33" + ] + +}, |ctx, patterns| { + let futures = ::patternsleuth::resolvers::futures::future::join_all( + patterns.iter() + .map(|p| ctx.scan(::patternsleuth::scanner::Pattern::new(p).unwrap())) + ).await; + + let lvec = futures.into_iter().flatten(); + let lvec2: Vec = lvec.clone().collect(); + // println!("JoinData: {:#?}", lvec); + // patternsleuth::resolvers::try_ensure_one(lvec.get(1).unwrap())? + + // let mut fns = patternsleuth::resolvers::unreal::util::root_functions(ctx, &lvec2)?; + // // crate::sinfo![f; "Funcs: {:#?}", fns]; + let mut cnt = 0; + let base_addr = globals().get_base_address(); + // fns.clone().into_iter().for_each(|x| { + // crate::sinfo![f; "{}: 0x{:#?}", cnt, x - base_addr]; + // cnt += 1; + // }); + lvec2.clone().into_iter().for_each(|x| { + crate::sinfo![f; "{}: 0x14{:X?}", cnt, x - base_addr]; + cnt += 1; + }); + // *fns.get(0).unwrap() // 2 and 3 point to the correct one + // 0x0cdabd0 + base_addr + let val: usize = 0x1b5dba0; + let offset:usize = (0x1b5dba0 & 0xFFFFFFF); + let sel_addr: usize = offset + base_addr; + + // crate::sinfo![f; "Selected: 0x{sel_addr:X?}, base 0x{base_addr:X?}, offset 0x{offset:X?} TEST: 0x{val:X?}"]; + // [21:49:25 INFO ] [resolver] Selected: 0x140699541494688, base 0x140699512799232, offset 0x28695456 TEST: 0x28695456 + let sel2 = *lvec2.get(1).unwrap(); + let sel_temp: usize = sel2 - base_addr; + crate::sinfo![f; "Selected: 0x{sel_temp:X?}"]; + // sel_addr + // sel2 + 0x1951330 + base_addr + // ::patternsleuth::resolvers::ensure_one()? +}); + +#[cfg(feature = "dev")] +// CREATE_HOOK!(JoinDataTwo, c_void, (arg0: *mut c_void, str2: *mut c_void),{ +// CREATE_HOOK!(JoinDataTwo, c_void, (param_1: *mut c_longlong, param_2: *mut *mut c_void),{ +CREATE_HOOK!(JoinDataTwo, c_void, (param_1: u64, param_2: *mut u16, param_3: *mut c_char),{ // some other + unsafe { + + // let my_string = std::ffi::CString::new("Hello world").expect("CString::new failed"); + // // let ptr: *mut c_char + // let raw = my_string.into_raw(); // takes ownership, must free later + + // *param_3 = *raw; + // unsafe { + // // Use `ptr` as needed... + // println!("ptr = {}", std::ffi::CStr::from_ptr(param_3).to_string_lossy()); + + // // When done, free the memory + // let _ = std::ffi::CString::from_raw(param_3); // Reclaim to drop it + // } + + + // let fstring = FString::from( + // widestring::U16CString::from_ptr_str(param_2) + // .as_slice_with_nul()); + // // let string_ref: &FString = unsafe{ &*arg1 }; + // // let message = string_ref.to_string(); + // println!("JoinDataTwo: {}", fstring); + + log::info!("C string: {}", std::ffi::CStr::from_ptr(param_3).to_string_lossy()); + + crate::sinfo![f; "Triggered!"]; + println!("ASDFG"); + } +}); + +// Disables startup message +// InitializeModule? +// FIXME: Nihi: offset in macro +// xref search + offset +// 11.06.25 Steam 19626AE + 0xF = 19626BD +// 19626[ae] 4c 8d 05 LEA R8,[s_Ple +// 3b 30 dd 02 +// 19626b5 48 8b cf MOV RCX,RDI +// 19626b8 48 8d 54 LEA RDX,[RSP + 0x50] +// 24 50 +// 19626[bd] {e8 6e ec} CALL FUN_141951330 +// {fe ff} +// 19626c2 48 85 db TEST RBX,RBX +// 19626c5 74 08 JZ LAB_1419626cf +// 14.06.2025 EGS +// 14193dcd4 4c 8d 05 LEA R8,[s_Please,_start_the_game_via_Chivalry2Laun = "Please, start the game via Ch +// b5 5c e0 02 +// 14193dcdb 48 8b cf MOV RCX,RDI +// 14193dcde 48 8d 55 40 LEA RDX,[RBP + 0x40] +// 14193dce2 e8 59 dc CALL FUN_14192b940 undefined FUN_14192b940() +// fe ff +// 14193dce7 48 85 db TEST RBX,RBX +// 14193dcea 74 08 JZ LAB_14193dcf4 + +// 4c 8d 05 +// ?? ?? ?? ?? +// 48 8b cf +// 48 ?? ?? +// ?? ?? +// ?? ?? ?? +// ?? ?? +// 48 85 db +// 74 08 + + +// 4c 8d 05 +// 3b 30 dd 02 +// 48 8b cf +// 48 8d 54 +// 24 50 +// e8 6e ec +// fe ff +// 48 85 db +// 74 08 +#[cfg(feature = "dev")] +define_pattern_resolver!(ShowSusMessage, Simple, { + EGS: ["4c 8d 05 b5 5c e0 02 48 8b cf 48 8d 55 40 e8 59 dc fe ff 48 85 db 74 08"], + STEAM: ["4c 8d 05 3b 30 dd 02 48 8b cf 48 8d 54 24 50 e8 6e ec fe ff 48 85 db 74 08"] + // patternsleuth::resolvers::unreal::util::utf8_pattern("Please, start the game") +} +// , |ctx, patterns| { +// let sig = First_signature(patterns.first().unwrap().clone()); +// // let strings = ctx.scan(patterns.first().unwrap().clone()).await; +// // let refs: Vec = patternsleuth::resolvers::unreal::util::scan_xrefs(ctx, &strings).await; +// // match globals().get_platform() { +// // } +// } +); + +// #[cfg(feature = "dev")] +// CREATE_HOOK!(ShowSusMessage, c_void, (param_1: c_longlong),{ +// println!("ASDFG"); +// crate::sinfo![f; "Triggered!"]; +// }); + +// #[cfg(feature = "dev")] +// define_pattern_resolver!(JoinDataFour, [ +// "DE AD BE EF AA AA AA AA AA" +// ], +// |ctx, patterns| { +// // 0x1d25da0 + globals().get_base_address() +// }); + +// #[cfg(feature = "dev")] +// CREATE_HOOK!(JoinDataFour, c_void, (param_1: *mut FString),{ +// let string_ref: &FString = unsafe{ &*param_1 }; +// println!("ASDFG {:#?}", string_ref); +// crate::sinfo![f; "Triggered!"]; +// }); + +#[cfg(feature = "rpc-debug")] +define_pattern_resolver!(LogReliableRPCFailed,[ + "48 89 5C 24 08 57 48 83 EC 40 41 83 78 08 00 49 8B F8 48 8B D9 ?? ?? 49 8B 00 ?? ?? 48" + ]); + +// FIXME: Nihi: prints are messed up +// void __thiscall +// UNetConnection::LogReliableRPCFailed +// (UNetConnection* this, FInBunch* param_1, FString* param_2, int param_3) +#[cfg(feature = "rpc-debug")] +CREATE_HOOK!(LogReliableRPCFailed, c_void, (this_ptr: *mut c_void, arg1: *mut FString, arg2: u32), { + if !arg1.is_null() { + let string_ref: &FString = unsafe{ &*arg1 }; + let message = string_ref.to_string(); + if string_ref.len() < 1024 { + println!("LogReliableRPCFailed: {}", message); + } + else { + println!("LogReliableRPCFailed"); + } + } + else { + println!("LogReliableRPCFailed"); + } + // println!("LogReliableRPCFailed"); + // crate::sinfo![f; "Triggered!"]; +}); + +#[cfg(feature = "rpc-debug")] +define_pattern_resolver!(LogReliableRPC,[ + "48 89 5C 24 10 48 89 6C 24 18 48 89 74 24 20 41 56 48 83 EC 20 48 8B 01 41 8B E8 48 8B DA 4C 8B F1 ?? ?? ?? ?? ?? ?? 48 8B C8 ?? ?? ?? ?? ?? 48 8B F0 48 85 C0 ?? ?? ?? ?? ?? ?? ?? 48 8B 4E 10 48" + ]); + +//void __thiscall ATBLCharacter::LogReliableRPC(ATBLCharacter *this,FName param_1,int param_2) +#[cfg(feature = "rpc-debug")] +CREATE_HOOK!(LogReliableRPC, c_void, (this_ptr: *mut c_void, arg1: FName, arg2: u32), { + println!("LogReliableRPC: {}", arg1); +}); + + +#[cfg(feature = "dev")] +define_pattern_resolver!(ClientTravelToSession,["48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 50 48 8B 79 30 33 ED 49 8B D8 8B F2"]); +#[cfg(feature = "dev")] +// Nihi: looks like this is never called +// bool __thiscall UGameInstance::ClientTravelToSession(UGameInstance *this,int param_1,FName param_2) +CREATE_HOOK!(ClientTravelToSession, bool, (this_ptr: *mut c_void, param: i32, Name: *mut FName), { + sinfo![F; "{}", unsafe { &*Name }]; +}); diff --git a/sleuth/src/resolvers/macros.rs b/sleuth/src/resolvers/macros.rs index 17114dd..2a1d9ea 100644 --- a/sleuth/src/resolvers/macros.rs +++ b/sleuth/src/resolvers/macros.rs @@ -14,7 +14,284 @@ // #[macro_use] // extern crate paste; // concat strings -use std::{future::Future, pin::Pin}; +// unsafe fn attach_TestFunction(base_address: usize, offsets: HashMap) -> Result<(), Box>{ +// let address = base_address + offsets["TestFunction"] as usize; +// let target: FnTestFunction = mem::transmute(address); +// type FnTestFunction = unsafe extern "C" fn(*mut c_void, f32, u8); +// static_detour! { +// static TestFunction: unsafe extern "C" fn(*mut c_void, f32, u8); +// } +// fn detour_fkt(engine:*mut c_void, delta:f32, state:u8) { +// println!("rust TestFunction delta: {}", delta); +// unsafe { TestFunction.call( engine, delta, state) } +// } +// TestFunction +// .initialize(target, detour_fkt)? +// .enable()?; +// Ok(()) +// } +/// ```rust +/// unsafe fn attach_GameEngineTick(base_address: usize, offsets: HashMap) -> Result<(), Box>{ +/// let address = base_address + offsets["UGameEngineTick"] as usize; +/// let target: FnUGameEngineTick = mem::transmute(address); +/// type FnUGameEngineTick = unsafe extern "C" fn(*mut c_void, f32, u8); +/// static_detour! { +/// static UGameEngineTick: unsafe extern "C" fn(*mut c_void, f32, u8); +/// } +/// fn detour_fkt(engine:*mut c_void, delta:f32, state:u8) { +/// println!("rust UGameEngineTick delta: {}", delta); +/// unsafe { UGameEngineTick.call( engine, delta, state) } +/// } +/// UGameEngineTick +/// .initialize(target, detour_fkt)? +/// .enable()?; +/// Ok(()) +/// } +/// ``` +/// +/// +// TODO: replace this with registration similar to resolvers +pub type HookFn = unsafe fn(usize, HashMap) -> Result, Box>; +// macro_rules! attach_hooks_list { +// ( [ $( $pattern:ident ),+ $(,)? ]) => { +// paste::paste!{ +// { +// let hooks: HashMap= [ $( ( stringify![$pattern], [] ) ),+ ] +// .into_iter().map(|(name, func)| (name.to_string(), func)).collect(); +// Ok(hooks) +// } +// } +// }; +// } + +// #[macro_export] +// macro_rules! attach_hooks_list { +// ( [ $( $pattern:ident ),+ $(,)? ]) => {{ +// use std::collections::HashMap; +// use crate::resolvers::macros::HookFn; +// paste::paste! { +// let hooks: HashMap<&'static str, HookFn> = [ +// $((stringify!($pattern), [] as HookFn)),+ +// ] +// .into_iter() +// .collect(); + +// hooks +// } +// }}; +// } +#[macro_export] +macro_rules! attach_hooks_list { + ( [ $( + $(#[$attr:meta])* + $pattern:ident + ),+ $(,)? ]) => {{ + use std::collections::HashMap; + use $crate::resolvers::macros::HookFn; + paste::paste! { + #[allow(dead_code)] + enum ActiveHooks { + $( + $(#[$attr])* + $pattern + ),+ + } + + let hooks: HashMap<&'static str, HookFn> = [ + $( + $(#[$attr])* + (stringify!($pattern), [] as HookFn) + ),+ + ] + .into_iter() + .collect(); + + hooks + } + }}; +} + + +// generate_stub!(StubName); +#[macro_export] +macro_rules! CREATE_HOOK { + + // ($name:ident, $mode:ident, $rettype:ident, ( $( $call_type:ident: $pattern:expr ),+ $(,)? )) => { + // ($name:ident, $mode:ident, $rettype:ident, ( $( $call_type:ident: $pattern:expr ),+ $(,)? )) => { + // println!($name); + // println!($mode); + // println!($rettype); + + // [ $( $call_type ($pattern) ),+ ]; + // }; + + // No ret type specified + ($name:ident, ( $( $arg:ident: $ty:ty ),+ $(,)? ), $body:expr) => { + CREATE_HOOK!($name, ::std::ffi::c_void, ( $( $arg: $ty ),+ ), $body); + }; + + // No hook type specified - run before original by default + ($name:ident, $out_type:ty, ( $( $arg:ident: $ty:ty ),+ $(,)? ), $body:expr) => { + CREATE_HOOK![$name, PRE, $out_type, ( $( $arg: $ty ),+ ), $body]; + }; + + + (@gen_detour NONE, $name:ident, $out_type:ty, ( $( $arg:ident: $ty:ty ),+ $(,)? ), $body:expr) => { + + paste::paste! { + #[allow(non_snake_case)] + pub fn [<$name _detour_fkt>]( $( $arg: $ty ),+ ) -> $out_type { + // println!("rust $name delta: {}", delta); + $body + // unsafe { [].call ( $( $arg ),+ ) } + } + } + }; + + (@gen_detour POST, $name:ident, $out_type:ty, ( $( $arg:ident: $ty:ty ),+ $(,)? ), $body:expr) => { + + paste::paste! { + #[allow(non_snake_case)] + pub fn [<$name _detour_fkt>]( $( $arg: $ty ),+ ) -> $out_type { + // println!("rust $name delta: {}", delta); + let ret_val = unsafe { [].call ( $( $arg ),+ ) }; + // let body_val = $body; + // let mut fallback = None; + + // let _ = match body_val { + // () => fallback = Some(ret_val), + // val => fallback = Some(body_val), + // }; + + // fallback.unwrap() + let ret_val = ret_val; + ($body(ret_val)) + } + } + }; + + (@gen_detour PRE, $name:ident, $out_type:ty, ( $( $arg:ident: $ty:ty ),+ $(,)? ), $body:expr) => { + + paste::paste! { + #[allow(non_snake_case)] + pub fn [<$name _detour_fkt>]( $( $arg: $ty ),+ ) -> $out_type { + $body + unsafe { [].call ( $( $arg ),+ ) } + } + } + }; + + ($name:ident, $hook_type:ident, $out_type:ty, ( $( $arg:ident: $ty:ty ),+ $(,)? ), $body:expr) => { + + paste::paste! { + + ::retour::static_detour! { + pub static []: unsafe extern "C" fn ($( $ty ),+ ) -> $out_type; + } + + CREATE_HOOK![@gen_detour $hook_type, $name, $out_type, ( $( $arg: $ty ),+ ), $body]; + + // #[allow(non_snake_case)] + // pub fn [<$name _detour_fkt>]( $( $arg: $ty ),+ ) -> $out_type { + // // println!("rust $name delta: {}", delta); + + // let someValue = $body; + // if (someValue != ()) { + // crate::serror!("SomeValue: {someValue:?}"); + // } + // unsafe { [].call ( $( $arg ),+ ) } + // // $body + // // unsafe { [].call ( $( $arg ),+ ) } + // } + + #[allow(non_snake_case)] + pub unsafe fn [](base_address: usize, offsets: std::collections::HashMap) -> Result, Box>{ + // pub unsafe fn [](base_address: usize, offsets: HashMap) -> Result<(), Box { + + // TODO: propagate error? why panic + match offsets.get(stringify![$name]) { + None => { + Err("No address found.".into())// Err("No Address found."),//log::error!["Failed to attach: {}", stringify![$name]], + }, + Some(_) => { + // log::info!["attached"]; + // ( $( $arg: $ty ),+ ); + let rel_address = offsets[stringify![$name]] as usize; + let target: [] = std::mem::transmute(base_address + rel_address); + + type [] = unsafe extern "C" fn ($( $ty ),+ ) -> $out_type; + + let res = [] + .initialize(target, [<$name _detour_fkt>]); + + match res { + Ok(_) => crate::sdebug!(f; "INIT Attached!"), + Err(e) => crate::serror!(f; "INIT FAILED TO ATTACH! {e}"), + } + let res2 = [] + .enable(); + + match res2 { + Ok(_) => crate::sdebug!(f; "ENABLE Attached!"), + Err(e) => crate::serror!(f; "ENABLE FAILED TO ATTACH! {e}"), + } + + // crate::debug_where!("Attached [ 0x{:#x?} ]", rel_address); + $crate::sdebug!(f; "Attached [ 0x{:#x?} ]", rel_address); + Ok(Some(rel_address as usize)) + }, + } + } + } + }; +} + +// #[macro_export] +// macro_rules! CREATE_HOOK { + +// // ($name:ident, $mode:ident, $rettype:ident, ( $( $call_type:ident: $pattern:expr ),+ $(,)? )) => { +// // ($name:ident, $mode:ident, $rettype:ident, ( $( $call_type:ident: $pattern:expr ),+ $(,)? )) => { +// // println!($name); +// // println!($mode); +// // println!($rettype); + +// // [ $( $call_type ($pattern) ),+ ]; +// // }; +// ($name:ident, ( $( $arg:ident: $ty:ty ),+ $(,)? ), $body:block) => { +// paste::paste! { +// #[allow(non_snake_case)] +// pub unsafe fn [](base_address: usize, offsets: HashMap) -> Result<(), Box>{ + +// // ( $( $arg: $ty ),+ ); +// let address = base_address + offsets[stringify![$name]] as usize; +// let target: [] = mem::transmute(address); + +// type [] = unsafe extern "C" fn ($( $ty ),+ ); + +// static_detour! { +// pub static []: unsafe extern "C" fn ($( $ty ),+ ); +// } + +// pub fn detour_fkt( $( $arg: $ty ),+ ) { +// // println!("rust $name delta: {}", delta); +// $body +// unsafe { [].call ( $( $arg ),+ ) } +// } + +// [] +// .initialize(target, detour_fkt)? +// .enable()?; + +// Ok(()) +// } +// } + + +// }; +// } + + +use std::{collections::HashMap, future::Future, pin::Pin}; use patternsleuth::resolvers::{AsyncContext, ResolveError}; @@ -65,7 +342,7 @@ macro_rules! define_pocess { // use patternsleuth::MemoryTrait; define_pocess!(@emit_process_inline $name, |$ctx, $patterns| { let mut results = Vec::new(); - // FIXME: group sigs by type, run Signature func on multiple + // FIXME: Nihi: group sigs by type, run Signature func on multiple for pat in $patterns { // match pat.kind { // SignatureKind::Call => println!("call"), @@ -81,8 +358,8 @@ macro_rules! define_pocess { }}; // Scan for Xrefs, return last - // FIXME: expects max. 2 results - // FIXME: handles only one pattern + // FIXME: Nihi: expects max. 2 results + // FIXME: Nihi: handles only one pattern (@emit_body $name:ident, XrefLast, $ctx:ident, $patterns:ident) => {{ use patternsleuth::resolvers::unreal::util; use patternsleuth::resolvers::ensure_one; @@ -92,7 +369,7 @@ macro_rules! define_pocess { let refs = util::scan_xrefs($ctx, &strings).await; let mut fns = util::root_functions($ctx, &refs)?; if fns.len() == 2 { - fns[0] = fns[1]; // FIXME: deque? last? + fns[0] = fns[1]; // FIXME: Nihi: deque? last? fns.pop(); } ensure_one(fns)? @@ -102,10 +379,29 @@ macro_rules! define_pocess { // Wrap code and define_pattern_resolver (@emit_process_inline $name:ident, |$ctx:ident, $patterns:ident| $body:block) => {{ let result = $body; + log::debug![target:"sig_scan", "[ 0x{:#x?} ]: {}", result, stringify![$name]]; Ok($name(result)) }}; } +#[allow(unused_macros)] +macro_rules! generate_stub { + ( $name:ident ) => { + // $name + #[cfg(feature="dev")] + define_pattern_resolver!($name, [ + "4C" + ]); + + #[cfg(feature="dev")] + CREATE_HOOK!($name, (arg0: *mut c_void), { + crate::sinfo![f; "Triggered!"]; + }); + }; +} + +// inline this +// generate_stub!(StubName); #[macro_export] macro_rules! define_pattern_resolver { @@ -259,8 +555,9 @@ macro_rules! define_process { } // custom handlers - define_pattern_resolver!(@emit_header DefaultResult); + +#[allow(dead_code)] impl DefaultResult { pub fn offset(&self) -> usize { self.0 // assuming it's something like `pub struct DefaultResult(pub usize)` @@ -284,6 +581,7 @@ pub struct Signature<'a> { pub signature_string: String, } +#[allow(dead_code)] impl<'a> Signature<'a> { pub async fn calculate_offset(&self, ctx: &'a AsyncContext<'a>) -> Result { (self.offset_calculator)(ctx).await @@ -357,7 +655,7 @@ macro_rules! define_signature_fn { ) => { #[allow(non_snake_case)] #[allow(dead_code)] - pub fn $fn_name<'a>(s: &'a str) -> crate::resolvers::macros::Signature<'a> { + pub fn $fn_name<'a>(s: &'a str) -> $crate::resolvers::macros::Signature<'a> { let calc: std::sync::Arc< dyn Fn(&AsyncContext<'a>) -> Pin> + Send + 'a>> + Send @@ -375,7 +673,7 @@ macro_rules! define_signature_fn { Box::pin(fut) }); - crate::resolvers::macros::Signature { + $crate::resolvers::macros::Signature { // kind: $kind, offset_calculator: calc, signature_string: s.to_string(), @@ -402,7 +700,7 @@ macro_rules! wrap_process_macro { }; } -// FIXME: move somewhere so those are not buried? +// FIXME: Nihi: move somewhere so those are not buried? // Possible to auto generate from macro? wrap_process_macro!(Simple); wrap_process_macro!(Call); diff --git a/sleuth/src/resolvers/mod.rs b/sleuth/src/resolvers/mod.rs index 144838d..f343ad8 100644 --- a/sleuth/src/resolvers/mod.rs +++ b/sleuth/src/resolvers/mod.rs @@ -1,11 +1,13 @@ #[macro_use] -mod macros; +pub mod macros; +// use dll_hook::ue; use once_cell::sync::OnceCell; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "UPPERCASE")] +#[allow(clippy::upper_case_acronyms)] pub enum PlatformType { EGS, STEAM, @@ -14,6 +16,7 @@ pub enum PlatformType { } pub static PLATFORM: OnceCell = OnceCell::new(); +pub static BASE_ADDR: OnceCell = OnceCell::new(); pub fn current_platform() -> PlatformType { *PLATFORM.get().expect("Platform not initialized") @@ -21,7 +24,7 @@ pub fn current_platform() -> PlatformType { impl std::fmt::Display for PlatformType { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self) + write!(f, "{self:?}") } } @@ -38,10 +41,88 @@ impl std::str::FromStr for PlatformType { } } } +// use std::ffi::OsStr; +// use std::os::raw::c_int; +// use std::os::windows::ffi::OsStrExt; +// use std::ptr::null_mut; +// #[repr(C)] +// pub struct FString { +// pub str: *mut u16, // wchar_t* == *mut u16 on Windows +// pub letter_count: c_int, +// pub max_letters: c_int, +// } + +// impl FString { +// /// Create an FString from a Rust `&str` (or `String`) +// pub fn from_string(s: &str) -> (Self, Box<[u16]>) { +// // Convert to UTF-16 and null-terminate +// let wide: Vec = OsStr::new(s) +// .encode_wide() +// .chain(std::iter::once(0)) // null terminator +// .collect(); + +// let letter_count = wide.len() as c_int; + +// // Box it to keep it alive (heap allocation) +// let boxed = wide.into_boxed_slice(); +// let ptr = boxed.as_ptr() as *mut u16; + +// // Return both FString and the boxed data +// ( +// FString { +// str: ptr, +// letter_count, +// max_letters: letter_count, +// }, +// boxed, +// ) +// } +// /// Creates an `FString` from a Rust wide string slice (`&[u16]` or `Vec`) +// pub fn new_from_wide_str(wide: &[u16]) -> Self { +// let letter_count = (wide.len()+1) as c_int; +// Self { +// str: wide.as_ptr() as *mut u16, +// letter_count, +// max_letters: letter_count, +// } +// } + +// /// Creates an `FString` from a wide string pointer (like `*const u16`) +// /// WARNING: This assumes the pointer is null-terminated. +// pub unsafe fn from_ptr(ptr: *const u16) -> Self { +// if ptr.is_null() { +// return Self { +// str: null_mut(), +// letter_count: 0, +// max_letters: 0, +// }; +// } + +// // Count the number of wide characters (including null terminator) +// let mut len = 0; +// while *ptr.add(len) != 0 { +// len += 1; +// } +// let letter_count = len as c_int + 1; + +// Self { +// str: ptr as *mut u16, +// letter_count, +// max_letters: letter_count, +// } +// } +// } + + +pub mod hook_retour; pub mod admin_control; pub mod asset_loading; pub mod backend_hooks; pub mod etc_hooks; pub mod ownership_overrides; -pub mod unchained_integration; \ No newline at end of file +pub mod unchained_integration; +pub mod rcon; +#[cfg(feature="kismet-log")] +pub mod kismet_dev; + diff --git a/sleuth/src/resolvers/rcon.rs b/sleuth/src/resolvers/rcon.rs new file mode 100644 index 0000000..54482a8 --- /dev/null +++ b/sleuth/src/resolvers/rcon.rs @@ -0,0 +1,69 @@ +use std::{ + io::{stdin, BufRead, BufReader}, + net::TcpListener, + sync::{Arc, Mutex}, + thread, +}; + +use log::{error, info, warn}; +use once_cell::sync::Lazy; + + +#[cfg(feature="rcon")] +fn get_rcon_port() -> Option { + Some(9001) +} +pub static COMMAND_PENDING: Lazy>>> = Lazy::new(|| Arc::new(Mutex::new(None))); +pub static LAST_COMMAND: Lazy>>> = Lazy::new(|| Arc::new(Mutex::new(None))); +// pub static FLAST_COMMAND: Lazy>>> = Lazy::new(|| Arc::new(Mutex::new(None))); + +#[cfg(feature="rcon")] +pub fn handle_rcon() { + let port = match get_rcon_port() { + Some(p) => p, + None => return, + }; + + let listener = TcpListener::bind(("127.0.0.1", port)) + .expect("[RCON] Failed to bind to port"); + + info!("[RCON] Listening on 127.0.0.1:{port}"); + + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let cmd_store: Arc>> = Arc::clone(&LAST_COMMAND); + let cmd_pending = Arc::clone(&COMMAND_PENDING); + thread::spawn(move || { + let reader = BufReader::new(stream); + for line in reader.lines().map_while(Result::ok) { + if !line.trim().is_empty() { + warn!("[RCON] Received: {}", line.trim()); + *cmd_store.lock().unwrap() = Some(line.trim().to_string()); + *cmd_pending.lock().unwrap() = Some(true); + } + } + }); + } + Err(e) => error!("[RCON] Connection failed: {e}"), + } + } +} + + +// FIME: Nihi: this need some validation +// maybe a proper prompt etc +#[cfg(feature="cli-commands")] +pub fn handle_cmd() { + // let line = String::new(); + loop { + let mut input = String::new(); + stdin().read_line(&mut input) + .expect("UTF-8 unsupported"); + let cmd_store: Arc>> = Arc::clone(&LAST_COMMAND); + *cmd_store.lock().unwrap() = Some(input.trim().to_string()); + if input.as_str() == "findobj" { + crate::sdebug!(f; "findobj {:?}", 123); + } + } +} \ No newline at end of file diff --git a/sleuth/src/scan.rs b/sleuth/src/scan.rs index de6bd94..5af1bc2 100644 --- a/sleuth/src/scan.rs +++ b/sleuth/src/scan.rs @@ -4,41 +4,59 @@ use patternsleuth::resolvers::resolvers; use std::process; +// pub static RESOLUTION: +// Vec, +// patternsleuth::resolvers::ResolveError +// >> = Vec::new(); + +use once_cell::sync::OnceCell; + + +pub static OFFSETS: OnceCell> = OnceCell::new(); + + + pub fn scan() -> Result, String> { - let pid = Some(process::id() as i32); + + let pid = process::id() as i32; let resolvers = resolvers().collect::>(); let dyn_resolvers = resolvers.iter().map(|res| res.getter).collect::>(); - let name = format!("PID={}", pid.unwrap()); - let game_name = format!("pid={}", pid.unwrap()); // fixme + // let name = format!("PID={}", pid.unwrap()); + let game_name = format!("pid={pid}"); // fixme let exe = patternsleuth::process::internal::read_image().map_err(|e| e.to_string())?; - println!("GAME '{:?}' '{:x?}'", name, exe.base_address); - + let resolution = tracing::info_span!("scan", game = game_name) .in_scope(|| exe.resolve_many(&dyn_resolvers)); - // get Names and offsets from resolution - let mut offsets = HashMap::new(); + let mut offsets: HashMap = HashMap::new(); + let mut offsets_resolver: HashMap = HashMap::new(); + + // FIXME: Nihi: ugh for (resolver, resolution) in resolvers.iter().zip(&resolution) { if let Ok(r) = resolution { - // FIXME: Less nasty way? + // FIXME: Nihi: Less nasty way? if let Some(hex) = format!("{r:?}") .split(['(', ')']) .nth(1) .and_then(|s| s.parse::().ok()) - .map(|n| format!("{:#x}", n)) + .map(|n| format!("{n:#x}")) { // sigs_json.insert(MyItem { id: resolver.name.to_string(), name: hex.to_string() }); let val = u64::from_str_radix(hex.trim_start_matches("0x"), 16).map_err(|e| e.to_string())?; let base = exe.base_address as u64; - println!("{} {} {} {:x?}", resolver.name, hex, val, (val-base) & 0xFFFFFFF); + // println!("{} {} {} {:x?}", resolver.name, hex, val, (val-base) & 0xFFFFFFF); offsets.insert(resolver.name.to_string(), (val-base) & 0xFFFFFFF); + offsets_resolver.insert(resolver.name.to_string(), val as usize); + // let ptr = Arc::as_ptr(resolver) as *const (); + // offsets_resolver.insert(resolver as *const (), val as usize); } } } - // let res = dump_builds(offsets); + let _ = OFFSETS.set(offsets_resolver); // Safe, only allowed once - Ok(offsets) -} \ No newline at end of file + Ok(offsets) // Return the original u64-based map +} diff --git a/sleuth/src/tools/log_macros.rs b/sleuth/src/tools/log_macros.rs new file mode 100644 index 0000000..3f47d22 --- /dev/null +++ b/sleuth/src/tools/log_macros.rs @@ -0,0 +1,190 @@ + +#[macro_export] +macro_rules! function { + () => {{ + fn f() {} + fn type_name_of(_: T) -> &'static str { + std::any::type_name::() + } + let name = type_name_of(f); + &name[..name.len() - 3] + }}; +} + + + +#[macro_export] +macro_rules! __slog_internal { + // With flags + ( $level:ident, $( $flag:ident ),+ ; $($arg:tt)* ) => {{ + // use std::io::Write; + + let mut context_parts = vec![]; + let mut target: Option = None; + + $( + match stringify!($flag) { + "f" => { + fn extract_segment(s: &str) -> Option { + let mut end = s; + while let Some(stripped) = end.strip_suffix("::{{closure}}") { + end = stripped; + } + end.rsplit("::").next().map(|s| s.to_string()) + } + let short_name = extract_segment($crate::function!()).unwrap(); + context_parts.push(format!("{}", short_name)); + // target = Some(short_name); + target = Some("function".to_string()); + } + "func" => { + target = Some("function".to_string()); + context_parts.push(format!("{}", $crate::function!())) + }, + "file" => context_parts.push(file!().to_string()), + "line" => context_parts.push(format!("L{}", line!())), + "column" => context_parts.push(format!("C{}", std::column!())), + "mod" => context_parts.push(format!("M{}", std::module_path!())), + _ => {} + } + )+ + if let Some(tgt) = target { + log::$level!(target: &tgt, "[{}] {}", context_parts.join("|"), format_args!($($arg)*)); + } + else { + log::$level!("[{}]", context_parts.join("|")); + } + // if let Some(tgt) = target { + // if !context_parts.is_empty() { + // log::$level!(target: &tgt, "[{}]", context_parts.join(":")); + // } + // log::$level!(target: &tgt, $($arg)*); + // } + // else { + // if !context_parts.is_empty() { + // log::$level!("[{}]", context_parts.join(":")); + // } + // log::$level!($($arg)*); + // } + + }}; + + // No flags + ( $level:ident, $($arg:tt)* ) => {{ + // log::$level!( + // "{} (in {} [{}:{}:{}])", + // $crate::function!(), + // std::module_path!(), + // std::file!(), + // std::line!(), + // std::column!() + // ); + log::$level!( + "{}:{}:{}", + $crate::function!(), + std::line!(), + std::column!() + ); + log::$level!($($arg)*); + }}; +} + +// FIXME: Nihi: couldn't figure out how to generalize it +// not possible to make nested macros with repeating patterns? +// #[macro_export] +// macro_rules! generate_slog_macro { +// ($name:ident, $level:ident) => { +// #[macro_export] +// macro_rules! $name { +// ( $sublevel:ident ; $( $flag:ident ),+ ; $($arg:tt)* ) => { +// println![stringify!(sublevel)]; +// $crate::__slog_internal!($level, $( $flag ),+ ; $($arg)*); +// }; +// ( $( $flag:ident ),+ ; $($arg:tt)* ) => { +// $crate::__slog_internal!($level, $( $flag ),+ ; $($arg)*); +// }; +// ($($arg:tt)*) => { +// $crate::__slog_internal!($level, $($arg)*); +// }; +// } +// }; +// } + +#[macro_export] +macro_rules! sinfo { + // ( $(fn|file|line|column|mod)+ ; $($arg:tt)* ) => { + // $crate::__slog_internal!(info, $($arg)*); + // }; + // ( $sublevel:ident; $( $flag:ident ),+ ; $($arg:tt)* ) => { + // println![stringify!(sublevel)]; + // $crate::__slog_internal!(info, $( $flag ),+ ; $($arg)*); + // }; + ( $( $flag:ident ),+ ; $($arg:tt)* ) => { + $crate::__slog_internal!(info, $( $flag ),+ ; $($arg)*) + }; + ($($arg:tt)*) => { + $crate::__slog_internal!(info, $($arg)*); + }; +} + +#[macro_export] +macro_rules! swarn { + ( $( $flag:ident ),+ ; $($arg:tt)* ) => { + $crate::__slog_internal!(warn, $( $flag ),+ ; $($arg)*) + }; + ($($arg:tt)*) => { + $crate::__slog_internal!(warn, $($arg)*); + }; +} + +#[macro_export] +macro_rules! sdebug { + ( $( $flag:ident ),+ ; $($arg:tt)* ) => { + $crate::__slog_internal!(debug, $( $flag ),+ ; $($arg)*); + }; + ($($arg:tt)*) => { + $crate::__slog_internal!(debug, $($arg)*); + }; +} + +#[macro_export] +macro_rules! strace { + ( $( $flag:ident ),+ ; $($arg:tt)* ) => { + $crate::__slog_internal!(trace, $( $flag ),+ ; $($arg)*); + }; + ($($arg:tt)*) => { + $crate::__slog_internal!(trace, $($arg)*); + }; +} + +#[macro_export] +macro_rules! serror { + ( $( $flag:ident ),+ ; $($arg:tt)* ) => { + $crate::__slog_internal!(error, $( $flag ),+ ; $($arg)*) + }; + ($($arg:tt)*) => { + $crate::__slog_internal!(error, $($arg)*); + }; +} + +/// ## Example usage +/// ```rust +/// debug_where!(); +/// ``` +/// ```rust +/// debug_where!("Entering important state {}", state); +/// ``` +#[macro_export] +macro_rules! debug_where { + () => { + log::debug!(target: "function", "From: {}", $crate::function!()); + }; + ($($arg:tt)*) => { + log::debug!( + target: "function", + "[{}] - {}", + $crate::function!(), + format!($($arg)*) + ); + }; +} \ No newline at end of file diff --git a/sleuth/src/tools/logger.rs b/sleuth/src/tools/logger.rs new file mode 100644 index 0000000..bacaa87 --- /dev/null +++ b/sleuth/src/tools/logger.rs @@ -0,0 +1,96 @@ + + +use log4rs::{append::{console::ConsoleAppender, file::FileAppender}, config::{Appender, Root}, encode::pattern::PatternEncoder, filter::threshold::ThresholdFilter, init_config, Config}; + +use super::syslog::SyslogAppender; + +// use log::LevelFilter; +// use log4rs::config::{ Logger}; + +// fn main() { +// let stdout = ConsoleAppender::builder().build(); + +// let requests = FileAppender::builder() +// .encoder(Box::new(PatternEncoder::new("{d} - {m}{n}"))) +// .build("log/requests.log") +// .unwrap(); + +// let config = Config::builder() +// .appender(Appender::builder().build("stdout", Box::new(stdout))) +// .appender(Appender::builder().build("requests", Box::new(requests))) +// .logger(Logger::builder().build("app::backend::db", LevelFilter::Info)) +// .logger(Logger::builder() +// .appender("requests") +// .additive(false) +// .build("app::requests", LevelFilter::Info)) +// .build(Root::builder().appender("stdout").build(LevelFilter::Warn)) +// .unwrap(); + +// // let handle = log4rs::init_config(config).unwrap(); + +// // use handle to change logger configuration at runtime +// } + +pub fn init_syslog() -> anyhow::Result<()> { + // use function name + let console = ConsoleAppender::builder() + .encoder(Box::new(PatternEncoder::new( + // TODO: make this configurable opt? Maybe only for syslog or only file log + // "[{d(%Y-%m-%d %H:%M:%S)} {h({l:5})}] [{f}:{L}] {m}{n}", // Log file name and line + "{h([{d(%H:%M:%S)} {l:5}])} {m}{n}", + ))) + .build(); + + #[cfg(feature="syslog-client")] + let syslog = SyslogAppender::builder() + .encoder(Box::new(PatternEncoder::new( + // TODO: make this configurable opt? Maybe only for syslog or only file log + // FIXME: Nihi: add valid syslog pattern in Appender + "[{d(%Y-%m-%d %H:%M:%S)}] [{l:5}] {m}{n}", // Log file name and line + ))) + .build(); + + let file = FileAppender::builder() + // .encoder(Box::new(PatternEncoder::new("[{d(%Y-%m-%d %H:%M:%S)}] [{l:5}] [{M}] [{f}:{L}] {m}{n}\n"))) + // .encoder(Box::new(PatternEncoder::new("[{d(%Y-%m-%d %H:%M:%S)}] {P} [{l:6}] [{t}] {m}{n}"))) + .encoder(Box::new(PatternEncoder::new("[{d(%Y-%m-%d %H:%M:%S)} {P} {l:6}| {t:10}] {m}{n}"))) + // .build("my_log_file.log")?; + // .build(r"U:\Unchained\UnchainedSleuth\unchained.log")?; // FIXME: Nihi: LOCAL FILE + .build(r"unchained.log")?; // FIXME: Nihi: LOCAL FILE + let kismet = FileAppender::builder() + .encoder(Box::new(PatternEncoder::new("[{d(%Y-%m-%d %H:%M:%S)} {P} {l:6}| {t} ] {m}{n}"))) + // .build(r"U:\Unchained\UnchainedSleuth\kismet.log")?; + .build(r"kismet.log")?; + let console_filter = ThresholdFilter::new(log::LevelFilter::Info); + // let console_filter: MetaDataFilter = MetaDataFilter::new(log::LevelFilter::Info); + + // Build the config programmatically + let mut builder = Config::builder() + .appender(Appender::builder().filter(Box::new(console_filter)).build("console", Box::new(console))); + + #[cfg(feature="syslog-client")] + { + builder = builder + .appender(Appender::builder().build("syslog", Box::new(syslog))); + } + + // let config = Config::builder() + // .appender(Appender::builder().filter(Box::new(console_filter)).build("console", Box::new(console))) + // // .appender(Appender::builder().build("syslog", Box::new(syslog))) + let config = builder + .appender(Appender::builder().build("file", Box::new(file))) + .appender(Appender::builder().build("kismet", Box::new(kismet))) + .build( + Root::builder() + .appender("console") + // .appender("syslog") + .appender("file") + // .additive(false) + // .appender("kismet") + .build(log::LevelFilter::Debug), + )?; + + init_config(config)?; + + Ok(()) +} diff --git a/sleuth/src/tools/memtools.rs b/sleuth/src/tools/memtools.rs new file mode 100644 index 0000000..3a9ddb7 --- /dev/null +++ b/sleuth/src/tools/memtools.rs @@ -0,0 +1,44 @@ +use std::{ptr, slice}; +use windows::Win32::System::Memory::{ + VirtualProtect, PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS, +}; + +/// Change memory protection for a given region. +unsafe fn protect(addr: *mut u8, size: usize, new_protect: PAGE_PROTECTION_FLAGS) -> PAGE_PROTECTION_FLAGS { + let mut old: PAGE_PROTECTION_FLAGS = PAGE_PROTECTION_FLAGS(0); + let _ = VirtualProtect(addr as _, size, new_protect, &mut old); + old +} + +/// Overwrite memory with custom bytes. +pub unsafe fn patch(addr: *mut u8, data: &[u8]) { + let size = data.len(); + let old = protect(addr, size, PAGE_EXECUTE_READWRITE); + ptr::copy_nonoverlapping(data.as_ptr(), addr, size); + protect(addr, size, old); +} + +/// Fill memory with NOPs (0x90). +pub unsafe fn nop(addr: *mut u8, count: usize) { + let old = protect(addr, count, PAGE_EXECUTE_READWRITE); + ptr::write_bytes(addr, 0x90, count); + protect(addr, count, old); +} + +/// Read memory at address into a Vec. +pub unsafe fn read_memory(addr: *const u8, size: usize) -> Vec { + slice::from_raw_parts(addr, size).to_vec() +} + +/// Overwrite a pointer-sized value. +pub unsafe fn write_ptr(addr: *mut T, value: T) { + let size = std::mem::size_of::(); + let old = protect(addr as *mut u8, size, PAGE_EXECUTE_READWRITE); + ptr::write(addr, value); + protect(addr as *mut u8, size, old); +} + +/// Read a value from memory. +pub unsafe fn read_ptr(addr: *const T) -> T { + ptr::read(addr) +} diff --git a/sleuth/src/tools/mod.rs b/sleuth/src/tools/mod.rs new file mode 100644 index 0000000..8902e48 --- /dev/null +++ b/sleuth/src/tools/mod.rs @@ -0,0 +1,12 @@ + +pub mod syslog; +pub mod logger; +pub mod memtools; +#[macro_use] +// pub mod log_macros_squashed; +// pub mod log_macros_kv; +pub mod log_macros; + +#[cfg(feature="server-registration")] +pub mod registration; +// pub mod server_registration; \ No newline at end of file diff --git a/sleuth/src/tools/registration.rs b/sleuth/src/tools/registration.rs new file mode 100644 index 0000000..0c01190 --- /dev/null +++ b/sleuth/src/tools/registration.rs @@ -0,0 +1,361 @@ +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +use a2s::A2SClient; +// use anyhow::Ok; +// use anyhow::Ok; +// use once_cell::sync::Lazy; +use reqwest::blocking::Client; +use serde::{Deserialize, Serialize}; + +use crate::globals; + +// Register Request +#[derive(Debug, Serialize)] +struct RegisterRequest<'a> { + ports: Ports, + name: &'a str, + description: &'a str, + password_protected: bool, + current_map: &'a str, + player_count: i32, + max_players: i32, + local_ip_address: &'a str, + mods: &'a [ModInfo<'a>], +} + +#[derive(Debug, Serialize)] +struct ModInfo<'a> { + name: &'a str, + version: &'a str, +} + +#[derive(Debug, Serialize)] +struct Ports { + game: u16, + ping: u16, + a2s: u16, +} + +// TODO: Maybe use Identity instead +#[derive(Debug, Deserialize, Clone)] +struct RegisterResponse { + server: RegisteredServer, + key: String, + refresh_before: f64, +} + +impl RegisterResponse { + fn refresh_eta_secs(&self) -> u64 { + let start = SystemTime::now(); + let since_epoch = start.duration_since(UNIX_EPOCH).expect("Time went backwards"); + sinfo!(f; "ETA: {}", self.refresh_before as u64 - since_epoch.as_secs()); + self.refresh_before as u64 - since_epoch.as_secs() + } +} + +#[derive(Debug, Deserialize, Clone)] +struct RegisteredServer { + unique_id: String, +} + +// Server id/key +struct Identity { + id: String, + key: String, + refresh_period: u64, +} + +impl From for Identity { + fn from(res: RegisterResponse) -> Self { + Identity { + id: res.server.unique_id.clone(), + key: res.key.clone(), + refresh_period: res.refresh_eta_secs() + } + } +} + +impl Identity { + fn default() -> Self { + Self { + id: String::new(), + key: String::new(), + refresh_period: 60, + } + } + + pub fn new(id: impl Into, key: impl Into) -> Self { + Self { + id: id.into(), + key: key.into(), + refresh_period: 60, + } + } +} + +#[derive(Debug, Serialize)] +struct UpdatePayload<'a> { + player_count: u8, + max_players: u8, + map_name: &'a str, +} + +pub struct Registration{ + server_addr: String, + client: Client, + a2s: A2SClient, + identity: Mutex>, + stop_update: Arc<(Mutex, Condvar)>, + stop_heartbeat: Arc<(Mutex, Condvar)>, + heartbeat_thread: Mutex>>>>, +} +impl Registration { + pub fn new(ip: &str, query_port: u16) -> Self { + Self { + server_addr: format!("{ip}:{query_port}"), + // query_port, + client: Client::new(), + a2s: A2SClient::new().unwrap(), + identity: Mutex::new(None), + stop_update: Arc::new((Mutex::new(false), Condvar::new())), + stop_heartbeat: Arc::new((Mutex::new(false), Condvar::new())), + heartbeat_thread: Mutex::new(None), + // last_info: None + } + } + + fn register_server(self: Arc, info: a2s::info::Info) -> Result { + let args = &globals().cli_args; + let desc = format!("{} (build {})\n{} server ", + info.game, + info.version, + info.folder); + let request = RegisterRequest{ + ports: Ports { + game: info.extended_server_info.port.unwrap(), + ping: args.game_server_ping_port.unwrap(), + a2s: args.game_server_query_port.unwrap(), + }, + name: &info.name, + description: &desc, + password_protected: args.server_password.is_some(), // TODO + current_map: &info.map, + player_count: info.players as i32, + max_players: info.max_players as i32, + local_ip_address: "127.0.0.1", + mods: &[], + }; + let backend = args.server_browser_backend.clone(); + let response = self.client + .post(format!("{}/api/v1/servers", &backend.unwrap())) + .json(&request) + .send().unwrap(); + + swarn!(f; "request {:#?}", request); + swarn!(f; "response {:#?}", response); + match response.json() as Result { + Ok(res) => { + swarn!(f; "json {:#?}", res); + + let mut identity_lock = self.identity.lock().unwrap(); + // *identity_lock = Some(Identity::new(&res.server.unique_id, &res.key)); + *identity_lock = Some(res.clone().into()); + Ok(res) + }, + Err(e) => { serror!(f; "Error: {}", e); Err(e) }, + } + } + + fn a2s_get_info(&self, retries: usize, period_s: f32) -> Result> { + let stop_flag = self.stop_update.clone(); + let mut itr = 0; + while itr < retries { + let (lock, cvar) = &*stop_flag; + if *lock.lock().unwrap() { + break; + } + sinfo!(f; "Retry {itr}"); + match self.a2s.info(&self.server_addr) { + Result::Ok(info) => { + serror!(f; "Connected {:#?}", info); + // serror!(f; "Players {:#?}", self.a2s.players(&self.server_addr)); // ! + // serror!(f; "Rules {:#?}", self.a2s.rules(&self.server_addr)); + return Ok(info) + }, + Err(e) => serror!(f; "Failed to get info: {e}"), + } + itr += 1; + if itr < retries { // TODO: do..while? + thread::sleep(Duration::from_secs(1)); + } + } + Err(format!("A2S failed after {retries} retries.").into()) + } + + fn start_discovery(self: Arc) -> Result> { + + match self.a2s_get_info(50, 1.0) { + Ok(info) => { + sinfo!(f; "discovered server!"); + match self.register_server(info) { + Ok(rinfo) => { + sinfo!(f; "ok"); + Ok(rinfo) + }, // TODO: handle player list? + Err(e) => { + serror!(f; "Not ok :{e}"); + Err(e.into()) + }, + } + }, + Err(e) => { + serror!(f; "Error: {}", e); + Err(format!("Error: {}", e).into()) + }, + } + // Err("Reached max retries".into()) + } + + pub fn start_a2s(self: Arc) { + let reg = self.clone(); + + thread::spawn(move || { + // reg.start_a2s(); + }); + } + + pub fn start(self: Arc) { + // self.clone().start_heartbeat(); + // self.clone().start_a2s(); + let reg = self.clone(); + + // spawn discovery thread + thread::spawn(move || { + thread::sleep(Duration::from_secs(20)); + match reg.start_discovery() { + Ok(_) => { + println!("Discovery successful, starting heartbeat..."); + match self.start_heartbeat() { + Ok(_) => sinfo!(f; "Heartbeat started"), + Err(e) => serror!(f; "Error: {e}"), + } + // Register server + // start heartbeat + // reg.start_heartbeat(); + } + Err(e) => { + eprintln!("Discovery failed: {:?}", e); + } + } + }); + } + + pub fn stop(self: Arc) { + + } + + fn send_update(self: Arc) -> Result<(), Box>{ + sinfo!(f; "start"); + let client = self.client.clone(); + // let url = self.server_addr.clone(); + let args = &globals().cli_args; + let backend = args.server_browser_backend.clone().unwrap(); + sinfo!(f; "getting lock"); + let identity_lock: std::sync::MutexGuard<'_, Option> = self.identity.lock().unwrap(); + sinfo!(f; "getting ident"); + let ident = identity_lock.as_ref() + .ok_or("Heartbeat with unknown identity")?; + sinfo!(f; "getting info"); + match self.a2s_get_info(1, 0.0) { + Ok(info) => { + sinfo!(f; "got a2s info"); + let payload = UpdatePayload { + player_count: info.players, + max_players: info.max_players, + map_name: info.map.as_str(), + }; + + let res = client.post(format!("{}/update", backend)) + .json(&payload) + .send(); + + match res { + Ok(update) => { + sinfo!(f; "sent update payload {:#?}", update); + // sinfo!("Sending update!"); + let res_hb = client + .post(format!("{}/{}/heartbeat", backend, ident.id)) + .header("x-chiv2-server-browser-key", ident.key.as_str()) + .send(); + + match res_hb { + Ok(hb) => { + sinfo!("Sent heartbeat!"); + Ok(()) + }, + Err(e) => Err(format!("Update: failed to send heartbeat: {}", e).into()), + } + }, + Err(e) => Err(format!("Update: failed to send update: {}", e).into()), + } + + + + // FIXME: why not derived here? + // Ok::<(), Box>(()) + } + + Err(e) => Err(format!("Update: failed to get A2S: {}", e).into()), + } + } + + pub fn start_heartbeat(self: Arc) -> Result<(), Box> { + sinfo!(f; "start"); + let stop_signal = Arc::clone(&self.stop_heartbeat); + let this = Arc::clone(&self); + // let identity = self.identity.lock().unwrap(); + // match self.identity.lock().unwrap().as_ref() { + // Some(ident) => todo!(), + // None => todo!(), + // }; + let handle = thread::spawn(move || -> Result<(), Box> { + let (lock, cvar) = &*stop_signal; + loop { + let mut stopped = lock.lock().unwrap(); + + if *stopped { + println!("🛑 Heartbeat stopping."); + break; + } + + + match this.clone().send_update() { + Ok(_) => sinfo!(f; "upadte success"), + Err(e) => sinfo!(f; "upadte error: {}", e), + }; + + let identity_lock = this.identity.lock().unwrap(); + let ident = identity_lock.as_ref() + .ok_or("Heartbeat with unknown identity")?; + + let result = cvar.wait_timeout(stopped, Duration::from_secs(ident.refresh_period)).unwrap(); + stopped = result.0; + // if *stopped { + // println!("🛑 Heartbeat stopping."); + // break; + // } + } + Ok(()) + }); + + *self.heartbeat_thread.lock().unwrap() = Some(handle); + Ok(()) + } + + pub fn stop_heartbeat(self: Arc) { + + } + +} \ No newline at end of file diff --git a/sleuth/src/tools/server_registration.rs b/sleuth/src/tools/server_registration.rs new file mode 100644 index 0000000..11d701d --- /dev/null +++ b/sleuth/src/tools/server_registration.rs @@ -0,0 +1,393 @@ +use std::{ + sync::{Arc, Mutex, Condvar}, + thread, + time::{Duration, Instant}, +}; +use a2s::A2SClient; +use once_cell::sync::Lazy; +use reqwest::blocking::Client; + +const MAX_RETRIES: u8 = 10; + +// Reg start +use serde::{Deserialize, Serialize}; + +use crate::globals; + +#[derive(Serialize)] +struct RegisterRequest<'a> { + ports: Ports, + name: &'a str, + description: &'a str, + password_protected: bool, + current_map: &'a str, + player_count: i32, + max_players: i32, + local_ip_address: &'a str, + mods: &'a [ModInfo<'a>], +} + +#[derive(Serialize)] +struct Ports { + game: u16, + ping: u16, + a2s: u16, +} + +#[derive(Serialize)] +struct ModInfo<'a> { + name: &'a str, + version: &'a str, +} + +#[derive(Deserialize)] +struct RegisterResponse { + server: RegisteredServer, + key: String, + refresh_before: f64, +} + +#[derive(Deserialize)] +struct RegisteredServer { + unique_id: String, +} + +// Reg end +#[derive(Debug, Serialize)] +struct UpdatePayload<'a> { + player_count: u8, + max_players: u8, + map_name: &'a str, +} +// static mut LAST_INFO:Option = None; +pub static LAST_INFO: Lazy>>> = Lazy::new(|| Arc::new(Mutex::new(None))); + +// Info { +// protocol: 85, +// name: "Créc", +// map: "TO_Hippodrome", +// folder: "TO", +// game: "Chivalry 2", +// app_id: 100, +// players: 1, +// max_players: 64, +// bots: 0, +// server_type: Listen, +// server_os: Windows, +// visibility: false, +// vac: false, +// the_ship: None, +// version: "261740", +// edf: 128, +// extended_server_info: ExtendedServerInfo { +// port: Some( +// 7777, +// ), +// steam_id: None, +// keywords: None, +// game_id: None, +// }, +// source_tv: None, +// } + +// static EMPTY_MODS: &[ModInfo] = &[]; // FIXME: Nihi: yuck +// static EMPTY_MODS: &[ModInfo<'static>] = &[]; +// pub static REGISTRATION: Lazy>>> = Lazy::new(|| Arc::new(Mutex::new(None))); +pub struct Registration { + server_addr: String, + // query_port: u16, + client: Client, + stop_update: Arc<(Mutex, Condvar)>, + stop_heartbeat: Arc<(Mutex, Condvar)>, + heartbeat_thread: Mutex>>, + // last_info: Option +} + +fn instant_from_unix_time(unix_secs: f64) -> Option { + // Convert f64 seconds to Duration + let whole = unix_secs.trunc() as u64; + let frac = unix_secs.fract(); + let nanos = (frac * 1_000_000_000.0) as u32; + + let sys_time = std::time::UNIX_EPOCH.checked_add(Duration::new(whole, nanos))?; + let now = std::time::SystemTime::now(); + + if sys_time > now { + // time in the future: compute duration from now + let dur = sys_time.duration_since(now).ok()?; + Some(Instant::now() + dur) + } else { + // time in the past: compute duration ago + let dur = now.duration_since(sys_time).ok()?; + Instant::now().checked_sub(dur) + } +} + +impl Registration { + pub fn new(ip: &str, query_port: u16) -> Self { + Self { + server_addr: format!("{ip}:{query_port}"), + // query_port, + client: Client::new(), + stop_update: Arc::new((Mutex::new(false), Condvar::new())), + stop_heartbeat: Arc::new((Mutex::new(false), Condvar::new())), + heartbeat_thread: Mutex::new(None), + // last_info: None + } + } + + pub fn register_server( + &self, + server_list_url: &str, + local_ip: &str, + game_port: u16, + ping_port: u16, + query_port: u16, + name: &str, + description: &str, + current_map: &str, + player_count: i32, + max_players: i32, + // mods: &[ModInfo], + password_protected: bool, + // ) -> Result<(String, String, f64), reqwest::Error> { + + ) -> Result<(String, String, f64), String> { + let mods: &[ModInfo] = &[]; + let req_body = RegisterRequest { + ports: Ports { + game: game_port, + ping: ping_port, + a2s: query_port, + }, + name, + description, + password_protected, + current_map, + player_count, + max_players, + local_ip_address: local_ip, + mods, + }; + + let response = self + .client + .post(format!("{server_list_url}/api/v1/servers")) + .json(&req_body) + .send().unwrap(); + + if !response.status().is_success() { + // You can implement detailed error handling here + eprintln!("Registration failed: {}", + reqwest::StatusCode::from_u16(response.status().as_u16()).unwrap()); + // return Err(reqwest::Error::new(Kind::Request, "Registration Failed")); + return Err("ERROR".to_string()) + // return Err(reqwest::Error::new( + // reqwest::StatusCode::from_u16(response.status().as_u16()).unwrap(), + // "Registration failed", + // )); + } + + // let parsed: RegisterResponse = response.json()?; + let resp: Result<(String, String, f64), String> = match response.json() as Result { + Ok(resp) => { + Ok(( + resp.server.unique_id, + resp.key, + resp.refresh_before, + )) + }, + _ => { + eprintln!("NO RESPONSE"); + Err("some".to_string()) + } + }; + resp + + } + + pub fn start(&self, server_list_url: &str, _: &str, _: &str) { + // pub fn start(&self, server_list_url: &str, id: &str, key: &str) { + let client = self.client.clone(); + let server_addr = self.server_addr.clone(); + let stop_flag = self.stop_update.clone(); + // todo: run registration from here? + // let id = id.to_string(); + // let key = key.to_string(); + let url = server_list_url.to_string(); + + thread::spawn(move || { + let a2s = A2SClient::new().unwrap(); + loop { + let (lock, cvar) = &*stop_flag; + if *lock.lock().unwrap() { + break; + } + + let mut retries = 0; + while retries < MAX_RETRIES { + // match a2s.info(&server_addr) { + // Ok(info) => { + // println!("CONNECTED {info:#?}") + // }, + // Err(e) => println!("failed {e}"), + // } + if let Ok(info) = a2s.info(&server_addr) { + let payload = UpdatePayload { + player_count: info.players, + max_players: info.max_players, + // map_name: &info.map_name, + map_name: info.map.as_str(), + }; + + let res = client.post(format!("{url}/update")) + .json(&payload) + .send(); + + if res.is_ok() { + // self.last_info = Some(info.clone()); + let last_info = Arc::clone(&LAST_INFO); + *last_info.lock().unwrap() = Some(info.clone()); + sdebug!(f; "Updated server: {:?}", payload); + break; + } + } + else { + sdebug!(f; "Failed to connect to a2s"); + } + + retries += 1; + sdebug!(f; "Retrying A2S query ({}/{})", retries, MAX_RETRIES); + thread::sleep(Duration::from_secs(1)); + } + + let timeout = Duration::from_secs(10); + let _ = cvar.wait_timeout(lock.lock().unwrap(), timeout).unwrap(); + } + }); + } + + // FIXME: Nihi: implement + #[allow(dead_code)] + pub fn stop(&self) { + let (lock, cvar) = &*self.stop_update; + *lock.lock().unwrap() = true; + cvar.notify_all(); + } + + pub fn start_heartbeat(self: Arc, server_list_url: &str, id: &str, key: &str) { + // let stop_flag = self.stop_heartbeat.clone(); + let client = self.client.clone(); + let url = server_list_url.to_string(); + let mut id = id.to_string(); + let mut key = key.to_string(); + // let refresh_before: f64 = 0.0; + let self_clone = Arc::clone(&self); + let stop_flag = self_clone.stop_heartbeat.clone(); + + let handle = thread::spawn(move || { + let mut refresh_by = Instant::now() + Duration::from_secs(30); // default interval + + loop { + let (lock, cvar) = &*stop_flag; + if *lock.lock().unwrap() { + break; + } + + // Only send heartbeat if it's near refresh_by time + if Instant::now() >= refresh_by { + // Send heartbeat POST/GET, here assumed POST to "/heartbeat" + // Replace with your actual heartbeat logic & parsing + + let res = client.post(format!("{url}/heartbeat")) + .json(&serde_json::json!({ + "id": id, + "key": key, + })) + .send(); + + match res { + Ok(resp) if resp.status().is_success() => { + // If your server returns next refresh interval, parse it here. + // For demo, assume fixed 30s interval: + refresh_by = Instant::now() + Duration::from_secs(30); + sdebug!(f; "Heartbeat successful"); + } + Ok(resp) if resp.status().as_u16() == 404 => { + sdebug!(f; "Registration expired; re-register here"); + + // let last_info = Arc::clone(&LAST_INFO); + // *last_info.lock().unwrap() = Some(info.clone()); + // let empty: &[ModInfo<'_>] = &[]; + if let Some(info) = LAST_INFO.lock().unwrap().as_ref() { + let args = &globals().cli_args; + let name = format!("{}\n(local server)", info.name); + let txt = format!("{} (build {})\n{} server ", info.game, info.version, info.folder); + + let res = self_clone.register_server( + &url, + "127.0.0.1", + info.extended_server_info.port.unwrap(), + args.game_server_ping_port.unwrap(), + args.game_server_query_port.unwrap(), + &name, + &txt, + &info.map, + info.players as i32, + info.max_players as i32, + // EMPTY_MODS, + args.server_password.is_some(), + ); + + // sdebug!(f; "INFO: {info:#?}"); + + match res { + Ok((unique_id, new_key, refresh)) => { + id = unique_id; + key = new_key; + // let test = Instant::now() + (Duration::from_secs_f64(refresh) - std::time::UNIX_EPOCH); + refresh_by = instant_from_unix_time(refresh).unwrap() - Duration::from_secs(5); + }, + Err(e) => serror!(f; "FAILED TO REGISTER {e}"), + } + } + else { + serror!(f; "No info saved"); + refresh_by = Instant::now() + Duration::from_secs(5); + } + + // TODO: re-register logic (POST register, update id/key) + } + Ok(resp) => { + serror!(f; "Heartbeat failed with status: {}", resp.status()); + } + Err(e) => { + serror!(f; "Heartbeat error: {}", e); + } + } + } + + // Sleep until next check or stop signal + let wait_time = refresh_by.saturating_duration_since(Instant::now()); + let lock_guard = lock.lock().unwrap(); + if *cvar.wait_timeout(lock_guard, wait_time).unwrap().0 { + break; + } + } + }); + + *self.heartbeat_thread.lock().unwrap() = Some(handle); + } + + // FIXME: Nihi: implement + #[allow(dead_code)] + pub fn stop_heartbeat(&self) { + let (lock, cvar) = &*self.stop_heartbeat; + *lock.lock().unwrap() = true; + cvar.notify_all(); + + if let Some(handle) = self.heartbeat_thread.lock().unwrap().take() { + handle.join().unwrap(); + } + } +} diff --git a/sleuth/src/tools/syslog.rs b/sleuth/src/tools/syslog.rs new file mode 100644 index 0000000..3333870 --- /dev/null +++ b/sleuth/src/tools/syslog.rs @@ -0,0 +1,316 @@ +// use anyhow::Result; +// use chrono::Local; +// use std::net::UdpSocket; +// use std::sync::mpsc::{self, Sender}; +// use std::thread; +// use std::time::Duration; + +// fn format_syslog_message(hostname: &str, tag: &str, message: &str) -> String { +// let stamp = Local::now().format("%b %d %H:%M:%S"); +// let pri = 13; +// format!("<{pri}>{stamp} {hostname} {tag}: {message}") +// } + +// pub fn spawn_syslog_sender(syslog_addr: &'static str) -> Sender { +// let (tx, rx) = mpsc::channel::(); +// thread::spawn(move || { +// let socket = UdpSocket::bind("0.0.0.0:0") +// .expect("Failed to bind udp socket"); + +// for line in rx { +// let msg = format_syslog_message("rust-client", "rustapp", &line); +// if let Err(e) = socket.send_to(msg.as_bytes(), syslog_addr) { +// eprintln!("Failed to send syslog msg: {e}"); +// } +// } +// }); +// tx +// } + +// pub fn start_log_generator(tx: Sender) { +// thread::spawn(move || { +// let messages = [ +// "Some test", +// "Blabliblub", +// ]; +// for msg in messages.iter().cycle() { +// if tx.send(msg.to_string()).is_err() { // recv fail +// break; +// } +// thread::sleep(Duration::from_secs(2)); +// } +// }); +// } + +use std::cell::RefCell; +use std::io::{self, Cursor, Write}; +use std::sync::Arc; +use log4rs::filter::{Filter, Response}; + +const DEFAULT_BUF_SIZE: usize = 4096; +type PersistentBuf = Cursor>; + +thread_local! { + static PERSISTENT_BUF: RefCell = + RefCell::new(Cursor::new(Vec::with_capacity(DEFAULT_BUF_SIZE))); +} + +// Optional: for some kind of global shared output string +// pub static SYSLOG_BUF: Lazy>>> = +// Lazy::new(|| Arc::new(Mutex::new(None))); + +pub struct BufWriter; + +impl BufWriter { + pub fn new() -> Self { + PERSISTENT_BUF.with(|buf| { + buf.borrow_mut().set_position(0); // Reset position + }); + BufWriter + } + + /// Returns the current buffer as a UTF-8 string and resets buffer. + pub fn flush_to_string(&self) -> String { + PERSISTENT_BUF.with(|buf| { + let buf = buf.borrow_mut(); + let pos = buf.position() as usize; + let slice = &buf.get_ref()[..pos]; + match std::str::from_utf8(slice) { + Ok(s) => s.to_string(), + Err(_) => "".to_string(), + } + }) + } +} + +impl Write for BufWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + PERSISTENT_BUF.with(|pbuf| pbuf.borrow_mut().write(buf)) + } + + fn flush(&mut self) -> io::Result<()> { + // In case you want to trigger network send from here + // let log_line = self.flush_to_string(); + // println!("Sending syslog: {}", log_line); + // send_to_syslog(log_line); // You can call your network send function here + Ok(()) + } +} +impl log4rs::encode::Write for BufWriter {} + +// https://en.wikipedia.org/wiki/Syslog + +use std::fmt; +use std::net::UdpSocket; + +use log::{LevelFilter, Record}; +use log4rs::{ + append::Append, + encode::{pattern::PatternEncoder, Encode}, + // ConfigBuilder, +}; + +// #[derive(Debug)] +pub struct SyslogAppender { + // writer: Writer, + encoder: Box, + // do_write: bool, + socket: Arc, + target_addr: String, + hostname: String, + tag: String, +} + +impl Append for SyslogAppender { + fn append(&self, record: &Record) -> anyhow::Result<()> { + // TODO: pre-process record (long paths etc) + let mut buf = BufWriter::new(); + self.encoder.encode(&mut buf, record)?; + // println!("SYSLOG {}", buf.flush_to_string()); + // let msg = format!("{}", record.args()); + // let full_msg = self.format_syslog_message(record.level(), &msg); + // println!("{:#?}", record); + let _ = self.socket.send_to(buf.flush_to_string().as_bytes(), &self.target_addr); + // let _ = self.socket.send_to(buf.as_bytes(), &self.target_addr); + Ok(()) + } + + fn flush(&self) {} +} + +impl SyslogAppender { + /// Create new builder for `SyslogAppender`. + pub fn builder() -> SyslogAppenderBuilder { + SyslogAppenderBuilder { + encoder: None, + // target: Target::Stdout, + } + } +} +// TODO: syslog hostname (cli?) +// impl SyslogAppender { +// /// Creates a new `SyslogAppender` builder. +// pub fn builder() -> SyslogAppenderBuilder { +// SyslogAppenderBuilder { +// encoder: None, +// target: Target::Stdout, +// tty_only: false, +// } +// } +// } +/// A builder for `SyslogAppender`s. +pub struct SyslogAppenderBuilder { + encoder: Option>, + // target: Target, +} + +impl SyslogAppenderBuilder { + /// Sets the output encoder for the `SyslogAppender`. + pub fn encoder(mut self, encoder: Box) -> SyslogAppenderBuilder { + self.encoder = Some(encoder); + self + } + + /// Consumes the `SyslogAppenderBuilder`, producing a `SyslogAppender`. + pub fn build(self) -> SyslogAppender { + // let writer = match self.target { + // Target::Stderr => match SyslogWriter::stderr() { + // Some(writer) => Writer::Tty(writer), + // None => Writer::Raw(StdWriter::stderr()), + // }, + // Target::Stdout => match SyslogWriter::stdout() { + // Some(writer) => Writer::Tty(writer), + // None => Writer::Raw(StdWriter::stdout()), + // }, + // }; + + // let do_write = writer.is_tty() || !self.tty_only; + + let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); + SyslogAppender { + // writer, + encoder: self + .encoder + .unwrap_or_else(|| Box::::default()), + // do_write: true, + socket: Arc::new(socket), + target_addr: "127.0.0.1:514".to_string(), + hostname: "unchained".to_string(), + tag: "some_tag".to_string(), + } + } +} + +impl SyslogAppender { + // pub fn new(syslog_addr: &str, hostname: &str, tag: &str) -> std::io::Result { + // let socket = UdpSocket::bind("0.0.0.0:0")?; + // Ok(Self { + // socket: Arc::new(socket), + // target_addr: syslog_addr.to_string(), + // hostname: hostname.to_string(), + // tag: tag.to_string(), + // encoder: todo!(), + // // do_write: todo!(), + // }) + // } + + // fn format_syslog_message(&self, level: Level, msg: &str) -> String { + // let pri = match level { + // Level::Error => 3, + // Level::Warn => 4, + // Level::Info => 6, + // Level::Debug | Level::Trace => 7, + // } + 8; // facility 1 (user) + // // TODO: Extend facility, let user provide it. Enum? + // // Also syslog it supports more severity levels + + // let timestamp = Local::now().format("%b %d %H:%M:%S"); + // format!( + // "<{}>{} {} {}: {}", + // pri, timestamp, self.hostname, self.tag, msg + // ) + // } +} +impl fmt::Debug for SyslogAppender { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SyslogAppender") + .field("target_addr", &self.target_addr) + .field("hostname", &self.hostname) + .field("tag", &self.tag) + .finish() + } +} + + +// Filter + +// FIXME: Nihi: implement +#[allow(dead_code)] +pub struct MetaDataFilterConfig { + level: LevelFilter, +} + +// FIXME: Nihi: implement +#[allow(dead_code)] +/// A filter that rejects all events at a level below a provided threshold. +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct MetaDataFilter { + level: LevelFilter, +} + +// FIXME: Nihi: implement +#[allow(dead_code)] +impl MetaDataFilter { + /// Creates a new `MetaDataFilter` with the specified threshold. + pub fn new(level: LevelFilter) -> MetaDataFilter { + MetaDataFilter { level } + } +} + +// FIXME: Nihi: implement +#[allow(dead_code)] +impl Filter for MetaDataFilter { + fn filter(&self, record: &Record) -> Response { + fn strip_ansi_codes(input: &str) -> String { + let ansi_regex = regex::Regex::new(r"\x1b\[[0-9;]*[a-zA-Z]").unwrap(); + ansi_regex.replace_all(input, "").into_owned() + } + + println!("FILTERING {record:#?}"); + // let clean_str = strip_ansi_codes(asd); + if record.level() > self.level { + Response::Reject + } else { + Response::Neutral + } + } +} + +// /// A deserializer for the `MetaDataFilter`. +// /// +// /// # Configuration +// /// +// /// ```yaml +// /// kind: threshold +// /// +// /// # The threshold log level to filter at. Required +// /// level: warn +// /// ``` +// #[cfg(feature = "config_parsing")] +// #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +// pub struct MetaDataFilterDeserializer; + +// #[cfg(feature = "config_parsing")] +// impl Deserialize for MetaDataFilterDeserializer { +// type Trait = dyn Filter; + +// type Config = MetaDataFilterConfig; + +// fn deserialize( +// &self, +// config: MetaDataFilterConfig, +// _: &Deserializers, +// ) -> anyhow::Result> { +// Ok(Box::new(MetaDataFilter::new(config.level))) +// } +// } diff --git a/sleuth/src/ue.rs b/sleuth/src/ue.rs new file mode 100644 index 0000000..c6b1a2c --- /dev/null +++ b/sleuth/src/ue.rs @@ -0,0 +1,704 @@ +// From trumank/patternsleuth +// https://github.com/trumank/patternsleuth/blob/master/examples/dll_hook/src/ue.rs +// FIXME: Nihi: the file is unchanged. Find a way to get use it via git without submodules + +#![allow(dead_code, private_interfaces)] + +use std::{ + cell::UnsafeCell, + ffi::c_void, + fmt::Display, + ops::{Deref, DerefMut}, +}; + +use windows::Win32::System::Threading::{ + EnterCriticalSection, LeaveCriticalSection, CRITICAL_SECTION, +}; + +use crate::globals; + +pub type FnFFrameStep = + unsafe extern "system" fn(stack: &mut kismet::FFrame, *mut UObject, result: *mut c_void); +pub type FnFFrameStepExplicitProperty = unsafe extern "system" fn( + stack: &mut kismet::FFrame, + result: *mut c_void, + property: *const FProperty, +); + +pub type FnFNameToString = unsafe extern "system" fn(&FName, &mut FString); +impl Display for FName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut string = FString::new(); + unsafe { + (globals().fname_to_string())(self, &mut string); + }; + write!(f, "{string}") + } +} + +pub type FnUObjectBaseUtilityGetPathName = + unsafe extern "system" fn(&UObjectBase, Option<&UObject>, &mut FString); +impl UObjectBase { + pub fn get_path_name(&self, stop_outer: Option<&UObject>) -> String { + let mut string = FString::new(); + unsafe { + (globals().uobject_base_utility_get_path_name())(self, stop_outer, &mut string); + } + string.to_string() + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct FMalloc { + vtable: *const FMallocVTable, +} +unsafe impl Sync for FMalloc {} +unsafe impl Send for FMalloc {} +impl FMalloc { + pub fn malloc(&self, count: usize, alignment: u32) -> *mut c_void { + unsafe { ((*self.vtable).malloc)(self, count, alignment) } + } + pub fn realloc(&self, original: *mut c_void, count: usize, alignment: u32) -> *mut c_void { + unsafe { ((*self.vtable).realloc)(self, original, count, alignment) } + } + pub fn free(&self, original: *mut c_void) { + unsafe { ((*self.vtable).free)(self, original) } + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct FMallocVTable { + pub __vec_del_dtor: *const (), + pub exec: *const (), + pub malloc: + unsafe extern "system" fn(this: &FMalloc, count: usize, alignment: u32) -> *mut c_void, + pub try_malloc: + unsafe extern "system" fn(this: &FMalloc, count: usize, alignment: u32) -> *mut c_void, + pub realloc: unsafe extern "system" fn( + this: &FMalloc, + original: *mut c_void, + count: usize, + alignment: u32, + ) -> *mut c_void, + pub try_realloc: unsafe extern "system" fn( + this: &FMalloc, + original: *mut c_void, + count: usize, + alignment: u32, + ) -> *mut c_void, + pub free: unsafe extern "system" fn(this: &FMalloc, original: *mut c_void), + pub quantize_size: *const (), + pub get_allocation_size: *const (), + pub trim: *const (), + pub setup_tls_caches_on_current_thread: *const (), + pub clear_and_disable_tlscaches_on_current_thread: *const (), + pub initialize_stats_metadata: *const (), + pub update_stats: *const (), + pub get_allocator_stats: *const (), + pub dump_allocator_stats: *const (), + pub is_internally_thread_safe: *const (), + pub validate_heap: *const (), + pub get_descriptive_name: *const (), +} + +#[derive(Debug)] +#[repr(C)] +pub struct FWindowsCriticalSection(UnsafeCell); +impl FWindowsCriticalSection { + fn crit_ptr_mut(&self) -> *mut CRITICAL_SECTION { + &self.0 as *const _ as *mut _ + } + unsafe fn lock(&self) { + simple_log::info!("LOCKING objects"); + EnterCriticalSection(self.crit_ptr_mut()); + } + unsafe fn unlock(&self) { + simple_log::info!("UNLOCKING objects"); + LeaveCriticalSection(self.crit_ptr_mut()); + } +} + +pub struct CriticalSectionGuard<'crit, 'data, T: ?Sized + 'data> { + critical_section: &'crit FWindowsCriticalSection, + data: &'data UnsafeCell, +} +impl<'crit, 'data, T: ?Sized> CriticalSectionGuard<'crit, 'data, T> { + fn lock(critical_section: &'crit FWindowsCriticalSection, data: &'data UnsafeCell) -> Self { + unsafe { + critical_section.lock(); + } + Self { + critical_section, + data, + } + } +} +impl Drop for CriticalSectionGuard<'_, '_, T> { + fn drop(&mut self) { + unsafe { self.critical_section.unlock() } + } +} +impl Deref for CriticalSectionGuard<'_, '_, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.data.get() } + } +} +impl DerefMut for CriticalSectionGuard<'_, '_, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.data.get() } + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct FUObjectCreateListener; + +#[derive(Debug)] +#[repr(C)] +pub struct FUObjectDeleteListener; + +type ObjectIndex = i32; + +#[derive(Debug)] +#[repr(C)] +pub struct FUObjectArray { + obj_first_gcindex: i32, + obj_last_non_gcindex: i32, + max_objects_not_considered_by_gc: i32, + open_for_disregard_for_gc: bool, + + obj_objects: UnsafeCell, + obj_objects_critical: FWindowsCriticalSection, + obj_available_list: [u8; 0x88], + uobject_create_listeners: TArray<*const FUObjectCreateListener>, + uobject_delete_listeners: TArray<*const FUObjectDeleteListener>, + uobject_delete_listeners_critical: FWindowsCriticalSection, + master_serial_number: std::sync::atomic::AtomicI32, +} +impl FUObjectArray { + pub fn objects(&self) -> CriticalSectionGuard<'_, '_, FChunkedFixedUObjectArray> { + CriticalSectionGuard::lock(&self.obj_objects_critical, &self.obj_objects) + } + pub fn allocate_serial_number(&self, index: ObjectIndex) -> i32 { + use std::sync::atomic::Ordering; + + let objects = unsafe { &*self.obj_objects.get() }; + let item = objects.item(index); + + let current = item.serial_number.load(Ordering::SeqCst); + if current != 0 { + current + } else { + let new = self.master_serial_number.fetch_add(1, Ordering::SeqCst); + + let exchange = + item.serial_number + .compare_exchange(0, new, Ordering::SeqCst, Ordering::SeqCst); + match exchange { + Ok(_) => new, + Err(old) => old, + } + } + } +} + +pub struct ObjectIterator<'a> { + array: &'a FChunkedFixedUObjectArray, + index: i32, +} +impl<'a> Iterator for ObjectIterator<'a> { + type Item = Option<&'a UObjectBase>; + fn size_hint(&self) -> (usize, Option) { + let size = self.array.num_elements as usize; + (size, Some(size)) + } + fn nth(&mut self, n: usize) -> Option { + let n = n as i32; + if self.index < n { + self.index = n; + } + self.next() + } + fn next(&mut self) -> Option> { + if self.index >= self.array.num_elements { + None + } else { + let obj = unsafe { self.array.item(self.index).object.as_ref() }; + + self.index += 1; + Some(obj) + } + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct FChunkedFixedUObjectArray { + pub objects: *const *const FUObjectItem, + pub pre_allocated_objects: *const FUObjectItem, + pub max_elements: i32, + pub num_elements: i32, + pub max_chunks: i32, + pub num_chunks: i32, +} +impl FChunkedFixedUObjectArray { + pub fn iter(&self) -> ObjectIterator<'_> { + ObjectIterator { + array: self, + index: 0, + } + } + fn item_ptr(&self, index: ObjectIndex) -> *const FUObjectItem { + let per_chunk = self.max_elements / self.max_chunks; + + unsafe { + (*self.objects.add((index / per_chunk) as usize)).add((index % per_chunk) as usize) + } + } + fn item(&self, index: ObjectIndex) -> &FUObjectItem { + unsafe { &*self.item_ptr(index) } + } + fn item_mut(&mut self, index: ObjectIndex) -> &mut FUObjectItem { + unsafe { &mut *(self.item_ptr(index) as *mut FUObjectItem) } + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct FUObjectItem { + pub object: *const UObjectBase, + pub flags: i32, + pub cluster_root_index: i32, + pub serial_number: std::sync::atomic::AtomicI32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FWeakObjectPtr { + object_index: i32, + object_serial_number: i32, +} +impl FWeakObjectPtr { + pub fn new(object: &UObjectBase) -> Self { + Self::new_from_index(object.internal_index) + } + pub fn new_from_index(index: ObjectIndex) -> Self { + Self { + object_index: index, + // serial allocation performs only atomic operations + object_serial_number: unsafe { + globals() + .guobject_array_unchecked() + .allocate_serial_number(index) + }, + } + } + pub fn get(&self, object_array: &FUObjectArray) -> Option<&UObjectBase> { + // TODO check valid + unsafe { + let objects = &*object_array.obj_objects.get(); + let item = objects.item(self.object_index); + Some(&*item.object) + } + } +} + +bitflags::bitflags! { + #[derive(Debug, Clone)] + pub struct EObjectFlags: u32 { + const RF_NoFlags = 0x0000; + const RF_Public = 0x0001; + const RF_Standalone = 0x0002; + const RF_MarkAsNative = 0x0004; + const RF_Transactional = 0x0008; + const RF_ClassDefaultObject = 0x0010; + const RF_ArchetypeObject = 0x0020; + const RF_Transient = 0x0040; + const RF_MarkAsRootSet = 0x0080; + const RF_TagGarbageTemp = 0x0100; + const RF_NeedInitialization = 0x0200; + const RF_NeedLoad = 0x0400; + const RF_KeepForCooker = 0x0800; + const RF_NeedPostLoad = 0x1000; + const RF_NeedPostLoadSubobjects = 0x2000; + const RF_NewerVersionExists = 0x4000; + const RF_BeginDestroyed = 0x8000; + const RF_FinishDestroyed = 0x00010000; + const RF_BeingRegenerated = 0x00020000; + const RF_DefaultSubObject = 0x00040000; + const RF_WasLoaded = 0x00080000; + const RF_TextExportTransient = 0x00100000; + const RF_LoadCompleted = 0x00200000; + const RF_InheritableComponentTemplate = 0x00400000; + const RF_DuplicateTransient = 0x00800000; + const RF_StrongRefOnFrame = 0x01000000; + const RF_NonPIEDuplicateTransient = 0x02000000; + const RF_Dynamic = 0x04000000; + const RF_WillBeLoaded = 0x08000000; + } +} +bitflags::bitflags! { + #[derive(Debug, Clone)] + pub struct EFunctionFlags: u32 { + const FUNC_None = 0x0000; + const FUNC_Final = 0x0001; + const FUNC_RequiredAPI = 0x0002; + const FUNC_BlueprintAuthorityOnly = 0x0004; + const FUNC_BlueprintCosmetic = 0x0008; + const FUNC_Net = 0x0040; + const FUNC_NetReliable = 0x0080; + const FUNC_NetRequest = 0x0100; + const FUNC_Exec = 0x0200; + const FUNC_Native = 0x0400; + const FUNC_Event = 0x0800; + const FUNC_NetResponse = 0x1000; + const FUNC_Static = 0x2000; + const FUNC_NetMulticast = 0x4000; + const FUNC_UbergraphFunction = 0x8000; + const FUNC_MulticastDelegate = 0x00010000; + const FUNC_Public = 0x00020000; + const FUNC_Private = 0x00040000; + const FUNC_Protected = 0x00080000; + const FUNC_Delegate = 0x00100000; + const FUNC_NetServer = 0x00200000; + const FUNC_HasOutParms = 0x00400000; + const FUNC_HasDefaults = 0x00800000; + const FUNC_NetClient = 0x01000000; + const FUNC_DLLImport = 0x02000000; + const FUNC_BlueprintCallable = 0x04000000; + const FUNC_BlueprintEvent = 0x08000000; + const FUNC_BlueprintPure = 0x10000000; + const FUNC_EditorOnly = 0x20000000; + const FUNC_Const = 0x40000000; + const FUNC_NetValidate = 0x80000000; + const FUNC_AllFlags = 0xffffffff; + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct UObjectBase { + pub vtable: *const c_void, + pub object_flags: EObjectFlags, + pub internal_index: i32, + pub class_private: *const UClass, + pub name_private: FName, + pub outer_private: *const UObject, +} + +#[derive(Debug)] +#[repr(C)] +pub struct UObjectBaseUtility { + pub uobject_base: UObjectBase, +} + +#[derive(Debug)] +#[repr(C)] +pub struct UObject { + pub uobject_base_utility: UObjectBaseUtility, +} + +#[derive(Debug)] +#[repr(C)] +struct FOutputDevice { + vtable: *const c_void, + b_suppress_event_tag: bool, + b_auto_emit_line_terminator: bool, +} + +#[derive(Debug)] +#[repr(C)] +pub struct UField { + pub uobject: UObject, + pub next: *const UField, +} + +#[derive(Debug)] +#[repr(C)] +pub struct FStructBaseChain { + pub struct_base_chain_array: *const *const FStructBaseChain, + pub num_struct_bases_in_chain_minus_one: i32, +} + +#[derive(Debug)] +#[repr(C)] +struct FFieldClass { + // TODO + name: FName, +} + +#[derive(Debug)] +#[repr(C)] +struct FFieldVariant { + container: *const c_void, + b_is_uobject: bool, +} + +#[derive(Debug)] +#[repr(C)] +pub struct FField { + class_private: *const FFieldClass, + owner: FFieldVariant, + next: *const FField, + name_private: FName, + flags_private: EObjectFlags, +} + +pub struct FProperty { + // TODO +} + +#[derive(Debug)] +#[repr(C)] +pub struct UStruct { + pub ufield: UField, + pub fstruct_base_chain: FStructBaseChain, + pub super_struct: *const UStruct, + pub children: *const UField, + pub child_properties: *const FField, + pub properties_size: i32, + pub min_alignment: i32, + pub script: TArray, + pub property_link: *const FProperty, + pub ref_link: *const FProperty, + pub destructor_link: *const FProperty, + pub post_construct_link: *const FProperty, + pub script_and_property_object_references: TArray<*const UObject>, + pub unresolved_script_properties: *const (), //TODO pub TArray,int>,TSizedDefaultAllocator<32> >* + pub unversioned_schema: *const (), //TODO const FUnversionedStructSchema* +} + +#[derive(Debug)] +#[repr(C)] +pub struct UFunction { + pub ustruct: UStruct, + pub function_flags: EFunctionFlags, + pub num_parms: u8, + pub parms_size: u16, + pub return_value_offset: u16, + pub rpc_id: u16, + pub rpc_response_id: u16, + pub first_property_to_init: *const FProperty, + pub event_graph_function: *const UFunction, + pub event_graph_call_offset: i32, + pub func: unsafe extern "system" fn(*mut UObject, *mut kismet::FFrame, *mut c_void), +} + +#[derive(Debug)] +#[repr(C)] +pub struct UClass { + pub ustruct: UStruct, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FName { + pub comparison_index: FNameEntryId, + pub number: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FNameEntryId { + pub value: u32, +} + +#[derive(Debug)] +#[repr(C)] +pub struct TSharedPtr { + pub object: *const T, + pub reference_controller: *const FReferenceControllerBase, +} + +#[derive(Debug)] +#[repr(C)] +pub struct FReferenceControllerBase { + pub shared_reference_count: i32, + pub weak_reference_count: i32, +} + +pub type FString = TArray; + +#[derive(Debug)] +#[repr(C)] +pub struct TArray { + data: *const T, + num: i32, + max: i32, +} +impl TArray { + fn new() -> Self { + Self { + data: std::ptr::null(), + num: 0, + max: 0, + } + } +} +impl Drop for TArray { + fn drop(&mut self) { + unsafe { + std::ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut( + self.data.cast_mut(), + self.num as usize, + )) + } + globals().gmalloc().free(self.data as *mut c_void); + } +} +impl Default for TArray { + fn default() -> Self { + Self { + data: std::ptr::null(), + num: 0, + max: 0, + } + } +} +impl TArray { + pub fn with_capacity(capacity: usize) -> Self { + Self { + data: globals().gmalloc().malloc( + capacity * std::mem::size_of::(), + std::mem::align_of::() as u32, + ) as *const T, + num: 0, + max: capacity as i32, + } + } + pub fn len(&self) -> usize { + self.num as usize + } + pub fn capacity(&self) -> usize { + self.max as usize + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn as_slice(&self) -> &[T] { + if self.num == 0 { + &[] + } else { + unsafe { std::slice::from_raw_parts(self.data, self.num as usize) } + } + } + pub fn as_mut_slice(&mut self) -> &mut [T] { + if self.num == 0 { + &mut [] + } else { + unsafe { std::slice::from_raw_parts_mut(self.data as *mut _, self.num as usize) } + } + } + pub fn clear(&mut self) { + let elems: *mut [T] = self.as_mut_slice(); + + unsafe { + self.num = 0; + std::ptr::drop_in_place(elems); + } + } + pub fn push(&mut self, new_value: T) { + if self.num >= self.max { + self.max = u32::next_power_of_two((self.max + 1) as u32) as i32; + let new = globals().gmalloc().realloc( + self.data as *mut c_void, + self.max as usize * std::mem::size_of::(), + std::mem::align_of::() as u32, + ) as *const T; + self.data = new; + } + unsafe { + std::ptr::write(self.data.add(self.num as usize).cast_mut(), new_value); + } + self.num += 1; + } +} + +impl From<&[T]> for TArray +where + T: Copy, +{ + fn from(value: &[T]) -> Self { + let mut new = Self::with_capacity(value.len()); + // TODO this is probably unsound + new.num = value.len() as i32; + new.as_mut_slice().copy_from_slice(value); + new + } +} + +impl Display for FString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let slice = self.as_slice(); + let last = slice.len() + - slice + .iter() + .cloned() + .rev() + .position(|c| c != 0) + .unwrap_or_default(); + write!( + f, + "{}", + widestring::U16Str::from_slice(&slice[..last]) + .to_string() + .unwrap() + ) + } +} + +#[derive(Debug, Default)] +#[repr(C)] +pub struct FVector { + pub x: f32, + pub y: f32, + pub z: f32, +} + +#[derive(Debug, Default)] +#[repr(C)] +pub struct FLinearColor { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +pub mod kismet { + use super::*; + + #[derive(Debug)] + #[repr(C)] + pub struct FFrame { + pub base: FOutputDevice, + pub node: *const c_void, + pub object: *mut UObject, + pub code: *const c_void, + pub locals: *const c_void, + pub most_recent_property: *const FProperty, + pub most_recent_property_address: *const c_void, + pub flow_stack: [u8; 0x30], + pub previous_frame: *const FFrame, + pub out_parms: *const c_void, + pub property_chain_for_compiled_in: *const FField, + pub current_native_function: *const c_void, + pub b_array_context_failed: bool, + } + + pub fn arg(stack: &mut FFrame, output: &mut T) { + let output = output as *const _ as *mut _; + unsafe { + if stack.code.is_null() { + let cur = stack.property_chain_for_compiled_in; + stack.property_chain_for_compiled_in = (*cur).next; + (globals().fframe_step_explicit_property())(stack, output, cur as *const FProperty); + } else { + (globals().fframe_step())(stack, stack.object, output); + } + } + } +} diff --git a/src/hooks/admin_control.hpp b/src/hooks/admin_control.hpp index f6fa29f..678d6cc 100644 --- a/src/hooks/admin_control.hpp +++ b/src/hooks/admin_control.hpp @@ -180,4 +180,4 @@ CREATE_HOOK( } o_ClientMessage(this_ptr, param_1, param_2, param_3); } -AUTO_HOOK(ClientMessage); \ No newline at end of file +// AUTO_HOOK(ClientMessage); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4b644e8..ab6f42c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -125,7 +125,7 @@ void CreateDebugConsole() { freopen_s(&pCerr, "CONOUT$", "w", stderr); std::ios::sync_with_stdio(true); - SetConsoleTitleA("Chivalry 2 Unchained Debug"); + // SetConsoleTitleA("Chivalry 2 Unchained Debug"); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); DWORD consoleMode; @@ -141,6 +141,7 @@ DWORD WINAPI main_thread(LPVOID lpParameter) { initialize_global_logger(LogLevel::INFO); GLOG_INFO("Logger initialized {}", generate_json()); + GLOG_INFO("Parsing CLI args"); auto cliArgs = CLIArgs::Parse(GetCommandLineW()); HMODULE hModule = static_cast(lpParameter); @@ -209,12 +210,18 @@ DWORD WINAPI main_thread(LPVOID lpParameter) { // Dedicated server hook in ApproveLogin //Nop(module_base + g_state->GetBuildMetadata().GetOffset(strFunc[F_ApproveLogin]) + 0x46, 6); + // 19626AE + 0xF FIXME: THIS IS STEAM ONLYYY + // Ptch_Nop(module_base + 0x19626bd, 5); // nop the function call which assigns str or smth + + // Ptch_Repl(module_base + 0x196260a, 0xEB); // try to replace if in eos msg + + if (!all_hooks_successful) { GLOG_ERROR("Failed to hook all functions. Unchained may not function as expected."); } GLOG_INFO("Continuing to RCON"); - handleRCON(); //this has an infinite loop for commands! Keep this at the end! + // handleRCON(); //this has an infinite loop for commands! Keep this at the end! ExitThread(0); } catch (const std::exception& e) {