Reviewed-on: WutheringSlaves/wicked-waifus-win-patch#7
This commit is contained in:
xavo95 2025-05-16 10:51:56 +00:00
parent 47c5c9d123
commit 2b2a11df4c
10 changed files with 423 additions and 326 deletions

66
Cargo.lock generated
View file

@ -13,9 +13,19 @@ dependencies = [
[[package]]
name = "bitflags"
version = "2.9.0"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "curly-injector"
version = "0.1.0"
source = "git+https://git.xeondev.com/ReversedRoomsMisc/curly-injector.git#1184af99d3788931ee691f5922c55d9ea06b3003"
dependencies = [
"ilhook",
"interceptor-rs",
"regex",
]
[[package]]
name = "iced-x86"
@ -37,14 +47,23 @@ dependencies = [
"lazy_static",
"libc",
"regex",
"thiserror",
"thiserror 1.0.69",
"windows-sys",
]
[[package]]
name = "injector-utils"
version = "0.1.0"
source = "git+https://git.xeondev.com/ReversedRoomsMisc/process-launcher-rs.git#4dc7349c86020b92d795f74a30c9f3c76414f2f4"
dependencies = [
"thiserror 2.0.12",
"windows",
]
[[package]]
name = "interceptor-rs"
version = "0.1.0"
source = "git+https://git.xeondev.com/xavo95/interceptor-rs.git#418aef083cc6768201f0512fdbdca5c03aa4f787"
source = "git+https://git.xeondev.com/ReversedRoomsMisc/interceptor-rs.git#418aef083cc6768201f0512fdbdca5c03aa4f787"
dependencies = [
"ilhook",
]
@ -57,9 +76,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.171"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "memchr"
@ -69,9 +88,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "proc-macro2"
version = "1.0.94"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
@ -116,9 +135,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "syn"
version = "2.0.100"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
@ -131,7 +150,16 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
"thiserror-impl 1.0.69",
]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl 2.0.12",
]
[[package]]
@ -145,6 +173,17 @@ dependencies = [
"syn",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
@ -154,8 +193,9 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unreal-niggery-rs"
version = "0.1.0"
source = "git+https://git.xeondev.com/xavo95/unreal-niggery-rs.git#07330a27e1e49f0544f5fde51698c0a2300cc737"
source = "git+https://git.xeondev.com/ReversedRoomsMisc/unreal-niggery-rs.git#e07eda21e461e1ec234ec9ef2562dc8187742631"
dependencies = [
"thiserror 2.0.12",
"widestring",
]
@ -163,7 +203,9 @@ dependencies = [
name = "wicked-waifus-win-patch"
version = "0.1.0"
dependencies = [
"curly-injector",
"ilhook",
"injector-utils",
"interceptor-rs",
"regex",
"unreal-niggery-rs",

View file

@ -1,7 +1,7 @@
[package]
name = "wicked-waifus-win-patch"
version = "0.1.0"
edition = "2021"
edition = "2024"
[lib]
name = "wicked_waifus_win"
@ -9,17 +9,18 @@ crate-type = ["cdylib"]
[features]
advanced = []
cn_beta_2_3_0 = []
os_live_2_2_0 = []
cn_beta_2_4_0 = []
enable-sdk = []
only-sig-bypass = []
regular = ["dep:regex", "dep:widestring"]
[dependencies]
curly-injector = { git = "https://git.xeondev.com/ReversedRoomsMisc/curly-injector.git" }
ilhook = "2.1.1"
interceptor-rs = { git = "https://git.xeondev.com/xavo95/interceptor-rs.git" }
injector-utils = { git = "https://git.xeondev.com/ReversedRoomsMisc/process-launcher-rs.git" }
interceptor-rs = { git = "https://git.xeondev.com/ReversedRoomsMisc/interceptor-rs.git" }
regex = { version = "1.11.1", optional = true }
unreal-niggery-rs = { git = "https://git.xeondev.com/xavo95/unreal-niggery-rs.git" }
unreal-niggery-rs = { git = "https://git.xeondev.com/ReversedRoomsMisc/unreal-niggery-rs.git" }
widestring = { version = "1.2.0", optional = true }
windows = { version = "0.61.1", features = [
"Win32_Foundation",

View file

@ -1,3 +1,140 @@
# CN BETA 2.3.0
```rust
#[cfg(feature = "cn_beta_2_3_0")]
pub(crate) const CONFIG: InjectConfiguration = InjectConfiguration {
f_pak_file_check: 0x4274440,
f_pak_file_check_preamble: 0x8D48574157565540,
resize_grow: 0x8E2D30,
f_print_f: 0x28E5F70,
add_pak_folders_entry: 0x427B910,
add_pak_folders_ret: 0x427E1B0,
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
ue_curl_config: CurlConfig {
handle_rcx_relative_offset: 0x110,
url_handle_relative_offset: 0x880,
http_headers_handle_relative_offset: None,
curl_easy_setopt: 0x66325A0,
curl_easy_perform: 0x3C0BFA0,
},
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
replacement_config: ReplacementConfig {
config_server_regex: r#"^(https|http)://.*/([a-zA-Z0-9]{32}/index\.json)$"#,
// hotpatch_server_regex: "",
log_server_regex: r#"^(https|http)://.*\.cos\..*\.myqcloud\.com/(.*)$"#,
sdk_server_regex: r#"^(https|http)://.*\.cos\..*\.myqcloud\.com/(.*)$"#,
replacement_defaults: &ReplacementDefaults {
config_server_default: "127.0.0.1:10001",
// hotpatch_server_default: "127.0.0.1:10001",
log_server_default: "127.0.0.1:10001",
sdk_server_default: "127.0.0.1:10001",
},
},
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
disable_sdk: DisableSdkConfiguration {
sdk_dll: s!("KRSDKEx.dll"),
eula_accept: 0x4F410,
sdk_go_away: 0x93620,
},
#[cfg(all(feature = "enable-sdk", not(feature = "only-sig-bypass"), feature = "regular"))]
kr_curl: KrCurlConfiguration {
curl_dll: s!("libkrsdkcurl.dll"),
curl_config: CurlConfig {
handle_rcx_relative_offset: 0,
url_handle_relative_offset: 0x1220,
http_headers_handle_relative_offset: Some(0x340),
curl_easy_setopt: 0x36E50,
curl_easy_perform: 0xE3D0,
},
}
};
```
# OS LIVE 2.2.0
```rust
#[cfg(feature = "os_live_2_2_0")]
pub(crate) const CONFIG: InjectConfiguration = InjectConfiguration {
f_pak_file_check: 0x418A2F0,
f_pak_file_check_preamble: 0x8D48574157565540,
resize_grow: 0x08D6D70,
f_print_f: 0x280B240,
add_pak_folders_entry: 0x41917D0,
add_pak_folders_ret: 0x4194070,
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
ue_curl_config: CurlConfig {
handle_rcx_relative_offset: Some(0x110),
url_handle_relative_offset: 0x880,
http_headers_handle_relative_offset: None,
curl_easy_setopt: 0x64FF840,
curl_easy_perform: 0x3B21490,
},
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
replacement_config: ReplacementConfig {
config_server_regex: r#"^(https|http)://.*/([a-zA-Z0-9]{32}/index\.json)$"#,
// hotpatch_server_regex: "",
log_server_regex: r#"^(https|http)://.*\.cos\..*\.myqcloud\.com/(.*)$"#,
// sdk_server_regex: "",
// replacement_defaults: &ReplacementDefaults {
// config_server_default: "127.0.0.1:10001",
// // hotpatch_server_default: "127.0.0.1:10001",
// log_server_default: "127.0.0.1:10001",
// sdk_server_default: "127.0.0.1:10001",
// },
},
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
disable_sdk: DisableSdkConfiguration {
sdk_dll: s!("KRSDK.dll"),
eula_accept: 0x96800,
sdk_go_away: 0xA2680,
},
// TODO: Ported for compliance in the future, not supported on 2.2.0 OS
#[cfg(all(feature = "enable-sdk", not(feature = "only-sig-bypass"), feature = "regular"))]
kr_curl: KrCurlConfiguration {
curl_dll: s!("libkrsdkcurl.dll"),
curl_config: CurlConfig {
handle_rcx_relative_offset: None,
url_handle_relative_offset: 0,
http_headers_handle_relative_offset: None,
curl_easy_setopt: 0,
curl_easy_perform: 0,
},
}
};
```
# CN BETA 2.2.1
```rust
#[cfg(feature = "cn_beta_2_2_1")]
pub(crate) const CONFIG: InjectConfiguration = InjectConfiguration {
f_pak_file_check: 0x41CE7F0,
f_pak_file_check_preamble: 0x8D48574157565540,
resize_grow: 0x08D9510,
f_print_f: 0x2852CE0,
add_pak_folders_entry: 0x41D5CD0,
add_pak_folders_ret: 0x41D8570,
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
ue_curl_config: CurlConfig {
handle_rcx_relative_offset: 0x110,
url_handle_relative_offset: 0x880,
curl_easy_setopt: 0x657A660,
curl_easy_perform: 0x3B6A440,
},
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
replacement_config: ReplacementConfig {
config_server_regex: r#"^(https|http)://.*/([a-zA-Z0-9]{32}/index\.json)$"#,
// hotpatch_server_regex: "",
log_server_regex: r#"^(https|http)://.*\.cos\..*\.myqcloud\.com/(.*)$"#,
// sdk_server_regex: "",
},
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
disable_sdk: DisableSdkConfiguration {
sdk_dll: s!("KRSDKEx.dll"),
eula_accept: 0x4ED80,
sdk_go_away: 0x91FE0,
},
};
```
# OS LIVE 2.1.0
```rust

View file

@ -1,14 +1,15 @@
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
use windows::core::{PCSTR, s};
use curly_injector::CurlConfig;
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) const CONFIG_SERVER_DEFAULT: &'static str = "127.0.0.1:10001";
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
// pub(crate) const HOTPATCH_SERVER_DEFAULT: &'static str = "127.0.0.1:10001";
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) const LOG_SERVER_DEFAULT: &'static str = "127.0.0.1:10001";
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
// pub(crate) const SDK_SERVER_DEFAULT: &'static str = "127.0.0.1:10001";
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) struct ReplacementDefaults {
pub(crate) config_server_default: &'static str,
// pub(crate) hotpatch_server_default: &'static str,
pub(crate) log_server_default: &'static str,
#[cfg(feature = "enable-sdk")]
pub(crate) sdk_server_default: &'static str,
}
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) struct DisableSdkConfiguration {
@ -17,20 +18,20 @@ pub(crate) struct DisableSdkConfiguration {
pub(crate) sdk_go_away: usize,
}
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) struct CurlConfig {
pub(crate) handle_rcx_relative_offset: u64,
pub(crate) url_handle_relative_offset: usize,
pub(crate) curl_easy_setopt: usize,
pub(crate) curl_easy_perform: usize,
}
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) struct ReplacementConfig {
pub(crate) config_server_regex: &'static str,
// pub(crate) hotpatch_server_regex: &'static str,
pub(crate) log_server_regex: &'static str,
// pub(crate) sdk_server_regex: &'static str,
#[cfg(feature = "enable-sdk")]
pub(crate) sdk_server_regex: &'static str,
pub(crate) replacement_defaults: &'static ReplacementDefaults,
}
#[cfg(all(feature = "enable-sdk", not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) struct KrCurlConfiguration {
pub(crate) curl_dll: PCSTR,
pub(crate) curl_config: CurlConfig,
}
pub(crate) struct InjectConfiguration {
@ -46,64 +47,56 @@ pub(crate) struct InjectConfiguration {
pub(crate) replacement_config: ReplacementConfig,
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) disable_sdk: DisableSdkConfiguration,
#[cfg(all(feature = "enable-sdk", not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) kr_curl: KrCurlConfiguration,
}
#[cfg(feature = "cn_beta_2_3_0")]
#[cfg(feature = "cn_beta_2_4_0")]
pub(crate) const CONFIG: InjectConfiguration = InjectConfiguration {
f_pak_file_check: 0x4274440,
f_pak_file_check: 0x42CF240,
f_pak_file_check_preamble: 0x8D48574157565540,
resize_grow: 0x8E2D30,
f_print_f: 0x28E5F70,
add_pak_folders_entry: 0x427B910,
add_pak_folders_ret: 0x427E1B0,
resize_grow: 0x08E1690,
f_print_f: 0x2912CF0,
add_pak_folders_entry: 0x42D6720,
add_pak_folders_ret: 0x42D8FC0,
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
ue_curl_config: CurlConfig {
handle_rcx_relative_offset: 0x110,
url_handle_relative_offset: 0x880,
curl_easy_setopt: 0x66325A0,
curl_easy_perform: 0x3C0BFA0,
http_headers_handle_relative_offset: None,
curl_easy_setopt: 0x66B3720,
curl_easy_perform: 0x3C65C60,
},
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
replacement_config: ReplacementConfig {
config_server_regex: r#"^(https|http)://.*/([a-zA-Z0-9]{32}/index\.json)$"#,
// hotpatch_server_regex: "",
log_server_regex: r#"^(https|http)://.*\.cos\..*\.myqcloud\.com/(.*)$"#,
// sdk_server_regex: "",
#[cfg(feature = "enable-sdk")]
sdk_server_regex: r#"^(https|http)://.*\.cos\..*\.myqcloud\.com/(.*)$"#,
replacement_defaults: &ReplacementDefaults {
config_server_default: "127.0.0.1:10001",
// hotpatch_server_default: "127.0.0.1:10001",
log_server_default: "127.0.0.1:10001",
#[cfg(feature = "enable-sdk")]
sdk_server_default: "127.0.0.1:10001",
},
},
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
disable_sdk: DisableSdkConfiguration {
sdk_dll: s!("KRSDKEx.dll"),
eula_accept: 0x4F410,
sdk_go_away: 0x93620,
},
};
#[cfg(feature = "os_live_2_2_0")]
pub(crate) const CONFIG: InjectConfiguration = InjectConfiguration {
f_pak_file_check: 0x418A2F0,
f_pak_file_check_preamble: 0x8D48574157565540,
resize_grow: 0x08D6D70,
f_print_f: 0x280B240,
add_pak_folders_entry: 0x41917D0,
add_pak_folders_ret: 0x4194070,
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
ue_curl_config: CurlConfig {
handle_rcx_relative_offset: 0x110,
url_handle_relative_offset: 0x880,
curl_easy_setopt: 0x64FF840,
curl_easy_perform: 0x3B21490,
},
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
replacement_config: ReplacementConfig {
config_server_regex: r#"^(https|http)://.*/([a-zA-Z0-9]{32}/index\.json)$"#,
// hotpatch_server_regex: "",
log_server_regex: r#"^(https|http)://.*\.cos\..*\.myqcloud\.com/(.*)$"#,
// sdk_server_regex: "",
},
#[cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
disable_sdk: DisableSdkConfiguration {
sdk_dll: s!("KRSDK.dll"),
eula_accept: 0x96800,
sdk_go_away: 0xA2680,
eula_accept: 0x4F490,
sdk_go_away: 0x93FD0,
},
#[cfg(all(feature = "enable-sdk", not(feature = "only-sig-bypass"), feature = "regular"))]
kr_curl: KrCurlConfiguration {
curl_dll: s!("libkrsdkcurl.dll"),
curl_config: CurlConfig {
handle_rcx_relative_offset: 0,
url_handle_relative_offset: 0x1220,
http_headers_handle_relative_offset: Some(0x340),
curl_easy_setopt: 0x36E50,
curl_easy_perform: 0xE3D0,
},
}
};

93
src/curl_hook.rs Normal file
View file

@ -0,0 +1,93 @@
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
use crate::config::ReplacementConfig;
use curly_injector::replacer::AbstractReplacer;
use curly_injector::utils::EnvBoolMapper;
use curly_injector::{CurlConfig, CurlUserData};
use std::sync::OnceLock;
use windows::core::PCSTR;
static mut UE_CURL_EASY: OnceLock<CurlUserData> = OnceLock::new();
#[cfg(feature = "enable-sdk")]
static mut KR_CURL_EASY: OnceLock<CurlUserData> = OnceLock::new();
pub(crate) fn configure_ue_curl(
interceptor: &mut interceptor_rs::Interceptor,
module_name: Option<PCSTR>,
config: &'static CurlConfig,
replacement: &ReplacementConfig,
) {
let module = injector_utils::get_module_base(module_name);
let replacer = vec![
// Config Server Replacer
AbstractReplacer::GenericReplacer(curly_injector::replacer::GenericReplacer {
regex: regex::Regex::new(replacement.config_server_regex).unwrap(),
replacement: std::env::var("CFG_SERVER_URL").unwrap_or(
replacement
.replacement_defaults
.config_server_default
.to_string(),
),
force_http: std::env::var("CFG_SERVER_FORCE_HTTP").map_env_bool(true),
}),
// TODO: Hotpatch Server replacer
// Log server replacer
AbstractReplacer::GenericReplacer(curly_injector::replacer::GenericReplacer {
regex: regex::Regex::new(replacement.log_server_regex).unwrap(),
replacement: std::env::var("LOG_SERVER_URL").unwrap_or(
replacement
.replacement_defaults
.log_server_default
.to_string(),
),
force_http: std::env::var("LOG_SERVER_FORCE_HTTP").map_env_bool(true),
}),
];
unsafe {
curly_injector::hook_curl(
interceptor,
module.0 as usize,
config,
replacer,
None,
&UE_CURL_EASY,
);
}
}
// Not sig bypass and regular check already done at top of the file
#[cfg(feature = "enable-sdk")]
pub(crate) fn configure_kr_curl(
interceptor: &mut interceptor_rs::Interceptor,
module_name: Option<PCSTR>,
config: &'static CurlConfig,
replacement: &ReplacementConfig,
) {
let module = injector_utils::get_module_base(module_name);
let replacer = vec![
// SDK server replacer
AbstractReplacer::GenericReplacer(curly_injector::replacer::GenericReplacer {
regex: regex::Regex::new(replacement.sdk_server_regex).unwrap(),
replacement: std::env::var("SDK_SERVER_URL").unwrap_or(
replacement
.replacement_defaults
.sdk_server_default
.to_string(),
),
force_http: std::env::var("SDK_SERVER_FORCE_HTTP").map_env_bool(true),
}),
];
let proxy_config = Some(ProxyConfig {
proxy_url: "http://127.0.0.1:8888",
skip_url_replace: true,
});
curly_injector::hook_curl(
interceptor,
module.0 as usize,
config,
replacer,
proxy_config,
&KR_CURL_EASY,
);
}

View file

@ -1,26 +0,0 @@
#![cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
#![allow(unused)]
const CURL_OPT_TYPE_LONG: u64 = 0;
const CURL_OPT_TYPE_OBJECT_POINT: u64 = 10000;
const CURL_OPT_TYPE_FUNCTION_POINT: u64 = 20000;
const CURL_OPT_TYPE_OFF_T: u64 = 30000;
const CURL_OPT_TYPE_BLOB: u64 = 40000;
const CURL_OPT_TYPE_STRING_POINT: u64 = CURL_OPT_TYPE_OBJECT_POINT;
const CURL_OPT_TYPE_S_LIST_POINT: u64 = CURL_OPT_TYPE_OBJECT_POINT;
const CURL_OPT_TYPE_CB_POINT: u64 = CURL_OPT_TYPE_OBJECT_POINT;
const CURL_OPT_TYPE_VALUES: u64 = CURL_OPT_TYPE_LONG;
#[macro_export]
macro_rules! curl_opt {
($name:ident, $typ:ident, $value:literal) => {
pub(crate) const $name: u64 = $typ + $value;
};
}
curl_opt!(CURL_OPT_URL, CURL_OPT_TYPE_STRING_POINT, 2);
curl_opt!(CURL_OPT_SSL_VERIFY_PEER, CURL_OPT_TYPE_LONG, 64);
curl_opt!(CURL_OPT_CA_INFO, CURL_OPT_TYPE_STRING_POINT, 65);
curl_opt!(CURL_OPT_SSL_VERIFY_HOST, CURL_OPT_TYPE_LONG, 81);
curl_opt!(CURL_OPT_CA_PATH, CURL_OPT_TYPE_STRING_POINT, 97);

View file

@ -1,123 +0,0 @@
#![cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
use std::env::VarError;
use std::ffi::{c_char, CStr, CString};
use std::sync::OnceLock;
use std::thread;
use std::time::Duration;
use ilhook::x64::Registers;
use windows::core::PCSTR;
use windows::Win32::System::LibraryLoader::GetModuleHandleA;
use crate::{config, curl_utils};
use crate::config::{CONFIG, CurlConfig};
use crate::replacer::{AbstractReplacer, GenericReplacer, Replacer};
type CurlEasySetStr = fn(handle: usize, tag: u64, value: *const c_char);
static mut URL_REPLACER: OnceLock<Vec<AbstractReplacer>> = OnceLock::new();
static UE_CURL_EASY_SETOPT_FUNC: OnceLock<usize> = OnceLock::new();
trait EnvBoolMapper {
fn map_env_bool(self, default: bool) -> bool;
}
impl EnvBoolMapper for Result<String, VarError> {
fn map_env_bool(self, default: bool) -> bool {
self.map(|val| match val.as_str() {
"y" => true,
_ => false
}).unwrap_or(default)
}
}
pub(crate) fn configure_extras(interceptor: &mut interceptor_rs::Interceptor) {
unsafe {
URL_REPLACER.set(vec![
// Config Server Replacer
AbstractReplacer::GenericReplacer(GenericReplacer {
regex: regex::Regex::new(CONFIG.replacement_config.config_server_regex).unwrap(),
replacement: std::env::var("CFG_SERVER_URL")
.unwrap_or(config::CONFIG_SERVER_DEFAULT.to_string()),
force_http: std::env::var("CFG_SERVER_FORCE_HTTP").map_env_bool(true),
}),
// TODO: Hotpatch Server replacer
// Log server replacer
AbstractReplacer::GenericReplacer(GenericReplacer {
regex: regex::Regex::new(CONFIG.replacement_config.log_server_regex).unwrap(),
replacement: std::env::var("LOG_SERVER_URL")
.unwrap_or(config::LOG_SERVER_DEFAULT.to_string()),
force_http: std::env::var("LOG_SERVER_FORCE_HTTP").map_env_bool(true),
}),
// TODO: SDK Server replacer
]).unwrap()
}
let module = unsafe { GetModuleHandleA(PCSTR::null()) }.unwrap();
println!("Game base: {:X}", module.0 as usize);
let _ = UE_CURL_EASY_SETOPT_FUNC.set(module.0 as usize + CONFIG.ue_curl_config.curl_easy_setopt);
interceptor
.attach(
(module.0 as usize) + CONFIG.ue_curl_config.curl_easy_perform,
on_curl_easy_perform,
Some(&CONFIG.ue_curl_config as *const _ as usize)
).unwrap();
let krsdk_ex = loop {
match unsafe { GetModuleHandleA(CONFIG.disable_sdk.sdk_dll) } {
Ok(handle) => break handle,
Err(_) => thread::sleep(Duration::from_millis(1)),
}
};
interceptor
.replace((krsdk_ex.0 as usize) + CONFIG.disable_sdk.eula_accept, dummy, None)
.unwrap();
interceptor
.replace((krsdk_ex.0 as usize) + CONFIG.disable_sdk.sdk_go_away, dummy, None)
.unwrap();
}
unsafe extern "win64" fn dummy(_: *mut Registers, _: usize, _: usize) -> usize {
1
}
unsafe extern "win64" fn on_curl_easy_perform(reg: *mut Registers, user_data: usize) {
let config = std::ptr::read(user_data as *const CurlConfig);
let curl_handle = unsafe {
*(((*reg).rcx + config.handle_rcx_relative_offset) as *const usize)
};
let url_ptr = unsafe {
*((curl_handle + config.url_handle_relative_offset) as *const usize)
};
let url = unsafe { CStr::from_ptr(url_ptr as *const i8) }.to_str().unwrap();
println!("[curl_easy_perform] Original URL: {url}");
for replacer in unsafe { URL_REPLACER.get_mut().unwrap() } {
match replacer.replace(url) {
Ok(result) => {
println!("[curl_easy_perform] Replacement URL: {result}");
let url = CString::new(result.as_str()).unwrap();
unsafe {
// TODO: Rethink this for other curl interceptors
std::mem::transmute::<usize, CurlEasySetStr>(*UE_CURL_EASY_SETOPT_FUNC.get().unwrap())(
curl_handle,
curl_utils::CURL_OPT_URL,
url.as_ptr(),
)
}
// TODO: Future stuff
// let headers_ptr = unsafe { *(((*reg).rcx + 0x118) as *const usize) };
// let headers = unsafe { std::slice::from_raw_parts(*(headers_ptr as *const usize) as *const u8, 1000) };
// println!("Headers: {headers:02X?}");
return;
}
Err(_) => {}
};
};
println!("No valid url match found");
}

View file

@ -6,7 +6,9 @@ use std::time::Duration;
use unreal_niggery_rs::f_string::{FString, Printf};
use unreal_niggery_rs::t_array::TArray;
use unreal_niggery_rs::Add;
use windows::core::{PCSTR, PCWSTR};
use windows::core::PCSTR;
#[cfg(any(feature = "only-sig-bypass", feature = "regular"))]
use windows::core::PCWSTR;
use windows::Win32::Foundation::HINSTANCE;
use windows::Win32::System::Console;
use windows::Win32::System::LibraryLoader::GetModuleHandleA;
@ -16,11 +18,9 @@ use config::CONFIG;
mod config;
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
mod curl_utils;
mod curl_hook;
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
mod extras;
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
mod replacer;
mod sdk;
static CUSTOM_PAK_FOLDER: OnceLock<String> = OnceLock::new();
@ -41,6 +41,7 @@ fn thread_func() {
}
let mut interceptor = Interceptor::new();
#[cfg(any(feature = "only-sig-bypass", feature = "regular"))]
interceptor
.replace(
(module.0 as usize) + CONFIG.f_pak_file_check,
@ -71,11 +72,7 @@ fn thread_func() {
.unwrap();
}
#[cfg(all(
not(feature = "only-sig-bypass"),
feature = "regular",
feature = "advanced"
))]
#[cfg(feature = "advanced")]
wicked_waifus_win_payload_advanced::enable_advanced_features(
module.0 as usize,
&mut interceptor,
@ -90,39 +87,67 @@ fn thread_func() {
);
#[cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
extras::configure_extras(&mut interceptor);
curl_hook::configure_ue_curl(
&mut interceptor,
None,
&CONFIG.ue_curl_config,
&CONFIG.replacement_config,
);
#[cfg(all(
not(feature = "enable-sdk"),
not(feature = "only-sig-bypass"),
feature = "regular"
))]
sdk::configure_sdk(&mut interceptor);
#[cfg(all(
feature = "enable-sdk",
not(feature = "only-sig-bypass"),
feature = "regular"
))]
curl_hook::configure_kr_curl(
&mut interceptor,
Some(CONFIG.kr_curl.curl_dll),
&CONFIG.kr_curl.curl_config,
&CONFIG.replacement_config,
);
println!("Successfully initialized!");
thread::sleep(Duration::from_secs(u64::MAX));
}
#[cfg(any(feature = "only-sig-bypass", feature = "regular"))]
unsafe extern "win64" fn fpakfile_check_replacement(
reg: *mut Registers,
_: usize,
_: usize,
) -> usize {
let wstr = *(((*reg).rcx + 8) as *const usize) as *const u16;
let pak_name = PCWSTR::from_raw(wstr).to_string().unwrap();
let pak_name = unsafe {
PCWSTR::from_raw(*(((*reg).rcx + 8) as *const usize) as *const u16)
.to_string()
.unwrap()
};
println!("Trying to verify pak: {pak_name}, returning true");
1
}
unsafe extern "win64" fn add_pak_folders(reg: *mut Registers, _: usize) {
let local_ptr = ((*reg).rbp - 0x20) as usize; // Uninitialized local FString pointer
let local_ptr = unsafe { ((*reg).rbp - 0x20) as usize }; // Uninitialized local FString pointer
let pak_folder = CUSTOM_PAK_FOLDER.get().unwrap();
FString::printf(local_ptr, pak_folder);
let _ = FString::printf(local_ptr, pak_folder).unwrap();
let mut f_string = FString(TArray::read(local_ptr));
println!("Injecting custom pak folder: {}", f_string);
unsafe {
TArray::read((*reg).rdx as usize).add(&mut f_string.0);
}
}
unsafe extern "win64" fn debug_get_pak_folders(reg: *mut Registers, _: usize) {
println!("Loading Paks from: {}", TArray::read((*reg).rbx as usize));
println!("Loading Paks from: {}", unsafe { TArray::read((*reg).rbx as usize) });
}
#[no_mangle]
#[unsafe(no_mangle)]
unsafe extern "system" fn DllMain(_: HINSTANCE, call_reason: u32, _: *mut ()) -> bool {
if call_reason == DLL_PROCESS_ATTACH {
thread::spawn(|| thread_func());

View file

@ -1,83 +0,0 @@
#![cfg(all(not(feature = "only-sig-bypass"), feature = "regular"))]
pub(crate) trait Replacer {
fn replace(&mut self, original: &str) -> Result<String, String>;
}
#[derive(Debug)]
pub(crate) enum AbstractReplacer {
GenericReplacer(GenericReplacer),
GenericCdnReplacer(GenericCdnReplacer),
}
#[derive(Debug)]
pub(crate) struct GenericReplacer {
pub(crate) regex: regex::Regex,
pub(crate) replacement: String,
pub(crate) force_http: bool,
}
#[derive(Debug)]
pub(crate) struct GenericCdnReplacer {
pub(crate) regex: regex::Regex,
pub(crate) replacement: Vec<String>,
pub(crate) force_http: bool,
pub(crate) url_index: u8,
}
impl Replacer for AbstractReplacer {
fn replace(&mut self, original: &str) -> Result<String, String> {
match self {
AbstractReplacer::GenericReplacer(replacer) => replacer.replace(original),
AbstractReplacer::GenericCdnReplacer(replacer) => replacer.replace(original)
}
}
}
impl Replacer for GenericReplacer {
fn replace(&mut self, original: &str) -> Result<String, String> {
// Prepare output array
let mut results: Vec<String> = vec![];
// Perform the capture over input
for (_, [scheme, path]) in self.regex.captures_iter(original).map(|c| c.extract()) {
results.push(format!(
"{}://{}/{}",
if self.force_http { "http" } else { scheme },
self.replacement,
path
));
}
// We are supposed to only parse one entry from text
if 1 == results.len() {
Ok(results.remove(0))
} else if results.is_empty() {
Err("No valid url match found so returning original url".to_string())
} else {
Err(format!("Invalid number of entries parsed, expected 1, obtained {:?}", results.len()))
}
}
}
impl Replacer for GenericCdnReplacer {
fn replace(&mut self, original: &str) -> Result<String, String> {
// Prepare output array
let mut results: Vec<String> = vec![];
// Perform the capture over input
for (_, [scheme, path]) in self.regex.captures_iter(original).map(|c| c.extract()) {
results.push(format!(
"{}://{}/{}",
if self.force_http { "http" } else { scheme },
self.replacement[self.url_index as usize],
path
));
}
// We are supposed to only parse one entry from text
if 1 == results.len() {
self.url_index = (self.url_index + 1) % self.replacement.len() as u8;
Ok(results.remove(0))
} else if results.is_empty() {
Err("No valid url match found".to_string())
} else {
Err(format!("Invalid number of entries parsed, expected 1, obtained {:?}", results.len()))
}
}
}

38
src/sdk.rs Normal file
View file

@ -0,0 +1,38 @@
#![cfg(all(not(feature = "enable-sdk"), not(feature = "only-sig-bypass"), feature = "regular"))]
use std::thread;
use std::time::Duration;
use ilhook::x64::Registers;
use windows::Win32::System::LibraryLoader::GetModuleHandleA;
use crate::config::CONFIG;
pub(crate) fn configure_sdk(interceptor: &mut interceptor_rs::Interceptor) {
let krsdk_ex = loop {
match unsafe { GetModuleHandleA(CONFIG.disable_sdk.sdk_dll) } {
Ok(handle) => break handle,
Err(_) => thread::sleep(Duration::from_millis(1)),
}
};
interceptor
.replace(
(krsdk_ex.0 as usize) + CONFIG.disable_sdk.eula_accept,
dummy,
None,
)
.unwrap();
interceptor
.replace(
(krsdk_ex.0 as usize) + CONFIG.disable_sdk.sdk_go_away,
dummy,
None,
)
.unwrap();
}
unsafe extern "win64" fn dummy(_: *mut Registers, _: usize, _: usize) -> usize {
1
}