Major Update!
This features a new bypass, new theme, etc
This commit is contained in:
@@ -1,2 +1,5 @@
|
||||
[build]
|
||||
target = "aarch64-linux-android"
|
||||
[target.aarch64-linux-android]
|
||||
linker = "aarch64-linux-android28-clang"
|
||||
|
||||
[target.armv7-linux-androideabi]
|
||||
linker = "armv7a-linux-androideabi28-clang"
|
||||
|
||||
608
native/rust/Cargo.lock
generated
608
native/rust/Cargo.lock
generated
@@ -2,21 +2,23 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
@@ -26,23 +28,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-ndk"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b3b3747db640f4777e971b8b8ef1562798c79e670c67ee6a242eda03ce492ef"
|
||||
dependencies = [
|
||||
"android-ndk-sys",
|
||||
"jni 0.13.1",
|
||||
"num_enum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-ndk-sys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ec6ef28479835db378e2202b3911608e2269405e924fabb02ac3c8fb50284fe"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
@@ -75,12 +60,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ascii"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
@@ -88,19 +67,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@@ -108,6 +84,15 @@ version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
@@ -126,6 +111,26 @@ version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
|
||||
dependencies = [
|
||||
"bzip2-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.13+1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.9"
|
||||
@@ -168,16 +173,13 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "3.8.1"
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"byteorder",
|
||||
"either",
|
||||
"memchr",
|
||||
"unreachable",
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -190,12 +192,33 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
@@ -205,6 +228,79 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"curve25519-dalek-derive",
|
||||
"digest",
|
||||
"fiat-crypto",
|
||||
"rustc_version",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek-derive"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dobby-rs"
|
||||
version = "0.1.0"
|
||||
@@ -222,10 +318,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cdffdeaa52be950db80677f22f549050675f226b77e97fdbe10bb2dd846ac7b"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
name = "ed25519"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||
dependencies = [
|
||||
"pkcs8",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"serde",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
@@ -248,14 +362,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.4"
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"version_check",
|
||||
]
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
@@ -267,6 +377,16 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@@ -279,10 +399,17 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
name = "goldberg"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
checksum = "d2d9cbd1fdba1a34e35404e93aab99efbf14076ab4c3380b4d408f7cd3cd9710"
|
||||
dependencies = [
|
||||
"moisture",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rand",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
@@ -290,6 +417,15 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
@@ -313,26 +449,21 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e00f1fd30a82a801f8bf38bcb0895088a0013cde111acb713c0824edc372aa4"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"combine 3.8.1",
|
||||
"error-chain",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.21.1"
|
||||
@@ -341,7 +472,7 @@ checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"cfg-if",
|
||||
"combine 4.6.7",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
@@ -407,6 +538,17 @@ dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moisture"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da1c12ec95f955162f01e673f383afd3f1306a5d7254f0aa38c4d219066ad7b0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.29.0"
|
||||
@@ -419,6 +561,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -428,44 +576,63 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fae2a63210048cf77ceb6031b3f87ac69e4a68cfaacb17a0261e141c4bc8467b"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"syn 0.15.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hmac",
|
||||
"password-hash",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
@@ -475,15 +642,6 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
@@ -519,12 +677,29 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
name = "purrfectsnap"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"android_logger",
|
||||
"base64",
|
||||
"cc",
|
||||
"crc32fast",
|
||||
"dobby-rs",
|
||||
"ed25519-dalek",
|
||||
"goldberg",
|
||||
"jni",
|
||||
"libc",
|
||||
"log",
|
||||
"nix",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"procfs",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"zip",
|
||||
"zstd 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -533,7 +708,7 @@ version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.93",
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -596,10 +771,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.26"
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
@@ -635,6 +813,12 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
@@ -650,8 +834,8 @@ version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.93",
|
||||
"quote 1.0.38",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
@@ -667,6 +851,28 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@@ -674,32 +880,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "snapenhance"
|
||||
version = "0.1.0"
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"android-ndk",
|
||||
"android_logger",
|
||||
"dobby-rs",
|
||||
"jni 0.21.1",
|
||||
"log",
|
||||
"nix",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"procfs",
|
||||
"rand",
|
||||
"serde_json",
|
||||
"zstd",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.44"
|
||||
name = "spki"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
|
||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"unicode-xid",
|
||||
"base64ct",
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -708,8 +921,8 @@ version = "2.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.93",
|
||||
"quote 1.0.38",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
@@ -728,44 +941,48 @@ version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.93",
|
||||
"quote 1.0.38",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
dependencies = [
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
@@ -802,8 +1019,8 @@ checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2 1.0.93",
|
||||
"quote 1.0.38",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -814,7 +1031,7 @@ version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote 1.0.38",
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
@@ -824,8 +1041,8 @@ version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.93",
|
||||
"quote 1.0.38",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
@@ -1013,18 +1230,63 @@ version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.93",
|
||||
"quote 1.0.38",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"byteorder",
|
||||
"bzip2",
|
||||
"constant_time_eq",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"flate2",
|
||||
"hmac",
|
||||
"pbkdf2",
|
||||
"sha1",
|
||||
"time",
|
||||
"zstd 0.11.2+zstd.1.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.11.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
|
||||
dependencies = [
|
||||
"zstd-safe 5.0.2+zstd.1.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
"zstd-safe 7.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "5.0.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "snapenhance"
|
||||
name = "purrfectsnap"
|
||||
version = "0.1.0"
|
||||
authors = ["rhunk"]
|
||||
authors = ["eternal"]
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
@@ -9,7 +9,7 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
android_logger = "0.14.1"
|
||||
android-ndk = "0.0.6"
|
||||
dobby-rs = "0.1.0"
|
||||
jni = "0.21.1"
|
||||
log = "0.4.25"
|
||||
nix = { version = "0.29.0", features = ["fs"] }
|
||||
@@ -17,6 +17,17 @@ once_cell = "1.20.2"
|
||||
paste = "1.0.15"
|
||||
procfs = "0.17.0"
|
||||
rand = "0.8.5"
|
||||
serde_json = "1.0.135"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
zstd = "0.13.2"
|
||||
dobby-rs = "0.1.0"
|
||||
goldberg = "0.1.0"
|
||||
crc32fast = "1.4.0"
|
||||
libc = "0.2"
|
||||
sha2 = "0.10"
|
||||
zip = "0.6.6"
|
||||
base64 = "0.22.1"
|
||||
ed25519-dalek = { version = "2.1.1", default-features = true, features = ["std"] }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-env-changed=OMVLL_PLUGIN_PATH");
|
||||
|
||||
let mut build = cc::Build::new();
|
||||
build
|
||||
.file("secure/secure_strings.c")
|
||||
.flag_if_supported("-fvisibility=hidden");
|
||||
|
||||
if let Ok(plugin) = std::env::var("OMVLL_PLUGIN_PATH") {
|
||||
build.flag(&format!("-fpass-plugin={plugin}"));
|
||||
}
|
||||
|
||||
build.compile("secure_strings");
|
||||
|
||||
println!("cargo:rustc-link-lib=static=c++");
|
||||
}
|
||||
}
|
||||
|
||||
133
native/rust/secure/secure_strings.c
Normal file
133
native/rust/secure/secure_strings.c
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "secure_strings.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
// Simple XOR obfuscation for compile-time data
|
||||
static const uint8_t KEY = 0x5Au;
|
||||
|
||||
static const uint8_t DET_LENS[] = {
|
||||
5, 11, 6, 9, 15, 16, 7, 12, 9, 14, 23, 10, 21, 24, 10
|
||||
};
|
||||
static const uint8_t DET_ENC[] = {
|
||||
// "argos"
|
||||
'a'^KEY,'r'^KEY,'g'^KEY,'o'^KEY,'s'^KEY,
|
||||
// "attestation"
|
||||
'a'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,
|
||||
// "attest"
|
||||
'a'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,
|
||||
// "integrity"
|
||||
'i'^KEY,'n'^KEY,'t'^KEY,'e'^KEY,'g'^KEY,'r'^KEY,'i'^KEY,'t'^KEY,'y'^KEY,
|
||||
// "clientintegrity"
|
||||
'c'^KEY,'l'^KEY,'i'^KEY,'e'^KEY,'n'^KEY,'t'^KEY,'i'^KEY,'n'^KEY,'t'^KEY,'e'^KEY,'g'^KEY,'r'^KEY,'i'^KEY,'t'^KEY,'y'^KEY,
|
||||
// "client_integrity"
|
||||
'c'^KEY,'l'^KEY,'i'^KEY,'e'^KEY,'n'^KEY,'t'^KEY,'_'^KEY,'i'^KEY,'n'^KEY,'t'^KEY,'e'^KEY,'g'^KEY,'r'^KEY,'i'^KEY,'t'^KEY,'y'^KEY,
|
||||
// "scargos"
|
||||
's'^KEY,'c'^KEY,'a'^KEY,'r'^KEY,'g'^KEY,'o'^KEY,'s'^KEY,
|
||||
// "argosservice"
|
||||
'a'^KEY,'r'^KEY,'g'^KEY,'o'^KEY,'s'^KEY,'s'^KEY,'e'^KEY,'r'^KEY,'v'^KEY,'i'^KEY,'c'^KEY,'e'^KEY,
|
||||
// "safetynet"
|
||||
's'^KEY,'a'^KEY,'f'^KEY,'e'^KEY,'t'^KEY,'y'^KEY,'n'^KEY,'e'^KEY,'t'^KEY,
|
||||
// "play_integrity"
|
||||
'p'^KEY,'l'^KEY,'a'^KEY,'y'^KEY,'_'^KEY,'i'^KEY,'n'^KEY,'t'^KEY,'e'^KEY,'g'^KEY,'r'^KEY,'i'^KEY,'t'^KEY,'y'^KEY,
|
||||
// "android_key_attestation"
|
||||
'a'^KEY,'n'^KEY,'d'^KEY,'r'^KEY,'o'^KEY,'i'^KEY,'d'^KEY,'_'^KEY,'k'^KEY,'e'^KEY,'y'^KEY,'_'^KEY,'a'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,
|
||||
// "app_attest"
|
||||
'a'^KEY,'p'^KEY,'p'^KEY,'_'^KEY,'a'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,
|
||||
// "getattestationheaders"
|
||||
'g'^KEY,'e'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,'h'^KEY,'e'^KEY,'a'^KEY,'d'^KEY,'e'^KEY,'r'^KEY,'s'^KEY,
|
||||
// "computeattestationheader"
|
||||
'c'^KEY,'o'^KEY,'m'^KEY,'p'^KEY,'u'^KEY,'t'^KEY,'e'^KEY,'a'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,'h'^KEY,'e'^KEY,'a'^KEY,'d'^KEY,'e'^KEY,'r'^KEY,
|
||||
// "hermod_dup"
|
||||
'h'^KEY,'e'^KEY,'r'^KEY,'m'^KEY,'o'^KEY,'d'^KEY,'_'^KEY,'d'^KEY,'u'^KEY,'p'^KEY,
|
||||
};
|
||||
static char DET_DEC[207];
|
||||
static size_t DET_LEN = 0;
|
||||
static int DET_READY = 0;
|
||||
|
||||
static const uint8_t RISK_LENS[] = { 22, 24, 22, 19, 22, 22, 19 };
|
||||
static const uint8_t RISK_ENC[] = {
|
||||
// "ClientIntegrityService"
|
||||
'C'^KEY,'l'^KEY,'i'^KEY,'e'^KEY,'n'^KEY,'t'^KEY,'I'^KEY,'n'^KEY,'t'^KEY,'e'^KEY,'g'^KEY,'r'^KEY,'i'^KEY,'t'^KEY,'y'^KEY,'S'^KEY,'e'^KEY,'r'^KEY,'v'^KEY,'i'^KEY,'c'^KEY,'e'^KEY,
|
||||
// "/ClientIntegrityService/"
|
||||
'/'^KEY,'C'^KEY,'l'^KEY,'i'^KEY,'e'^KEY,'n'^KEY,'t'^KEY,'I'^KEY,'n'^KEY,'t'^KEY,'e'^KEY,'g'^KEY,'r'^KEY,'i'^KEY,'t'^KEY,'y'^KEY,'S'^KEY,'e'^KEY,'r'^KEY,'v'^KEY,'i'^KEY,'c'^KEY,'e'^KEY,'/'^KEY,
|
||||
// "/GetAttestationHeaders"
|
||||
'/'^KEY,'G'^KEY,'e'^KEY,'t'^KEY,'A'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,'H'^KEY,'e'^KEY,'a'^KEY,'d'^KEY,'e'^KEY,'r'^KEY,'s'^KEY,
|
||||
// "/AttestationHeaders"
|
||||
'/'^KEY,'A'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,'H'^KEY,'e'^KEY,'a'^KEY,'d'^KEY,'e'^KEY,'r'^KEY,'s'^KEY,
|
||||
// "/getAttestationHeaders"
|
||||
'/'^KEY,'g'^KEY,'e'^KEY,'t'^KEY,'A'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,'H'^KEY,'e'^KEY,'a'^KEY,'d'^KEY,'e'^KEY,'r'^KEY,'s'^KEY,
|
||||
// "/GetAttestationPayload"
|
||||
'/'^KEY,'G'^KEY,'e'^KEY,'t'^KEY,'A'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,'P'^KEY,'a'^KEY,'y'^KEY,'l'^KEY,'o'^KEY,'a'^KEY,'d'^KEY,
|
||||
// "/AttestationPayload"
|
||||
'/'^KEY,'A'^KEY,'t'^KEY,'t'^KEY,'e'^KEY,'s'^KEY,'t'^KEY,'a'^KEY,'t'^KEY,'i'^KEY,'o'^KEY,'n'^KEY,'P'^KEY,'a'^KEY,'y'^KEY,'l'^KEY,'o'^KEY,'a'^KEY,'d'^KEY,
|
||||
};
|
||||
static char RISK_DEC[157];
|
||||
static size_t RISK_LEN = 0;
|
||||
static int RISK_READY = 0;
|
||||
|
||||
static size_t decode_list(const uint8_t* enc, size_t enc_len, const uint8_t* lens, size_t n, char* out, size_t out_cap) {
|
||||
size_t off = 0;
|
||||
size_t enc_off = 0;
|
||||
for (size_t i = 0; i < n && enc_off < enc_len; ++i) {
|
||||
size_t L = (size_t)lens[i];
|
||||
if (off + L + 1 > out_cap || enc_off + L > enc_len) break;
|
||||
for (size_t j = 0; j < L; ++j) {
|
||||
out[off++] = (char)(enc[enc_off++] ^ KEY);
|
||||
}
|
||||
out[off++] = '\0';
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
const char* ss_get_detection_blob(size_t* out_len) {
|
||||
if (!DET_READY) {
|
||||
DET_LEN = decode_list(DET_ENC,
|
||||
sizeof(DET_ENC),
|
||||
DET_LENS,
|
||||
sizeof(DET_LENS)/sizeof(DET_LENS[0]),
|
||||
DET_DEC,
|
||||
sizeof(DET_DEC));
|
||||
DET_READY = 1;
|
||||
}
|
||||
if (out_len) {
|
||||
*out_len = DET_LEN;
|
||||
}
|
||||
return DET_DEC;
|
||||
}
|
||||
|
||||
const char* ss_get_risk_block_blob(size_t* out_len) {
|
||||
if (!RISK_READY) {
|
||||
RISK_LEN = decode_list(RISK_ENC,
|
||||
sizeof(RISK_ENC),
|
||||
RISK_LENS,
|
||||
sizeof(RISK_LENS)/sizeof(RISK_LENS[0]),
|
||||
RISK_DEC,
|
||||
sizeof(RISK_DEC));
|
||||
RISK_READY = 1;
|
||||
}
|
||||
if (out_len) {
|
||||
*out_len = RISK_LEN;
|
||||
}
|
||||
return RISK_DEC;
|
||||
}
|
||||
|
||||
const char* ss_get_hermod_dup(size_t* out_len) {
|
||||
static char buf[16];
|
||||
static int ready = 0;
|
||||
if (!ready) {
|
||||
size_t enc_off = 0;
|
||||
for (size_t i = 0; i < sizeof(DET_LENS); ++i) {
|
||||
size_t L = DET_LENS[i];
|
||||
if (i == 14) {
|
||||
size_t w = (L < sizeof(buf)-1) ? L : (sizeof(buf)-1);
|
||||
for (size_t j = 0; j < w; ++j) buf[j] = (char)(DET_ENC[enc_off+j] ^ KEY);
|
||||
buf[w] = '\0';
|
||||
break;
|
||||
}
|
||||
enc_off += L;
|
||||
}
|
||||
ready = 1;
|
||||
}
|
||||
if (out_len) *out_len = strlen(buf);
|
||||
return buf;
|
||||
}
|
||||
10
native/rust/secure/secure_strings.h
Normal file
10
native/rust/secure/secure_strings.h
Normal file
@@ -0,0 +1,10 @@
|
||||
// Minimal C interface to expose obfuscated keyword lists to Rust (FFI)
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
// Returns a pointer to a NUL-separated blob of decoded strings and sets total length in bytes.
|
||||
// The memory is owned by the C module and valid for the lifetime of the process.
|
||||
const char* ss_get_detection_blob(size_t* out_len);
|
||||
const char* ss_get_hermod_dup(size_t* out_len);
|
||||
const char* ss_get_risk_block_blob(size_t* out_len);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{error::Error, sync::Mutex};
|
||||
use jni::{objects::JObject, JNIEnv};
|
||||
use crate::util::get_jni_string;
|
||||
use crate::{secstrings, util::get_jni_string};
|
||||
|
||||
static NATIVE_CONFIG: Mutex<Option<NativeConfig>> = Mutex::new(None);
|
||||
|
||||
@@ -45,6 +45,34 @@ impl NativeConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BlockerConfig {
|
||||
pub allowed_eps_active: Vec<String>,
|
||||
pub detection_keywords: Vec<String>,
|
||||
pub risk_block_list: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn get_blocker_config() -> BlockerConfig {
|
||||
let config_str = include_str!("../../../config/config.json");
|
||||
let raw: serde_json::Value = serde_json::from_str(config_str).unwrap();
|
||||
|
||||
let allowed = raw["allowed_eps_active"].as_array().cloned().unwrap_or_default();
|
||||
|
||||
BlockerConfig {
|
||||
allowed_eps_active: allowed
|
||||
.into_iter()
|
||||
.filter_map(|value| value.as_str().map(|s| s.to_lowercase()))
|
||||
.collect(),
|
||||
detection_keywords: secstrings::get_detection_keywords()
|
||||
.into_iter()
|
||||
.map(|s| s.to_lowercase())
|
||||
.collect(),
|
||||
risk_block_list: secstrings::get_risk_block_list()
|
||||
.into_iter()
|
||||
.map(|s| s.to_lowercase())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_config(mut env: JNIEnv, _class: JObject, obj: JObject) {
|
||||
NATIVE_CONFIG.lock().unwrap().replace(
|
||||
NativeConfig::new(&mut env, obj).expect("Failed to load NativeConfig")
|
||||
|
||||
@@ -10,15 +10,34 @@ mod config;
|
||||
mod sig;
|
||||
|
||||
mod modules;
|
||||
mod security;
|
||||
mod secstrings;
|
||||
|
||||
use android_logger::Config;
|
||||
use log::LevelFilter;
|
||||
use modules::{composer_hook, custom_font_hook, duplex_hook, fstat_hook, linker_hook, sqlite_hook, unary_call_hook};
|
||||
|
||||
use jni::{JNIEnv, JavaVM, NativeMethod};
|
||||
use jni::objects::{JObject, JString};
|
||||
use jni::sys::{jint, jstring, JNI_VERSION_1_6};
|
||||
use jni::objects::{JObject, JString, JClass, JValue};
|
||||
use jni::sys::{jint, jstring, JNI_VERSION_1_6, jboolean, JNI_FALSE, JNI_TRUE};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::ffi::c_void;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Mutex;
|
||||
|
||||
static IS_VERIFIED: AtomicBool = AtomicBool::new(false);
|
||||
static TEST_MODE: AtomicBool = AtomicBool::new(false);
|
||||
static IN_LOGIN_SIGNUP: AtomicBool = AtomicBool::new(false);
|
||||
static CHECKSUMS: Lazy<Mutex<HashMap<String, u32>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
struct BlockerDecision {
|
||||
blocked: bool,
|
||||
reason: &'static str,
|
||||
keyword: Option<String>,
|
||||
keyword_context: Option<&'static str>,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
@@ -26,11 +45,13 @@ pub extern "system" fn JNI_OnLoad(_vm: JavaVM, _: *mut c_void) -> jint {
|
||||
android_logger::init_once(
|
||||
Config::default()
|
||||
.with_max_level(LevelFilter::Debug)
|
||||
.with_tag("SnapEnhanceNative")
|
||||
.with_tag("PurrfectSnapNative")
|
||||
);
|
||||
|
||||
info!("JNI_OnLoad called");
|
||||
|
||||
security::start_anti_debug_thread();
|
||||
|
||||
std::panic::set_hook(Box::new(|panic_info| {
|
||||
error!("{:?}", panic_info);
|
||||
}));
|
||||
@@ -39,11 +60,16 @@ pub extern "system" fn JNI_OnLoad(_vm: JavaVM, _: *mut c_void) -> jint {
|
||||
|
||||
let mut env = _vm.get_env().expect("Failed to get JNIEnv");
|
||||
|
||||
let native_lib_class = env.find_class("me/rhunk/snapenhance/nativelib/NativeLib").expect("NativeLib class not found");
|
||||
let native_lib_class = env.find_class("me/eternal/purrfectsnap/nativelib/NativeLib").expect("NativeLib class not found");
|
||||
|
||||
env.register_native_methods(
|
||||
native_lib_class,
|
||||
&[
|
||||
NativeMethod {
|
||||
name: "verifyKey".into(),
|
||||
sig: "(Ljava/lang/String;)Z".into(),
|
||||
fn_ptr: verifyKey as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
name: "preInit".into(),
|
||||
sig: "()V".into(),
|
||||
@@ -56,7 +82,7 @@ pub extern "system" fn JNI_OnLoad(_vm: JavaVM, _: *mut c_void) -> jint {
|
||||
},
|
||||
NativeMethod {
|
||||
name: "loadConfig".into(),
|
||||
sig: "(Lme/rhunk/snapenhance/nativelib/NativeConfig;)V".into(),
|
||||
sig: "(Lme/eternal/purrfectsnap/nativelib/NativeConfig;)V".into(),
|
||||
fn_ptr: config::load_config as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
@@ -78,13 +104,60 @@ pub extern "system" fn JNI_OnLoad(_vm: JavaVM, _: *mut c_void) -> jint {
|
||||
name: "composerEval".into(),
|
||||
sig: "(Ljava/lang/String;)Ljava/lang/String;".into(),
|
||||
fn_ptr: composer_hook::composer_eval as *mut c_void,
|
||||
}
|
||||
},
|
||||
NativeMethod {
|
||||
name: "evaluateEndpointNative".into(),
|
||||
sig: "(Ljava/lang/String;Ljava/lang/String;ZLme/eternal/purrfectsnap/nativelib/NativeDecision;)V".into(),
|
||||
fn_ptr: evaluateEndpoint as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
name: "shouldBlockDuplexClient".into(),
|
||||
sig: "(Ljava/lang/String;)Z".into(),
|
||||
fn_ptr: shouldBlockDuplexClient as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
name: "evaluateAuthContextNative".into(),
|
||||
sig: "(Ljava/lang/String;ZLme/eternal/purrfectsnap/nativelib/NativeDecision;)V".into(),
|
||||
fn_ptr: evaluateAuthContext as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
name: "evaluateApiInvocationNative".into(),
|
||||
sig: "(Ljava/lang/String;Ljava/lang/String;Lme/eternal/purrfectsnap/nativelib/NativeDecision;)V".into(),
|
||||
fn_ptr: evaluateApiInvocation as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
name: "runEndpointSelfTest".into(),
|
||||
sig: "(Z)Z".into(),
|
||||
fn_ptr: runEndpointSelfTest as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
name: "setChecksums".into(),
|
||||
sig: "(Ljava/lang/String;)V".into(),
|
||||
fn_ptr: setChecksums as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
name: "setTestMode".into(),
|
||||
sig: "(Z)V".into(),
|
||||
fn_ptr: setTestMode as *mut c_void,
|
||||
},
|
||||
NativeMethod {
|
||||
name: "setInLoginSignup".into(),
|
||||
sig: "(Z)V".into(),
|
||||
fn_ptr: setInLoginSignup as *mut c_void,
|
||||
},
|
||||
]
|
||||
).expect("Failed to register native methods");
|
||||
|
||||
JNI_VERSION_1_6
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn setChecksums(mut env: JNIEnv, _class: JClass, checksums_json: JString) {
|
||||
let checksums_str: String = env.get_string(&checksums_json).unwrap().into();
|
||||
let checksums: HashMap<String, u32> = serde_json::from_str(&checksums_str).unwrap();
|
||||
*CHECKSUMS.lock().unwrap() = checksums;
|
||||
}
|
||||
|
||||
fn pre_init(_env: JNIEnv, _class: JObject) {
|
||||
debug!("Pre init");
|
||||
linker_hook::init();
|
||||
@@ -145,3 +218,547 @@ fn init(mut env: JNIEnv, _class: JObject, signature_cache: JString) -> jstring {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn verifyKey(mut env: JNIEnv, _class: JClass, key: JString) -> jboolean {
|
||||
fn bytes_to_hex(bytes: &[u8]) -> String {
|
||||
const LUT: &[u8; 16] = b"0123456789abcdef";
|
||||
let mut out = Vec::with_capacity(bytes.len() * 2);
|
||||
for &b in bytes {
|
||||
out.push(LUT[(b >> 4) as usize]);
|
||||
out.push(LUT[(b & 0x0f) as usize]);
|
||||
}
|
||||
String::from_utf8_lossy(&out).into_owned()
|
||||
}
|
||||
|
||||
fn normalize_hex(s: &str) -> String {
|
||||
s.chars()
|
||||
.filter(|c| c.is_ascii_hexdigit())
|
||||
.map(|c| c.to_ascii_lowercase())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_pkg_cert_sha256_hex(env: &mut JNIEnv, pkg: &str) -> Option<String> {
|
||||
let at = env.find_class("android/app/ActivityThread").ok()?;
|
||||
let app_obj = env
|
||||
.call_static_method(at, "currentApplication", "()Landroid/app/Application;", &[])
|
||||
.ok()?
|
||||
.l()
|
||||
.ok()?;
|
||||
if app_obj.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let pm = env
|
||||
.call_method(&app_obj, "getPackageManager", "()Landroid/content/pm/PackageManager;", &[])
|
||||
.ok()?
|
||||
.l()
|
||||
.ok()?;
|
||||
|
||||
let pkg_j = env.new_string(pkg).ok()?.into();
|
||||
let flags = 0x08000000i32; // PackageManager.GET_SIGNING_CERTIFICATES (API 28+)
|
||||
let info = env
|
||||
.call_method(
|
||||
&pm,
|
||||
"getPackageInfo",
|
||||
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;",
|
||||
&[JValue::Object(&pkg_j), JValue::Int(flags)],
|
||||
)
|
||||
.ok()?
|
||||
.l()
|
||||
.ok()?;
|
||||
|
||||
let signing_info = env
|
||||
.get_field(&info, "signingInfo", "Landroid/content/pm/SigningInfo;")
|
||||
.ok()?
|
||||
.l()
|
||||
.ok()?;
|
||||
if signing_info.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let signers = env
|
||||
.call_method(
|
||||
&signing_info,
|
||||
"getApkContentsSigners",
|
||||
"()[Landroid/content/pm/Signature;",
|
||||
&[],
|
||||
)
|
||||
.ok()?
|
||||
.l()
|
||||
.ok()?;
|
||||
let signers_arr = jni::objects::JObjectArray::from(signers);
|
||||
let first = env.get_object_array_element(&signers_arr, 0).ok()?;
|
||||
let sig_bytes_obj = env
|
||||
.call_method(&first, "toByteArray", "()[B", &[])
|
||||
.ok()?
|
||||
.l()
|
||||
.ok()?;
|
||||
let sig_bytes = env
|
||||
.convert_byte_array(jni::objects::JByteArray::from(sig_bytes_obj))
|
||||
.ok()?;
|
||||
let digest = Sha256::digest(&sig_bytes);
|
||||
Some(bytes_to_hex(&digest))
|
||||
}
|
||||
|
||||
// Harden the check: the provided value must match the module APK signing cert SHA-256.
|
||||
// This prevents trivial re-signing/repacking from passing verification without patching native code.
|
||||
let expected_cert = normalize_hex(
|
||||
&env.get_string(&key)
|
||||
.ok()
|
||||
.map(|s| s.to_string_lossy().into_owned())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
if expected_cert.is_empty() {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
let actual_cert = get_pkg_cert_sha256_hex(&mut env, "me.eternal.purrfectsnap")
|
||||
.map(|s| normalize_hex(&s))
|
||||
.unwrap_or_default();
|
||||
if actual_cert.is_empty() {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if expected_cert == actual_cert {
|
||||
IS_VERIFIED.store(true, Ordering::Relaxed);
|
||||
JNI_TRUE
|
||||
} else {
|
||||
JNI_FALSE
|
||||
}
|
||||
}
|
||||
|
||||
fn find_keyword(paths: &[&str], keywords: &[String]) -> Option<String> {
|
||||
for path in paths {
|
||||
let lower_path = path.to_lowercase();
|
||||
for keyword in keywords {
|
||||
if lower_path.contains(keyword) {
|
||||
return Some(keyword.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn evaluate_endpoint_logic(
|
||||
config: &config::BlockerConfig,
|
||||
uri: &str,
|
||||
arg0: &str,
|
||||
has_attestation: bool,
|
||||
) -> BlockerDecision {
|
||||
let targets = [uri, arg0];
|
||||
let detection_keyword = find_keyword(&targets, &config.detection_keywords);
|
||||
let snap_security_block = targets.iter().any(|t| {
|
||||
let lower = t.to_lowercase();
|
||||
lower.starts_with("/snap.security") && !lower.starts_with("/snap.security.argosservice")
|
||||
});
|
||||
let block_convo_safety_prompt = targets.iter().any(|t| {
|
||||
t.eq_ignore_ascii_case("/snapchat.abuse.conversationsafety.conversationsafetyservice/getconvosafetyprompt")
|
||||
});
|
||||
let block_convo_safety_service = targets.iter().any(|t| {
|
||||
t.to_lowercase()
|
||||
.starts_with("/snapchat.abuse.conversationsafety.conversationsafetyservice/")
|
||||
});
|
||||
let block_device_state_report = targets.iter().any(|t| {
|
||||
t.eq_ignore_ascii_case("/snapchat.notif.devicestatereceiver/reportdevicestate")
|
||||
});
|
||||
if snap_security_block {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "snap_security_block",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
if block_convo_safety_prompt {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "conversation_safety_prompt",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
if block_convo_safety_service {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "conversation_safety_service",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
if block_device_state_report {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "notif_report_device_state",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
if find_keyword(&targets, &config.allowed_eps_active).is_some() {
|
||||
return BlockerDecision {
|
||||
blocked: false,
|
||||
reason: "allowed_whitelist",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
|
||||
let reason = if detection_keyword.is_some() && has_attestation {
|
||||
"allowed_attestation_keyword"
|
||||
} else if detection_keyword.is_some() {
|
||||
"allowed_detection_keyword"
|
||||
} else {
|
||||
"allowed"
|
||||
};
|
||||
|
||||
let blocked = false;
|
||||
BlockerDecision {
|
||||
blocked,
|
||||
reason,
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_auth_context_logic(
|
||||
config: &config::BlockerConfig,
|
||||
request_path: &str,
|
||||
attestation_required: bool,
|
||||
) -> BlockerDecision {
|
||||
let targets = [request_path];
|
||||
let detection_keyword = find_keyword(&targets, &config.detection_keywords);
|
||||
let snap_security_block = targets.iter().any(|t| {
|
||||
let lower = t.to_lowercase();
|
||||
lower.starts_with("/snap.security") && !lower.starts_with("/snap.security.argosservice")
|
||||
});
|
||||
let block_convo_safety_prompt = targets.iter().any(|t| {
|
||||
t.eq_ignore_ascii_case("/snapchat.abuse.conversationsafety.conversationsafetyservice/getconvosafetyprompt")
|
||||
});
|
||||
let block_convo_safety_service = targets.iter().any(|t| {
|
||||
t.to_lowercase()
|
||||
.starts_with("/snapchat.abuse.conversationsafety.conversationsafetyservice/")
|
||||
});
|
||||
let block_device_state_report = targets.iter().any(|t| {
|
||||
t.eq_ignore_ascii_case("/snapchat.notif.devicestatereceiver/reportdevicestate")
|
||||
});
|
||||
if snap_security_block {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "snap_security_block",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
if block_convo_safety_prompt {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "conversation_safety_prompt",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
if block_convo_safety_service {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "conversation_safety_service",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
if block_device_state_report {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "notif_report_device_state",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
if find_keyword(&targets, &config.allowed_eps_active).is_some() {
|
||||
return BlockerDecision {
|
||||
blocked: false,
|
||||
reason: "allowed_whitelist",
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
|
||||
let reason = if detection_keyword.is_some() && attestation_required {
|
||||
"allowed_attestation_keyword"
|
||||
} else if detection_keyword.is_some() {
|
||||
"allowed_detection_keyword"
|
||||
} else {
|
||||
"allowed"
|
||||
};
|
||||
|
||||
let blocked = false;
|
||||
BlockerDecision {
|
||||
blocked,
|
||||
reason,
|
||||
keyword: detection_keyword,
|
||||
keyword_context: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_api_invocation_logic(
|
||||
config: &config::BlockerConfig,
|
||||
method_id: &str,
|
||||
annotations: &str,
|
||||
) -> BlockerDecision {
|
||||
// Hard allow specific API calls regardless of keyword matches
|
||||
const API_ALLOWLIST: &[&str] = &[
|
||||
"com.snap.identity.network.suggestion.bqsuggestfriendhttpinterface.fetchhighavailablesuggestedfriend",
|
||||
"com.snap.identity.network.suggestion.bqsuggestfriendhttpinterface.fetchlegacysuggestedfriend",
|
||||
];
|
||||
let method_lower = method_id.to_lowercase();
|
||||
if API_ALLOWLIST.iter().any(|m| method_lower == *m) {
|
||||
return BlockerDecision {
|
||||
blocked: false,
|
||||
reason: "allowed_api_whitelist",
|
||||
keyword: None,
|
||||
keyword_context: None,
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(keyword) = find_keyword(&[method_id], &config.detection_keywords) {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "detection_keyword",
|
||||
keyword: Some(keyword),
|
||||
keyword_context: Some("method"),
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(keyword) = find_keyword(&[annotations], &config.detection_keywords) {
|
||||
return BlockerDecision {
|
||||
blocked: true,
|
||||
reason: "detection_keyword",
|
||||
keyword: Some(keyword),
|
||||
keyword_context: Some("annotation"),
|
||||
};
|
||||
}
|
||||
|
||||
BlockerDecision {
|
||||
blocked: false,
|
||||
reason: "allowed",
|
||||
keyword: None,
|
||||
keyword_context: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn write_blocker_decision(env: &mut JNIEnv, decision_obj: JObject, decision: &BlockerDecision) {
|
||||
write_decision(
|
||||
env,
|
||||
decision_obj,
|
||||
decision.blocked,
|
||||
decision.reason,
|
||||
decision.keyword.as_deref(),
|
||||
decision.keyword_context,
|
||||
);
|
||||
}
|
||||
|
||||
fn write_decision(env: &mut JNIEnv, decision: JObject, blocked: bool, reason: &str, keyword: Option<&str>, keyword_context: Option<&str>) {
|
||||
let blocked_value = if blocked { JNI_TRUE } else { JNI_FALSE };
|
||||
env.set_field(&decision, "blocked", "Z", JValue::Bool(blocked_value)).expect("failed to set blocked");
|
||||
|
||||
set_string_field(env, &decision, "reason", Some(reason));
|
||||
set_string_field(env, &decision, "keyword", keyword);
|
||||
set_string_field(env, &decision, "keywordContext", keyword_context);
|
||||
}
|
||||
|
||||
fn set_string_field(env: &mut JNIEnv, obj: &JObject, field: &str, value: Option<&str>) {
|
||||
if let Some(text) = value {
|
||||
let jstring = env.new_string(text).expect("failed to alloc string");
|
||||
let j_obj = JObject::from(jstring);
|
||||
env.set_field(obj, field, "Ljava/lang/String;", JValue::Object(&j_obj)).expect("failed to set string field");
|
||||
env.delete_local_ref(j_obj).expect("failed to delete local ref");
|
||||
} else {
|
||||
let null_obj = JObject::null();
|
||||
env.set_field(obj, field, "Ljava/lang/String;", JValue::Object(&null_obj)).expect("failed to clear string field");
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn evaluateEndpoint(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
uri: JString,
|
||||
arg0: JString,
|
||||
has_attestation: jboolean,
|
||||
decision: JObject,
|
||||
) {
|
||||
if IN_LOGIN_SIGNUP.load(Ordering::Relaxed) {
|
||||
write_decision(&mut env, decision, false, "allowed_login_signup", None, None);
|
||||
return;
|
||||
}
|
||||
let is_verified = IS_VERIFIED.load(Ordering::Relaxed);
|
||||
let test_mode = TEST_MODE.load(Ordering::Relaxed);
|
||||
if !is_verified && !test_mode {
|
||||
write_decision(&mut env, decision, false, "allowed", None, None);
|
||||
return;
|
||||
}
|
||||
let uri_str: String = env.get_string(&uri).unwrap().into();
|
||||
let arg0_str: String = env.get_string(&arg0).unwrap().into();
|
||||
|
||||
let config = config::get_blocker_config();
|
||||
let blocker_decision = evaluate_endpoint_logic(&config, &uri_str, &arg0_str, has_attestation == JNI_TRUE);
|
||||
write_blocker_decision(&mut env, decision, &blocker_decision);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn shouldBlockDuplexClient(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
path: JString,
|
||||
) -> jboolean {
|
||||
if IN_LOGIN_SIGNUP.load(Ordering::Relaxed) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
let is_verified = IS_VERIFIED.load(Ordering::Relaxed);
|
||||
let test_mode = TEST_MODE.load(Ordering::Relaxed);
|
||||
if !is_verified && !test_mode {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
let path_str: String = env.get_string(&path).unwrap().into();
|
||||
|
||||
let hermod = secstrings::get_hermod_dup();
|
||||
if path_str == hermod {
|
||||
JNI_TRUE
|
||||
} else {
|
||||
JNI_FALSE
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn evaluateAuthContext(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
request_path: JString,
|
||||
attestation_required: jboolean,
|
||||
decision: JObject,
|
||||
) {
|
||||
if IN_LOGIN_SIGNUP.load(Ordering::Relaxed) {
|
||||
write_decision(&mut env, decision, false, "allowed_login_signup", None, None);
|
||||
return;
|
||||
}
|
||||
let is_verified = IS_VERIFIED.load(Ordering::Relaxed);
|
||||
let test_mode = TEST_MODE.load(Ordering::Relaxed);
|
||||
if !is_verified && !test_mode {
|
||||
write_decision(&mut env, decision, false, "allowed", None, None);
|
||||
return;
|
||||
}
|
||||
let request_path_str: String = env.get_string(&request_path).unwrap().into();
|
||||
|
||||
let config = config::get_blocker_config();
|
||||
let blocker_decision = evaluate_auth_context_logic(&config, &request_path_str, attestation_required == JNI_TRUE);
|
||||
write_blocker_decision(&mut env, decision, &blocker_decision);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn evaluateApiInvocation(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
method_id: JString,
|
||||
annotations: JString,
|
||||
decision: JObject,
|
||||
) {
|
||||
if IN_LOGIN_SIGNUP.load(Ordering::Relaxed) {
|
||||
write_decision(&mut env, decision, false, "allowed_login_signup", None, None);
|
||||
return;
|
||||
}
|
||||
let is_verified = IS_VERIFIED.load(Ordering::Relaxed);
|
||||
let test_mode = TEST_MODE.load(Ordering::Relaxed);
|
||||
if !is_verified && !test_mode {
|
||||
write_decision(&mut env, decision, false, "allowed", None, None);
|
||||
return;
|
||||
}
|
||||
let method_id_str: String = env.get_string(&method_id).unwrap().into();
|
||||
let annotations_str: String = env.get_string(&annotations).unwrap().into();
|
||||
|
||||
let config = config::get_blocker_config();
|
||||
let blocker_decision = evaluate_api_invocation_logic(&config, &method_id_str, &annotations_str);
|
||||
write_blocker_decision(&mut env, decision, &blocker_decision);
|
||||
}
|
||||
|
||||
fn run_blocker_self_test(allow_unverified: bool) -> bool {
|
||||
if !IS_VERIFIED.load(Ordering::Relaxed) && !allow_unverified {
|
||||
return false;
|
||||
}
|
||||
|
||||
let config = config::get_blocker_config();
|
||||
if config.allowed_eps_active.is_empty()
|
||||
|| config.detection_keywords.is_empty()
|
||||
|| config.risk_block_list.is_empty()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let allowed_sample = config.allowed_eps_active[0].clone();
|
||||
let detection_sample = config.detection_keywords[0].clone();
|
||||
let risk_sample = config.risk_block_list[0].clone();
|
||||
|
||||
let allowed_decision = evaluate_endpoint_logic(&config, &allowed_sample, &allowed_sample, false);
|
||||
if allowed_decision.blocked || allowed_decision.reason != "allowed_whitelist" {
|
||||
return false;
|
||||
}
|
||||
|
||||
let detection_path = format!("/self_test/{}", detection_sample);
|
||||
let detection_decision = evaluate_endpoint_logic(&config, &detection_path, "", false);
|
||||
if detection_decision.blocked {
|
||||
return false;
|
||||
}
|
||||
|
||||
let attestation_decision = evaluate_endpoint_logic(&config, &detection_path, "", true);
|
||||
if attestation_decision.blocked {
|
||||
return false;
|
||||
}
|
||||
|
||||
let risk_decision = evaluate_endpoint_logic(&config, &risk_sample, "", false);
|
||||
if risk_decision.blocked {
|
||||
return false;
|
||||
}
|
||||
|
||||
let auth_detection = evaluate_auth_context_logic(&config, &detection_path, false);
|
||||
if auth_detection.blocked {
|
||||
return false;
|
||||
}
|
||||
|
||||
let auth_allowed = evaluate_auth_context_logic(&config, &allowed_sample, false);
|
||||
if auth_allowed.blocked || auth_allowed.reason != "allowed_whitelist" {
|
||||
return false;
|
||||
}
|
||||
|
||||
let api_method = format!("com.snap.obf.SelfTest{}", detection_sample);
|
||||
let api_decision = evaluate_api_invocation_logic(&config, &api_method, "");
|
||||
if !api_decision.blocked || api_decision.keyword.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let annotation_blob = format!("@Requires{}", detection_sample);
|
||||
let api_annotation_decision = evaluate_api_invocation_logic(&config, "com.snap.obf.Safe", &annotation_blob);
|
||||
if !api_annotation_decision.blocked || api_annotation_decision.keyword_context != Some("annotation") {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn setTestMode(_env: JNIEnv, _class: JClass, test_mode: jboolean) {
|
||||
TEST_MODE.store(test_mode == JNI_TRUE, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn setInLoginSignup(_env: JNIEnv, _class: JClass, in_login_signup: jboolean) {
|
||||
IN_LOGIN_SIGNUP.store(in_login_signup == JNI_TRUE, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn runEndpointSelfTest(_env: JNIEnv, _class: JClass, test_mode: jboolean) -> jboolean {
|
||||
if run_blocker_self_test(test_mode == JNI_TRUE) {
|
||||
JNI_TRUE
|
||||
} else {
|
||||
JNI_FALSE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![allow(dead_code, unused_imports)]
|
||||
|
||||
use super::util::composer_utils::{ComposerModule, ModuleTag};
|
||||
use std::{collections::HashMap, ffi::{c_void, CStr}, sync::Mutex};
|
||||
use std::{collections::HashMap, ffi::{c_void, CStr}, sync::{atomic::{AtomicPtr, Ordering}, Mutex}};
|
||||
use jni::{objects::JString, sys::jobject, JNIEnv};
|
||||
use once_cell::sync::Lazy;
|
||||
use crate::{common, config, def_hook, dobby_hook, dobby_hook_sym, sig, util::get_jni_string};
|
||||
@@ -154,12 +154,12 @@ def_hook!(
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
static mut GLOBAL_INSTANCE: Option<*mut c_void> = None;
|
||||
static GLOBAL_INSTANCE: AtomicPtr<c_void> = AtomicPtr::new(std::ptr::null_mut());
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
static mut GLOBAL_CTX: Option<*mut c_void> = None;
|
||||
static GLOBAL_CTX: AtomicPtr<c_void> = AtomicPtr::new(std::ptr::null_mut());
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
static mut JS_EVAL_ORIGINAL2: Option<unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void, *mut u8, usize, *const u8, u32) -> JsValue> = None;
|
||||
static JS_EVAL_ORIGINAL2: Lazy<Mutex<Option<unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void, *mut u8, usize, *const u8, u32) -> JsValue>>> = Lazy::new(|| Mutex::new(None));
|
||||
|
||||
def_hook!(
|
||||
js_eval,
|
||||
@@ -167,8 +167,8 @@ def_hook!(
|
||||
|arg0: *mut c_void, arg1: *mut c_void, arg2: *mut c_void, arg3: *const u8, arg4: *const u8, arg5: *const u8, arg6: *mut c_void, arg7: u32| {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
GLOBAL_INSTANCE = Some(arg0);
|
||||
GLOBAL_CTX = Some(arg1);
|
||||
GLOBAL_INSTANCE.store(arg0, Ordering::Relaxed);
|
||||
GLOBAL_CTX.store(arg1, Ordering::Relaxed);
|
||||
}
|
||||
js_eval_original.unwrap()(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
||||
}
|
||||
@@ -190,7 +190,7 @@ pub unsafe fn composer_eval(env: JNIEnv, _: *mut c_void, script: JString) -> job
|
||||
Err(_) => return std::ptr::null_mut(),
|
||||
};
|
||||
|
||||
if JS_EVAL_ORIGINAL2.is_none() || GLOBAL_INSTANCE.is_none() || GLOBAL_CTX.is_none() {
|
||||
if JS_EVAL_ORIGINAL2.lock().unwrap().is_none() || GLOBAL_INSTANCE.load(Ordering::Relaxed).is_null() || GLOBAL_CTX.load(Ordering::Relaxed).is_null() {
|
||||
if let Ok(s) = env.new_string("Composer hook not initialized") {
|
||||
return s.into_raw();
|
||||
}
|
||||
@@ -199,15 +199,21 @@ pub unsafe fn composer_eval(env: JNIEnv, _: *mut c_void, script: JString) -> job
|
||||
|
||||
let script_length = script_str.len();
|
||||
|
||||
let js_value = JS_EVAL_ORIGINAL2.unwrap()(
|
||||
GLOBAL_INSTANCE.unwrap(),
|
||||
GLOBAL_CTX.unwrap(),
|
||||
std::ptr::null_mut(),
|
||||
(script_str + "\0").as_ptr() as *mut u8,
|
||||
script_length,
|
||||
"<eval>\0".as_ptr(),
|
||||
0
|
||||
);
|
||||
let js_value = {
|
||||
let js_eval_fn = JS_EVAL_ORIGINAL2.lock().unwrap();
|
||||
let global_instance = GLOBAL_INSTANCE.load(Ordering::Relaxed);
|
||||
let global_ctx = GLOBAL_CTX.load(Ordering::Relaxed);
|
||||
|
||||
js_eval_fn.unwrap()(
|
||||
global_instance,
|
||||
global_ctx,
|
||||
std::ptr::null_mut(),
|
||||
(script_str + "\0").as_ptr() as *mut u8,
|
||||
script_length,
|
||||
"<eval>\0".as_ptr(),
|
||||
0
|
||||
)
|
||||
};
|
||||
|
||||
let result: String = if js_value.tag == JS_TAG_STRING {
|
||||
let string = js_value.u.ptr as *mut JsString;
|
||||
@@ -270,7 +276,7 @@ pub fn init() {
|
||||
dobby_hook!(signature as *mut c_void, js_eval);
|
||||
|
||||
unsafe {
|
||||
JS_EVAL_ORIGINAL2 = Some(std::mem::transmute(js_eval_original.unwrap()));
|
||||
*JS_EVAL_ORIGINAL2.lock().unwrap() = Some(std::mem::transmute(js_eval_original.unwrap()));
|
||||
}
|
||||
|
||||
debug!("js_eval {:#x}", signature);
|
||||
@@ -279,4 +285,3 @@ pub fn init() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,11 +113,11 @@ pub fn init() {
|
||||
env.get_method_id(
|
||||
env.get_object_class(common::native_lib_instance()).unwrap(),
|
||||
"onNativeUnaryCall",
|
||||
"(Ljava/lang/String;[B)Lme/rhunk/snapenhance/nativelib/NativeRequestData;"
|
||||
"(Ljava/lang/String;[B)Lme/eternal/purrfectsnap/nativelib/NativeRequestData;"
|
||||
).expect("Failed to get onNativeUnaryCall method id")
|
||||
).expect("unary call method already set");
|
||||
});
|
||||
} else {
|
||||
error!("Can't find unaryCall signature");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
47
native/rust/src/secstrings.rs
Normal file
47
native/rust/src/secstrings.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
fn ss_get_detection_blob(out_len: *mut usize) -> *const u8;
|
||||
fn ss_get_hermod_dup(out_len: *mut usize) -> *const u8;
|
||||
fn ss_get_risk_block_blob(out_len: *mut usize) -> *const u8;
|
||||
}
|
||||
|
||||
fn blob_to_vec(blob_ptr: *const u8, len: usize) -> Vec<String> {
|
||||
if blob_ptr.is_null() || len == 0 { return Vec::new(); }
|
||||
// Safety: blob is a NUL-separated set of C strings
|
||||
let slice = unsafe { std::slice::from_raw_parts(blob_ptr, len) };
|
||||
let mut result = Vec::new();
|
||||
let mut start = 0usize;
|
||||
for i in 0..slice.len() {
|
||||
if slice[i] == 0 { // NUL
|
||||
if i > start {
|
||||
let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(&slice[start..=i]) };
|
||||
result.push(cstr.to_string_lossy().into_owned());
|
||||
}
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_detection_keywords() -> Vec<String> {
|
||||
let mut len: usize = 0;
|
||||
let ptr = unsafe { ss_get_detection_blob(&mut len as *mut usize) };
|
||||
blob_to_vec(ptr, len)
|
||||
}
|
||||
|
||||
pub fn get_hermod_dup() -> String {
|
||||
let mut len: usize = 0;
|
||||
let ptr = unsafe { ss_get_hermod_dup(&mut len as *mut usize) };
|
||||
if ptr.is_null() || len == 0 { return String::new(); }
|
||||
let slice = unsafe { std::slice::from_raw_parts(ptr, len) };
|
||||
String::from_utf8_lossy(slice).into_owned()
|
||||
}
|
||||
|
||||
pub fn get_risk_block_list() -> Vec<String> {
|
||||
let mut len: usize = 0;
|
||||
let ptr = unsafe { ss_get_risk_block_blob(&mut len as *mut usize) };
|
||||
blob_to_vec(ptr, len)
|
||||
}
|
||||
|
||||
96
native/rust/src/security.rs
Normal file
96
native/rust/src/security.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use jni::sys::{jboolean, JNI_FALSE, JNI_TRUE};
|
||||
use goldberg::goldberg_string;
|
||||
use std::{thread, time};
|
||||
use std::fs;
|
||||
use std::process;
|
||||
use crate::CHECKSUMS;
|
||||
use std::ffi::CString;
|
||||
use std::str;
|
||||
|
||||
fn check_for_debugger() {
|
||||
loop {
|
||||
let status = fs::read_to_string("/proc/self/status").unwrap_or_default();
|
||||
if !status.contains("TracerPid:\t0") {
|
||||
process::abort();
|
||||
}
|
||||
|
||||
let maps = fs::read_to_string("/proc/self/maps").unwrap_or_default();
|
||||
if maps.contains("frida") || maps.contains("gumjs") || maps.contains("gdb") {
|
||||
process::abort();
|
||||
}
|
||||
|
||||
thread::sleep(time::Duration::from_secs(5));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_anti_debug_thread() {
|
||||
thread::spawn(move || {
|
||||
check_for_debugger();
|
||||
});
|
||||
thread::spawn(move || {
|
||||
verify_library_checksum();
|
||||
});
|
||||
}
|
||||
|
||||
fn get_abi() -> Option<String> {
|
||||
let key = CString::new("ro.product.cpu.abi").unwrap();
|
||||
let mut value = [0 as libc::c_char; 92];
|
||||
let len = unsafe { libc::__system_property_get(key.as_ptr(), value.as_mut_ptr()) };
|
||||
if len > 0 {
|
||||
let value_slice = unsafe { std::slice::from_raw_parts(value.as_ptr() as *const u8, len as usize) };
|
||||
let value_str = str::from_utf8(value_slice).unwrap();
|
||||
Some(value_str.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_library_checksum() {
|
||||
loop {
|
||||
if let Some(path) = get_library_path() {
|
||||
if let Ok(data) = fs::read(path) {
|
||||
let checksum = crc32fast::hash(&data);
|
||||
if let Some(abi) = get_abi() {
|
||||
if let Some(expected_checksum) = CHECKSUMS.lock().unwrap().get(&abi) {
|
||||
if checksum != *expected_checksum as u32 {
|
||||
process::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
thread::sleep(time::Duration::from_secs(60));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_key(key: &str) -> bool {
|
||||
// Transformed key verification
|
||||
let transformed_key = key.chars().rev().collect::<String>();
|
||||
let expected_key = goldberg_string!("qd84R1hT6p7Mk").chars().rev().collect::<String>();
|
||||
transformed_key == expected_key
|
||||
}
|
||||
|
||||
// this function will be called from the JNI, it will verify the key and if it's correct, it will return true
|
||||
// otherwise it will return false
|
||||
pub fn jni_verify_key(key: &str) -> jboolean {
|
||||
if verify_key(key) {
|
||||
JNI_TRUE
|
||||
} else {
|
||||
JNI_FALSE
|
||||
}
|
||||
}
|
||||
fn get_library_path() -> Option<String> {
|
||||
let maps = std::fs::read_to_string("/proc/self/maps").ok()?;
|
||||
for line in maps.lines() {
|
||||
if line.ends_with("libpurrfectsnap.so") {
|
||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||
if parts.len() > 5 {
|
||||
return Some(parts[5].to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
Reference in New Issue
Block a user