From d126537e8463309aabc2e1d8ad7450a4b2d55f32 Mon Sep 17 00:00:00 2001 From: hamflx Date: Sat, 9 Apr 2022 19:18:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AE=89=E8=A3=85=E4=B9=8B?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E5=8D=8E=E4=B8=BA=E7=94=B5=E8=84=91=E7=AE=A1?= =?UTF-8?q?=E5=AE=B6=E7=9A=84=E4=BD=BF=E7=94=A8=E6=8A=80=E5=B7=A7=E5=8F=8A?= =?UTF-8?q?=E5=A4=9A=E5=B1=8F=E5=8D=8F=E5=90=8C=20(#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add FnGetSystemFirmwareTable hook * docs: Add x64 build command line * chore: 使用可用的产品名称 * feat: run as admin, ui demo * feat: Add browse and install support for gui * chore: Restore crate-type of lib. * chore: Remove deprecated code. * docs: Add version.dll impl methods. * refactor: Add version.dll package. * feat: Add proxy dll version.dll. * feat: Add option to inject sub processes. * fix: Fix arch mismatch errors. * fix: Fix crashes caused by multiple initializations. * feat: Add file logger, pretty ui. * feat: Add install patch. * feat: optimize installing process. * fix: Fix services problems caused by inject system process. * fix: Fix crashes caused by initializing logger errors. * docs: Add usage and principle. --- .gitignore | 1 + Cargo.lock | 2712 ++++++++++++++++- Cargo.toml | 31 +- README.md | 30 +- build.bat | 7 + docs/images/install.png | Bin 0 -> 66906 bytes docs/images/location.png | Bin 0 -> 60249 bytes packages/common/Cargo.toml | 24 + packages/common/src/common.rs | 679 +++++ {src => packages/common/src}/communication.rs | 0 packages/common/src/lib.rs | 2 + .../Cargo.toml | 17 + .../src/lib.rs | 58 + .../huawei-pc-manager-bootstrap/Cargo.toml | 27 + .../huawei-pc-manager-bootstrap/src/app.rs | 372 +++ .../huawei-pc-manager-bootstrap/src/main.rs | 35 + packages/version/Cargo.toml | 21 + packages/version/src/lib.rs | 197 ++ src/common.rs | 352 --- src/lib.rs | 40 - src/main.rs | 40 - version.exports | 17 + 22 files changed, 4049 insertions(+), 613 deletions(-) create mode 100644 build.bat create mode 100644 docs/images/install.png create mode 100644 docs/images/location.png create mode 100644 packages/common/Cargo.toml create mode 100644 packages/common/src/common.rs rename {src => packages/common/src}/communication.rs (100%) create mode 100644 packages/common/src/lib.rs create mode 100644 packages/huawei-pc-manager-bootstrap-core/Cargo.toml create mode 100644 packages/huawei-pc-manager-bootstrap-core/src/lib.rs create mode 100644 packages/huawei-pc-manager-bootstrap/Cargo.toml create mode 100644 packages/huawei-pc-manager-bootstrap/src/app.rs create mode 100644 packages/huawei-pc-manager-bootstrap/src/main.rs create mode 100644 packages/version/Cargo.toml create mode 100644 packages/version/src/lib.rs delete mode 100644 src/common.rs delete mode 100644 src/lib.rs delete mode 100644 src/main.rs create mode 100644 version.exports diff --git a/.gitignore b/.gitignore index ea8c4bf..4f96631 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/dist diff --git a/Cargo.lock b/Cargo.lock index 9ade45c..d1fd40a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,170 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ab_glyph" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e" + +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_glue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" + [[package]] name = "anyhow" version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +[[package]] +name = "async-broadcast" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b" +dependencies = [ + "easy-parallel", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-io" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +dependencies = [ + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi 0.3.9", +] + +[[package]] +name = "async-lock" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-task" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" + +[[package]] +name = "async-trait" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic_refcell" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b5e5f48b927f04e952dedc932f31995a65a0bf65ec971c74436e51bf6e970d" + [[package]] name = "atty" version = "0.2.14" @@ -19,6 +177,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bincode" version = "1.3.3" @@ -34,18 +198,172 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "bytemuck" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cache-padded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + +[[package]] +name = "cairo-sys-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "calloop" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82" +dependencies = [ + "log", + "nix 0.22.3", +] + [[package]] name = "cc" version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-expr" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e068cb2806bbc15b439846dc16c5f89f8599f2c3e4d73d4449d38f9b2f0b6c5" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time 0.1.43", + "winapi 0.3.9", +] + +[[package]] +name = "clipboard-win" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" +dependencies = [ + "lazy-bytes-cast", + "winapi 0.3.9", +] + +[[package]] +name = "cocoa" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation 0.9.3", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + [[package]] name = "colored" version = "2.0.0" @@ -58,245 +376,2122 @@ dependencies = [ ] [[package]] -name = "detour" -version = "0.8.1" +name = "combine" +version = "4.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c83fabcc3bc336e19320c13576ea708a15deec201d6b879b7ad1b92734d7b9" +checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" dependencies = [ - "cfg-if", - "generic-array", - "lazy_static", + "bytes", + "memchr", +] + +[[package]] +name = "common" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "detour", + "log", + "serde", + "simple_logger", + "widestring", + "windows-sys", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "copypasta" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b" +dependencies = [ + "clipboard-win", + "objc", + "objc-foundation", + "objc_id", + "smithay-clipboard", + "x11-clipboard", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", "libc", - "libudis86-sys", - "mmap-fixed", - "region", - "slice-pool", ] [[package]] -name = "generic-array" -version = "0.14.5" +name = "core-foundation" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ - "typenum", - "version_check", + "core-foundation-sys 0.8.3", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation 0.9.3", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation 0.9.3", + "foreign-types", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" +dependencies = [ + "cfg-if 0.1.10", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.2", + "libc", + "objc", ] [[package]] -name = "hermit-abi" +name = "ctrlc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf" +dependencies = [ + "nix 0.23.1", + "winapi 0.3.9", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "dark-light" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b83576e2eee2d9cdaa8d08812ae59cbfe1b5ac7ac5ac4b8400303c6148a88c1" +dependencies = [ + "dconf_rs", + "detect-desktop-environment", + "dirs", + "objc", + "rust-ini", + "web-sys", + "winreg", + "zbus", + "zvariant", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dconf_rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "detect-desktop-environment" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810" + +[[package]] +name = "detour" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c83fabcc3bc336e19320c13576ea708a15deec201d6b879b7ad1b92734d7b9" +dependencies = [ + "cfg-if 1.0.0", + "generic-array", + "lazy_static", + "libc", + "libudis86-sys", + "mmap-fixed", + "region", + "slice-pool", +] + +[[package]] +name = "directories" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading", +] + +[[package]] +name = "dlv-list" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" +dependencies = [ + "rand", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "easy-parallel" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" + +[[package]] +name = "eframe" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9fe0985844076809b8c08b609266567797a6b721abb6a4975e158ab413cd6f2" +dependencies = [ + "egui", + "egui-winit", + "egui_glow", + "egui_web", + "epi", +] + +[[package]] +name = "egui" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a3cd1d47e12f7a17912595241622e373aa652a4e0fa90b3f9278f90a64aedf7" +dependencies = [ + "ahash 0.7.6", + "epaint", + "nohash-hasher", + "tracing", +] + +[[package]] +name = "egui-winit" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43eac3180ea178ef1a5f3048cc12c58bcbcb17fc3401813f7229c99ef2ffc1d9" +dependencies = [ + "copypasta", + "dark-light", + "egui", + "epi", + "instant", + "tracing", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_glow" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04a252f6d333fceb910a8f5b3ef2d4402e1646cd4daa11e7b11ea38d1b6190d3" +dependencies = [ + "bytemuck", + "egui", + "egui-winit", + "epi", + "glow", + "glutin", + "memoffset", + "tracing", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "egui_web" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030f81109b90583cd7b3bc7e4bb31dfae615f4adcc422b1b313030929d3b350c" +dependencies = [ + "bytemuck", + "egui", + "egui_glow", + "epi", + "js-sys", + "percent-encoding", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "emath" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a977a80456be58a2c2d48e69c1d0baadef46cecef5a0c98df141c468da006f12" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "enumflags2" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b3ab37dc79652c9d85f1f7b6070d77d321d2467f5fe7b00d6b7a86c57b092ae" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "epaint" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033292846059f08e03a71e1b5db2ee6ab7c9622c3b48da21f4bd13258ebee2db" +dependencies = [ + "ab_glyph", + "ahash 0.7.6", + "atomic_refcell", + "bytemuck", + "emath", + "nohash-hasher", +] + +[[package]] +name = "epi" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95445deccef4d29fa30488d3f7f2e942dd343eef01228becc7cefd5b918176e" +dependencies = [ + "egui", + "tracing", +] + +[[package]] +name = "event-listener" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[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.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "gio-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi 0.3.9", +] + +[[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 = "glib-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glow" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ea9dbe544bc8a657c4c4a798c2d16cd01b549820e47657297549d28371f6d2" +dependencies = [ + "android_glue", + "cgl", + "cocoa", + "core-foundation 0.9.3", + "glutin_egl_sys", + "glutin_emscripten_sys", + "glutin_gles2_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "lazy_static", + "libloading", + "log", + "objc", + "osmesa-sys", + "parking_lot", + "wayland-client", + "wayland-egl", + "winapi 0.3.9", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211" +dependencies = [ + "gl_generator", + "winapi 0.3.9", +] + +[[package]] +name = "glutin_emscripten_sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1" + +[[package]] +name = "glutin_gles2_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103" +dependencies = [ + "gl_generator", + "objc", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gobject-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.7", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "huawei-pc-manager-bootstrap" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "common", + "ctrlc", + "directories", + "eframe", + "log", + "rfd", + "simplelog", + "windows-sys", +] + +[[package]] +name = "huawei-pc-manager-bootstrap-core" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "chrono", + "common", + "directories", + "log", + "simplelog", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "lazy-bytes-cast" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if 1.0.0", + "winapi 0.3.9", +] + +[[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 = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +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 = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memmap2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" +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 = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "winapi 0.3.9", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "mmap-fixed" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c1ae264d6343d3b4079549f6bc9e6d074dc4106cb1324c7753c6ce11d07b21" +dependencies = [ + "kernel32-sys", + "libc", + "winapi 0.2.8", +] + +[[package]] +name = "ndk" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.2.2", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5cc68637e21fe8f077f6a1c9e0b9ca495bb74895226b476310f613325884" + +[[package]] +name = "ndk-glue" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1c68f70683c5fc9a747a383744206cd371741b2f0b31781ab6770487ec572e2" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.5.0", + "ndk-context", + "ndk-macro", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ffb7443daba48349d545028777ca98853b018b4c16624aa01223bc29e078da" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.6.0", + "ndk-context", + "ndk-macro", + "ndk-sys 0.3.0", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num_threads" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +dependencies = [ + "libc", +] + +[[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-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "ordered-multimap" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" +dependencies = [ + "dlv-list", + "hashbrown", +] + +[[package]] +name = "ordered-stream" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "osmesa-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" +dependencies = [ + "shared_library", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1e509cfe7a12db2a90bfa057dfcdbc55a347f5da677c506b53dd099cfec9d" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "pango-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.9", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "polling" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "log", + "wepoll-ffi", + "winapi 0.3.9", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-xml" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "raw-window-handle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" +dependencies = [ + "cty", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "region" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi 0.3.9", +] + +[[package]] +name = "rfd" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca9214be1b6d296d4d539a31e795e556cdb43e60cbf0b77003be5b01075c13" +dependencies = [ + "block", + "dispatch", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "lazy_static", + "log", + "objc", + "objc-foundation", + "objc_id", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows", +] + +[[package]] +name = "rust-ini" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" +dependencies = [ + "cfg-if 1.0.0", + "ordered-multimap", +] + +[[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 = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_repr" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + +[[package]] +name = "simple_logger" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75a9723083573ace81ad0cdfc50b858aa3c366c48636edb4109d73122a0c0ea" +dependencies = [ + "atty", + "colored", + "log", + "time 0.3.9", + "winapi 0.3.9", +] + +[[package]] +name = "simplelog" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1348164456f72ca0116e4538bdaabb0ddb622c7d9f16387c725af3e96d6001c" +dependencies = [ + "chrono", + "log", + "termcolor", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "slice-pool" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733fc6e5f1bd3a8136f842c9bdea4e5f17c910c2fcc98c90c3aa7604ef5e2e7a" + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "smithay-client-toolkit" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1325f292209cee78d5035530932422a30aa4c8fda1a16593ac083c1de211e68a" +dependencies = [ + "bitflags", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.22.3", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610b551bd25378bfd2b8e7a0fcbd83d427e8f2f6a40c47ae0f70688e9949dd55" +dependencies = [ + "smithay-client-toolkit", + "wayland-client", +] + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "tracing" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "ttf-parser" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c74c96594835e10fa545e2a51e8709f30b173a092bfd6036ef2cec53376244f3" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ - "libc", + "tinyvec", ] [[package]] -name = "itoa" -version = "1.0.1" +name = "unicode-xid" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "url" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "form_urlencoded", + "idna", + "matches", + "percent-encoding", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "version" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "common", + "directories", + "log", + "simplelog", + "windows-sys", +] + +[[package]] +name = "version-compare" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" [[package]] -name = "libc" -version = "0.2.121" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "libudis86-sys" -version = "0.2.1" +name = "waker-fn" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139bbf9ddb1bfc90c1ac64dd2923d9c957cd433cee7315c018125d72ab08a6b0" -dependencies = [ - "cc", - "libc", -] +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] -name = "log" -version = "0.4.14" +name = "walkdir" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ - "cfg-if", + "same-file", + "winapi 0.3.9", + "winapi-util", ] [[package]] -name = "mach" -version = "0.3.2" +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" -dependencies = [ - "libc", -] +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] -name = "mmap-fixed" -version = "0.1.5" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c1ae264d6343d3b4079549f6bc9e6d074dc4106cb1324c7753c6ce11d07b21" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ - "kernel32-sys", - "libc", - "winapi 0.2.8", + "cfg-if 1.0.0", + "wasm-bindgen-macro", ] [[package]] -name = "num_threads" -version = "0.1.5" +name = "wasm-bindgen-backend" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ - "libc", + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", ] [[package]] -name = "proc-macro2" -version = "1.0.36" +name = "wasm-bindgen-futures" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" dependencies = [ - "unicode-xid", + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "program-bootstrap" -version = "0.1.0" +name = "wasm-bindgen-macro" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ - "anyhow", - "bincode", - "detour", - "log", - "serde", - "simple_logger", - "widestring", - "windows-sys", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "quote" -version = "1.0.16" +name = "wasm-bindgen-macro-support" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] -name = "region" -version = "2.2.0" +name = "wasm-bindgen-shared" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "wayland-client" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" dependencies = [ "bitflags", + "downcast-rs", "libc", - "mach", - "winapi 0.3.9", + "nix 0.22.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys", ] [[package]] -name = "serde" -version = "1.0.136" +name = "wayland-commons" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" dependencies = [ - "serde_derive", + "nix 0.22.3", + "once_cell", + "smallvec", + "wayland-sys", ] [[package]] -name = "serde_derive" -version = "1.0.136" +name = "wayland-cursor" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" dependencies = [ - "proc-macro2", - "quote", - "syn", + "nix 0.22.3", + "wayland-client", + "xcursor", ] [[package]] -name = "simple_logger" -version = "2.1.0" +name = "wayland-egl" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75a9723083573ace81ad0cdfc50b858aa3c366c48636edb4109d73122a0c0ea" +checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a" dependencies = [ - "atty", - "colored", - "log", - "time", - "winapi 0.3.9", + "wayland-client", + "wayland-sys", ] [[package]] -name = "slice-pool" -version = "0.4.1" +name = "wayland-protocols" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733fc6e5f1bd3a8136f842c9bdea4e5f17c910c2fcc98c90c3aa7604ef5e2e7a" +checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] [[package]] -name = "syn" -version = "1.0.89" +name = "wayland-scanner" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "xml-rs", ] [[package]] -name = "time" -version = "0.3.7" +name = "wayland-sys" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" dependencies = [ - "itoa", - "libc", - "num_threads", - "time-macros", + "dlib", + "lazy_static", + "pkg-config", ] [[package]] -name = "time-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" - -[[package]] -name = "typenum" -version = "1.15.0" +name = "web-sys" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "webbrowser" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "f9c28b6b6a78440b02647358625e3febc90724126480b9da6a967b5f674b3554" +dependencies = [ + "jni", + "ndk-glue 0.6.1", + "url", + "web-sys", + "widestring", + "winapi 0.3.9", +] [[package]] -name = "version_check" -version = "0.9.4" +name = "wepoll-ffi" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] [[package]] name = "widestring" @@ -332,51 +2527,278 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + [[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.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0128fa8e65e0616e45033d68dc0b7fbd521080b7844e5cad3a4a4d201c4b2bd2" +dependencies = [ + "windows_aarch64_msvc 0.33.0", + "windows_i686_gnu 0.33.0", + "windows_i686_msvc 0.33.0", + "windows_x86_64_gnu 0.33.0", + "windows_x86_64_msvc 0.33.0", +] + [[package]] name = "windows-sys" -version = "0.34.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "c700bb45cfcbdb738ce92c41fc13e512514d4eaf6a99e8c87e2260a227175c16" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.35.0", + "windows_i686_gnu 0.35.0", + "windows_i686_msvc 0.35.0", + "windows_x86_64_gnu 0.35.0", + "windows_x86_64_msvc 0.35.0", ] [[package]] name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3bc5134e8ce0da5d64dcec3529793f1d33aee5a51fc2b4662e0f881dd463e6" + +[[package]] +name = "windows_i686_gnu" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" [[package]] name = "windows_i686_gnu" -version = "0.34.0" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0343a6f35bf43a07b009b8591b78b10ea03de86b06f48e28c96206cd0f453b50" + +[[package]] +name = "windows_i686_msvc" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" [[package]] name = "windows_i686_msvc" -version = "0.34.0" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1acdcbf4ca63d8e7a501be86fee744347186275ec2754d129ddeab7a1e3a02e4" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" [[package]] name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "893c0924c5a990ec73cd2264d1c0cba1773a929e1a3f5dbccffd769f8c4edebb" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" [[package]] name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a29bd61f32889c822c99a8fdf2e93378bd2fae4d7efd2693fab09fcaaf7eff4b" + +[[package]] +name = "winit" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a" +dependencies = [ + "bitflags", + "cocoa", + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "core-video-sys", + "dispatch", + "instant", + "lazy_static", + "libc", + "log", + "mio", + "ndk 0.5.0", + "ndk-glue 0.5.1", + "ndk-sys 0.2.2", + "objc", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "wayland-protocols", + "web-sys", + "winapi 0.3.9", + "x11-dl", +] + +[[package]] +name = "winreg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d107f8c6e916235c4c01cabb3e8acf7bea8ef6a63ca2e7fa0527c049badfc48c" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "x11-clipboard" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c" +dependencies = [ + "xcb", +] + +[[package]] +name = "x11-dl" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +dependencies = [ + "lazy_static", + "libc", + "pkg-config", +] + +[[package]] +name = "xcb" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c" +dependencies = [ + "libc", + "log", + "quick-xml", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + +[[package]] +name = "zbus" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb86f3d4592e26a48b2719742aec94f8ae6238ebde20d98183ee185d1275e9a" +dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", + "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", + "byteorder", + "derivative", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "lazy_static", + "nix 0.23.1", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "winapi 0.3.9", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36823cc10fddc3c6b19f048903262dacaf8274170e9a255784bdd8b4570a8040" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "zbus_names" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zvariant" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ea5dc38b2058fae6a5b79009388143dadce1e91c26a67f984a0fc0381c8033" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "8c2cecc5a61c2a053f7f653a24cd15b3b0195d7f7ddb5042c837fb32e161fb7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 9e4019e..d622674 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,27 +1,4 @@ -[package] -name = "program-bootstrap" -version = "0.1.0" -edition = "2021" - -[lib] -name = "program_bootstrap_core" -crate-type = ["cdylib"] - -[dependencies] -anyhow = "1.0.56" -bincode = "1.3.3" -detour = "0.8.1" -log = "0.4.14" -widestring = "0.5.1" -windows-sys = { version = "0.34.0", features = [ - "Win32_Foundation", - "Win32_Security", - "Win32_System_LibraryLoader", - "Win32_UI_WindowsAndMessaging", - "Win32_System_Threading", - "Win32_System_Memory", - "Win32_System_Diagnostics_Debug", - "Win32_System_SystemInformation" -] } -serde = { version = "1.0", features = ["derive"] } -simple_logger = "2.1.0" +[workspace] +members = [ + "packages/*" +] diff --git a/README.md b/README.md index c4b563b..abf036b 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,34 @@ 该仓库用以解决华为电脑管家 V12 无法在非华为电脑上安装的问题。 -**声明:该仓库目前只解决了安装问题,安装后部分功能会无法使用或者不好用(基础的多屏协同可用但是交互会有些异常)。** +## 使用方式 -对于部分功能无法使用的问题,可以使用汉客儿网站的 `version.dll`(目前最新的是 `PCManagerMgrPatch.exe`)来解决,但是该工具是未开源的。 +下载最新版本的安装器:。 -## 使用方式 +下载最新版本的华为电脑管家(目前测试支持的版本为:12.0.1.26(C233D003)),并将其解压,与安装器解压之后放置于同一个目录,如下图所示: + +![解压位置](./docs/images/location.png "解压后的位置") + +双击 `huawei-pc-manager-bootstrap.exe` 启动安装器(注意,启动安装器之后,将会请求管理员权限,因为华为电脑管家管家是需要管理员权限的)。 + +打开安装器之后,点击“自动扫描”按钮,安装器会查找所在目录的华为电脑管家安装包,如果找到安装包,会自动将安装包路径填写到上方的输入框中(如果未能自动找到安装包,应点击“浏览”按照选择安装包,或者手动输入绝对路径)。 + +![安装器自动扫描](./docs/images/install.png "安装器自动扫描") -先安装 `Rust` 开发环境,这里就不赘述了。安装完环境后,克隆源码并构建: +点击“安装”按钮,安装器将启动安装包程序。**注意,安装过程中,安装器将会自动检测华为电脑管家的主程序是否已经安装完毕(即 `C:\Program Files\Huawei\PCManager\PCManager.exe` 该文件已经存在)。如果检测到该文件,则会自动释放补丁文件 `version.dll` 到该目录。** + +## 从源码构建 + +输入以下命令,所有命令都成功之后,会在项目下建立 `dist` 目录,保存构建成功的文件。 ```cmd git clone https://github.com/hamflx/huawei-pc-manager-bootstrap.git cd huawei-pc-manager-bootstrap -cargo +nightly-i686-pc-windows-msvc build --target=i686-pc-windows-msvc + +.\build.bat ``` -构建成功后,将会在该目录 `target\i686-pc-windows-msvc\debug\program-bootstrap.exe` 中看到 `program-bootstrap.exe`。开启一个管理员(华为电脑管家安装需要管理员权限)命令行窗口,进入到该目录运行: +## 实现思路 -```cmd -program-bootstrap.exe PCManager_Setup_12.0.1.26(C233D003).exe -``` +1. 安装器启动安装包进行安装,在安装包执行 `"C:\Program Files\Huawei\PCManager\tmp\MBAInstallPre.exe" isSupportDevice` 和 `"C:\Program Files\Huawei\PCManager\tmp\MBAInstallPre.exe" IsSupportBaZhang` 时,结束该进程,并返回一个通过的值。 +2. 上一步仅能保证能安装成功,但是在打开华为电脑管家时交互有些异常,以及一些联网功能无法使用。因此通过 `dll` 劫持让华为电脑管家加载自己开发的 `version.dll` 然后在该 `dll` 加载时,劫持 `GetSystemFirmwareTable` 函数,返回一个华为的型号即可。 diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..8d64b8c --- /dev/null +++ b/build.bat @@ -0,0 +1,7 @@ +if not exist dist mkdir dist + +cargo +nightly-x86_64-pc-windows-msvc build --release -p version --target=x86_64-pc-windows-msvc || exit 1 +cargo +nightly-i686-pc-windows-msvc build --release -p huawei-pc-manager-bootstrap-core -p huawei-pc-manager-bootstrap --target=i686-pc-windows-msvc || exit 1 + +copy target\i686-pc-windows-msvc\release\huawei_pc_manager_bootstrap_core.dll dist +copy target\i686-pc-windows-msvc\release\huawei-pc-manager-bootstrap.exe dist diff --git a/docs/images/install.png b/docs/images/install.png new file mode 100644 index 0000000000000000000000000000000000000000..d5fa295fd782b46247f21b68b3f56ed21b529e8d GIT binary patch literal 66906 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

?cwPOHn+-chR2T+;Vc<= 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 literal 0 HcmV?d00001 diff --git a/packages/common/Cargo.toml b/packages/common/Cargo.toml new file mode 100644 index 0000000..5438905 --- /dev/null +++ b/packages/common/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "common" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.56" +bincode = "1.3.3" +detour = "0.8.1" +log = "0.4.14" +widestring = "0.5.1" +windows-sys = { version = "0.35.0", features = [ + "Win32_Foundation", + "Win32_Security", + "Win32_System_LibraryLoader", + "Win32_UI_Shell", + "Win32_UI_WindowsAndMessaging", + "Win32_System_Threading", + "Win32_System_Memory", + "Win32_System_Diagnostics_Debug", + "Win32_System_SystemInformation" +] } +serde = { version = "1.0", features = ["derive"] } +simple_logger = "2.1.0" diff --git a/packages/common/src/common.rs b/packages/common/src/common.rs new file mode 100644 index 0000000..e215256 --- /dev/null +++ b/packages/common/src/common.rs @@ -0,0 +1,679 @@ +use detour::static_detour; +use log::{info, warn}; +use serde::{Deserialize, Serialize}; +use std::{ + ffi::{c_void, CStr, CString}, + intrinsics::transmute, + mem::MaybeUninit, + ptr, + slice::from_raw_parts, +}; +use widestring::U16CString; +use windows_sys::{ + core::{PCSTR, PCWSTR, PWSTR}, + Win32::{ + Foundation::{GetLastError, BOOL, FARPROC, HANDLE}, + Security::SECURITY_ATTRIBUTES, + System::{ + Diagnostics::Debug::{WriteProcessMemory, PROCESSOR_ARCHITECTURE_INTEL}, + LibraryLoader::{GetModuleFileNameA, GetProcAddress, LoadLibraryA}, + Memory::{VirtualAllocEx, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE}, + SystemInformation::{ + GetNativeSystemInfo, GetSystemDirectoryA, FIRMWARE_TABLE_ID, + FIRMWARE_TABLE_PROVIDER, SYSTEM_INFO, + }, + Threading::{ + CreateRemoteThread, GetCurrentProcess, GetExitCodeThread, GetThreadId, + IsWow64Process, ResumeThread, TerminateProcess, WaitForSingleObject, + CREATE_SUSPENDED, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, STARTUPINFOW, + }, + }, + }, +}; + +#[derive(Serialize, Deserialize, Clone)] +pub struct InjectOptions { + pub server_address: Option, + pub inject_sub_process: bool, + pub includes_system_process: bool, +} + +#[repr(C)] +#[derive(Serialize, Deserialize)] +pub struct INJECT_OPTIONS_WRAPPER { + pub len: usize, + pub ptr: u64, +} + +#[repr(C)] +#[derive(Clone)] +#[allow(non_snake_case)] +pub struct RawSMBIOSData { + pub Used20CallingMethod: u8, + pub SMBIOSMajorVersion: u8, + pub SMBIOSMinorVersion: u8, + pub DmiRevision: u8, + pub Length: u32, + pub SMBIOSTableData: [u8; 0], +} + +#[repr(C)] +#[derive(Clone)] +#[allow(non_snake_case)] +pub struct SMBIOSHEADER { + pub Type: u8, + pub Length: u8, + pub Handle: u16, +} + +#[repr(C)] +#[derive(Clone)] +#[allow(non_snake_case)] +pub struct SystemInfo { + pub Header: SMBIOSHEADER, + pub Manufacturer: u8, + pub ProductName: u8, + pub Version: u8, + pub SN: u8, + pub UUID: [u8; 16], + pub WakeUpType: u8, + pub SKUNumber: u8, + pub Family: u8, +} + +type FnCreateProcessW = unsafe extern "system" fn( + PCWSTR, + PWSTR, + *const SECURITY_ATTRIBUTES, + *const SECURITY_ATTRIBUTES, + BOOL, + PROCESS_CREATION_FLAGS, + *const c_void, + PCWSTR, + *const STARTUPINFOW, + *mut PROCESS_INFORMATION, +) -> BOOL; +type FnGetSystemFirmwareTable = unsafe extern "system" fn( + FIRMWARE_TABLE_PROVIDER, + FIRMWARE_TABLE_ID, + *mut ::core::ffi::c_void, + u32, +) -> u32; +type FnEnumSystemFirmwareTables = unsafe extern "system" fn( + firmwaretableprovidersignature: FIRMWARE_TABLE_PROVIDER, + pfirmwaretableenumbuffer: *mut FIRMWARE_TABLE_ID, + buffersize: u32, +) -> u32; + +static_detour! { + static HookCreateProcessW: unsafe extern "system" fn( + PCWSTR, + PWSTR, + *const SECURITY_ATTRIBUTES, + *const SECURITY_ATTRIBUTES, + BOOL, + PROCESS_CREATION_FLAGS, + *const c_void, + PCWSTR, + *const STARTUPINFOW, + *mut PROCESS_INFORMATION + ) -> BOOL; + static HookGetSystemFirmwareTable: unsafe extern "system" fn( + u32, + u32, + *mut c_void, + u32 + ) -> u32; + static HookEnumSystemFirmwareTables: unsafe extern "system" fn( + u32, + *mut u32, + u32 + ) -> u32; +} + +static LIBRARY_NAME: &str = "huawei_pc_manager_bootstrap_core.dll"; + +fn detour_get_system_firmware_table( + firmwaretableprovidersignature: FIRMWARE_TABLE_PROVIDER, + firmwaretableid: FIRMWARE_TABLE_ID, + pfirmwaretablebuffer: *mut ::core::ffi::c_void, + buffersize: u32, +) -> u32 { + let sig_name = get_firmware_table_provider_signature(firmwaretableprovidersignature); + let id_name = get_firmware_table_provider_signature(firmwaretableid); + info!( + "Calling GetSystemFirmwareTable: {}({}), {}({}), 0x{:x}, {}", + firmwaretableprovidersignature, + sig_name, + firmwaretableid, + id_name, + pfirmwaretablebuffer as usize, + buffersize + ); + + let result = unsafe { + HookGetSystemFirmwareTable.call( + firmwaretableprovidersignature, + firmwaretableid, + pfirmwaretablebuffer, + buffersize, + ) + }; + if result != 0 && !pfirmwaretablebuffer.is_null() { + unsafe { + let raw_bios_ptr = pfirmwaretablebuffer as *mut RawSMBIOSData; + let start_ptr: *mut u8 = transmute(&(*raw_bios_ptr).SMBIOSTableData); + let end_ptr = start_ptr.add((*raw_bios_ptr).Length as usize); + let mut header_ptr: *mut SMBIOSHEADER = transmute(start_ptr as *mut u8); + + loop { + if (*header_ptr).Type == 1 { + // http://huaweisn.com/ + let new_sys_info = construct_own_sys_info( + header_ptr as *mut SystemInfo, + "HUAWEI", + "HKD-WXX", + "1.0", + "5EKPM18320000397", + "C233", + ); + let first_str_ptr = (header_ptr as *mut u8).add((*header_ptr).Length as usize); + new_sys_info + .iter() + .enumerate() + .for_each(|(i, ch)| *(first_str_ptr.add(i)) = *ch); + + dump_sys_info(header_ptr); + } + + if (*header_ptr).Type == 127 && (*header_ptr).Length == 4 { + break; + } + + let mut next_header = (header_ptr as *const u8).offset((*header_ptr).Length.into()); + while 0 != (*next_header | *(next_header.offset(1))) { + next_header = next_header.offset(1); + } + next_header = next_header.offset(2); + if next_header >= end_ptr { + break; + } + header_ptr = next_header as *mut SMBIOSHEADER; + } + } + } + result +} + +fn dump_sys_info(header_ptr: *const SMBIOSHEADER) { + let system_info_ptr = header_ptr as *const SystemInfo; + let first_str_ptr = unsafe { (header_ptr as *const u8).add((*header_ptr).Length as usize) }; + info!( + "Manufacturer: {}", + locate_string(first_str_ptr, unsafe { (*system_info_ptr).Manufacturer }) + .unwrap_or_else(|| String::from("No Manufacturer")) + ); + info!( + "ProductName: {}", + locate_string(first_str_ptr, unsafe { (*system_info_ptr).ProductName }) + .unwrap_or_else(|| String::from("No ProductName")) + ); + info!( + "Version: {}", + locate_string(first_str_ptr, unsafe { (*system_info_ptr).Version }) + .unwrap_or_else(|| String::from("No Version")) + ); + info!( + "SN: {}", + locate_string(first_str_ptr, unsafe { (*system_info_ptr).SN }) + .unwrap_or_else(|| String::from("No SN")) + ); + info!( + "SysInfoData: {:?}", + String::from_utf8_lossy(unsafe { from_raw_parts(first_str_ptr, 100) }) + ); +} + +fn construct_own_sys_info( + sys_info_header: *mut SystemInfo, + manufacture: &str, + product_name: &str, + version: &str, + sn: &str, + _sku: &str, +) -> Vec { + let sys_info_data = format!("{}\0{}\0{}\0{}\0", manufacture, product_name, version, sn); + + unsafe { + (*sys_info_header).Manufacturer = 1; + (*sys_info_header).ProductName = 2; + (*sys_info_header).Version = 3; + (*sys_info_header).SN = 4; + + (*sys_info_header).WakeUpType = 0; + (*sys_info_header).SKUNumber = 0; + (*sys_info_header).Family = 0; + } + + sys_info_data.as_bytes().to_vec() +} + +fn locate_string(oem_str: *const u8, index: u8) -> Option { + if index == 0 || unsafe { *oem_str } == 0 { + return None; + } + let mut i = index; + let mut str_ptr = oem_str; + loop { + i -= 1; + if i == 0 { + break; + } + str_ptr = unsafe { str_ptr.add(str_len(str_ptr) as usize + 1) } + } + Some( + unsafe { CStr::from_ptr(str_ptr as *const i8) } + .to_str() + .unwrap() + .to_string(), + ) +} + +fn str_len(cstr: *const u8) -> usize { + let mut current_ptr = cstr; + let mut count = 0; + while unsafe { *current_ptr != 0 } { + count += 1; + current_ptr = unsafe { current_ptr.offset(1) }; + } + return count; +} + +fn detour_enum_system_firmware_tables( + firmwaretableprovidersignature: FIRMWARE_TABLE_PROVIDER, + pfirmwaretableenumbuffer: *mut FIRMWARE_TABLE_ID, + buffersize: u32, +) -> u32 { + let sig_name = get_firmware_table_provider_signature(firmwaretableprovidersignature); + info!( + "Calling EnumSystemFirmwareTables: {}, 0x{:x}, {}", + sig_name, pfirmwaretableenumbuffer as usize, buffersize + ); + + let result = unsafe { + HookEnumSystemFirmwareTables.call( + firmwaretableprovidersignature, + pfirmwaretableenumbuffer, + buffersize, + ) + }; + result +} + +#[allow(clippy::too_many_arguments)] +fn detour_create_process( + opts: &Option, + app_name: PCWSTR, + cmd_line: PWSTR, + proc_attrs: *const SECURITY_ATTRIBUTES, + th_attrs: *const SECURITY_ATTRIBUTES, + inherit: BOOL, + flags: PROCESS_CREATION_FLAGS, + env: *const c_void, + cur_dir: PCWSTR, + startup_info: *const STARTUPINFOW, + proc_info: *mut PROCESS_INFORMATION, +) -> BOOL { + unsafe { + let app_name_string = if app_name.is_null() { + String::new() + } else { + U16CString::from_ptr_str(app_name).to_string().unwrap() + }; + let cmd_line_string = if cmd_line.is_null() { + String::new() + } else { + U16CString::from_ptr_str(cmd_line).to_string().unwrap() + }; + info!("CreateProcessW: {} {}", app_name_string, cmd_line_string); + let flags_with_suspend = CREATE_SUSPENDED | flags; + let creating_res = HookCreateProcessW.call( + app_name, + cmd_line, + proc_attrs, + th_attrs, + inherit, + flags_with_suspend, + env, + cur_dir, + startup_info, + proc_info, + ); + + if creating_res != 0 { + info!("New process id: {:?}", (*proc_info).dwProcessId); + if cmd_line_string.contains("isSupportDevice") { + info!("Command line contains isSupportDevice, exit with 1"); + TerminateProcess((*proc_info).hProcess, 1); + return creating_res; + } + if cmd_line_string.contains("IsSupportBaZhang") { + info!("Command line contains IsSupportBaZhang, exit with 2"); + TerminateProcess((*proc_info).hProcess, 2); + return creating_res; + } + let should_inject = opts + .as_ref() + .map(|opts| { + opts.includes_system_process + || (!app_name_string.trim().is_empty() + && !check_path_is_system(app_name_string.as_str()) + || !cmd_line_string.trim().is_empty() + && !check_path_is_system(cmd_line_string.as_str())) + }) + .unwrap_or(true); + if should_inject { + if let Err(err) = inject_to_process((*proc_info).hProcess, opts) { + warn!("inject_to_process error: {}", err); + } + } else { + info!("Skip system process."); + } + if flags & CREATE_SUSPENDED == 0 { + if ResumeThread((*proc_info).hThread) == u32::MAX { + warn!("ResumeThread error: {}", GetLastError()); + } + } + } else { + warn!("CreateProcessW failed: {}", GetLastError()); + } + + creating_res + } +} + +pub fn enable_hook(opts: Option) -> anyhow::Result<()> { + let inject_sub_process = opts + .as_ref() + .map(|opts| opts.inject_sub_process) + .unwrap_or(false); + unsafe { + let fp_create_process: FnCreateProcessW = transmute( + get_proc_address("CreateProcessW", "kernel32.dll").ok_or_else(|| { + anyhow::anyhow!("GetProcAddress(CreateProcessW) failed: {}", GetLastError()) + })?, + ); + let fp_get_system_firmware_table: FnGetSystemFirmwareTable = transmute( + get_proc_address("GetSystemFirmwareTable", "kernel32.dll").ok_or_else(|| { + anyhow::anyhow!( + "GetProcAddress(GetSystemFirmwareTable) failed: {}", + GetLastError() + ) + })?, + ); + let fp_enum_system_firmware_tables: FnEnumSystemFirmwareTables = transmute( + get_proc_address("EnumSystemFirmwareTables", "kernel32.dll").ok_or_else(|| { + anyhow::anyhow!( + "GetProcAddress(EnumSystemFirmwareTables) failed: {}", + GetLastError() + ) + })?, + ); + + let opts = Box::leak(Box::new(opts)); + HookGetSystemFirmwareTable.initialize( + fp_get_system_firmware_table, + detour_get_system_firmware_table, + )?; + HookEnumSystemFirmwareTables.initialize( + fp_enum_system_firmware_tables, + detour_enum_system_firmware_tables, + )?; + HookCreateProcessW.initialize( + fp_create_process, + |app_name, + cmd_line, + proc_attrs, + th_attrs, + inherit, + flags, + env, + cur_dir, + startup_info, + proc_info| { + detour_create_process( + opts, + app_name, + cmd_line, + proc_attrs, + th_attrs, + inherit, + flags, + env, + cur_dir, + startup_info, + proc_info, + ) + }, + )?; + HookGetSystemFirmwareTable.enable()?; + HookEnumSystemFirmwareTables.enable()?; + if inject_sub_process { + HookCreateProcessW.enable()?; + } + } + + Ok(()) +} + +unsafe fn get_proc_address(proc_name: &str, module_name: &str) -> FARPROC { + let module_name_cstr = CString::new(module_name).ok()?; + let proc_name_cstr = CString::new(proc_name).ok()?; + let h_inst = LoadLibraryA(module_name_cstr.as_ptr() as PCSTR); + + if h_inst == 0 { + panic!("LoadLibraryA failed: {}", GetLastError()); + } + + GetProcAddress(h_inst, proc_name_cstr.as_ptr() as PCSTR) +} + +fn check_path_is_system(path: &str) -> bool { + let mut path_buffer = [0; 4096]; + let size = unsafe { GetSystemDirectoryA(path_buffer.as_mut_ptr(), path_buffer.len() as u32) }; + if size > 0 { + if let Ok(sys_dir) = String::from_utf8(path_buffer[..size as usize].to_vec()) { + let slash_sys_dir = sys_dir.replace("\\", "/"); + let slash_path = path.replace("\\", "/"); + return slash_path.starts_with(&slash_sys_dir) + || (slash_path.chars().nth(0) == Some('"') + && slash_path[1..].starts_with(&slash_sys_dir)); + } + } + false +} + +unsafe fn inject_to_process( + process_handle: HANDLE, + opts: &Option, +) -> anyhow::Result<()> { + let is_target_x86 = is_process_x86(process_handle)?; + let is_self_x86 = is_process_x86(GetCurrentProcess())?; + if is_target_x86 != is_self_x86 { + return Err(anyhow::anyhow!( + "Process architecture mismatch, expect {} got {}", + if is_self_x86 { "x86" } else { "x64" }, + if is_target_x86 { "x86" } else { "x64" } + )); + } + + let mut lib_full_path = std::env::current_exe()? + .parent() + .ok_or_else(|| anyhow::anyhow!("No path content"))? + .to_path_buf(); + lib_full_path.push(LIBRARY_NAME); + let lib_full_path = lib_full_path + .to_str() + .ok_or_else(|| anyhow::anyhow!("No path content"))?; + info!("Get enable_hook address from {}", lib_full_path); + let fp_enable_hook = get_proc_address("enable_hook", lib_full_path) + .ok_or_else(|| anyhow::anyhow!("No enable_hook function found"))?; + + let library_name_with_null = format!("{}\0", LIBRARY_NAME); + let core_module_handle = LoadLibraryA(library_name_with_null.as_ptr() as PCSTR); + let mut core_full_name_buffer = [0u8; 4096]; + if core_module_handle == 0 + || GetModuleFileNameA( + core_module_handle, + core_full_name_buffer.as_mut_ptr(), + core_full_name_buffer.len() as u32, + ) == 0 + { + return Err(anyhow::anyhow!( + "GetModuleFileNameA failed: {}", + GetLastError() + )); + } + let library_name_addr = write_process_memory(process_handle, &core_full_name_buffer)?; + let fp_load_library = get_proc_address("LoadLibraryA", "kernel32.dll") + .ok_or_else(|| anyhow::anyhow!("No LoadLibraryA function found"))?; + let load_library_thread = CreateRemoteThread( + process_handle, + ptr::null(), + 0, + Some(transmute(fp_load_library)), + library_name_addr, + 0, + ptr::null_mut(), + ); + if load_library_thread == 0 { + return Err(anyhow::anyhow!( + "CreateRemoteThread failed: {}", + GetLastError() + )); + } + info!( + "Created LoadLibraryA thread with id: {}", + GetThreadId(load_library_thread) + ); + let wait_result = WaitForSingleObject(load_library_thread, 0xFFFFFFFF); + if wait_result != 0 { + return Err(anyhow::anyhow!( + "WaitForSingleObject failed: {}", + wait_result + )); + } + let mut module_handle: u32 = 0; + if GetExitCodeThread(load_library_thread, &mut module_handle as *mut u32) != 0 + && module_handle == 0 + { + return Err(anyhow::anyhow!("Remote LoadLibraryA failed")); + } + + let enable_hook_params = if let Some(opts) = opts { + let opts_bytes = bincode::serialize(opts)?; + let opts_ptr = write_process_memory(process_handle, opts_bytes.as_slice())?; + info!("Write options to address {:?}", opts_ptr); + let opts_wrapper = INJECT_OPTIONS_WRAPPER { + len: opts_bytes.len(), + ptr: opts_ptr as u64, + }; + let opts_wrapper_bytes = bincode::serialize(&opts_wrapper)?; + let opts_wrapper_ptr = write_process_memory(process_handle, opts_wrapper_bytes.as_slice())?; + info!("Write options wrapper to address {:?}", opts_wrapper_ptr); + opts_wrapper_ptr + } else { + ptr::null() + }; + let thread_handle = CreateRemoteThread( + process_handle, + ptr::null(), + 0, + Some(transmute(fp_enable_hook)), + enable_hook_params, + 0, + ptr::null_mut(), + ); + if thread_handle == 0 { + return Err(anyhow::anyhow!( + "CreateRemoteThread failed: {}", + GetLastError() + )); + } + info!( + "Created enable_hook thread with id: {}", + GetThreadId(thread_handle) + ); + let wait_result = WaitForSingleObject(thread_handle, 0xFFFFFFFF); + if wait_result != 0 { + return Err(anyhow::anyhow!( + "WaitForSingleObject failed: {}", + wait_result + )); + } + + Ok(()) +} + +fn is_process_x86(process_handle: HANDLE) -> anyhow::Result { + let sys_info = unsafe { + let mut sys_info = MaybeUninit::::uninit(); + GetNativeSystemInfo(sys_info.as_mut_ptr()); + sys_info.assume_init() + }; + let processor_arch = unsafe { sys_info.Anonymous.Anonymous.wProcessorArchitecture }; + Ok(processor_arch == PROCESSOR_ARCHITECTURE_INTEL || is_wow64_process(process_handle)?) +} + +fn is_wow64_process(process_handle: HANDLE) -> anyhow::Result { + let mut is_wow64 = 0; + unsafe { + if IsWow64Process(process_handle, &mut is_wow64) == 0 { + return Err(anyhow::anyhow!("IsWow64Process failed: {}", GetLastError())); + } + } + Ok(is_wow64 != 0) +} + +unsafe fn write_process_memory( + process_handle: HANDLE, + content: &[u8], +) -> anyhow::Result<*mut c_void> { + let target_address = VirtualAllocEx( + process_handle, + ptr::null(), + content.len(), + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE, + ); + if target_address.is_null() { + return Err(anyhow::anyhow!("VirtualAllocEx failed: {}", GetLastError())); + } + let success = WriteProcessMemory( + process_handle, + target_address, + content.as_ptr() as *const c_void, + content.len(), + ptr::null_mut(), + ); + if success == 0 { + return Err(anyhow::anyhow!( + "WriteProcessMemory failed: {}", + GetLastError() + )); + } + Ok(target_address) +} + +fn get_firmware_table_provider_signature(firmwaretableprovidersignature: u32) -> String { + let mut sig_name_bytes = unsafe { + from_raw_parts( + &firmwaretableprovidersignature as *const u32 as *const u8, + 4, + ) + } + .to_vec(); + sig_name_bytes.reverse(); + let sig_name = String::from_utf8(sig_name_bytes).unwrap_or_else(|e| format!("Error({})", e)); + sig_name +} diff --git a/src/communication.rs b/packages/common/src/communication.rs similarity index 100% rename from src/communication.rs rename to packages/common/src/communication.rs diff --git a/packages/common/src/lib.rs b/packages/common/src/lib.rs new file mode 100644 index 0000000..e4dd0d1 --- /dev/null +++ b/packages/common/src/lib.rs @@ -0,0 +1,2 @@ +pub mod common; +pub mod communication; diff --git a/packages/huawei-pc-manager-bootstrap-core/Cargo.toml b/packages/huawei-pc-manager-bootstrap-core/Cargo.toml new file mode 100644 index 0000000..0c2c1b4 --- /dev/null +++ b/packages/huawei-pc-manager-bootstrap-core/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "huawei-pc-manager-bootstrap-core" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +common = { path = "../common" } + +anyhow = "1.0.56" +bincode = "1.3.3" +chrono = "0.4.19" +log = "0.4.14" +simplelog = "0.11.2" +directories = "4.0.1" diff --git a/packages/huawei-pc-manager-bootstrap-core/src/lib.rs b/packages/huawei-pc-manager-bootstrap-core/src/lib.rs new file mode 100644 index 0000000..e1eb866 --- /dev/null +++ b/packages/huawei-pc-manager-bootstrap-core/src/lib.rs @@ -0,0 +1,58 @@ +#![feature(ptr_const_cast)] + +use std::fs::File; +use std::slice::from_raw_parts; + +use common::common::{InjectOptions, INJECT_OPTIONS_WRAPPER}; +use common::communication::InterProcessComClient; +use log::{error, info, LevelFilter}; +use simplelog::{Config, WriteLogger}; + +#[no_mangle] +pub unsafe extern "system" fn enable_hook(opts_ptr: *const INJECT_OPTIONS_WRAPPER) { + let opts: Option = if opts_ptr.is_null() || (*opts_ptr).len == 0 { + None + } else { + let ptr = (*opts_ptr).ptr as *const u8; + bincode::deserialize(from_raw_parts(ptr, (*opts_ptr).len)).ok() + }; + + if let Some(opts) = &opts { + if let Some(address) = &opts.server_address { + if let Ok(client) = InterProcessComClient::connect(address) { + log::set_max_level(LevelFilter::Info); + log::set_logger(Box::leak(Box::new(client))).ok() + } else { + None + } + } else { + None + } + } else { + None + } + .or_else(|| initialize_file_logger().ok()); + + info!("Enabling hook ..."); + if let Err(err) = common::common::enable_hook(opts) { + error!("{}", err); + } +} + +pub fn initialize_file_logger() -> anyhow::Result<()> { + let project_dir = directories::ProjectDirs::from("cn", "hamflx", "huawei_pc_manager_bootstrap") + .ok_or_else(|| anyhow::anyhow!("No project dir"))?; + let cache_dir = project_dir.cache_dir(); + std::fs::create_dir_all(cache_dir)?; + + let mut log_file_path = cache_dir.to_path_buf(); + let now = chrono::Local::now(); + log_file_path.push(format!("core-{}.log", now.format("%Y%m%d%H%M%S"))); + + WriteLogger::init( + LevelFilter::Info, + Config::default(), + File::create(log_file_path)?, + )?; + Ok(()) +} diff --git a/packages/huawei-pc-manager-bootstrap/Cargo.toml b/packages/huawei-pc-manager-bootstrap/Cargo.toml new file mode 100644 index 0000000..f36834b --- /dev/null +++ b/packages/huawei-pc-manager-bootstrap/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "huawei-pc-manager-bootstrap" +version = "0.1.0" +edition = "2021" + +[dependencies] +common = { path = "../common" } + +anyhow = "1.0.56" +chrono = "0.4.19" +eframe = "0.17.0" # Gives us egui, epi and web+native backends +rfd = "0.8.1" +ctrlc = "3.2.1" +windows-sys = { version = "0.35.0", features = [ + "Win32_Foundation", + "Win32_Security", + "Win32_System_LibraryLoader", + "Win32_UI_Shell", + "Win32_UI_WindowsAndMessaging", + "Win32_System_Threading", + "Win32_System_Memory", + "Win32_System_Diagnostics_Debug", + "Win32_System_SystemInformation" +] } +log = "0.4.14" +simplelog = "0.11.2" +directories = "4.0.1" diff --git a/packages/huawei-pc-manager-bootstrap/src/app.rs b/packages/huawei-pc-manager-bootstrap/src/app.rs new file mode 100644 index 0000000..59feb33 --- /dev/null +++ b/packages/huawei-pc-manager-bootstrap/src/app.rs @@ -0,0 +1,372 @@ +use std::ffi::CStr; +use std::fs::File; +use std::path::PathBuf; +use std::process::Command; +use std::str::FromStr; +use std::thread; + +use common::common::InjectOptions; +use common::communication::InterProcessComServer; +use eframe::egui::FontDefinitions; +use eframe::epaint::FontFamily; +use eframe::{egui, epi}; +use log::{error, info, warn, LevelFilter}; +use rfd::FileDialog; +use simplelog::{ConfigBuilder, WriteLogger}; +use windows_sys::Win32::UI::Shell::{SHGetSpecialFolderPathA, CSIDL_PROGRAM_FILES}; + +pub struct BootstrapApp { + log_file_path: String, + executable_file_path: String, + status_text: String, + log_text: String, + ipc_logger_address: Option, +} + +const TIPS_BROWSE: &'static str = "点击“浏览”按钮选择华为电脑管家安装包(如:PCManager_Setup_12.0.1.26(C233D003).exe),然后点击“安装”。"; +const TIPS_AUTO_SCAN: &'static str = + "自动扫描当前目录下的华为电脑管家安装包,找到安装包后,需要点击“安装”按钮进行安装。"; +const TIPS_AUTO_SCAN_FOUND: &'static str = "已找到安装包,点击“安装”按钮进行安装。"; +const TIPS_AUTO_SCAN_NOT_FOUND: &'static str = "未找到安装包!"; + +impl BootstrapApp { + fn auto_scan(&mut self) -> anyhow::Result { + let dirs = [ + std::env::current_exe()? + .parent() + .ok_or_else(|| anyhow::anyhow!("current_exe() failed"))? + .to_path_buf(), + std::env::current_dir()?, + ]; + for dir in dirs { + for file in std::fs::read_dir(dir)? { + let file = file?; + let file_path = file.path(); + if let Some(file_name) = file_path.file_name() { + if let Some(file_name) = file_name.to_str() { + if file_name + .to_lowercase() + .contains(&"PCManager_Setup".to_lowercase()) + { + if let Some(file_path) = file_path.to_str() { + self.executable_file_path = file_path.to_owned(); + return Ok(true); + } + } + } + } + } + } + Ok(false) + } + + fn select_file(&mut self) { + let executable_file = FileDialog::new() + .add_filter("exe", &["exe"]) + .set_directory(std::env::current_exe().unwrap().parent().unwrap()) + .pick_file(); + + if let Some(executable_file) = executable_file { + self.executable_file_path = executable_file.to_str().unwrap().to_owned(); + info!("Selected file: {}", self.executable_file_path); + } + } + + fn setup_logger(&self) -> anyhow::Result<()> { + let config = ConfigBuilder::new() + .set_target_level(LevelFilter::Error) + .build(); + WriteLogger::init( + LevelFilter::Debug, + config, + File::create(&self.log_file_path)?, + )?; + info!("Logger setup successfully"); + + Ok(()) + } + + fn install_hooks(&self) -> anyhow::Result<()> { + common::common::enable_hook(Some(InjectOptions { + server_address: self.ipc_logger_address.clone(), + inject_sub_process: true, + includes_system_process: false, + })) + } + + fn start_ipc_logger(&mut self) -> anyhow::Result<()> { + let server = InterProcessComServer::listen("127.0.0.1:0")?; + let address = server.get_address()?; + server.start(); + + self.ipc_logger_address = Some(address.to_string()); + info!("Listening on {}", self.ipc_logger_address.as_ref().unwrap()); + + Ok(()) + } + + fn start_install(&self) -> anyhow::Result<()> { + let executable_file_path = self.executable_file_path.clone(); + let _ = thread::spawn(move || { + info!("Executing {}", executable_file_path); + match Command::new(&executable_file_path).spawn() { + Ok(mut wait_handle) => { + let mut is_patch_installed = false; + info!("Executed {}", executable_file_path); + loop { + match wait_handle.try_wait() { + Ok(Some(exit_status)) => { + info!( + "{} exited with status {}", + executable_file_path, exit_status + ); + break; + } + Ok(None) => { + if !is_patch_installed { + match Self::check_pc_manager_installed() { + Ok(true) => match Self::install_patch() { + Ok(_) => { + is_patch_installed = true; + info!("Installed patch successfully"); + } + Err(e) => { + warn!("Failed to install patch: {}", e); + } + }, + Ok(false) => { + info!("PCManager is not installed, wating ..."); + } + Err(err) => { + warn!("Failed to check PC Manager installed: {}", err); + } + } + } + thread::sleep(std::time::Duration::from_millis(100)); + } + Err(e) => { + warn!("{} exited with error: {}", executable_file_path, e); + break; + } + } + } + } + Err(e) => warn!("Failed to execute {}: {}", executable_file_path, e), + } + }); + + Ok(()) + } + + fn install_patch() -> anyhow::Result<()> { + #[cfg(debug_assertions)] + let patch_file_bytes = + include_bytes!("../../../target/x86_64-pc-windows-msvc/debug/version.dll"); + #[cfg(not(debug_assertions))] + let patch_file_bytes = + include_bytes!("../../../target/x86_64-pc-windows-msvc/release/version.dll"); + + let pc_manager_dir: PathBuf = Self::get_pc_manager_dir()?; + let target_version_dll_path = pc_manager_dir.join("version.dll"); + std::fs::write(&target_version_dll_path, patch_file_bytes)?; + + Ok(()) + } + + fn open_log_file(&self) { + let _ = Command::new("notepad").arg(&self.log_file_path).spawn(); + } + + fn open_log_file_dir(&self) -> anyhow::Result<()> { + let log_file_path = PathBuf::from_str(self.log_file_path.as_str())?; + let log_dir = log_file_path + .parent() + .ok_or_else(|| anyhow::anyhow!("No parent dir"))?; + let _ = Command::new("explorer").arg(log_dir).spawn()?; + Ok(()) + } + + fn check_pc_manager_installed() -> anyhow::Result { + let pc_manager_exe: PathBuf = Self::get_pc_manager_dir()?.join("PCManager.exe"); + Ok(pc_manager_exe.exists()) + } + + fn get_pc_manager_dir() -> anyhow::Result { + let mut path_buffer = [0; 4096]; + let get_dir_success = unsafe { + SHGetSpecialFolderPathA( + 0, + path_buffer.as_mut_ptr(), + CSIDL_PROGRAM_FILES.try_into().unwrap(), + 0, + ) + } != 0; + if !get_dir_success { + return Err(anyhow::anyhow!( + "SHGetSpecialFolderPathA failed: {}", + std::io::Error::last_os_error() + )); + } + + let program_files_dir = + unsafe { CStr::from_ptr(path_buffer.as_ptr() as *const i8).to_str()? }; + let x86_suffix = " (x86)"; + let program_files_dir = if program_files_dir.ends_with(x86_suffix) { + &program_files_dir[..program_files_dir.len() - x86_suffix.len()] + } else { + program_files_dir + }; + + Ok([program_files_dir, "Huawei", "PCManager"].iter().collect()) + } +} + +impl Default for BootstrapApp { + fn default() -> Self { + let project_dir = + directories::ProjectDirs::from("cn", "hamflx", "huawei_pc_manager_bootstrap") + .ok_or_else(|| anyhow::anyhow!("No project dir")) + .unwrap(); + let cache_dir = project_dir.cache_dir(); + std::fs::create_dir_all(cache_dir).unwrap(); + + let mut log_file_path = cache_dir.to_path_buf(); + let now = chrono::Local::now(); + log_file_path.push(format!("app-{}.log", now.format("%Y%m%d%H%M%S"))); + let log_file_path = log_file_path.to_str().unwrap().to_owned(); + let status_text = String::from(TIPS_BROWSE); + let log_text = format!("这里是日志区域,但是我跟编译器搏斗了半天,仍然是没能把日志输出到这里,只能把日志输出到文件:\n{}", log_file_path); + + Self { + log_file_path, + executable_file_path: String::new(), + status_text, + log_text, + ipc_logger_address: None, + } + } +} + +impl epi::App for BootstrapApp { + fn name(&self) -> &str { + "华为电脑管家安装器" + } + + /// Called once before the first frame. + fn setup( + &mut self, + ctx: &egui::Context, + _frame: &epi::Frame, + _storage: Option<&dyn epi::Storage>, + ) { + let mut fonts = FontDefinitions::default(); + let sys_font = std::fs::read("c:/Windows/Fonts/msyh.ttc").unwrap(); + fonts + .font_data + .insert("msyh".to_owned(), egui::FontData::from_owned(sys_font)); + + fonts + .families + .get_mut(&FontFamily::Monospace) + .unwrap() + .insert(0, "msyh".to_owned()); + fonts + .families + .get_mut(&FontFamily::Proportional) + .unwrap() + .insert(0, "msyh".to_owned()); + ctx.set_fonts(fonts); + + ctx.set_pixels_per_point(2.0); + + if let Err(err) = self.setup_logger() { + self.status_text = format!("Error: {}", err); + error!("Failed to setup logger: {}", err); + return; + } + + if let Err(err) = self.start_ipc_logger() { + self.status_text = format!("Error: {}", err); + error!("Failed to start ipc logger: {}", err); + return; + } + + if let Err(err) = self.install_hooks() { + self.status_text = format!("Error: {}", err); + error!("Failed to install hooks: {}", err); + return; + } + } + + /// Called each time the UI needs repainting, which may be many times per second. + /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. + fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { + egui::CentralPanel::default().show(ctx, |ui| { + ui.vertical_centered(|ui| { + ui.horizontal(|ui| { + ui.label("安装包位置:"); + }); + ui.horizontal(|ui| { + ui.with_layout( + egui::Layout::left_to_right().with_main_justify(true), + |ui| { + ui.text_edit_singleline(&mut self.executable_file_path); + }, + ); + }); + ui.horizontal(|ui| { + let auto_scan_button = ui.button("自动扫描").on_hover_text(TIPS_AUTO_SCAN); + if auto_scan_button.clicked() { + match self.auto_scan() { + Ok(true) => { + self.status_text = String::from(TIPS_AUTO_SCAN_FOUND); + } + Ok(false) => { + self.status_text = String::from(TIPS_AUTO_SCAN_NOT_FOUND); + } + Err(err) => { + self.status_text = format!("Error: {}", err); + warn!("Error: {}", err); + } + } + } + + let browse_button = ui.button("浏览").on_hover_text(TIPS_BROWSE); + if browse_button.clicked() { + self.select_file(); + } + + if ui.button("安装").clicked() { + if let Err(err) = self.start_install() { + self.status_text = format!("Installing failed: {}", err); + warn!("Installing failed: {}", err); + } + } + + if ui.button("安装补丁").clicked() { + if let Err(err) = Self::install_patch() { + self.status_text = format!("Installing failed: {}", err); + warn!("Installing failed: {}", err); + } + } + + if ui.button("打开日志").clicked() { + self.open_log_file(); + } + if ui.button("打开日志文件夹").clicked() { + if let Err(err) = self.open_log_file_dir() { + self.status_text = format!("Opening log dir failed: {}", err); + warn!("Opening log dir failed: {}", err); + } + } + }); + ui.horizontal(|ui| { + ui.add(egui::Label::new(&self.status_text).wrap(true)); + }); + ui.centered_and_justified(|ui| { + ui.text_edit_multiline(&mut self.log_text); + }); + }); + }); + } +} diff --git a/packages/huawei-pc-manager-bootstrap/src/main.rs b/packages/huawei-pc-manager-bootstrap/src/main.rs new file mode 100644 index 0000000..b5f2bf5 --- /dev/null +++ b/packages/huawei-pc-manager-bootstrap/src/main.rs @@ -0,0 +1,35 @@ +#![cfg_attr(not(debug_assertions), deny(warnings))] // Forbid warnings in release builds +#![warn(clippy::all, rust_2018_idioms)] +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] //Hide console window in release builds on Windows, this blocks stdout. + +use windows_sys::Win32::UI::Shell::{IsUserAnAdmin, ShellExecuteA}; + +mod app; + +fn main() { + let is_admin = unsafe { IsUserAnAdmin() != 0 }; + let ensure_admin = std::env::args().any(|a| a == "--ensure-admin"); + if !is_admin { + if ensure_admin { + println!("No administrator"); + return; + } + let executable_file_null_ter = + format!("{}\0", std::env::current_exe().unwrap().to_str().unwrap()); + unsafe { + ShellExecuteA( + 0, + "runas\0".as_ptr(), + executable_file_null_ter.as_ptr(), + "--ensure-admin\0".as_ptr(), + 0 as *const u8, + 5, + ) + }; + return; + } + + let app = app::BootstrapApp::default(); + let native_options = eframe::NativeOptions::default(); + eframe::run_native(Box::new(app), native_options); +} diff --git a/packages/version/Cargo.toml b/packages/version/Cargo.toml new file mode 100644 index 0000000..b8ab959 --- /dev/null +++ b/packages/version/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "version" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0.56" +chrono = "0.4.19" +common = { path = "../common" } +windows-sys = { version = "0.35.0", features = [ + "Win32_Foundation", + "Win32_System_Memory", + "Win32_System_LibraryLoader", + "Win32_UI_WindowsAndMessaging" +] } +simplelog = "0.11.2" +directories = "4.0.1" +log = "0.4.14" diff --git a/packages/version/src/lib.rs b/packages/version/src/lib.rs new file mode 100644 index 0000000..359cff3 --- /dev/null +++ b/packages/version/src/lib.rs @@ -0,0 +1,197 @@ +use std::{ + ffi::{c_void, CString}, + fs::OpenOptions, + slice::from_raw_parts_mut, +}; + +use common::common::InjectOptions; +use log::{error, info, warn}; +use simplelog::{Config, LevelFilter, WriteLogger}; +use windows_sys::Win32::{ + Foundation::{GetLastError, HINSTANCE}, + System::{ + LibraryLoader::{GetProcAddress, LoadLibraryA}, + Memory::{VirtualProtect, PAGE_EXECUTE_READWRITE}, + }, +}; + +macro_rules! export_function { + ($($proc:ident)*) => { + $( + #[no_mangle] + pub extern "system" fn $proc() -> u32 { + println!("==> do sth."); + 1 + } + )* + }; +} + +#[no_mangle] +pub extern "system" fn DllMain(inst: HINSTANCE, reason: u32, _: *const u8) -> u32 { + if reason == 1 { + if let Err(err) = initialize(inst) { + println!("{}", err); + return 0; + } + } + 1 +} + +pub fn initialize(inst: HINSTANCE) -> anyhow::Result<()> { + if let Err(err) = initialize_logger() { + warn!("Failed to initialize logger: {}", err); + } + + if let Err(err) = install_all_jumpers(inst) { + error!("{}", err); + } else { + // unsafe { + // windows_sys::Win32::UI::WindowsAndMessaging::MessageBoxA( + // 0, + // "Success\0".as_ptr(), + // "Jump\0".as_ptr(), + // 0, + // ) + // }; + } + + common::common::enable_hook(Some(InjectOptions { + server_address: None, + inject_sub_process: false, + includes_system_process: false, + }))?; + + Ok(()) +} + +fn initialize_logger() -> anyhow::Result<()> { + let project_dir = directories::ProjectDirs::from("cn", "hamflx", "huawei_pc_manager_bootstrap") + .ok_or_else(|| anyhow::anyhow!("No project dir"))?; + let cache_dir = project_dir.cache_dir(); + std::fs::create_dir_all(cache_dir)?; + + let mut log_file_path = cache_dir.to_path_buf(); + let now = chrono::Local::now(); + let exe_path_buf = std::env::current_exe()?; + let exe_name = exe_path_buf + .file_stem() + .map_or(None, |s| s.to_str()) + .unwrap_or("NoExeName"); + let pid = std::process::id(); + log_file_path.push(format!( + "hijacking-{}-{}-{}.log", + exe_name, + pid, + now.format("%Y%m%d%H%M%S") + )); + + WriteLogger::init( + LevelFilter::Info, + Config::default(), + OpenOptions::new() + .append(true) + .create(true) + .open(log_file_path)?, + )?; + + Ok(()) +} + +export_function!(GetFileVersionInfoA); +export_function!(GetFileVersionInfoByHandle); +export_function!(GetFileVersionInfoExA); +export_function!(GetFileVersionInfoExW); +export_function!(GetFileVersionInfoSizeA); +export_function!(GetFileVersionInfoSizeExA); +export_function!(GetFileVersionInfoSizeExW); +export_function!(GetFileVersionInfoSizeW); +export_function!(GetFileVersionInfoW); +export_function!(VerFindFileA); +export_function!(VerFindFileW); +export_function!(VerInstallFileA); +export_function!(VerInstallFileW); +export_function!(VerLanguageNameA); +export_function!(VerLanguageNameW); +export_function!(VerQueryValueA); +export_function!(VerQueryValueW); + +pub fn install_all_jumpers(inst: HINSTANCE) -> anyhow::Result<()> { + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoA")?; + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoByHandle")?; + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoExA")?; + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoExW")?; + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoSizeA")?; + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoSizeExA")?; + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoSizeExW")?; + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoSizeW")?; + make_proc_jump_to_real_address(inst, "version.dll", "GetFileVersionInfoW")?; + make_proc_jump_to_real_address(inst, "version.dll", "VerFindFileA")?; + make_proc_jump_to_real_address(inst, "version.dll", "VerFindFileW")?; + make_proc_jump_to_real_address(inst, "version.dll", "VerInstallFileA")?; + make_proc_jump_to_real_address(inst, "version.dll", "VerInstallFileW")?; + make_proc_jump_to_real_address(inst, "version.dll", "VerLanguageNameA")?; + make_proc_jump_to_real_address(inst, "version.dll", "VerLanguageNameW")?; + make_proc_jump_to_real_address(inst, "version.dll", "VerQueryValueA")?; + make_proc_jump_to_real_address(inst, "version.dll", "VerQueryValueW")?; + + Ok(()) +} + +pub fn make_proc_jump_to_real_address( + inst: HINSTANCE, + target_module: &str, + proc_name: &str, +) -> anyhow::Result<()> { + info!("Installing jumper for {}", proc_name); + let load_module_dir = "C:\\Windows\\System32\\"; + let module_full_path = format!("{}{}", load_module_dir, target_module); + let addr_in_current_module = get_proc_address_by_module(inst, proc_name)?; + let addr_in_remote_module = get_proc_address(module_full_path.as_str(), proc_name)?; + let protect_success = unsafe { + let mut old_protect = 0; + VirtualProtect( + addr_in_current_module as *const c_void, + 12, + PAGE_EXECUTE_READWRITE, + &mut old_protect, + ) + } != 0; + if !protect_success { + return Err(anyhow::anyhow!("VirtualProtect failed: {}", unsafe { + GetLastError() + })); + } + unsafe { + let mut bytes: [u8; 12] = [0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xe0]; + bytes[2..10].copy_from_slice((addr_in_remote_module as u64).to_le_bytes().as_slice()); + from_raw_parts_mut(addr_in_current_module as *mut _, 12).copy_from_slice(&bytes); + } + Ok(()) +} + +pub fn get_proc_address_by_module( + inst: HINSTANCE, + proc_name: &str, +) -> anyhow::Result isize> { + let proc_name = CString::new(proc_name)?; + unsafe { + GetProcAddress(inst, proc_name.as_ptr() as *const u8) + .ok_or_else(|| anyhow::anyhow!("GetProcAddress failed: {:x}", GetLastError())) + } +} + +pub fn get_proc_address( + module_name: &str, + proc_name: &str, +) -> anyhow::Result isize> { + let module_name = CString::new(module_name)?; + + unsafe { + let module_handle = LoadLibraryA(module_name.as_ptr() as *const u8); + if module_handle == 0 { + return Err(anyhow::anyhow!("LoadLibraryA failed: {:x}", GetLastError())); + } + get_proc_address_by_module(module_handle, proc_name) + } +} diff --git a/src/common.rs b/src/common.rs deleted file mode 100644 index f6b8a4b..0000000 --- a/src/common.rs +++ /dev/null @@ -1,352 +0,0 @@ -use detour::static_detour; -use log::{info, warn}; -use serde::{Deserialize, Serialize}; -use std::{ - ffi::{c_void, CString}, - intrinsics::transmute, - mem::MaybeUninit, - ptr, -}; -use widestring::U16CString; -use windows_sys::{ - core::{PCSTR, PCWSTR, PWSTR}, - Win32::{ - Foundation::{GetLastError, BOOL, FARPROC, HANDLE}, - Security::SECURITY_ATTRIBUTES, - System::{ - Diagnostics::Debug::{WriteProcessMemory, PROCESSOR_ARCHITECTURE_INTEL}, - LibraryLoader::{GetModuleFileNameA, GetProcAddress, LoadLibraryA}, - Memory::{VirtualAllocEx, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE}, - SystemInformation::{GetNativeSystemInfo, SYSTEM_INFO}, - Threading::{ - CreateRemoteThread, GetCurrentProcess, GetExitCodeThread, GetThreadId, - IsWow64Process, ResumeThread, TerminateProcess, WaitForSingleObject, - CREATE_SUSPENDED, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, STARTUPINFOW, - }, - }, - }, -}; - -#[derive(Serialize, Deserialize, Clone)] -pub struct InjectOptions { - pub server_address: Option, -} - -#[repr(C)] -#[derive(Serialize, Deserialize)] -pub struct INJECT_OPTIONS_WRAPPER { - pub len: usize, - pub ptr: u64, -} - -type FnCreateProcessW = unsafe extern "system" fn( - PCWSTR, - PWSTR, - *const SECURITY_ATTRIBUTES, - *const SECURITY_ATTRIBUTES, - BOOL, - PROCESS_CREATION_FLAGS, - *const c_void, - PCWSTR, - *const STARTUPINFOW, - *mut PROCESS_INFORMATION, -) -> BOOL; - -static_detour! { - static HookCreateProcessW: unsafe extern "system" fn( - PCWSTR, - PWSTR, - *const SECURITY_ATTRIBUTES, - *const SECURITY_ATTRIBUTES, - BOOL, - PROCESS_CREATION_FLAGS, - *const c_void, - PCWSTR, - *const STARTUPINFOW, - *mut PROCESS_INFORMATION - ) -> BOOL; -} - -static LIBRARY_NAME: &str = "program_bootstrap_core.dll"; - -#[allow(clippy::too_many_arguments)] -fn detour_create_process( - opts: &Option, - app_name: PCWSTR, - cmd_line: PWSTR, - proc_attrs: *const SECURITY_ATTRIBUTES, - th_attrs: *const SECURITY_ATTRIBUTES, - inherit: BOOL, - flags: PROCESS_CREATION_FLAGS, - env: *const c_void, - cur_dir: PCWSTR, - startup_info: *const STARTUPINFOW, - proc_info: *mut PROCESS_INFORMATION, -) -> BOOL { - unsafe { - let app_name_string = if app_name.is_null() { - String::new() - } else { - U16CString::from_ptr_str(app_name).to_string().unwrap() - }; - let cmd_line_string = if cmd_line.is_null() { - String::new() - } else { - U16CString::from_ptr_str(cmd_line).to_string().unwrap() - }; - info!("CreateProcessW: {} {}", app_name_string, cmd_line_string); - let flags_with_suspend = CREATE_SUSPENDED | flags; - let creating_res = HookCreateProcessW.call( - app_name, - cmd_line, - proc_attrs, - th_attrs, - inherit, - flags_with_suspend, - env, - cur_dir, - startup_info, - proc_info, - ); - - if creating_res != 0 { - info!("New process id: {:?}", (*proc_info).dwProcessId); - if cmd_line_string.contains("isSupportDevice") { - info!("Command line contains isSupportDevice, exit with 1"); - TerminateProcess((*proc_info).hProcess, 1); - return creating_res; - } - if cmd_line_string.contains("IsSupportBaZhang") { - info!("Command line contains IsSupportBaZhang, exit with 2"); - TerminateProcess((*proc_info).hProcess, 2); - return creating_res; - } - if let Err(err) = inject_to_process((*proc_info).hProcess, opts) { - warn!("inject_to_process error: {}", err); - } - if flags & CREATE_SUSPENDED == 0 { - if ResumeThread((*proc_info).hThread) == u32::MAX { - warn!("ResumeThread error: {}", GetLastError()); - } - } - } else { - warn!("CreateProcessW failed: {}", GetLastError()); - } - - creating_res - } -} - -pub fn enable_hook(opts: Option) { - unsafe { - let fp_create_process: FnCreateProcessW = - transmute(get_proc_address("CreateProcessW", "kernel32.dll").unwrap()); - - let opts = Box::leak(Box::new(opts)); - HookCreateProcessW - .initialize( - fp_create_process, - |app_name, - cmd_line, - proc_attrs, - th_attrs, - inherit, - flags, - env, - cur_dir, - startup_info, - proc_info| { - detour_create_process( - opts, - app_name, - cmd_line, - proc_attrs, - th_attrs, - inherit, - flags, - env, - cur_dir, - startup_info, - proc_info, - ) - }, - ) - .unwrap(); - HookCreateProcessW.enable().unwrap(); - } -} - -unsafe fn get_proc_address(proc_name: &str, module_name: &str) -> FARPROC { - let module_name_cstr = CString::new(module_name).ok()?; - let proc_name_cstr = CString::new(proc_name).ok()?; - let h_inst = LoadLibraryA(module_name_cstr.as_ptr() as PCSTR); - - if h_inst == 0 { - panic!("LoadLibraryA failed: {}", GetLastError()); - } - - GetProcAddress(h_inst, proc_name_cstr.as_ptr() as PCSTR) -} - -unsafe fn inject_to_process( - process_handle: HANDLE, - opts: &Option, -) -> anyhow::Result<()> { - let fp_enable_hook = get_proc_address("enable_hook", LIBRARY_NAME) - .ok_or_else(|| anyhow::anyhow!("No enable_hook function found"))?; - - let is_target_x86 = is_process_x86(process_handle)?; - let is_self_x86 = is_process_x86(GetCurrentProcess())?; - if is_target_x86 != is_self_x86 { - return Err(anyhow::anyhow!( - "Process architecture mismatch, expect {} got {}", - if is_target_x86 { "x86" } else { "x64" }, - if is_self_x86 { "x86" } else { "x64" } - )); - } - - let library_name_with_null = format!("{}\0", LIBRARY_NAME); - let core_module_handle = LoadLibraryA(library_name_with_null.as_ptr() as PCSTR); - let mut core_full_name_buffer = [0u8; 4096]; - if core_module_handle == 0 - || GetModuleFileNameA( - core_module_handle, - core_full_name_buffer.as_mut_ptr(), - core_full_name_buffer.len() as u32, - ) == 0 - { - return Err(anyhow::anyhow!( - "GetModuleFileNameA failed: {}", - GetLastError() - )); - } - let library_name_addr = write_process_memory(process_handle, &core_full_name_buffer)?; - let fp_load_library = get_proc_address("LoadLibraryA", "kernel32.dll") - .ok_or_else(|| anyhow::anyhow!("No LoadLibraryA function found"))?; - let load_library_thread = CreateRemoteThread( - process_handle, - ptr::null(), - 0, - Some(transmute(fp_load_library)), - library_name_addr, - 0, - ptr::null_mut(), - ); - if load_library_thread == 0 { - return Err(anyhow::anyhow!( - "CreateRemoteThread failed: {}", - GetLastError() - )); - } - info!( - "Created LoadLibraryA thread with id: {}", - GetThreadId(load_library_thread) - ); - let wait_result = WaitForSingleObject(load_library_thread, 0xFFFFFFFF); - if wait_result != 0 { - return Err(anyhow::anyhow!( - "WaitForSingleObject failed: {}", - wait_result - )); - } - let mut module_handle: u32 = 0; - if GetExitCodeThread(load_library_thread, &mut module_handle as *mut u32) != 0 - && module_handle == 0 - { - return Err(anyhow::anyhow!("Remote LoadLibraryA failed")); - } - - let enable_hook_params = if let Some(opts) = opts { - let opts_bytes = bincode::serialize(opts)?; - let opts_ptr = write_process_memory(process_handle, opts_bytes.as_slice())?; - info!("Write options to address {:?}", opts_ptr); - let opts_wrapper = INJECT_OPTIONS_WRAPPER { - len: opts_bytes.len(), - ptr: opts_ptr as u64, - }; - let opts_wrapper_bytes = bincode::serialize(&opts_wrapper)?; - let opts_wrapper_ptr = write_process_memory(process_handle, opts_wrapper_bytes.as_slice())?; - info!("Write options wrapper to address {:?}", opts_wrapper_ptr); - opts_wrapper_ptr - } else { - ptr::null() - }; - let thread_handle = CreateRemoteThread( - process_handle, - ptr::null(), - 0, - Some(transmute(fp_enable_hook)), - enable_hook_params, - 0, - ptr::null_mut(), - ); - if thread_handle == 0 { - return Err(anyhow::anyhow!( - "CreateRemoteThread failed: {}", - GetLastError() - )); - } - info!( - "Created enable_hook thread with id: {}", - GetThreadId(thread_handle) - ); - let wait_result = WaitForSingleObject(thread_handle, 0xFFFFFFFF); - if wait_result != 0 { - return Err(anyhow::anyhow!( - "WaitForSingleObject failed: {}", - wait_result - )); - } - - Ok(()) -} - -fn is_process_x86(process_handle: HANDLE) -> anyhow::Result { - let sys_info = unsafe { - let mut sys_info = MaybeUninit::::uninit(); - GetNativeSystemInfo(sys_info.as_mut_ptr()); - sys_info.assume_init() - }; - let processor_arch = unsafe { sys_info.Anonymous.Anonymous.wProcessorArchitecture }; - Ok(processor_arch == PROCESSOR_ARCHITECTURE_INTEL || is_wow64_process(process_handle)?) -} - -fn is_wow64_process(process_handle: HANDLE) -> anyhow::Result { - let mut is_wow64 = 0; - unsafe { - if IsWow64Process(process_handle, &mut is_wow64) == 0 { - return Err(anyhow::anyhow!("IsWow64Process failed: {}", GetLastError())); - } - } - Ok(is_wow64 != 0) -} - -unsafe fn write_process_memory( - process_handle: HANDLE, - content: &[u8], -) -> anyhow::Result<*mut c_void> { - let target_address = VirtualAllocEx( - process_handle, - ptr::null(), - content.len(), - MEM_COMMIT | MEM_RESERVE, - PAGE_EXECUTE_READWRITE, - ); - if target_address.is_null() { - return Err(anyhow::anyhow!("VirtualAllocEx failed: {}", GetLastError())); - } - let success = WriteProcessMemory( - process_handle, - target_address, - content.as_ptr() as *const c_void, - content.len(), - ptr::null_mut(), - ); - if success == 0 { - return Err(anyhow::anyhow!( - "WriteProcessMemory failed: {}", - GetLastError() - )); - } - Ok(target_address) -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 3e3f537..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![feature(ptr_const_cast)] - -use std::slice::from_raw_parts; - -use common::{InjectOptions, INJECT_OPTIONS_WRAPPER}; -use communication::InterProcessComClient; -use log::{info, LevelFilter}; -use simple_logger::SimpleLogger; - -mod common; -mod communication; - -#[no_mangle] -pub unsafe extern "system" fn enable_hook(opts_ptr: *const INJECT_OPTIONS_WRAPPER) { - let opts: Option = if opts_ptr.is_null() || (*opts_ptr).len == 0 { - None - } else { - let ptr = (*opts_ptr).ptr as *const u8; - bincode::deserialize(from_raw_parts(ptr, (*opts_ptr).len)).ok() - }; - - if let Some(opts) = &opts { - if let Some(address) = &opts.server_address { - if let Ok(client) = InterProcessComClient::connect(address) { - log::set_max_level(LevelFilter::Info); - log::set_logger(Box::leak(Box::new(client))).ok() - } else { - None - } - } else { - None - } - } else { - None - } - .or_else(|| SimpleLogger::new().init().ok()); - - info!("Enabling hook ..."); - common::enable_hook(opts); -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 68d9233..0000000 --- a/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::{env, process::Command}; - -use communication::InterProcessComServer; -use log::info; -use simple_logger::SimpleLogger; - -use crate::common::InjectOptions; - -mod common; -mod communication; - -fn main() { - SimpleLogger::new().init().unwrap(); - - let server = InterProcessComServer::listen("127.0.0.1:0").unwrap(); - let address = server.get_address().unwrap(); - server.start(); - - info!("Listening on {}", address.to_string()); - - common::enable_hook(Some(InjectOptions { - server_address: Some(address.to_string()), - })); - - let self_args: Vec = env::args().skip(1).collect(); - let command_name = self_args.get(0).unwrap().to_owned(); - let command_args = self_args.into_iter().skip(1).collect::>(); - info!( - "Executing {} with args: {}", - command_name, - command_args.join(" ") - ); - let mut command = Command::new(command_name) - .args(command_args) - .spawn() - .unwrap(); - - let exit = command.wait().unwrap(); - info!("Command exited with {}", exit); -} diff --git a/version.exports b/version.exports new file mode 100644 index 0000000..413364f --- /dev/null +++ b/version.exports @@ -0,0 +1,17 @@ +GetFileVersionInfoA +GetFileVersionInfoByHandle +GetFileVersionInfoExA +GetFileVersionInfoExW +GetFileVersionInfoSizeA +GetFileVersionInfoSizeExA +GetFileVersionInfoSizeExW +GetFileVersionInfoSizeW +GetFileVersionInfoW +VerFindFileA +VerFindFileW +VerInstallFileA +VerInstallFileW +VerLanguageNameA +VerLanguageNameW +VerQueryValueA +VerQueryValueW