Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
62a934011b
|
|||
|
b559c3b433
|
|||
|
8ed8c7c443
|
|||
|
1ec60097a6
|
|||
|
aec2a1e575
|
@@ -0,0 +1,99 @@
|
|||||||
|
name: Prebuilt release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
releases: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
prebuilt:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install nightly Rust
|
||||||
|
uses: dtolnay/rust-toolchain@nightly
|
||||||
|
with:
|
||||||
|
targets: x86_64-pc-windows-gnu
|
||||||
|
|
||||||
|
- name: Install MinGW and packaging tools
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y mingw-w64 zip unzip jq
|
||||||
|
|
||||||
|
- name: Build release binaries
|
||||||
|
env:
|
||||||
|
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: x86_64-w64-mingw32-gcc
|
||||||
|
run: cargo build --release --target x86_64-pc-windows-gnu -p ext -p launcher
|
||||||
|
|
||||||
|
- name: Package prebuilt release
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
rm -rf dist
|
||||||
|
mkdir -p dist
|
||||||
|
cp target/x86_64-pc-windows-gnu/release/hkrpg.dll dist/
|
||||||
|
cp target/x86_64-pc-windows-gnu/release/launcher.exe dist/
|
||||||
|
|
||||||
|
test -f dist/hkrpg.dll
|
||||||
|
test -f dist/launcher.exe
|
||||||
|
|
||||||
|
(
|
||||||
|
cd dist
|
||||||
|
zip -9 -q ../hkrpg.zip hkrpg.dll launcher.exe
|
||||||
|
)
|
||||||
|
unzip -l hkrpg.zip
|
||||||
|
|
||||||
|
- name: Publish prebuilt release
|
||||||
|
env:
|
||||||
|
GITEA_API_URL: ${{ gitea.server_url }}/api/v1
|
||||||
|
GITEA_REPOSITORY: ${{ gitea.repository }}
|
||||||
|
GITEA_SHA: ${{ gitea.sha }}
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
api="${GITEA_API_URL}"
|
||||||
|
repo="${GITEA_REPOSITORY}"
|
||||||
|
tag="prebuilt"
|
||||||
|
auth=(-H "Authorization: token ${GITEA_TOKEN}" -H "Accept: application/json")
|
||||||
|
|
||||||
|
release_status="$(curl -sS "${auth[@]}" -o release.json -w '%{http_code}' \
|
||||||
|
"${api}/repos/${repo}/releases/tags/${tag}" || true)"
|
||||||
|
|
||||||
|
case "${release_status}" in
|
||||||
|
200)
|
||||||
|
;;
|
||||||
|
404)
|
||||||
|
curl -fsS -X POST "${auth[@]}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"tag_name\":\"${tag}\",\"target_commitish\":\"${GITEA_SHA}\",\"name\":\"${tag}\",\"body\":\"Automated prebuilt binaries for ${GITEA_SHA}\",\"draft\":false,\"prerelease\":false}" \
|
||||||
|
"${api}/repos/${repo}/releases" > release.json
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
cat release.json
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
release_id="$(jq -er '.id' release.json)"
|
||||||
|
assets="$(curl -fsS "${auth[@]}" \
|
||||||
|
"${api}/repos/${repo}/releases/${release_id}/assets")"
|
||||||
|
|
||||||
|
while read -r asset_id; do
|
||||||
|
test -z "${asset_id}" || curl -fsS -X DELETE "${auth[@]}" \
|
||||||
|
"${api}/repos/${repo}/releases/${release_id}/assets/${asset_id}"
|
||||||
|
done < <(printf '%s' "${assets}" | jq -r '.[] | select(.name == "hkrpg.zip") | .id')
|
||||||
|
|
||||||
|
curl -fsS -X POST "${auth[@]}" \
|
||||||
|
-F "attachment=@hkrpg.zip;type=application/zip" \
|
||||||
|
"${api}/repos/${repo}/releases/${release_id}/assets?name=hkrpg.zip"
|
||||||
Generated
+84
-4
@@ -17,6 +17,32 @@ version = "2.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dashmap"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"hashbrown",
|
||||||
|
"lock_api",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ext"
|
name = "ext"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -25,10 +51,17 @@ dependencies = [
|
|||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hkrpg"
|
name = "hkrpg"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"dashmap",
|
||||||
"ilhook",
|
"ilhook",
|
||||||
"patternscan",
|
"patternscan",
|
||||||
"windows",
|
"windows",
|
||||||
@@ -77,6 +110,15 @@ version = "0.2.171"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
@@ -84,11 +126,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mhypbase"
|
name = "once_cell"
|
||||||
version = "0.1.0"
|
version = "1.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hkrpg",
|
"cfg-if",
|
||||||
"windows",
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -115,6 +168,15 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.5.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
@@ -144,6 +206,18 @@ version = "0.8.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.15.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.100"
|
version = "2.0.100"
|
||||||
@@ -201,6 +275,12 @@ dependencies = [
|
|||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|||||||
+8
-1
@@ -1,11 +1,17 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["hkrpg", "launcher", "mhypbase", "ext"]
|
members = ["hkrpg", "launcher", "ext"]
|
||||||
|
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "z"
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
strip = true
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
windows = { version = "0.54.0", features = [
|
windows = { version = "0.54.0", features = [
|
||||||
"Win32_Foundation",
|
"Win32_Foundation",
|
||||||
@@ -22,6 +28,7 @@ windows = { version = "0.54.0", features = [
|
|||||||
] }
|
] }
|
||||||
ilhook = "2.1.1"
|
ilhook = "2.1.1"
|
||||||
patternscan = "1.2.0"
|
patternscan = "1.2.0"
|
||||||
|
dashmap = "6.1.0"
|
||||||
|
|
||||||
# Local crates
|
# Local crates
|
||||||
hkrpg = { path = "hkrpg/" }
|
hkrpg = { path = "hkrpg/" }
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ features:
|
|||||||
- remove censorship
|
- remove censorship
|
||||||
- replace AccountRSAKey into custom public key (by default, compatible with [hoyo-sdk by xeondev](https://git.xeondev.com/reversedrooms/hoyo-sdk))
|
- replace AccountRSAKey into custom public key (by default, compatible with [hoyo-sdk by xeondev](https://git.xeondev.com/reversedrooms/hoyo-sdk))
|
||||||
|
|
||||||
currently, this has only been tested on CNBETAWin3.1.53 and may require an update for future versions.
|
currently, this has only been tested on CNBETAWin4.4.51 and may require an update for future versions.
|
||||||
|
|
||||||
note: if you plan to use `mhypbase.dll`, please make a copy of the original first in case something breaks. Otherwise, simply copy `hkrpg.dll` and `launcher.exe` into the game folder and run `launcher.exe` as an administrator.
|
note: simply copy `hkrpg.dll` and `launcher.exe` into the game folder and run `launcher.exe` as an administrator.
|
||||||
|
|
||||||
Sources:
|
Sources:
|
||||||
|
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ version.workspace = true
|
|||||||
windows.workspace = true
|
windows.workspace = true
|
||||||
ilhook.workspace = true
|
ilhook.workspace = true
|
||||||
patternscan.workspace = true
|
patternscan.workspace = true
|
||||||
|
dashmap.workspace = true
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudOyZJDKXjYQdUS+wN7d
|
||||||
|
lKBP2XkhkDO/sx6pttn719o+rJ8y8XOO3rftSoRasvw1nzidDQqEnHl1Aw5+a90D
|
||||||
|
OQvlgBaIda3npqVmi4X2sEzswR7EH5BOJizx7LAxixcoby3jOQathdpl44wQ04XR
|
||||||
|
+SIkukvxcL1jTepfuc0Pp+DD+4MU5O4/38b9v+ryizU+1CdwzukV27rkMvOtA6ok
|
||||||
|
Is6Vkb5ubcAC/W3vCIP5gv+QRdYB6ihzLhs5WI/9Ex2PrLpdpxr7gClvEFxkHcLy
|
||||||
|
LCvSfp9pvt/tnsYsk1tct0HKEr8tlaJ6t1zEGEvFQZRpBsahl/lhpT15vyM8iyiD
|
||||||
|
DwIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
+10
-21
@@ -7,12 +7,10 @@ use crate::util::scan_il2cpp_section;
|
|||||||
const IL2CPP_STRING_NEW_LEN: &str =
|
const IL2CPP_STRING_NEW_LEN: &str =
|
||||||
"E8 ? ? ? ? EB ? 31 C0 48 89 06 48 8B 47 ? 48 89 46 ? F2 0F 10 47";
|
"E8 ? ? ? ? EB ? 31 C0 48 89 06 48 8B 47 ? 48 89 46 ? F2 0F 10 47";
|
||||||
const MAKE_INITIAL_URL: &str =
|
const MAKE_INITIAL_URL: &str =
|
||||||
"E8 ? ? ? ? 48 89 D9 48 89 C2 E8 ? ? ? ? 48 89 D9 4C 89 FA E8 ? ? ? ? 49 89 5D"; // TODO
|
"55 41 56 56 57 53 48 81 EC 90 00 00 00 48 8D AC 24 ? ? ? ? 48 C7 45 ? ? ? ? ? 48 85 C9 74";
|
||||||
const SET_DITHER: &str = "E8 ? ? ? ? 84 C0 75 ? C7 43";
|
const SET_DITHER: &str = "E8 ? ? ? ? 84 C0 75 ? C7 43";
|
||||||
const SDK_PUBLIC_KEY_LITERAL: &str =
|
const SDK_PUBLIC_KEY_LITERAL: &str =
|
||||||
"48 8B 0D ? ? ? ? 4C 89 E2 E8 ? ? ? ? 48 89 C6 48 8B 0D ? ? ? ? E8 ? ? ? ? 48 89 C7 48 8B 0D";
|
"48 8B 0D ? ? ? ? 4C 89 E2 E8 ? ? ? ? 48 89 C6 48 8B 0D ? ? ? ? E8 ? ? ? ? 48 89 C7 48 8B 0D";
|
||||||
// const HK_CHECK1: &str = "55 41 56 56 57 53 48 81 EC 00 01 00 00 48 8D AC 24 80 00 00 00 C7 45 7C 00 00 00 00";
|
|
||||||
// const HK_CHECK2: &str = "55 41 57 41 56 41 55 41 54 56 57 53 48 81 EC B8 02 00 00";
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RVAConfig {
|
pub struct RVAConfig {
|
||||||
@@ -38,7 +36,15 @@ pub static GAME_ASSEMBLY_BASE: LazyLock<usize> =
|
|||||||
|
|
||||||
macro_rules! set_rva {
|
macro_rules! set_rva {
|
||||||
($base:ident, $config:ident, $field:ident, $scan_fn:ident, $rva_pat:expr, $fallback:expr) => {
|
($base:ident, $config:ident, $field:ident, $scan_fn:ident, $rva_pat:expr, $fallback:expr) => {
|
||||||
if let Some(addr) = unsafe { $scan_fn($rva_pat) } {
|
if $rva_pat == "" {
|
||||||
|
$config.$field = *$base + $fallback;
|
||||||
|
println!(
|
||||||
|
"[hkrpg::addr::set_rva] Using fallback relative address for {} [{}] -> 0x{:X}",
|
||||||
|
stringify!($field),
|
||||||
|
stringify!($base),
|
||||||
|
$config.$field - *$base
|
||||||
|
);
|
||||||
|
} else if let Some(addr) = unsafe { $scan_fn($rva_pat) } {
|
||||||
$config.$field = addr;
|
$config.$field = addr;
|
||||||
println!(
|
println!(
|
||||||
"[hkrpg::addr::set_rva] Found relative address for {} [{}] -> 0x{:X}",
|
"[hkrpg::addr::set_rva] Found relative address for {} [{}] -> 0x{:X}",
|
||||||
@@ -101,21 +107,4 @@ pub unsafe fn init_rvas() {
|
|||||||
SDK_PUBLIC_KEY_LITERAL,
|
SDK_PUBLIC_KEY_LITERAL,
|
||||||
0x0
|
0x0
|
||||||
)
|
)
|
||||||
|
|
||||||
// set_rva!(
|
|
||||||
// UNITY_PLAYER_BASE,
|
|
||||||
// config,
|
|
||||||
// hk_check1,
|
|
||||||
// scan_unity_player_section,
|
|
||||||
// HK_CHECK1,
|
|
||||||
// 0x0
|
|
||||||
// );
|
|
||||||
// set_rva!(
|
|
||||||
// UNITY_PLAYER_BASE,
|
|
||||||
// config,
|
|
||||||
// hk_check2,
|
|
||||||
// scan_unity_player_section,
|
|
||||||
// HK_CHECK2,
|
|
||||||
// 0x0
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -1,10 +1,10 @@
|
|||||||
#![feature(str_from_utf16_endian, once_cell_get_mut)]
|
#![feature(once_cell_get_mut)]
|
||||||
|
|
||||||
use std::{thread, time::Duration};
|
use std::{thread, time::Duration};
|
||||||
|
|
||||||
use modules::{
|
use modules::{
|
||||||
HkrpgModuleManager, censorship_patch::CensorshipPatch, crypto::Crypto, hk_check::HkCheck,
|
HkrpgModuleManager, apn::ApnPatch, censorship_patch::CensorshipPatch, crypto::Crypto,
|
||||||
misc::Misc, network::Network,
|
hk_check::HkCheck, misc::Misc, network::Network,
|
||||||
};
|
};
|
||||||
use windows::{
|
use windows::{
|
||||||
Win32::System::{Console, LibraryLoader::GetModuleHandleA},
|
Win32::System::{Console, LibraryLoader::GetModuleHandleA},
|
||||||
@@ -35,6 +35,7 @@ pub fn main() {
|
|||||||
addr::init_rvas();
|
addr::init_rvas();
|
||||||
|
|
||||||
let mut module_manager = HkrpgModuleManager::default();
|
let mut module_manager = HkrpgModuleManager::default();
|
||||||
|
module_manager.add::<ApnPatch>();
|
||||||
module_manager.add::<HkCheck>();
|
module_manager.add::<HkCheck>();
|
||||||
module_manager.add::<Network>();
|
module_manager.add::<Network>();
|
||||||
module_manager.add::<Crypto>();
|
module_manager.add::<Crypto>();
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
use dashmap::DashMap;
|
||||||
|
use ilhook::x64::Registers;
|
||||||
|
use patternscan::scan_first_match;
|
||||||
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
|
ffi::{CStr, CString},
|
||||||
|
path::Path,
|
||||||
|
sync::{LazyLock, OnceLock},
|
||||||
|
};
|
||||||
|
use windows::{
|
||||||
|
Win32::System::{
|
||||||
|
LibraryLoader::{GetModuleHandleW, LoadLibraryW},
|
||||||
|
ProcessStatus::{GetModuleInformation, MODULEINFO},
|
||||||
|
Threading::GetCurrentProcess,
|
||||||
|
},
|
||||||
|
core::{PCWSTR, w},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::modules::{HkrpgModule, HkrpgModuleContext};
|
||||||
|
|
||||||
|
pub struct ApnPatch;
|
||||||
|
|
||||||
|
impl HkrpgModule for HkrpgModuleContext<ApnPatch> {
|
||||||
|
unsafe fn init(&mut self) -> Result<(), ilhook::HookError> {
|
||||||
|
if !load_apn_dll() {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let base;
|
||||||
|
loop {
|
||||||
|
if let Ok(module) = unsafe { GetModuleHandleW(w!("AccountPlatNative.dll")) } {
|
||||||
|
base = module.0 as usize;
|
||||||
|
println!("AccountPlatNative.dll: 0x{base:X}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(string_alloc_rva) = scan_apn("E8 ? ? ? ? 41 89 BF") else {
|
||||||
|
println!("[AccountPlatNative] failed to scan string_alloc rva. patch disabled");
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
self.interceptor
|
||||||
|
.attach(base + string_alloc_rva, on_string_alloc)
|
||||||
|
.expect("Failed to hook AccountPlatNative string alloc");
|
||||||
|
|
||||||
|
println!("[AccountPlatNative] patch enabled");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "win64" fn on_string_alloc(reg: *mut Registers, _: usize) {
|
||||||
|
const SDK_PUBLIC_KEY: &str = include_str!("../../sdk_public_key.pem");
|
||||||
|
static STRING_CACHE_MAP: LazyLock<DashMap<Cow<'static, str>, CString>> =
|
||||||
|
LazyLock::new(DashMap::new);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let content = CStr::from_ptr((*reg).rdx as *const i8).to_string_lossy();
|
||||||
|
let size = (*reg).r8;
|
||||||
|
|
||||||
|
if let Some(cstring) = STRING_CACHE_MAP.get(&content) {
|
||||||
|
(*reg).rdx = cstring.as_ptr() as u64;
|
||||||
|
(*reg).r8 = cstring.count_bytes() as u64;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL string alloc
|
||||||
|
if content.starts_with("https://") && content.contains(".mihoyo.com") {
|
||||||
|
let mut new_url = String::from("http://127.0.0.1:21000");
|
||||||
|
content.split('/').skip(3).for_each(|s| {
|
||||||
|
new_url.push('/');
|
||||||
|
new_url.push_str(s);
|
||||||
|
});
|
||||||
|
|
||||||
|
let cstring = STRING_CACHE_MAP
|
||||||
|
.entry(content.clone())
|
||||||
|
.or_insert_with(|| CString::new(&*new_url).expect("Failed to create CString"));
|
||||||
|
|
||||||
|
(*reg).rdx = cstring.as_ptr() as u64;
|
||||||
|
(*reg).r8 = new_url.len() as u64;
|
||||||
|
|
||||||
|
println!("[AccountPlatNative] url {content} replaced to {new_url}");
|
||||||
|
}
|
||||||
|
// RSA public key string alloc
|
||||||
|
else if size == 268 && content.starts_with("-----BEGIN PUBLIC KEY-----") {
|
||||||
|
let cstring = STRING_CACHE_MAP
|
||||||
|
.entry(content.clone())
|
||||||
|
.or_insert_with(|| CString::new(SDK_PUBLIC_KEY).expect("Failed to create CString"));
|
||||||
|
|
||||||
|
(*reg).rdx = cstring.as_ptr() as u64;
|
||||||
|
(*reg).r8 = SDK_PUBLIC_KEY.len() as u64;
|
||||||
|
println!("[AccountPlatNative] sdk public key replaced! ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_apn_dll() -> bool {
|
||||||
|
let dll_path = "./StarRail_Data/Plugins/x86_64/AccountPlatNative.dll";
|
||||||
|
|
||||||
|
if !Path::new(dll_path).exists() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let wide_dll_path: Vec<u16> = dll_path.encode_utf16().chain(std::iter::once(0)).collect();
|
||||||
|
let ptr = wide_dll_path.as_ptr();
|
||||||
|
|
||||||
|
if let Err(err) = unsafe { LoadLibraryW(PCWSTR::from_raw(ptr)) } {
|
||||||
|
println!("[AccountPlatNative] Failed to inject {dll_path}. Error: {err:#?}",);
|
||||||
|
};
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scan_apn(pat: &str) -> Option<usize> {
|
||||||
|
let mut slice = apn_slice();
|
||||||
|
scan_first_match(&mut slice, pat).unwrap().map(|address| {
|
||||||
|
let slice = apn_slice();
|
||||||
|
match slice.get(address) {
|
||||||
|
// jmp sub_xxxxxxx
|
||||||
|
Some(&0xE8) => {
|
||||||
|
let offset =
|
||||||
|
i32::from_le_bytes(slice[address + 1..address + 5].try_into().unwrap());
|
||||||
|
address + 5 + offset as usize
|
||||||
|
}
|
||||||
|
// mov REGISTER, [rip + offset] (0x48 0x8B 0x0D XXXXXXXX)
|
||||||
|
Some(&0x48) if slice.get(address + 1) == Some(&0x8B) => {
|
||||||
|
let offset =
|
||||||
|
i32::from_le_bytes(slice[address + 3..address + 7].try_into().unwrap());
|
||||||
|
address + 7 + offset as usize
|
||||||
|
}
|
||||||
|
_ => address,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apn_slice() -> &'static [u8] {
|
||||||
|
static SLICE: OnceLock<&[u8]> = OnceLock::new();
|
||||||
|
unsafe {
|
||||||
|
SLICE.get_or_init(|| {
|
||||||
|
let module = GetModuleHandleW(w!("AccountPlatNative.dll")).unwrap();
|
||||||
|
let mut module_info = MODULEINFO {
|
||||||
|
lpBaseOfDll: std::ptr::null_mut(),
|
||||||
|
SizeOfImage: 0,
|
||||||
|
EntryPoint: std::ptr::null_mut(),
|
||||||
|
};
|
||||||
|
GetModuleInformation(
|
||||||
|
GetCurrentProcess(),
|
||||||
|
module,
|
||||||
|
&mut module_info,
|
||||||
|
std::mem::size_of::<MODULEINFO>() as u32,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
module.0 as *const u8,
|
||||||
|
module_info.SizeOfImage.try_into().unwrap(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,11 +2,12 @@ use std::marker::PhantomData;
|
|||||||
|
|
||||||
use crate::{addr, interceptor::Interceptor};
|
use crate::{addr, interceptor::Interceptor};
|
||||||
|
|
||||||
|
pub mod apn;
|
||||||
pub mod censorship_patch;
|
pub mod censorship_patch;
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod hk_check;
|
pub mod hk_check;
|
||||||
pub mod network;
|
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
|
pub mod network;
|
||||||
|
|
||||||
pub struct HkrpgModuleContext<T> {
|
pub struct HkrpgModuleContext<T> {
|
||||||
_base: usize,
|
_base: usize,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ impl HkrpgModule for HkrpgModuleContext<Network> {
|
|||||||
|
|
||||||
impl Network {
|
impl Network {
|
||||||
const SDK_URL: &str = "http://127.0.0.1:21000";
|
const SDK_URL: &str = "http://127.0.0.1:21000";
|
||||||
// const DISPATCH_URL: &str = "http://127.0.0.1:21000";
|
const DISPATCH_URL: &str = "http://127.0.0.1:21000";
|
||||||
const REDIRECT_SDK: bool = true;
|
const REDIRECT_SDK: bool = true;
|
||||||
const REDIRECT_DISPATCH: bool = true;
|
const REDIRECT_DISPATCH: bool = true;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ impl Network {
|
|||||||
s if (s.contains("bhsr.com") || s.contains("starrails.com"))
|
s if (s.contains("bhsr.com") || s.contains("starrails.com"))
|
||||||
&& Self::REDIRECT_DISPATCH =>
|
&& Self::REDIRECT_DISPATCH =>
|
||||||
{
|
{
|
||||||
Self::SDK_URL.to_string()
|
Self::DISPATCH_URL.to_string()
|
||||||
}
|
}
|
||||||
s => {
|
s => {
|
||||||
println!("Leaving request as-is: {s}");
|
println!("Leaving request as-is: {s}");
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
use std::{env, fs, path::PathBuf, process::Command};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match env::var("CARGO_CFG_TARGET_ENV").as_deref() {
|
||||||
|
Ok("msvc") => {
|
||||||
|
println!("cargo:rustc-link-arg-bin=launcher=/MANIFEST:EMBED");
|
||||||
|
println!("cargo:rustc-link-arg-bin=launcher=/MANIFESTUAC:level='requireAdministrator'");
|
||||||
|
}
|
||||||
|
Ok("gnu") => {
|
||||||
|
let Some(out_dir) = env::var_os("OUT_DIR") else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let out_dir = PathBuf::from(out_dir);
|
||||||
|
let manifest = out_dir.join("launcher.manifest");
|
||||||
|
let resource = out_dir.join("launcher.rc");
|
||||||
|
let object = out_dir.join("launcher-manifest.o");
|
||||||
|
|
||||||
|
if fs::write(&manifest, MANIFEST).is_err() || fs::write(&resource, RESOURCE).is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(status) = Command::new("x86_64-w64-mingw32-windres")
|
||||||
|
.current_dir(&out_dir)
|
||||||
|
.args(["launcher.rc", "-O", "coff", "-o"])
|
||||||
|
.arg(&object)
|
||||||
|
.status()
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-arg-bin=launcher={}", object.display());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const RESOURCE: &str = "1 24 \"launcher.manifest\"\n";
|
||||||
|
|
||||||
|
const MANIFEST: &str = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
</assembly>
|
||||||
|
"#;
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "mhypbase"
|
|
||||||
edition = "2024"
|
|
||||||
version.workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "mhypbase"
|
|
||||||
crate-type = ["cdylib"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
windows.workspace = true
|
|
||||||
hkrpg.workspace = true
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fn main() {
|
|
||||||
println!(
|
|
||||||
"cargo:rustc-link-search=native={}",
|
|
||||||
std::env::var("OUT_DIR").unwrap()
|
|
||||||
);
|
|
||||||
println!("cargo:rustc-link-arg=/DEF:mhypbase/mhypbase.def");
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
LIBRARY MHYPBASE
|
|
||||||
EXPORTS
|
|
||||||
Initialize @1
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
use windows::Win32::{
|
|
||||||
Foundation::HINSTANCE,
|
|
||||||
System::{
|
|
||||||
SystemServices::DLL_PROCESS_ATTACH,
|
|
||||||
Threading::{GetCurrentThread, TerminateThread},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
|
||||||
#[allow(non_snake_case, unused_variables)]
|
|
||||||
extern "cdecl" fn Initialize() -> bool {
|
|
||||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
TerminateThread(GetCurrentThread(), 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[unsafe(no_mangle)]
|
|
||||||
unsafe extern "system" fn DllMain(_: HINSTANCE, call_reason: u32, _: *mut ()) {
|
|
||||||
if call_reason == DLL_PROCESS_ATTACH {
|
|
||||||
std::thread::spawn(hkrpg::main);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user