├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── example_rust ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── cli │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ └── main.rs └── library │ ├── .gitignore │ ├── Cargo.toml │ └── src │ └── lib.rs ├── plonk.rs ├── plonk_inject.c └── plonk_inject_win.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest, macos-latest, windows-latest] 18 | runs-on: ${{ matrix.os }} 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Build 23 | run: cargo build -vv 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | deps/ 2 | *.so 3 | *.dylib 4 | target/ 5 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "autocfg" 22 | version = "1.1.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 25 | 26 | [[package]] 27 | name = "backtrace" 28 | version = "0.3.69" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 31 | dependencies = [ 32 | "addr2line", 33 | "cc", 34 | "cfg-if", 35 | "libc", 36 | "miniz_oxide", 37 | "object", 38 | "rustc-demangle", 39 | ] 40 | 41 | [[package]] 42 | name = "base64" 43 | version = "0.21.5" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" 46 | 47 | [[package]] 48 | name = "bitflags" 49 | version = "1.3.2" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 52 | 53 | [[package]] 54 | name = "bitflags" 55 | version = "2.4.1" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" 58 | 59 | [[package]] 60 | name = "bumpalo" 61 | version = "3.14.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" 64 | 65 | [[package]] 66 | name = "byteorder" 67 | version = "1.5.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 70 | 71 | [[package]] 72 | name = "bytes" 73 | version = "1.5.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" 76 | 77 | [[package]] 78 | name = "camino" 79 | version = "1.1.6" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" 82 | dependencies = [ 83 | "serde", 84 | ] 85 | 86 | [[package]] 87 | name = "cargo-platform" 88 | version = "0.1.5" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" 91 | dependencies = [ 92 | "serde", 93 | ] 94 | 95 | [[package]] 96 | name = "cargo-plonk" 97 | version = "0.1.0" 98 | dependencies = [ 99 | "cargo_metadata", 100 | "cc", 101 | "dynasmrt", 102 | "notify", 103 | "notify-debouncer-mini", 104 | "pico-args", 105 | "reqwest", 106 | "rustc-demangle", 107 | "winapi", 108 | ] 109 | 110 | [[package]] 111 | name = "cargo_metadata" 112 | version = "0.18.1" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" 115 | dependencies = [ 116 | "camino", 117 | "cargo-platform", 118 | "semver", 119 | "serde", 120 | "serde_json", 121 | "thiserror", 122 | ] 123 | 124 | [[package]] 125 | name = "cc" 126 | version = "1.0.83" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 129 | dependencies = [ 130 | "libc", 131 | ] 132 | 133 | [[package]] 134 | name = "cfg-if" 135 | version = "1.0.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 138 | 139 | [[package]] 140 | name = "core-foundation" 141 | version = "0.9.4" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 144 | dependencies = [ 145 | "core-foundation-sys", 146 | "libc", 147 | ] 148 | 149 | [[package]] 150 | name = "core-foundation-sys" 151 | version = "0.8.6" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 154 | 155 | [[package]] 156 | name = "crossbeam-channel" 157 | version = "0.5.8" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" 160 | dependencies = [ 161 | "cfg-if", 162 | "crossbeam-utils", 163 | ] 164 | 165 | [[package]] 166 | name = "crossbeam-utils" 167 | version = "0.8.16" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 170 | dependencies = [ 171 | "cfg-if", 172 | ] 173 | 174 | [[package]] 175 | name = "dynasm" 176 | version = "2.0.0" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "33dc03612f42465a8ed7f5e354bc2b79ba54cedefa81d5bd3a064f1835adaba8" 179 | dependencies = [ 180 | "bitflags 1.3.2", 181 | "byteorder", 182 | "lazy_static", 183 | "proc-macro-error", 184 | "proc-macro2", 185 | "quote", 186 | "syn 1.0.109", 187 | ] 188 | 189 | [[package]] 190 | name = "dynasmrt" 191 | version = "2.0.0" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "f7dccc31a678058996aef614f6bd418ced384da70f284e83e2b7bf29b27b6a28" 194 | dependencies = [ 195 | "byteorder", 196 | "dynasm", 197 | "fnv", 198 | "memmap2", 199 | ] 200 | 201 | [[package]] 202 | name = "encoding_rs" 203 | version = "0.8.33" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" 206 | dependencies = [ 207 | "cfg-if", 208 | ] 209 | 210 | [[package]] 211 | name = "equivalent" 212 | version = "1.0.1" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 215 | 216 | [[package]] 217 | name = "errno" 218 | version = "0.3.8" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 221 | dependencies = [ 222 | "libc", 223 | "windows-sys 0.52.0", 224 | ] 225 | 226 | [[package]] 227 | name = "fastrand" 228 | version = "2.0.1" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" 231 | 232 | [[package]] 233 | name = "filetime" 234 | version = "0.2.22" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" 237 | dependencies = [ 238 | "cfg-if", 239 | "libc", 240 | "redox_syscall 0.3.5", 241 | "windows-sys 0.48.0", 242 | ] 243 | 244 | [[package]] 245 | name = "fnv" 246 | version = "1.0.7" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 249 | 250 | [[package]] 251 | name = "foreign-types" 252 | version = "0.3.2" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 255 | dependencies = [ 256 | "foreign-types-shared", 257 | ] 258 | 259 | [[package]] 260 | name = "foreign-types-shared" 261 | version = "0.1.1" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 264 | 265 | [[package]] 266 | name = "form_urlencoded" 267 | version = "1.2.1" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 270 | dependencies = [ 271 | "percent-encoding", 272 | ] 273 | 274 | [[package]] 275 | name = "fsevent-sys" 276 | version = "4.1.0" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" 279 | dependencies = [ 280 | "libc", 281 | ] 282 | 283 | [[package]] 284 | name = "futures-channel" 285 | version = "0.3.29" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" 288 | dependencies = [ 289 | "futures-core", 290 | ] 291 | 292 | [[package]] 293 | name = "futures-core" 294 | version = "0.3.29" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" 297 | 298 | [[package]] 299 | name = "futures-io" 300 | version = "0.3.29" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" 303 | 304 | [[package]] 305 | name = "futures-sink" 306 | version = "0.3.29" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" 309 | 310 | [[package]] 311 | name = "futures-task" 312 | version = "0.3.29" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" 315 | 316 | [[package]] 317 | name = "futures-util" 318 | version = "0.3.29" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" 321 | dependencies = [ 322 | "futures-core", 323 | "futures-io", 324 | "futures-task", 325 | "memchr", 326 | "pin-project-lite", 327 | "pin-utils", 328 | "slab", 329 | ] 330 | 331 | [[package]] 332 | name = "gimli" 333 | version = "0.28.1" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 336 | 337 | [[package]] 338 | name = "h2" 339 | version = "0.3.22" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" 342 | dependencies = [ 343 | "bytes", 344 | "fnv", 345 | "futures-core", 346 | "futures-sink", 347 | "futures-util", 348 | "http", 349 | "indexmap", 350 | "slab", 351 | "tokio", 352 | "tokio-util", 353 | "tracing", 354 | ] 355 | 356 | [[package]] 357 | name = "hashbrown" 358 | version = "0.14.3" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 361 | 362 | [[package]] 363 | name = "hermit-abi" 364 | version = "0.3.3" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" 367 | 368 | [[package]] 369 | name = "http" 370 | version = "0.2.11" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" 373 | dependencies = [ 374 | "bytes", 375 | "fnv", 376 | "itoa", 377 | ] 378 | 379 | [[package]] 380 | name = "http-body" 381 | version = "0.4.5" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 384 | dependencies = [ 385 | "bytes", 386 | "http", 387 | "pin-project-lite", 388 | ] 389 | 390 | [[package]] 391 | name = "httparse" 392 | version = "1.8.0" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 395 | 396 | [[package]] 397 | name = "httpdate" 398 | version = "1.0.3" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 401 | 402 | [[package]] 403 | name = "hyper" 404 | version = "0.14.27" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" 407 | dependencies = [ 408 | "bytes", 409 | "futures-channel", 410 | "futures-core", 411 | "futures-util", 412 | "h2", 413 | "http", 414 | "http-body", 415 | "httparse", 416 | "httpdate", 417 | "itoa", 418 | "pin-project-lite", 419 | "socket2 0.4.10", 420 | "tokio", 421 | "tower-service", 422 | "tracing", 423 | "want", 424 | ] 425 | 426 | [[package]] 427 | name = "hyper-tls" 428 | version = "0.5.0" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 431 | dependencies = [ 432 | "bytes", 433 | "hyper", 434 | "native-tls", 435 | "tokio", 436 | "tokio-native-tls", 437 | ] 438 | 439 | [[package]] 440 | name = "idna" 441 | version = "0.5.0" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 444 | dependencies = [ 445 | "unicode-bidi", 446 | "unicode-normalization", 447 | ] 448 | 449 | [[package]] 450 | name = "indexmap" 451 | version = "2.1.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" 454 | dependencies = [ 455 | "equivalent", 456 | "hashbrown", 457 | ] 458 | 459 | [[package]] 460 | name = "inotify" 461 | version = "0.9.6" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" 464 | dependencies = [ 465 | "bitflags 1.3.2", 466 | "inotify-sys", 467 | "libc", 468 | ] 469 | 470 | [[package]] 471 | name = "inotify-sys" 472 | version = "0.1.5" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" 475 | dependencies = [ 476 | "libc", 477 | ] 478 | 479 | [[package]] 480 | name = "ipnet" 481 | version = "2.9.0" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 484 | 485 | [[package]] 486 | name = "itoa" 487 | version = "1.0.9" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 490 | 491 | [[package]] 492 | name = "js-sys" 493 | version = "0.3.66" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" 496 | dependencies = [ 497 | "wasm-bindgen", 498 | ] 499 | 500 | [[package]] 501 | name = "kqueue" 502 | version = "1.0.8" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" 505 | dependencies = [ 506 | "kqueue-sys", 507 | "libc", 508 | ] 509 | 510 | [[package]] 511 | name = "kqueue-sys" 512 | version = "1.0.4" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" 515 | dependencies = [ 516 | "bitflags 1.3.2", 517 | "libc", 518 | ] 519 | 520 | [[package]] 521 | name = "lazy_static" 522 | version = "1.4.0" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 525 | 526 | [[package]] 527 | name = "libc" 528 | version = "0.2.150" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" 531 | 532 | [[package]] 533 | name = "linux-raw-sys" 534 | version = "0.4.12" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" 537 | 538 | [[package]] 539 | name = "log" 540 | version = "0.4.20" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 543 | 544 | [[package]] 545 | name = "memchr" 546 | version = "2.6.4" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" 549 | 550 | [[package]] 551 | name = "memmap2" 552 | version = "0.5.10" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" 555 | dependencies = [ 556 | "libc", 557 | ] 558 | 559 | [[package]] 560 | name = "mime" 561 | version = "0.3.17" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 564 | 565 | [[package]] 566 | name = "miniz_oxide" 567 | version = "0.7.1" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 570 | dependencies = [ 571 | "adler", 572 | ] 573 | 574 | [[package]] 575 | name = "mio" 576 | version = "0.8.9" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" 579 | dependencies = [ 580 | "libc", 581 | "log", 582 | "wasi", 583 | "windows-sys 0.48.0", 584 | ] 585 | 586 | [[package]] 587 | name = "native-tls" 588 | version = "0.2.11" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" 591 | dependencies = [ 592 | "lazy_static", 593 | "libc", 594 | "log", 595 | "openssl", 596 | "openssl-probe", 597 | "openssl-sys", 598 | "schannel", 599 | "security-framework", 600 | "security-framework-sys", 601 | "tempfile", 602 | ] 603 | 604 | [[package]] 605 | name = "notify" 606 | version = "6.1.1" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" 609 | dependencies = [ 610 | "bitflags 2.4.1", 611 | "crossbeam-channel", 612 | "filetime", 613 | "fsevent-sys", 614 | "inotify", 615 | "kqueue", 616 | "libc", 617 | "log", 618 | "mio", 619 | "walkdir", 620 | "windows-sys 0.48.0", 621 | ] 622 | 623 | [[package]] 624 | name = "notify-debouncer-mini" 625 | version = "0.4.1" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "5d40b221972a1fc5ef4d858a2f671fb34c75983eb385463dff3780eeff6a9d43" 628 | dependencies = [ 629 | "crossbeam-channel", 630 | "log", 631 | "notify", 632 | ] 633 | 634 | [[package]] 635 | name = "num_cpus" 636 | version = "1.16.0" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 639 | dependencies = [ 640 | "hermit-abi", 641 | "libc", 642 | ] 643 | 644 | [[package]] 645 | name = "object" 646 | version = "0.32.1" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" 649 | dependencies = [ 650 | "memchr", 651 | ] 652 | 653 | [[package]] 654 | name = "once_cell" 655 | version = "1.18.0" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 658 | 659 | [[package]] 660 | name = "openssl" 661 | version = "0.10.61" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" 664 | dependencies = [ 665 | "bitflags 2.4.1", 666 | "cfg-if", 667 | "foreign-types", 668 | "libc", 669 | "once_cell", 670 | "openssl-macros", 671 | "openssl-sys", 672 | ] 673 | 674 | [[package]] 675 | name = "openssl-macros" 676 | version = "0.1.1" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 679 | dependencies = [ 680 | "proc-macro2", 681 | "quote", 682 | "syn 2.0.39", 683 | ] 684 | 685 | [[package]] 686 | name = "openssl-probe" 687 | version = "0.1.5" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 690 | 691 | [[package]] 692 | name = "openssl-sys" 693 | version = "0.9.97" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" 696 | dependencies = [ 697 | "cc", 698 | "libc", 699 | "pkg-config", 700 | "vcpkg", 701 | ] 702 | 703 | [[package]] 704 | name = "percent-encoding" 705 | version = "2.3.1" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 708 | 709 | [[package]] 710 | name = "pico-args" 711 | version = "0.5.0" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" 714 | 715 | [[package]] 716 | name = "pin-project-lite" 717 | version = "0.2.13" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 720 | 721 | [[package]] 722 | name = "pin-utils" 723 | version = "0.1.0" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 726 | 727 | [[package]] 728 | name = "pkg-config" 729 | version = "0.3.27" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 732 | 733 | [[package]] 734 | name = "proc-macro-error" 735 | version = "1.0.4" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 738 | dependencies = [ 739 | "proc-macro-error-attr", 740 | "proc-macro2", 741 | "quote", 742 | "syn 1.0.109", 743 | "version_check", 744 | ] 745 | 746 | [[package]] 747 | name = "proc-macro-error-attr" 748 | version = "1.0.4" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 751 | dependencies = [ 752 | "proc-macro2", 753 | "quote", 754 | "version_check", 755 | ] 756 | 757 | [[package]] 758 | name = "proc-macro2" 759 | version = "1.0.70" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" 762 | dependencies = [ 763 | "unicode-ident", 764 | ] 765 | 766 | [[package]] 767 | name = "quote" 768 | version = "1.0.33" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 771 | dependencies = [ 772 | "proc-macro2", 773 | ] 774 | 775 | [[package]] 776 | name = "redox_syscall" 777 | version = "0.3.5" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 780 | dependencies = [ 781 | "bitflags 1.3.2", 782 | ] 783 | 784 | [[package]] 785 | name = "redox_syscall" 786 | version = "0.4.1" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 789 | dependencies = [ 790 | "bitflags 1.3.2", 791 | ] 792 | 793 | [[package]] 794 | name = "reqwest" 795 | version = "0.11.22" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" 798 | dependencies = [ 799 | "base64", 800 | "bytes", 801 | "encoding_rs", 802 | "futures-core", 803 | "futures-util", 804 | "h2", 805 | "http", 806 | "http-body", 807 | "hyper", 808 | "hyper-tls", 809 | "ipnet", 810 | "js-sys", 811 | "log", 812 | "mime", 813 | "native-tls", 814 | "once_cell", 815 | "percent-encoding", 816 | "pin-project-lite", 817 | "serde", 818 | "serde_json", 819 | "serde_urlencoded", 820 | "system-configuration", 821 | "tokio", 822 | "tokio-native-tls", 823 | "tower-service", 824 | "url", 825 | "wasm-bindgen", 826 | "wasm-bindgen-futures", 827 | "web-sys", 828 | "winreg", 829 | ] 830 | 831 | [[package]] 832 | name = "rustc-demangle" 833 | version = "0.1.23" 834 | source = "registry+https://github.com/rust-lang/crates.io-index" 835 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 836 | 837 | [[package]] 838 | name = "rustix" 839 | version = "0.38.26" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" 842 | dependencies = [ 843 | "bitflags 2.4.1", 844 | "errno", 845 | "libc", 846 | "linux-raw-sys", 847 | "windows-sys 0.52.0", 848 | ] 849 | 850 | [[package]] 851 | name = "ryu" 852 | version = "1.0.15" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 855 | 856 | [[package]] 857 | name = "same-file" 858 | version = "1.0.6" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 861 | dependencies = [ 862 | "winapi-util", 863 | ] 864 | 865 | [[package]] 866 | name = "schannel" 867 | version = "0.1.22" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" 870 | dependencies = [ 871 | "windows-sys 0.48.0", 872 | ] 873 | 874 | [[package]] 875 | name = "security-framework" 876 | version = "2.9.2" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" 879 | dependencies = [ 880 | "bitflags 1.3.2", 881 | "core-foundation", 882 | "core-foundation-sys", 883 | "libc", 884 | "security-framework-sys", 885 | ] 886 | 887 | [[package]] 888 | name = "security-framework-sys" 889 | version = "2.9.1" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" 892 | dependencies = [ 893 | "core-foundation-sys", 894 | "libc", 895 | ] 896 | 897 | [[package]] 898 | name = "semver" 899 | version = "1.0.20" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" 902 | dependencies = [ 903 | "serde", 904 | ] 905 | 906 | [[package]] 907 | name = "serde" 908 | version = "1.0.193" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" 911 | dependencies = [ 912 | "serde_derive", 913 | ] 914 | 915 | [[package]] 916 | name = "serde_derive" 917 | version = "1.0.193" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" 920 | dependencies = [ 921 | "proc-macro2", 922 | "quote", 923 | "syn 2.0.39", 924 | ] 925 | 926 | [[package]] 927 | name = "serde_json" 928 | version = "1.0.108" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" 931 | dependencies = [ 932 | "itoa", 933 | "ryu", 934 | "serde", 935 | ] 936 | 937 | [[package]] 938 | name = "serde_urlencoded" 939 | version = "0.7.1" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 942 | dependencies = [ 943 | "form_urlencoded", 944 | "itoa", 945 | "ryu", 946 | "serde", 947 | ] 948 | 949 | [[package]] 950 | name = "slab" 951 | version = "0.4.9" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 954 | dependencies = [ 955 | "autocfg", 956 | ] 957 | 958 | [[package]] 959 | name = "socket2" 960 | version = "0.4.10" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" 963 | dependencies = [ 964 | "libc", 965 | "winapi", 966 | ] 967 | 968 | [[package]] 969 | name = "socket2" 970 | version = "0.5.5" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" 973 | dependencies = [ 974 | "libc", 975 | "windows-sys 0.48.0", 976 | ] 977 | 978 | [[package]] 979 | name = "syn" 980 | version = "1.0.109" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 983 | dependencies = [ 984 | "proc-macro2", 985 | "quote", 986 | "unicode-ident", 987 | ] 988 | 989 | [[package]] 990 | name = "syn" 991 | version = "2.0.39" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" 994 | dependencies = [ 995 | "proc-macro2", 996 | "quote", 997 | "unicode-ident", 998 | ] 999 | 1000 | [[package]] 1001 | name = "system-configuration" 1002 | version = "0.5.1" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 1005 | dependencies = [ 1006 | "bitflags 1.3.2", 1007 | "core-foundation", 1008 | "system-configuration-sys", 1009 | ] 1010 | 1011 | [[package]] 1012 | name = "system-configuration-sys" 1013 | version = "0.5.0" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 1016 | dependencies = [ 1017 | "core-foundation-sys", 1018 | "libc", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "tempfile" 1023 | version = "3.8.1" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" 1026 | dependencies = [ 1027 | "cfg-if", 1028 | "fastrand", 1029 | "redox_syscall 0.4.1", 1030 | "rustix", 1031 | "windows-sys 0.48.0", 1032 | ] 1033 | 1034 | [[package]] 1035 | name = "thiserror" 1036 | version = "1.0.50" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 1039 | dependencies = [ 1040 | "thiserror-impl", 1041 | ] 1042 | 1043 | [[package]] 1044 | name = "thiserror-impl" 1045 | version = "1.0.50" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 1048 | dependencies = [ 1049 | "proc-macro2", 1050 | "quote", 1051 | "syn 2.0.39", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "tinyvec" 1056 | version = "1.6.0" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1059 | dependencies = [ 1060 | "tinyvec_macros", 1061 | ] 1062 | 1063 | [[package]] 1064 | name = "tinyvec_macros" 1065 | version = "0.1.1" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1068 | 1069 | [[package]] 1070 | name = "tokio" 1071 | version = "1.34.0" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" 1074 | dependencies = [ 1075 | "backtrace", 1076 | "bytes", 1077 | "libc", 1078 | "mio", 1079 | "num_cpus", 1080 | "pin-project-lite", 1081 | "socket2 0.5.5", 1082 | "windows-sys 0.48.0", 1083 | ] 1084 | 1085 | [[package]] 1086 | name = "tokio-native-tls" 1087 | version = "0.3.1" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1090 | dependencies = [ 1091 | "native-tls", 1092 | "tokio", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "tokio-util" 1097 | version = "0.7.10" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" 1100 | dependencies = [ 1101 | "bytes", 1102 | "futures-core", 1103 | "futures-sink", 1104 | "pin-project-lite", 1105 | "tokio", 1106 | "tracing", 1107 | ] 1108 | 1109 | [[package]] 1110 | name = "tower-service" 1111 | version = "0.3.2" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1114 | 1115 | [[package]] 1116 | name = "tracing" 1117 | version = "0.1.40" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1120 | dependencies = [ 1121 | "pin-project-lite", 1122 | "tracing-core", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "tracing-core" 1127 | version = "0.1.32" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1130 | dependencies = [ 1131 | "once_cell", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "try-lock" 1136 | version = "0.2.4" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" 1139 | 1140 | [[package]] 1141 | name = "unicode-bidi" 1142 | version = "0.3.13" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 1145 | 1146 | [[package]] 1147 | name = "unicode-ident" 1148 | version = "1.0.12" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1151 | 1152 | [[package]] 1153 | name = "unicode-normalization" 1154 | version = "0.1.22" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1157 | dependencies = [ 1158 | "tinyvec", 1159 | ] 1160 | 1161 | [[package]] 1162 | name = "url" 1163 | version = "2.5.0" 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" 1165 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 1166 | dependencies = [ 1167 | "form_urlencoded", 1168 | "idna", 1169 | "percent-encoding", 1170 | ] 1171 | 1172 | [[package]] 1173 | name = "vcpkg" 1174 | version = "0.2.15" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1177 | 1178 | [[package]] 1179 | name = "version_check" 1180 | version = "0.9.4" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1183 | 1184 | [[package]] 1185 | name = "walkdir" 1186 | version = "2.4.0" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" 1189 | dependencies = [ 1190 | "same-file", 1191 | "winapi-util", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "want" 1196 | version = "0.3.1" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1199 | dependencies = [ 1200 | "try-lock", 1201 | ] 1202 | 1203 | [[package]] 1204 | name = "wasi" 1205 | version = "0.11.0+wasi-snapshot-preview1" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1208 | 1209 | [[package]] 1210 | name = "wasm-bindgen" 1211 | version = "0.2.89" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" 1214 | dependencies = [ 1215 | "cfg-if", 1216 | "wasm-bindgen-macro", 1217 | ] 1218 | 1219 | [[package]] 1220 | name = "wasm-bindgen-backend" 1221 | version = "0.2.89" 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" 1223 | checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" 1224 | dependencies = [ 1225 | "bumpalo", 1226 | "log", 1227 | "once_cell", 1228 | "proc-macro2", 1229 | "quote", 1230 | "syn 2.0.39", 1231 | "wasm-bindgen-shared", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "wasm-bindgen-futures" 1236 | version = "0.4.39" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" 1239 | dependencies = [ 1240 | "cfg-if", 1241 | "js-sys", 1242 | "wasm-bindgen", 1243 | "web-sys", 1244 | ] 1245 | 1246 | [[package]] 1247 | name = "wasm-bindgen-macro" 1248 | version = "0.2.89" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" 1251 | dependencies = [ 1252 | "quote", 1253 | "wasm-bindgen-macro-support", 1254 | ] 1255 | 1256 | [[package]] 1257 | name = "wasm-bindgen-macro-support" 1258 | version = "0.2.89" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" 1261 | dependencies = [ 1262 | "proc-macro2", 1263 | "quote", 1264 | "syn 2.0.39", 1265 | "wasm-bindgen-backend", 1266 | "wasm-bindgen-shared", 1267 | ] 1268 | 1269 | [[package]] 1270 | name = "wasm-bindgen-shared" 1271 | version = "0.2.89" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" 1274 | 1275 | [[package]] 1276 | name = "web-sys" 1277 | version = "0.3.66" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" 1280 | dependencies = [ 1281 | "js-sys", 1282 | "wasm-bindgen", 1283 | ] 1284 | 1285 | [[package]] 1286 | name = "winapi" 1287 | version = "0.3.9" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1290 | dependencies = [ 1291 | "winapi-i686-pc-windows-gnu", 1292 | "winapi-x86_64-pc-windows-gnu", 1293 | ] 1294 | 1295 | [[package]] 1296 | name = "winapi-i686-pc-windows-gnu" 1297 | version = "0.4.0" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1300 | 1301 | [[package]] 1302 | name = "winapi-util" 1303 | version = "0.1.6" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" 1306 | dependencies = [ 1307 | "winapi", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "winapi-x86_64-pc-windows-gnu" 1312 | version = "0.4.0" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1315 | 1316 | [[package]] 1317 | name = "windows-sys" 1318 | version = "0.48.0" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1321 | dependencies = [ 1322 | "windows-targets 0.48.5", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "windows-sys" 1327 | version = "0.52.0" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1330 | dependencies = [ 1331 | "windows-targets 0.52.0", 1332 | ] 1333 | 1334 | [[package]] 1335 | name = "windows-targets" 1336 | version = "0.48.5" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1339 | dependencies = [ 1340 | "windows_aarch64_gnullvm 0.48.5", 1341 | "windows_aarch64_msvc 0.48.5", 1342 | "windows_i686_gnu 0.48.5", 1343 | "windows_i686_msvc 0.48.5", 1344 | "windows_x86_64_gnu 0.48.5", 1345 | "windows_x86_64_gnullvm 0.48.5", 1346 | "windows_x86_64_msvc 0.48.5", 1347 | ] 1348 | 1349 | [[package]] 1350 | name = "windows-targets" 1351 | version = "0.52.0" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 1354 | dependencies = [ 1355 | "windows_aarch64_gnullvm 0.52.0", 1356 | "windows_aarch64_msvc 0.52.0", 1357 | "windows_i686_gnu 0.52.0", 1358 | "windows_i686_msvc 0.52.0", 1359 | "windows_x86_64_gnu 0.52.0", 1360 | "windows_x86_64_gnullvm 0.52.0", 1361 | "windows_x86_64_msvc 0.52.0", 1362 | ] 1363 | 1364 | [[package]] 1365 | name = "windows_aarch64_gnullvm" 1366 | version = "0.48.5" 1367 | source = "registry+https://github.com/rust-lang/crates.io-index" 1368 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1369 | 1370 | [[package]] 1371 | name = "windows_aarch64_gnullvm" 1372 | version = "0.52.0" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 1375 | 1376 | [[package]] 1377 | name = "windows_aarch64_msvc" 1378 | version = "0.48.5" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1381 | 1382 | [[package]] 1383 | name = "windows_aarch64_msvc" 1384 | version = "0.52.0" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 1387 | 1388 | [[package]] 1389 | name = "windows_i686_gnu" 1390 | version = "0.48.5" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1393 | 1394 | [[package]] 1395 | name = "windows_i686_gnu" 1396 | version = "0.52.0" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 1399 | 1400 | [[package]] 1401 | name = "windows_i686_msvc" 1402 | version = "0.48.5" 1403 | source = "registry+https://github.com/rust-lang/crates.io-index" 1404 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1405 | 1406 | [[package]] 1407 | name = "windows_i686_msvc" 1408 | version = "0.52.0" 1409 | source = "registry+https://github.com/rust-lang/crates.io-index" 1410 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 1411 | 1412 | [[package]] 1413 | name = "windows_x86_64_gnu" 1414 | version = "0.48.5" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1417 | 1418 | [[package]] 1419 | name = "windows_x86_64_gnu" 1420 | version = "0.52.0" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 1423 | 1424 | [[package]] 1425 | name = "windows_x86_64_gnullvm" 1426 | version = "0.48.5" 1427 | source = "registry+https://github.com/rust-lang/crates.io-index" 1428 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1429 | 1430 | [[package]] 1431 | name = "windows_x86_64_gnullvm" 1432 | version = "0.52.0" 1433 | source = "registry+https://github.com/rust-lang/crates.io-index" 1434 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 1435 | 1436 | [[package]] 1437 | name = "windows_x86_64_msvc" 1438 | version = "0.48.5" 1439 | source = "registry+https://github.com/rust-lang/crates.io-index" 1440 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1441 | 1442 | [[package]] 1443 | name = "windows_x86_64_msvc" 1444 | version = "0.52.0" 1445 | source = "registry+https://github.com/rust-lang/crates.io-index" 1446 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 1447 | 1448 | [[package]] 1449 | name = "winreg" 1450 | version = "0.50.0" 1451 | source = "registry+https://github.com/rust-lang/crates.io-index" 1452 | checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" 1453 | dependencies = [ 1454 | "cfg-if", 1455 | "windows-sys 0.48.0", 1456 | ] 1457 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo-plonk" 3 | description = "Recompile Rust faster. Good for your flow state." 4 | license = "MIT" 5 | version = "0.1.0" 6 | edition = "2021" 7 | 8 | [[bin]] 9 | name = "cargo-plonk" 10 | path = "plonk.rs" 11 | 12 | [dependencies] 13 | pico-args = "0.5.0" 14 | cargo_metadata = "0.18.1" 15 | notify-debouncer-mini = "0.4.1" 16 | rustc-demangle = { version = "0.1.23", features = ["std"] } 17 | notify = "6.1.1" 18 | 19 | [target.x86_64-pc-windows-msvc.dependencies] 20 | dynasmrt = "2.0.0" 21 | winapi = { version = "0.3.9", features = ["memoryapi", "synchapi"] } 22 | 23 | [build-dependencies] 24 | cc = "1.0.83" 25 | reqwest = { version = "0.11.22", features = ["blocking"] } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Plonk 2 | 3 | Copyright (c) 2023 Divy Srivastava 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # plonk 2 | 3 | Plonk is a development-time build tool for Rust projects. 4 | 5 | ```shell 6 | cargo install cargo-plonk 7 | ``` 8 | 9 | ![plonk_demo](https://github.com/littledivy/plonk/assets/34997667/bdc1e3c5-6740-42e7-b7b5-32c22cd45311) 10 | 11 | ```shell 12 | # fn main() { 13 | # lib::say_hello(); 14 | # } 15 | $ cargo build -p example_cli 16 | 17 | # pub fn say_hello() { 18 | # println!("Hello x1"); 19 | # } 20 | $ cargo plonk \ 21 | run \ 22 | --package example_lib \ 23 | --symbol say_hello 24 | 25 | Hello x1 26 | 27 | $ echo "pub fn say_hello() {\n println!('Hello x2');\n}" > example_lib/lib.rs 28 | 29 | $ cargo plonk \ 30 | run \ 31 | --package example_lib \ 32 | --symbol say_hello 33 | 34 | Hello x2 35 | ``` 36 | 37 | ## faq 38 | 39 | I am getting a "Library not loaded: @rpath/libstd" error: 40 | ``` 41 | [*] Could not open library ***.dylib 42 | [*] Error: dlopen(***.dylib, 0x0001): Library not loaded: @rpath/libstd-5563368f93f04a18.dylib 43 | Referenced from: ***.dylib 44 | Reason: tried: '/usr/local/lib/libstd-5563368f93f04a18.dylib' (no such file), '/usr/lib/libstd-5563368f93f04a18.dylib' (no such file, not in dyld cache) 45 | ``` 46 | 47 | You need to update your `$DYLD_LIBRARY_PATH` to include the rustc sysroot libraries: `$(rustc --print sysroot)/lib` 48 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Divy Srivastava 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | use std::env; 24 | use std::fs::{self, File}; 25 | use std::io; 26 | use std::path::Path; 27 | use std::process::Command; 28 | 29 | fn main() { 30 | let out_dir = std::env::var("OUT_DIR").unwrap(); 31 | 32 | let deps_dir = format!("{}/deps", out_dir); 33 | 34 | download_deps().expect("Failed to download dependencies"); 35 | 36 | let inject_dylib = format!( 37 | "{}{}", 38 | out_dir, 39 | if cfg!(target_os = "windows") { 40 | "\\inject.dll" 41 | } else { 42 | "/inject.dylib" 43 | } 44 | ); 45 | 46 | let mut cmd = Command::new("clang"); 47 | cmd.args(&[ 48 | "plonk_inject.c", 49 | "-o", 50 | &inject_dylib, 51 | "-shared", 52 | &format!("-L{}", deps_dir), 53 | &format!("-I{}", deps_dir), 54 | "-lfrida-gum", 55 | ]); 56 | 57 | if cfg!(target_os = "windows") { 58 | for lib in [ 59 | "dnsapi", "iphlpapi", "psapi", "winmm", "ws2_32", "advapi32", "crypt32", "gdi32", 60 | "kernel32", "ole32", "secur32", "shell32", "shlwapi", "user32", 61 | ] { 62 | cmd.arg(format!("-l{}", lib)); 63 | } 64 | } 65 | 66 | let output = cmd.spawn().expect("failed to execute process"); 67 | let output = output.wait_with_output().expect("failed to wait on child"); 68 | 69 | assert!(output.status.success()); 70 | println!("cargo:rustc-env=PLONK_INJECT_DYLIB={}", inject_dylib); 71 | } 72 | 73 | fn download_deps() -> Result<(), Box> { 74 | let arch = if cfg!(target_arch = "x86_64") { 75 | "x86_64" 76 | } else if cfg!(target_arch = "aarch64") { 77 | "arm64" 78 | } else if cfg!(target_os = "windows") { 79 | "windows" 80 | } else { 81 | panic!("Unsupported architecture") 82 | }; 83 | 84 | let os = if cfg!(target_os = "macos") { 85 | "macos" 86 | } else if cfg!(target_os = "linux") { 87 | "linux" 88 | } else if cfg!(target_os = "windows") { 89 | "windows" 90 | } else { 91 | panic!("Unsupported OS") 92 | }; 93 | 94 | let version = "16.0.19"; 95 | 96 | let devkit_name = format!("frida-gum-devkit-{}-{}-{}", version, os, arch); 97 | let frida_url = format!( 98 | "https://github.com/frida/frida/releases/download/{}/{}.tar.xz", 99 | version, devkit_name 100 | ); 101 | 102 | let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set by Cargo"); 103 | 104 | let deps_dir = Path::new(&out_dir).join("deps"); 105 | 106 | if !deps_dir.exists() { 107 | fs::create_dir_all(&deps_dir)?; 108 | } 109 | 110 | let tar_path = deps_dir.join(format!("{}.tar.xz", devkit_name)); 111 | 112 | if !tar_path.exists() { 113 | // Download the tarball 114 | let mut res = reqwest::blocking::get(&frida_url)?; 115 | let mut file = File::create(&tar_path)?; 116 | io::copy(&mut res, &mut file)?; 117 | } 118 | 119 | if tar_path.exists() { 120 | let output = Command::new("tar") 121 | .args(&["-xf", &tar_path.to_string_lossy()]) 122 | .current_dir(&deps_dir) 123 | .output()?; 124 | 125 | if output.status.success() { 126 | Ok(()) 127 | } else { 128 | Err(format!("Failed to extract tar file: {:?}", output).into()) 129 | } 130 | } else { 131 | Err("Tarball not found after download.".into()) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /example_rust/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /example_rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "example_cli" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "example_lib", 10 | ] 11 | 12 | [[package]] 13 | name = "example_lib" 14 | version = "0.1.0" 15 | -------------------------------------------------------------------------------- /example_rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "cli", 5 | "library" 6 | ] 7 | 8 | -------------------------------------------------------------------------------- /example_rust/README.md: -------------------------------------------------------------------------------- 1 | ```shell 2 | cargo build 3 | 4 | target/debug/example_cli 5 | Hello, world! x1 6 | 7 | # Change something in library/ 8 | # Only build library 9 | cargo rustc --crate-type=dylib -p example_lib --features=hot_swap 10 | 11 | # Run binary with hot swap 12 | VERBOSE=* \ 13 | SYMBOL=say_hello \ 14 | NEW_SYMBOL=say_hello \ 15 | PLONK_LIBRARY=/Users/divy/gh/deno_build/example_rust/target/debug/libexample_lib.dylib \ 16 | DYLD_INSERT_LIBRARIES="/Users/divy/gh/deno_build/inject.dylib" \ 17 | target/debug/example_cli 18 | 19 | [*] Plonking say_hello in /Users/divy/gh/deno_build/example_rust/target/debug/libexample_lib.dylib 20 | [*] Old address: 0x1029c0844 21 | [*] New address: 0x103633db8 22 | === 23 | Hello, world! x2 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /example_rust/cli/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /example_rust/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example_cli" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | example_lib = { path = "../library" } 8 | 9 | -------------------------------------------------------------------------------- /example_rust/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use example_lib::say_hello; 2 | 3 | fn main() { 4 | say_hello(); 5 | } 6 | -------------------------------------------------------------------------------- /example_rust/library/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /example_rust/library/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example_lib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | hot_swap = [] 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /example_rust/library/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub fn say_hello() { 3 | println!("Hello, world! x3"); 4 | } 5 | -------------------------------------------------------------------------------- /plonk.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Divy Srivastava 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | use cargo_metadata::{MetadataCommand, Node, Package, PackageId}; 24 | use notify::RecursiveMode; 25 | use notify_debouncer_mini::new_debouncer; 26 | use std::collections::HashMap; 27 | use std::collections::HashSet; 28 | use std::ffi::OsString; 29 | use std::path::PathBuf; 30 | use std::process::Command; 31 | use std::time::Duration; 32 | 33 | #[cfg(target_os = "windows")] 34 | mod plonk_inject_win; 35 | 36 | const HELP: &'static str = "\ 37 | plonk 38 | 39 | USAGE: 40 | plonk [COMMAND] [FLAGS] 41 | 42 | FLAGS: 43 | -h, --help Prints help information 44 | -v, --verbose Verbose output 45 | -p, --package Package to build 46 | -s, --symbol Hot reload for a specific symbol 47 | -r, --release Build in release mode 48 | -w, --watch Watch for changes and rebuild 49 | -b, --bin Manually specify binary package 50 | 51 | SUBCOMMANDS: 52 | build Compile the package 53 | run Run the binary 54 | "; 55 | 56 | #[derive(Default)] 57 | struct Options { 58 | // -v, --verbose 59 | verbose: bool, 60 | 61 | // -p, --package 62 | package: String, 63 | 64 | // -b, --bin 65 | bin: Option, 66 | 67 | // -r, --release 68 | release: bool, 69 | 70 | // -s, --symbol 71 | symbol: Option, 72 | 73 | // -w, --watch 74 | watch: bool, 75 | 76 | _internal_meta: bool, 77 | forward: Vec, 78 | 79 | #[allow(dead_code)] 80 | watch_cache: WatchCache, 81 | } 82 | 83 | #[derive(Default)] 84 | struct WatchCache { 85 | #[allow(dead_code)] 86 | bin_symbol: Option, 87 | } 88 | 89 | const INJECT_DYLIB: &'static str = env!("PLONK_INJECT_DYLIB"); 90 | 91 | fn main() { 92 | // `from_vec` takes `OsString`, not `String`. 93 | let mut args: Vec<_> = std::env::args_os().collect(); 94 | args.remove(0); // remove the executable path. 95 | 96 | // Find and process `--`. 97 | let forward = if let Some(dash_dash) = args.iter().position(|arg| arg == "--") { 98 | // Store all arguments following ... 99 | let later_args = args.drain(dash_dash + 1..).collect(); 100 | // .. then remove the `--` 101 | args.pop(); 102 | later_args 103 | } else { 104 | Vec::new() 105 | }; 106 | 107 | let mut pargs = pico_args::Arguments::from_vec(args); 108 | 109 | let mut cmd = pargs.subcommand().unwrap(); 110 | 111 | if pargs.contains(["-h", "--help"]) { 112 | print!("{}", HELP); 113 | return; 114 | } 115 | 116 | let mut opts = Options { 117 | verbose: pargs.contains(["-v", "--verbose"]), 118 | package: pargs 119 | .value_from_str(["-p", "--package"]) 120 | .unwrap_or_else(|_| ".".to_string()), 121 | bin: pargs.value_from_str(["-b", "--bin"]).ok(), 122 | release: pargs.contains(["-r", "--release"]), 123 | symbol: pargs.value_from_str(["-s", "--symbol"]).ok(), 124 | watch: pargs.contains(["-w", "--watch"]), 125 | forward, 126 | ..Default::default() 127 | }; 128 | 129 | // Invoked as `cargo plonk` 130 | if matches!(cmd.as_deref(), Some("plonk")) { 131 | cmd = pargs.subcommand().unwrap(); 132 | } 133 | 134 | let remaining = pargs.finish(); 135 | if !remaining.is_empty() { 136 | println!("Unknown arguments: {:?}", remaining); 137 | print!("{}", HELP); 138 | return; 139 | } 140 | 141 | match cmd.as_deref() { 142 | Some("build") => { 143 | build(&mut opts); 144 | } 145 | Some("run") => run(&mut opts), 146 | _ => { 147 | println!("No command specified"); 148 | print!("{}", HELP); 149 | } 150 | } 151 | } 152 | 153 | fn watch(pargs: &mut Options, fn_: fn(&mut Options) -> R) { 154 | let (tx, rx) = std::sync::mpsc::channel(); 155 | let mut debouncer = 156 | new_debouncer(Duration::from_millis(100), tx).expect("Failed to create watcher"); 157 | 158 | let local_deps = find_local_deps().expect("Failed to find local deps"); 159 | 160 | for dep in local_deps { 161 | debouncer 162 | .watcher() 163 | .watch(&dep, RecursiveMode::Recursive) 164 | .expect("Failed to watch"); 165 | } 166 | 167 | fn_(pargs); 168 | for _event in rx.iter() { 169 | fn_(pargs); 170 | } 171 | } 172 | 173 | fn build(pargs: &mut Options) -> Option { 174 | if pargs.watch { 175 | pargs.watch = false; 176 | watch(pargs, build); 177 | } 178 | 179 | let mut cargo = Command::new("cargo"); 180 | cargo 181 | .env("RUSTFLAGS", "-C prefer-dynamic") 182 | .arg("rustc") 183 | .arg("--crate-type=dylib") 184 | .arg("-p") 185 | .arg(&pargs.package); 186 | 187 | if pargs.release { 188 | cargo.arg("--release"); 189 | } 190 | 191 | if pargs.verbose { 192 | cargo.arg("-vv"); 193 | } 194 | 195 | if pargs._internal_meta { 196 | cargo.arg("--message-format=json-render-diagnostics"); 197 | } 198 | 199 | cargo.stderr(std::process::Stdio::inherit()); 200 | 201 | let cargo = cargo.output().expect("Failed to spawn cargo build"); 202 | assert!(cargo.status.success()); 203 | 204 | if pargs._internal_meta { 205 | let cursor = std::io::Cursor::new(&cargo.stdout[..]); 206 | let reader = std::io::BufReader::new(cursor); 207 | for message in cargo_metadata::Message::parse_stream(reader) { 208 | let message = message.expect("Failed to parse message"); 209 | match message { 210 | cargo_metadata::Message::CompilerArtifact(artifact) => { 211 | if artifact.target.kind.contains(&"dylib".to_string()) { 212 | return Some(artifact); 213 | } 214 | } 215 | _ => {} 216 | } 217 | } 218 | } 219 | 220 | None 221 | } 222 | 223 | fn get_bin_crates(meta: &cargo_metadata::Metadata, release: bool) -> Vec<(String, String)> { 224 | let mut bins = Vec::new(); 225 | for pkg in meta.packages.iter() { 226 | for bin in pkg.targets.iter() { 227 | if bin.kind.contains(&"bin".to_string()) { 228 | let mut path = meta.target_directory.clone(); 229 | path.push(if release { "release" } else { "debug" }); 230 | path.push(&bin.name); 231 | 232 | bins.push((pkg.name.clone(), path.to_string())); 233 | } 234 | } 235 | } 236 | bins 237 | } 238 | 239 | // https://github.com/watchexec/cargo-watch/blob/da7e7f5c631adffce74be97949e7aadfaff1c953/src/options.rs#L165 240 | fn find_local_deps() -> Result, String> { 241 | let metadata = MetadataCommand::new() 242 | .exec() 243 | .map_err(|e| format!("Failed to execute `cargo metadata`: {}", e))?; 244 | 245 | let resolve = match metadata.resolve { 246 | None => return Ok(Vec::new()), 247 | Some(resolve) => resolve, 248 | }; 249 | let id_to_node = 250 | HashMap::::from_iter(resolve.nodes.iter().map(|n| (n.id.clone(), n))); 251 | let id_to_package = HashMap::::from_iter( 252 | metadata.packages.iter().map(|p| (p.id.clone(), p)), 253 | ); 254 | 255 | let mut pkgids_seen = HashSet::new(); 256 | let mut pkgids_to_check = Vec::new(); 257 | match resolve.root { 258 | Some(root) => pkgids_to_check.push(root), 259 | None => pkgids_to_check.extend_from_slice(&metadata.workspace_members), 260 | }; 261 | 262 | // The set of directories of all packages we are interested in. 263 | let mut local_deps = HashSet::new(); 264 | 265 | while !pkgids_to_check.is_empty() { 266 | let current_pkgid = pkgids_to_check.pop().unwrap(); 267 | if !pkgids_seen.insert(current_pkgid.clone()) { 268 | continue; 269 | } 270 | 271 | let pkg = match id_to_package.get(¤t_pkgid) { 272 | None => continue, 273 | Some(&pkg) => pkg, 274 | }; 275 | 276 | // This means this is a remote package. Skip! 277 | if pkg.source.is_some() { 278 | continue; 279 | } 280 | 281 | // This is a path to Cargo.toml. 282 | let mut path = pkg.manifest_path.clone(); 283 | // We want the directory it's in. 284 | path.pop(); 285 | local_deps.insert(path.into_std_path_buf()); 286 | 287 | // And find dependencies. 288 | if let Some(node) = id_to_node.get(¤t_pkgid) { 289 | for dep in &node.deps { 290 | pkgids_to_check.push(dep.pkg.clone()); 291 | } 292 | } 293 | } 294 | 295 | Ok(local_deps.into_iter().collect::>()) 296 | } 297 | 298 | fn rustc_sysroot() -> PathBuf { 299 | let mut cmd = Command::new("rustc"); 300 | cmd.arg("--print").arg("sysroot"); 301 | let cmd = cmd.output().expect("Failed to spawn rustc"); 302 | let stdout = std::str::from_utf8(&cmd.stdout[..]).expect("Failed to parse rustc output"); 303 | PathBuf::from(stdout.trim()) 304 | } 305 | 306 | fn run(pargs: &mut Options) { 307 | if pargs.watch { 308 | pargs.watch = false; 309 | watch(pargs, run); 310 | } 311 | 312 | pargs._internal_meta = true; 313 | let artifact = build(pargs).expect("Failed to build"); 314 | 315 | let cmd = cargo_metadata::MetadataCommand::new(); 316 | let meta = cmd.exec().expect("Failed to get metadata"); 317 | 318 | let bins = get_bin_crates(&meta, pargs.release); 319 | let (_, bin) = match &pargs.bin { 320 | Some(package) => match bins.iter().find(|(pkg, _)| pkg == package) { 321 | None => { 322 | println!("No binary found with name: {}", package); 323 | println!("Available binaries: {:?}", bins); 324 | return; 325 | } 326 | Some(b) => b, 327 | }, 328 | None => { 329 | if bins.len() > 1 { 330 | println!("Multiple binaries found. Use -b to specify a binary"); 331 | println!("Available binaries: {:?}", bins); 332 | return; 333 | } else if bins.len() == 0 { 334 | println!("No binaries found"); 335 | return; 336 | } 337 | bins.first().unwrap() 338 | } 339 | }; 340 | 341 | let library_path = artifact.filenames[0].clone(); 342 | let mut lib = Command::new(&bin); 343 | if pargs.verbose { 344 | lib.env("VERBOSE", "y"); 345 | } 346 | 347 | #[cfg(not(target_os = "windows"))] 348 | { 349 | if let Some(symbol) = &pargs.symbol { 350 | let old_symbol = pargs 351 | .watch_cache 352 | .bin_symbol 353 | .clone() 354 | .or_else(|| find_symbol(&bin, &pargs.package, symbol)); 355 | match old_symbol { 356 | Some(old_symbol) => { 357 | lib.env("SYMBOL", &old_symbol); 358 | pargs.watch_cache.bin_symbol = Some(old_symbol); 359 | } 360 | None => { 361 | println!("Failed to find function symbol `{}` in {}", symbol, bin); 362 | println!("See FAQ"); // TODO 363 | return; 364 | } 365 | } 366 | 367 | let new_symbol = find_symbol(library_path.as_ref(), &pargs.package, symbol); 368 | match new_symbol { 369 | Some(new_symbol) => { 370 | lib.env("NEW_SYMBOL", &new_symbol); 371 | } 372 | None => { 373 | println!( 374 | "Failed to find function symbol `{}` in {}", 375 | symbol, library_path 376 | ); 377 | println!("See FAQ"); // TODO 378 | return; 379 | } 380 | }; 381 | } else { 382 | println!("No symbol specified. Use -s to specify a function"); 383 | print!("{}", HELP); 384 | return; 385 | } 386 | } 387 | 388 | lib.env("PLONK_LIBRARY", &library_path) 389 | .env("PLONK_BINARY", bin); 390 | #[cfg(target_os = "macos")] 391 | { 392 | lib.env("DYLD_INSERT_LIBRARIES", INJECT_DYLIB) 393 | .env("DYLD_LIBRARY_PATH", rustc_sysroot().join("lib")); 394 | } 395 | #[cfg(target_os = "linux")] 396 | { 397 | lib.env("LD_PRELOAD", INJECT_DYLIB) 398 | .env("LD_LIBRARY_PATH", rustc_sysroot().join("lib")); 399 | } 400 | #[cfg(target_os = "windows")] 401 | { 402 | if let Some(sym) = &pargs.symbol { 403 | lib.env("SYMBOL", sym); 404 | lib.env("NEW_SYMBOL", sym); 405 | } 406 | lib.env( 407 | "PATH", 408 | rustc_sysroot().join("lib/rustlib/x86_64-pc-windows-msvc/lib"), 409 | ); 410 | } 411 | 412 | for arg in &pargs.forward { 413 | lib.arg(arg); 414 | } 415 | 416 | if pargs.verbose { 417 | println!("[*] Running: {:?}", lib); 418 | } 419 | 420 | #[cfg(target_os = "windows")] 421 | { 422 | let escaped = INJECT_DYLIB.replace("\\", "\\\\"); 423 | unsafe { plonk_inject_win::inject(&mut lib, &escaped) }; 424 | 425 | return; 426 | } 427 | 428 | let mut lib = match lib.spawn() { 429 | Ok(lib) => lib, 430 | Err(_) => { 431 | println!("Failed to spawn binary: {}", bin); 432 | println!("Did you forget to build the binary with `cargo build`?"); 433 | 434 | println!("{}", HELP); 435 | return; 436 | } 437 | }; 438 | 439 | lib.wait().expect("Failed to wait for bin"); 440 | } 441 | 442 | #[cfg(not(target_os = "windows"))] 443 | fn find_symbol(path: &str, package: &str, symbol: &str) -> Option { 444 | let full_symbol = format!("{}::{}", package, symbol); 445 | let mut cmd = Command::new("nm"); 446 | cmd.arg(path); 447 | let cmd = cmd.output().expect("Failed to spawn nm"); 448 | 449 | let stdout = std::str::from_utf8(&cmd.stdout[..]).expect("Failed to parse nm output"); 450 | let stdout = stdout.split("\n").collect::>(); 451 | 452 | for line in stdout { 453 | let line = line.trim(); 454 | let cols = line.split(" ").collect::>(); 455 | if cols.len() < 3 { 456 | continue; 457 | } 458 | if cols[1] == "t" || cols[1] == "T" { 459 | if cols[2] == symbol { 460 | return Some(symbol.into()); 461 | } 462 | 463 | #[cfg(target_os = "macos")] 464 | // _. 465 | if cols[2] == format!("_{}", symbol) { 466 | return Some(symbol.to_string()); 467 | } 468 | 469 | let demangled = rustc_demangle::demangle(cols[2]).to_string(); 470 | if demangled.contains(&full_symbol) { 471 | #[cfg(target_os = "macos")] 472 | // Remove _ from _. 473 | return Some(cols[2][1..].to_string()); 474 | 475 | #[cfg(not(target_os = "macos"))] 476 | return Some(cols[2].to_string()); 477 | } 478 | } 479 | } 480 | 481 | None 482 | } 483 | -------------------------------------------------------------------------------- /plonk_inject.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Divy Srivastava 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | /* Injector dynamic library for Plonk */ 24 | 25 | #include 26 | #include 27 | 28 | #if defined(__APPLE__) || defined(__linux__) 29 | #include 30 | #define plonk_dlopen(name) dlopen(name, RTLD_LAZY) 31 | #define plonk_dlerror() dlerror() 32 | #define plonk_getenv(name) getenv(name) 33 | #endif 34 | 35 | #if defined(_WIN32) 36 | #include 37 | const char *dlerror() 38 | { 39 | static char buf[256]; 40 | DWORD err = GetLastError(); 41 | if (!err) 42 | return NULL; 43 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 44 | NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 45 | sizeof(buf), NULL); 46 | return buf; 47 | } 48 | char *plonk_getenv(const char *name) 49 | { 50 | // TODO(littledivy): this leaks 51 | char *buf = malloc(256); 52 | DWORD len = GetEnvironmentVariable(name, buf, 256); 53 | if (!len) 54 | return NULL; 55 | return buf; 56 | } 57 | #define plonk_dlopen(name) LoadLibrary(name) 58 | #define plonk_dlerror() dlerror() 59 | 60 | #endif 61 | 62 | #include "frida-gum.h" 63 | 64 | __attribute__((constructor)) 65 | static void init() 66 | { 67 | GumInterceptor * interceptor; 68 | char *sym, *new_sym, *lib, *bin, *verbose; 69 | void *dl, *original, *new; 70 | 71 | sym = plonk_getenv("SYMBOL"); 72 | new_sym = plonk_getenv("NEW_SYMBOL"); 73 | 74 | /* Library with the new symbols */ 75 | lib = plonk_getenv("PLONK_LIBRARY"); 76 | /* Binary with the original symbols */ 77 | bin = plonk_getenv("PLONK_BINARY"); 78 | verbose = plonk_getenv("VERBOSE"); 79 | 80 | if (!sym || !lib) 81 | return; 82 | /* Assume same identifier as the original symbol */ 83 | if (!new_sym) 84 | new_sym = sym; 85 | 86 | gum_init_embedded(); 87 | 88 | interceptor = gum_interceptor_obtain(); 89 | 90 | original = GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, sym)); 91 | if (!original) 92 | original = GSIZE_TO_POINTER(gum_module_find_symbol_by_name(bin, sym)); 93 | if (!original) { 94 | fprintf(stderr, "[*] Could not find symbol %s in bin\n", sym); 95 | return; 96 | } 97 | 98 | /* Leak (intentional) */ 99 | dl = plonk_dlopen(lib); 100 | if (!dl) { 101 | fprintf(stderr, "[*] Could not open library %s\n", lib); 102 | fprintf(stderr, "[*] Error: %s\n", plonk_dlerror()); 103 | return; 104 | } 105 | 106 | new = GSIZE_TO_POINTER (gum_module_find_export_by_name(lib, new_sym)); 107 | if (!new) { 108 | fprintf(stderr, "[*] Could not find symbol %s in %s\n", new_sym, lib); 109 | return; 110 | } 111 | 112 | if (new == original) { 113 | fprintf(stderr, "[*] New symbol %s is the same as the original\n", new_sym); 114 | return; 115 | } 116 | 117 | if (verbose) { 118 | printf("[*] Plonking %s in %s\n", sym, lib); 119 | printf("[*] Old address: %p\n", original); 120 | printf("[*] New address: %p\n", new); 121 | } 122 | 123 | gum_interceptor_replace_fast(interceptor, original, new, NULL); 124 | if (verbose) 125 | printf("===\n"); 126 | } 127 | -------------------------------------------------------------------------------- /plonk_inject_win.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Divy Srivastava 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | /* DLL injector for Windows */ 24 | 25 | use std::mem::size_of; 26 | use std::os::windows::ffi::OsStrExt; 27 | use std::os::windows::io::AsRawHandle; 28 | use std::process::Command; 29 | 30 | use dynasmrt::dynasm; 31 | use dynasmrt::DynasmApi; 32 | use dynasmrt::DynasmLabelApi; 33 | use winapi::shared::minwindef::HMODULE; 34 | use winapi::um::synchapi::WaitForSingleObject; 35 | use winapi::um::winbase::INFINITE; 36 | use winapi::um::winbase::WAIT_FAILED; 37 | 38 | /// This uses the `CreateRemoteThread` technique to inject a DLL into the process. 39 | pub unsafe fn inject(command: &mut Command, dll_path: &str) { 40 | let mut process = command.spawn().unwrap(); 41 | let process_handle = process.as_raw_handle(); 42 | 43 | let k32 = winapi::um::libloaderapi::GetModuleHandleA("kernel32.dll\0".as_ptr() as *const i8); 44 | if k32.is_null() { 45 | panic!("Failed to get kernel32.dll handle"); 46 | } 47 | 48 | let loadlib = 49 | winapi::um::libloaderapi::GetProcAddress(k32, "LoadLibraryW\0".as_ptr() as *const i8) 50 | as usize; 51 | if loadlib == 0 { 52 | panic!("Failed to get LoadLibraryA address"); 53 | } 54 | 55 | let get_last_error = 56 | winapi::um::libloaderapi::GetProcAddress(k32, "GetLastError\0".as_ptr() as *const i8) 57 | as usize; 58 | if get_last_error == 0 { 59 | panic!("Failed to get GetLastError address"); 60 | } 61 | 62 | let mut ops = dynasmrt::x64::Assembler::new().unwrap(); 63 | 64 | let hmodule = alloc_remote(process_handle, size_of::()).unwrap() as usize; 65 | dynasm!(ops 66 | ; .arch x64 67 | ; sub rsp, 40 68 | ; mov rax, QWORD loadlib as i64 69 | ; call rax 70 | ; movabs hmodule as i64, eax 71 | ); 72 | 73 | let label = ops.new_dynamic_label(); 74 | dynasm!(ops 75 | ; .arch x64 76 | ; test rax, rax 77 | ; mov rax, 0 78 | ; jnz =>label 79 | ; mov rax, QWORD get_last_error as i64 80 | ; call rax 81 | ); 82 | ops.dynamic_label(label); 83 | 84 | dynasm!(ops 85 | ; .arch x64 86 | ; add rsp, 40 87 | ; ret 88 | ); 89 | 90 | let code = ops.finalize().unwrap(); 91 | 92 | println!("Code compiled"); 93 | let code_alloc = alloc_remote(process_handle, code.len()).unwrap(); 94 | 95 | write_process_memory(process_handle, code_alloc, &code).unwrap(); 96 | 97 | let wide_dll_path = std::ffi::OsStr::new(dll_path) 98 | .encode_wide() 99 | .chain(std::iter::once(0)) 100 | .collect::>(); 101 | let wide_dll_byte_slice = std::slice::from_raw_parts( 102 | wide_dll_path.as_ptr() as *const u8, 103 | wide_dll_path.len() * size_of::(), 104 | ); 105 | let parameter = alloc_remote(process_handle, wide_dll_byte_slice.len()).unwrap(); 106 | write_process_memory(process_handle, parameter, wide_dll_byte_slice).unwrap(); 107 | 108 | let thread_handle = winapi::um::processthreadsapi::CreateRemoteThread( 109 | process_handle, 110 | std::ptr::null_mut(), 111 | 0, 112 | Some(std::mem::transmute(code_alloc)), 113 | parameter as _, 114 | 0, 115 | std::ptr::null_mut(), 116 | ); 117 | 118 | if thread_handle.is_null() { 119 | panic!("Failed to create remote thread"); 120 | } 121 | 122 | let reason = WaitForSingleObject(thread_handle, INFINITE); 123 | if reason == WAIT_FAILED { 124 | println!("{}", std::io::Error::last_os_error()); 125 | panic!("Failed to wait for remote thread"); 126 | } 127 | 128 | let mut exit_code = std::mem::MaybeUninit::uninit(); 129 | let result = unsafe { 130 | winapi::um::processthreadsapi::GetExitCodeThread(thread_handle, exit_code.as_mut_ptr()) 131 | }; 132 | 133 | if result == 0 { 134 | panic!("Failed to get exit code of remote thread"); 135 | } 136 | debug_assert_ne!( 137 | result as u32, 138 | winapi::um::minwinbase::STILL_ACTIVE, 139 | "GetExitCodeThread returned STILL_ACTIVE after WaitForSingleObject" 140 | ); 141 | 142 | let exit_code = unsafe { exit_code.assume_init() }; 143 | 144 | if exit_code != 0 { 145 | if exit_code == 0xc0000005 { 146 | println!("Exit code: (Access violation)"); 147 | } else { 148 | println!("{}", std::io::Error::from_raw_os_error(exit_code as i32)); 149 | } 150 | } 151 | 152 | process.wait().unwrap(); 153 | } 154 | 155 | fn alloc_remote( 156 | process_handle: winapi::um::winnt::HANDLE, 157 | size: usize, 158 | ) -> Result<*mut std::ffi::c_void, ()> { 159 | let address = unsafe { 160 | winapi::um::memoryapi::VirtualAllocEx( 161 | process_handle, 162 | std::ptr::null_mut(), 163 | size, 164 | winapi::um::winnt::MEM_COMMIT | winapi::um::winnt::MEM_RESERVE, 165 | winapi::um::winnt::PAGE_EXECUTE_READWRITE, 166 | ) 167 | }; 168 | 169 | if address.is_null() { 170 | return Err(()); 171 | } 172 | 173 | Ok(address) 174 | } 175 | 176 | fn write_process_memory( 177 | process_handle: winapi::um::winnt::HANDLE, 178 | address: *mut std::ffi::c_void, 179 | data: &[u8], 180 | ) -> Result<(), std::io::Error> { 181 | let mut bytes_written = 0; 182 | let result = unsafe { 183 | winapi::um::memoryapi::WriteProcessMemory( 184 | process_handle, 185 | address, 186 | data.as_ptr() as *const std::ffi::c_void, 187 | data.len(), 188 | &mut bytes_written, 189 | ) 190 | }; 191 | 192 | if result == 0 { 193 | return Err(std::io::Error::last_os_error()); 194 | } 195 | 196 | assert!(bytes_written == data.len()); 197 | 198 | Ok(()) 199 | } 200 | --------------------------------------------------------------------------------