1.1.0
This commit is contained in:
		
							parent
							
								
									c0b515853d
								
							
						
					
					
						commit
						54f2015efc
					
				
							
								
								
									
										168
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										168
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -337,6 +337,12 @@ dependencies = [ | |||||||
|  "log", |  "log", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "equivalent" | ||||||
|  | version = "1.0.2" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "errno" | name = "errno" | ||||||
| version = "0.3.14" | version = "0.3.14" | ||||||
| @ -403,7 +409,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn 2.0.106", |  "syn 2.0.107", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -461,6 +467,12 @@ dependencies = [ | |||||||
|  "wasip2", |  "wasip2", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "hashbrown" | ||||||
|  | version = "0.16.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "hermit-abi" | name = "hermit-abi" | ||||||
| version = "0.5.2" | version = "0.5.2" | ||||||
| @ -490,6 +502,16 @@ version = "1.0.3" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "indexmap" | ||||||
|  | version = "2.12.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" | ||||||
|  | dependencies = [ | ||||||
|  |  "equivalent", | ||||||
|  |  "hashbrown", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "io-uring" | name = "io-uring" | ||||||
| version = "0.7.10" | version = "0.7.10" | ||||||
| @ -938,6 +960,40 @@ version = "0.8.8" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" | checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "rust-embed" | ||||||
|  | version = "8.8.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "fb44e1917075637ee8c7bcb865cf8830e3a92b5b1189e44e3a0ab5a0d5be314b" | ||||||
|  | dependencies = [ | ||||||
|  |  "rust-embed-impl", | ||||||
|  |  "rust-embed-utils", | ||||||
|  |  "walkdir", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "rust-embed-impl" | ||||||
|  | version = "8.8.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "382499b49db77a7c19abd2a574f85ada7e9dbe125d5d1160fa5cad7c4cf71fc9" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "rust-embed-utils", | ||||||
|  |  "syn 2.0.107", | ||||||
|  |  "walkdir", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "rust-embed-utils" | ||||||
|  | version = "8.8.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "21fcbee55c2458836bcdbfffb6ec9ba74bbc23ca7aa6816015a3dd2c4d8fc185" | ||||||
|  | dependencies = [ | ||||||
|  |  "sha2", | ||||||
|  |  "walkdir", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "rustix" | name = "rustix" | ||||||
| version = "1.1.2" | version = "1.1.2" | ||||||
| @ -957,6 +1013,15 @@ version = "1.0.20" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "same-file" | ||||||
|  | version = "1.0.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" | ||||||
|  | dependencies = [ | ||||||
|  |  "winapi-util", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "scoped-tls" | name = "scoped-tls" | ||||||
| version = "1.0.1" | version = "1.0.1" | ||||||
| @ -990,7 +1055,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn 2.0.106", |  "syn 2.0.107", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -1006,6 +1071,15 @@ dependencies = [ | |||||||
|  "serde_core", |  "serde_core", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "serde_spanned" | ||||||
|  | version = "1.0.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" | ||||||
|  | dependencies = [ | ||||||
|  |  "serde_core", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde_urlencoded" | name = "serde_urlencoded" | ||||||
| version = "0.7.1" | version = "0.7.1" | ||||||
| @ -1029,6 +1103,17 @@ dependencies = [ | |||||||
|  "digest", |  "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]] | [[package]] | ||||||
| name = "shlex" | name = "shlex" | ||||||
| version = "1.3.0" | version = "1.3.0" | ||||||
| @ -1037,12 +1122,15 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" | |||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "sign" | name = "sign" | ||||||
| version = "0.1.0" | version = "1.0.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "cc", |  "cc", | ||||||
|  "data-encoding", |  "data-encoding", | ||||||
|  "ntex", |  "ntex", | ||||||
|  |  "rust-embed", | ||||||
|  "serde", |  "serde", | ||||||
|  |  "thiserror", | ||||||
|  |  "toml", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -1093,9 +1181,9 @@ dependencies = [ | |||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "syn" | name = "syn" | ||||||
| version = "2.0.106" | version = "2.0.107" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" | checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
| @ -1119,9 +1207,48 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn 2.0.106", |  "syn 2.0.107", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "toml" | ||||||
|  | version = "0.9.8" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" | ||||||
|  | dependencies = [ | ||||||
|  |  "indexmap", | ||||||
|  |  "serde_core", | ||||||
|  |  "serde_spanned", | ||||||
|  |  "toml_datetime", | ||||||
|  |  "toml_parser", | ||||||
|  |  "toml_writer", | ||||||
|  |  "winnow", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "toml_datetime" | ||||||
|  | version = "0.7.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" | ||||||
|  | dependencies = [ | ||||||
|  |  "serde_core", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "toml_parser" | ||||||
|  | version = "1.0.4" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" | ||||||
|  | dependencies = [ | ||||||
|  |  "winnow", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "toml_writer" | ||||||
|  | version = "1.0.4" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "tracing" | name = "tracing" | ||||||
| version = "0.1.41" | version = "0.1.41" | ||||||
| @ -1158,7 +1285,7 @@ checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn 2.0.106", |  "syn 2.0.107", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -1167,6 +1294,16 @@ version = "0.9.5" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "walkdir" | ||||||
|  | version = "2.5.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" | ||||||
|  | dependencies = [ | ||||||
|  |  "same-file", | ||||||
|  |  "winapi-util", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "wasip2" | name = "wasip2" | ||||||
| version = "1.0.1+wasi-0.2.4" | version = "1.0.1+wasi-0.2.4" | ||||||
| @ -1198,6 +1335,15 @@ version = "0.4.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "winapi-util" | ||||||
|  | version = "0.1.11" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" | ||||||
|  | dependencies = [ | ||||||
|  |  "windows-sys 0.61.2", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "winapi-x86_64-pc-windows-gnu" | name = "winapi-x86_64-pc-windows-gnu" | ||||||
| version = "0.4.0" | version = "0.4.0" | ||||||
| @ -1292,6 +1438,12 @@ version = "0.52.6" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "winnow" | ||||||
|  | version = "0.7.13" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "wit-bindgen" | name = "wit-bindgen" | ||||||
| version = "0.46.0" | version = "0.46.0" | ||||||
| @ -1315,5 +1467,5 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn 2.0.106", |  "syn 2.0.107", | ||||||
| ] | ] | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| [package] | [package] | ||||||
| name = "sign" | name = "sign" | ||||||
| version = "1.0.0" | version = "1.1.0" | ||||||
| edition = "2024" | edition = "2024" | ||||||
| readme = "README.md" | readme = "README.md" | ||||||
| license = "AGPL-3.0-only" | license = "AGPL-3.0-only" | ||||||
| @ -12,7 +12,10 @@ cc = "1.2.41" | |||||||
| [dependencies] | [dependencies] | ||||||
| data-encoding = "2.9.0" | data-encoding = "2.9.0" | ||||||
| ntex = { version = "2.16.0", features = ["compio"] } | ntex = { version = "2.16.0", features = ["compio"] } | ||||||
|  | rust-embed = "8.8.0" | ||||||
| serde = { version = "1.0.228", features = ["derive"] } | serde = { version = "1.0.228", features = ["derive"] } | ||||||
|  | thiserror = "2.0.17" | ||||||
|  | toml = "0.9.8" | ||||||
| 
 | 
 | ||||||
| [profile.release] | [profile.release] | ||||||
| codegen-units = 1 | codegen-units = 1 | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							| @ -6,7 +6,7 @@ This project can only be used on Linux. | |||||||
| 
 | 
 | ||||||
| First, go to the official website to download QQ. | First, go to the official website to download QQ. | ||||||
| 
 | 
 | ||||||
| I recommend downloading the Linux x64 3.2.19-39038 version. If you need to download other versions, you will need to modify the `src/main.rs` file. | I recommend downloading the Linux x64 3.2.19-39038 version. If you want use another version, go to visit [Config section](#config). | ||||||
| 
 | 
 | ||||||
| Then unzip or install QQ. | Then unzip or install QQ. | ||||||
| 
 | 
 | ||||||
| @ -21,6 +21,14 @@ Place the `libsymbols.so` and `target/release/sign` files into the folder that c | |||||||
| 
 | 
 | ||||||
| Switch the directory to the folder containing `wrapper.node`, and then run `./sign`. | Switch the directory to the folder containing `wrapper.node`, and then run `./sign`. | ||||||
| 
 | 
 | ||||||
| The server will listen on `127.0.0.1:8080`. If you want to listen on other endpoints, please go to modify the `src/main.rs` file. | The server will listen on `127.0.0.1:8080`. If you want to listen on other endpoints, go to modify the `src/main.rs` file. | ||||||
| 
 | 
 | ||||||
| Enjoy! | Enjoy! | ||||||
|  | 
 | ||||||
|  | ## Config | ||||||
|  | 
 | ||||||
|  | Copy the `sign.config.toml` file to the folder where the `wrapper.node` is located. | ||||||
|  | 
 | ||||||
|  | Then modify the configuration file according to your needs. | ||||||
|  | 
 | ||||||
|  | If you use other versions of QQ, put `{version}.json` in the same directory. For specific content, refer to `src/appinfo/3.2.19-39038.json`. | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								sign.config.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								sign.config.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | preloads = ["libgnutls.so.30", "./libsymbols.so"] | ||||||
|  | listen = "127.0.0.1:8080" | ||||||
|  | offset = 0x5ADE220 | ||||||
|  | version = "3.2.19-39038" | ||||||
							
								
								
									
										18
									
								
								src/appinfo/3.2.19-39038.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/appinfo/3.2.19-39038.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | { | ||||||
|  |   "Os": "Linux", | ||||||
|  |   "VendorOs": "linux", | ||||||
|  |   "Kernel": "Linux", | ||||||
|  |   "CurrentVersion": "3.2.19-39038", | ||||||
|  |   "MiscBitmap": 32764, | ||||||
|  |   "PtVersion": "2.0.0", | ||||||
|  |   "SsoVersion": 19, | ||||||
|  |   "PackageName": "com.tencent.qq", | ||||||
|  |   "WtLoginSdk": "nt.wtlogin.0.0.1", | ||||||
|  |   "AppId": 1600001615, | ||||||
|  |   "SubAppId": 537313942, | ||||||
|  |   "AppIdQrCode": 537313942, | ||||||
|  |   "AppClientVersion": 39038, | ||||||
|  |   "MainSigMap": 169742560, | ||||||
|  |   "SubSigMap": 0, | ||||||
|  |   "NTLoginType": 1 | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								src/config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/config.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | // SPDX-License-Identifier: AGPL-3.0-only
 | ||||||
|  | // Copyright (C) 2025 Moew72 <Moew72@proton.me>
 | ||||||
|  | 
 | ||||||
|  | use std::fs; | ||||||
|  | use std::io::Read; | ||||||
|  | use std::sync::LazyLock; | ||||||
|  | 
 | ||||||
|  | use serde::Deserialize; | ||||||
|  | 
 | ||||||
|  | pub(crate) static CONFIG: LazyLock<Config> = LazyLock::new(|| { | ||||||
|  |     if fs::exists("sign.config.toml").unwrap() { | ||||||
|  |         let mut buf = Vec::new(); | ||||||
|  |         fs::File::open("sign.config.toml") | ||||||
|  |             .unwrap() | ||||||
|  |             .read_to_end(&mut buf) | ||||||
|  |             .unwrap(); | ||||||
|  |         toml::from_slice::<Config>(&buf).unwrap() | ||||||
|  |     } else { | ||||||
|  |         Config::default() | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Deserialize)] | ||||||
|  | pub(crate) struct Config { | ||||||
|  |     pub(crate) preloads: Vec<String>, | ||||||
|  |     pub(crate) listen: String, | ||||||
|  |     pub(crate) offset: usize, | ||||||
|  |     pub(crate) version: String, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Default for Config { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { | ||||||
|  |             preloads: vec!["libgnutls.so.30".to_string(), "./libsymbols.so".to_string()], | ||||||
|  |             listen: "127.0.0.1:8080".to_string(), | ||||||
|  |             offset: 0x5ADE220, | ||||||
|  |             version: "3.2.19-39038".to_string(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								src/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/error.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | // SPDX-License-Identifier: AGPL-3.0-only
 | ||||||
|  | // Copyright (C) 2025 Moew72 <Moew72@proton.me>
 | ||||||
|  | 
 | ||||||
|  | use ntex::web; | ||||||
|  | use serde::Serialize; | ||||||
|  | 
 | ||||||
|  | #[derive(thiserror::Error, Debug)] | ||||||
|  | pub(crate) enum Error { | ||||||
|  |     #[error("std io: `{0}`")] | ||||||
|  |     Io(#[from] std::io::Error), | ||||||
|  |     #[error("from utf8: `{0}`")] | ||||||
|  |     FromUtf8(#[from] std::string::FromUtf8Error), | ||||||
|  |     #[error("data_encoding: `{0}`")] | ||||||
|  |     DataEncoding(#[from] data_encoding::DecodeError), | ||||||
|  |     #[error("ntex runtime JoinHandle: `{0}`")] | ||||||
|  |     NtexRuntimeJoinHandle(#[from] ntex::rt::JoinError), | ||||||
|  |     #[error("other: `{0}`")] | ||||||
|  |     Other(String), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub type Result<T> = std::result::Result<T, Error>; | ||||||
|  | 
 | ||||||
|  | pub(crate) trait Context<T> { | ||||||
|  |     fn context(self, ctx: Error) -> Result<T>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> Context<T> for Option<T> { | ||||||
|  |     fn context(self, ctx: Error) -> Result<T> { | ||||||
|  |         match self { | ||||||
|  |             Some(v) => Ok(v), | ||||||
|  |             None => Err(ctx), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl web::WebResponseError for Error { | ||||||
|  |     fn error_response(&self, _: &ntex::web::HttpRequest) -> ntex::http::Response { | ||||||
|  |         #[derive(Debug, Serialize)] | ||||||
|  |         struct RespBody { | ||||||
|  |             status: u16, | ||||||
|  |             message: String, | ||||||
|  |         } | ||||||
|  |         web::HttpResponse::build(self.status_code()).json(&RespBody { | ||||||
|  |             status: 400, | ||||||
|  |             message: self.to_string(), | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										134
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -1,127 +1,35 @@ | |||||||
| // SPDX-License-Identifier: AGPL-3.0-only
 | // SPDX-License-Identifier: AGPL-3.0-only
 | ||||||
| // Copyright (C) 2025 Moew72 <Moew72@proton.me>
 | // Copyright (C) 2025 Moew72 <Moew72@proton.me>
 | ||||||
| 
 | 
 | ||||||
| use std::ffi::{CString, c_char}; | mod config; | ||||||
| use std::mem::ManuallyDrop; | mod error; | ||||||
| use std::ptr::null; | mod service; | ||||||
|  | mod sign; | ||||||
| 
 | 
 | ||||||
| use data_encoding::HEXUPPER; |  | ||||||
| use ntex::web; | use ntex::web; | ||||||
| use serde::{Deserialize, Serialize}; |  | ||||||
| 
 | 
 | ||||||
| mod lib { | use crate::{ | ||||||
|     use std::ffi::*; |     config::CONFIG, | ||||||
|     type Func = extern "C" fn(*const c_char, *const c_uchar, c_int, c_int, *mut c_uchar); |     sign::{load_module, set_libs, set_offset, unload_module}, | ||||||
|     unsafe extern "C" { | }; | ||||||
|         pub(super) static mut libs: *mut *const c_char; |  | ||||||
|         pub(super) static mut offset: usize; |  | ||||||
|         pub(super) static mut sign: Func; |  | ||||||
|         pub(super) fn load_module() -> c_int; |  | ||||||
|         pub(super) fn unload_module(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn set_libs(libs: Vec<&str>) { |  | ||||||
|     let mut libs = libs |  | ||||||
|         .iter() |  | ||||||
|         .map(|&x| ManuallyDrop::new(CString::new(x).unwrap()).as_ptr()) |  | ||||||
|         .collect::<Vec<*const c_char>>(); |  | ||||||
|     libs.push(null()); |  | ||||||
|     unsafe { |  | ||||||
|         lib::libs = ManuallyDrop::new(libs).as_mut_ptr(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn set_offset(offset: usize) { |  | ||||||
|     unsafe { |  | ||||||
|         lib::offset = offset; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn load_module() { |  | ||||||
|     let ret = unsafe { lib::load_module() }; |  | ||||||
|     if ret != 0 { |  | ||||||
|         panic!("load module error."); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[allow(unused)] |  | ||||||
| fn unload_module() { |  | ||||||
|     unsafe { lib::unload_module() } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn sign(cmd: &str, src: &[u8], seq: i32) -> [Vec<u8>; 3] { |  | ||||||
|     const TOKEN_DATA_OFFSET: usize = 0x000; |  | ||||||
|     const TOKEN_LEN_OFFSET: usize = 0x0FF; |  | ||||||
|     const EXTRA_DATA_OFFSET: usize = 0x100; |  | ||||||
|     const EXTRA_LEN_OFFSET: usize = 0x1FF; |  | ||||||
|     const SIGN_DATA_OFFSET: usize = 0x200; |  | ||||||
|     const SIGN_LEN_OFFSET: usize = 0x2FF; |  | ||||||
| 
 |  | ||||||
|     let c_cmd = CString::new(cmd).unwrap(); |  | ||||||
|     let mut buf = [0u8; 0x300]; |  | ||||||
|     let _ = unsafe { |  | ||||||
|         lib::sign( |  | ||||||
|             c_cmd.as_ptr(), |  | ||||||
|             src.as_ptr(), |  | ||||||
|             src.len() as i32, |  | ||||||
|             seq, |  | ||||||
|             buf.as_mut_ptr(), |  | ||||||
|         ) |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     let token_len = buf[TOKEN_LEN_OFFSET]; |  | ||||||
|     let token = &buf[TOKEN_DATA_OFFSET..TOKEN_DATA_OFFSET + token_len as usize]; |  | ||||||
|     let extra_len = buf[EXTRA_LEN_OFFSET]; |  | ||||||
|     let extra = &buf[EXTRA_DATA_OFFSET..EXTRA_DATA_OFFSET + extra_len as usize]; |  | ||||||
|     let sign_len = buf[SIGN_LEN_OFFSET]; |  | ||||||
|     let sign = &buf[SIGN_DATA_OFFSET..SIGN_DATA_OFFSET + sign_len as usize]; |  | ||||||
| 
 |  | ||||||
|     [Vec::from(token), Vec::from(extra), Vec::from(sign)] |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| #[ntex::main] | #[ntex::main] | ||||||
| async fn main() -> std::io::Result<()> { | async fn main() -> std::io::Result<()> { | ||||||
|     set_libs(vec!["libgnutls.so.30", "./libsymbols.so"]); |     set_libs(CONFIG.preloads.clone()); | ||||||
|     set_offset(0x5ADE220); |     set_offset(CONFIG.offset); | ||||||
|     load_module(); |     load_module(); | ||||||
|     web::HttpServer::new(|| web::App::new().service(sign_service)) |  | ||||||
|         .bind(("127.0.0.1", 8080))? |  | ||||||
|         .run() |  | ||||||
|         .await |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| #[web::post("/")] |     web::HttpServer::new(|| { | ||||||
| async fn sign_service(params: web::types::Json<Params>) -> impl web::Responder { |         web::App::new() | ||||||
|     let ret = HEXUPPER.decode(params.src.to_uppercase().as_bytes()); |             .service(service::sign_get) | ||||||
|     let src = match ret { |             .service(service::sign_post) | ||||||
|         Ok(v) => v, |             .service(service::appinfo) | ||||||
|         Err(err) => return web::HttpResponse::InternalServerError().body(err.to_string()), |     }) | ||||||
|     }; |     .bind(CONFIG.listen.clone())? | ||||||
|     let [token, extra, sign] = sign(¶ms.cmd, &src, params.seq); |     .run() | ||||||
|     let token = HEXUPPER.encode(&token); |     .await?; | ||||||
|     let extra = HEXUPPER.encode(&extra); |  | ||||||
|     let sign = HEXUPPER.encode(&sign); |  | ||||||
|     let value = Value { token, extra, sign }; |  | ||||||
|     let body = RespBody { value }; |  | ||||||
|     web::HttpResponse::Ok().json(&body) |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| #[derive(Deserialize)] |     unload_module(); | ||||||
| struct Params { |  | ||||||
|     cmd: String, |  | ||||||
|     src: String, |  | ||||||
|     seq: i32, |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| #[derive(Serialize)] |     Ok(()) | ||||||
| struct RespBody { |  | ||||||
|     value: Value, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Serialize)] |  | ||||||
| struct Value { |  | ||||||
|     token: String, |  | ||||||
|     extra: String, |  | ||||||
|     sign: String, |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										87
									
								
								src/service.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/service.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | |||||||
|  | // SPDX-License-Identifier: AGPL-3.0-only
 | ||||||
|  | // Copyright (C) 2025 Moew72 <Moew72@proton.me>
 | ||||||
|  | 
 | ||||||
|  | use std::fs; | ||||||
|  | use std::io::Read; | ||||||
|  | 
 | ||||||
|  | use data_encoding::HEXUPPER; | ||||||
|  | use ntex::http::Response; | ||||||
|  | use ntex::http::StatusCode; | ||||||
|  | use ntex::http::header::CONTENT_TYPE; | ||||||
|  | use ntex::rt::spawn; | ||||||
|  | use ntex::web; | ||||||
|  | use serde::{Deserialize, Serialize}; | ||||||
|  | 
 | ||||||
|  | use crate::config::CONFIG; | ||||||
|  | use crate::error::{Context, Error, Result}; | ||||||
|  | 
 | ||||||
|  | #[derive(rust_embed::Embed)] | ||||||
|  | #[folder = "src/appinfo"] | ||||||
|  | struct Asset; | ||||||
|  | 
 | ||||||
|  | #[derive(Deserialize)] | ||||||
|  | struct Params { | ||||||
|  |     cmd: String, | ||||||
|  |     src: String, | ||||||
|  |     seq: i32, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[web::get("/")] | ||||||
|  | pub(crate) async fn sign_get(params: web::types::Query<Params>) -> Result<Response> { | ||||||
|  |     sign_common(params.0).await | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[web::post("/")] | ||||||
|  | pub(crate) async fn sign_post(params: web::types::Json<Params>) -> Result<Response> { | ||||||
|  |     sign_common(params.0).await | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[inline] | ||||||
|  | async fn sign_common(params: Params) -> Result<Response> { | ||||||
|  |     #[derive(Serialize)] | ||||||
|  |     struct RespBody { | ||||||
|  |         platform: String, | ||||||
|  |         version: String, | ||||||
|  |         value: Value, | ||||||
|  |     } | ||||||
|  |     #[derive(Serialize)] | ||||||
|  |     struct Value { | ||||||
|  |         token: String, | ||||||
|  |         extra: String, | ||||||
|  |         sign: String, | ||||||
|  |     } | ||||||
|  |     let src = HEXUPPER.decode(params.src.to_uppercase().as_bytes())?; | ||||||
|  |     let [token, extra, sign] = | ||||||
|  |         spawn(async move { crate::sign::sign(¶ms.cmd, &src, params.seq) }).await?; | ||||||
|  |     let token = HEXUPPER.encode(&token); | ||||||
|  |     let extra = HEXUPPER.encode(&extra); | ||||||
|  |     let sign = HEXUPPER.encode(&sign); | ||||||
|  |     let value = Value { token, extra, sign }; | ||||||
|  |     let body = RespBody { | ||||||
|  |         platform: "Linux".to_string(), | ||||||
|  |         value, | ||||||
|  |         version: CONFIG.version.clone(), | ||||||
|  |     }; | ||||||
|  |     let resp = web::HttpResponse::Ok().json(&body); | ||||||
|  |     Ok(resp) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[web::get("/appinfo")] | ||||||
|  | pub(crate) async fn appinfo() -> Result<Response> { | ||||||
|  |     let path = &format!("{}.json", CONFIG.version.clone()); | ||||||
|  |     let body = if fs::exists(path)? { | ||||||
|  |         let mut buf = String::new(); | ||||||
|  |         fs::File::open(path)?.read_to_string(&mut buf)?; | ||||||
|  |         buf | ||||||
|  |     } else { | ||||||
|  |         let data = Asset::get(path) | ||||||
|  |             .context(Error::Other(format!("appinfo {} not found.", path)))? | ||||||
|  |             .data | ||||||
|  |             .to_vec(); | ||||||
|  |         String::from_utf8(data)? | ||||||
|  |     }; | ||||||
|  |     let resp = web::HttpResponse::build(StatusCode::OK) | ||||||
|  |         .set_header(CONTENT_TYPE, "application/json") | ||||||
|  |         .body(body); | ||||||
|  |     Ok(resp) | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								src/sign.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/sign.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | // SPDX-License-Identifier: AGPL-3.0-only
 | ||||||
|  | // Copyright (C) 2025 Moew72 <Moew72@proton.me>
 | ||||||
|  | 
 | ||||||
|  | use std::ffi::{CString, c_char}; | ||||||
|  | use std::mem::ManuallyDrop; | ||||||
|  | use std::ptr::null; | ||||||
|  | 
 | ||||||
|  | mod lib { | ||||||
|  |     use std::ffi::*; | ||||||
|  |     type Func = extern "C" fn(*const c_char, *const c_uchar, c_int, c_int, *mut c_uchar); | ||||||
|  |     unsafe extern "C" { | ||||||
|  |         pub(super) static mut libs: *mut *const c_char; | ||||||
|  |         pub(super) static mut offset: usize; | ||||||
|  |         pub(super) static mut sign: Func; | ||||||
|  |         pub(super) fn load_module() -> c_int; | ||||||
|  |         pub(super) fn unload_module(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) fn set_libs(libs: Vec<String>) { | ||||||
|  |     let mut libs = libs | ||||||
|  |         .iter() | ||||||
|  |         .map(|x| ManuallyDrop::new(CString::new(x.as_str()).unwrap()).as_ptr()) | ||||||
|  |         .collect::<Vec<*const c_char>>(); | ||||||
|  |     libs.push(null()); | ||||||
|  |     unsafe { | ||||||
|  |         lib::libs = ManuallyDrop::new(libs).as_mut_ptr(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) fn set_offset(offset: usize) { | ||||||
|  |     unsafe { | ||||||
|  |         lib::offset = offset; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) fn load_module() { | ||||||
|  |     let ret = unsafe { lib::load_module() }; | ||||||
|  |     if ret != 0 { | ||||||
|  |         panic!("load module error."); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[allow(unused)] | ||||||
|  | pub(crate) fn unload_module() { | ||||||
|  |     unsafe { lib::unload_module() } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) fn sign(cmd: &str, src: &[u8], seq: i32) -> [Vec<u8>; 3] { | ||||||
|  |     const TOKEN_DATA_OFFSET: usize = 0x000; | ||||||
|  |     const TOKEN_LEN_OFFSET: usize = 0x0FF; | ||||||
|  |     const EXTRA_DATA_OFFSET: usize = 0x100; | ||||||
|  |     const EXTRA_LEN_OFFSET: usize = 0x1FF; | ||||||
|  |     const SIGN_DATA_OFFSET: usize = 0x200; | ||||||
|  |     const SIGN_LEN_OFFSET: usize = 0x2FF; | ||||||
|  | 
 | ||||||
|  |     let c_cmd = CString::new(cmd).unwrap(); | ||||||
|  |     let mut buf = [0u8; 0x300]; | ||||||
|  |     let _ = unsafe { | ||||||
|  |         lib::sign( | ||||||
|  |             c_cmd.as_ptr(), | ||||||
|  |             src.as_ptr(), | ||||||
|  |             src.len() as i32, | ||||||
|  |             seq, | ||||||
|  |             buf.as_mut_ptr(), | ||||||
|  |         ) | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let token_len = buf[TOKEN_LEN_OFFSET]; | ||||||
|  |     let token = &buf[TOKEN_DATA_OFFSET..TOKEN_DATA_OFFSET + token_len as usize]; | ||||||
|  |     let extra_len = buf[EXTRA_LEN_OFFSET]; | ||||||
|  |     let extra = &buf[EXTRA_DATA_OFFSET..EXTRA_DATA_OFFSET + extra_len as usize]; | ||||||
|  |     let sign_len = buf[SIGN_LEN_OFFSET]; | ||||||
|  |     let sign = &buf[SIGN_DATA_OFFSET..SIGN_DATA_OFFSET + sign_len as usize]; | ||||||
|  | 
 | ||||||
|  |     [Vec::from(token), Vec::from(extra), Vec::from(sign)] | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user