mirror of
https://github.com/redstrate/LauncherTweaks.git
synced 2025-05-20 17:37:46 +00:00
Add an option to inject new command line arguments for the game
This can be used to add custom lobbies to the game, otherwise there's no way to normally. (The retail client will use the built-in URLs in the executable, the launcher doesn't pass any.)
This commit is contained in:
parent
282a2d0fd8
commit
ace27b7e6c
6 changed files with 377 additions and 0 deletions
220
Cargo.lock
generated
220
Cargo.lock
generated
|
@ -6,6 +6,8 @@ version = 4
|
|||
name = "LauncherTweaks"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"physis",
|
||||
"proxy-dll",
|
||||
"retour",
|
||||
"serde",
|
||||
|
@ -14,12 +16,53 @@ dependencies = [
|
|||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "array-init"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "binrw"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "173901312e9850391d4d7c1318c4e099fdc037d61870fca427429830efdb4e5f"
|
||||
dependencies = [
|
||||
"array-init",
|
||||
"binrw_derive",
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "binrw_derive"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb515fdd6f8d3a357c8e19b8ec59ef53880807864329b1cb1cba5c53bf76557e"
|
||||
dependencies = [
|
||||
"either",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.19"
|
||||
|
@ -29,12 +72,37 @@ dependencies = [
|
|||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.17.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.26"
|
||||
|
@ -45,6 +113,12 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
|
@ -61,12 +135,28 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.9.0"
|
||||
|
@ -93,6 +183,16 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-ng-sys"
|
||||
version = "1.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7118c2c2a3c7b6edc279a8b19507672b9c4d716f95e671172dfa4e23f9fd824"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.2"
|
||||
|
@ -124,12 +224,67 @@ dependencies = [
|
|||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modular-bitfield"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74"
|
||||
dependencies = [
|
||||
"modular-bitfield-impl",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modular-bitfield-impl"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "physis"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53ea3f3a8d52b4dd21bfe3a3e0730cfdacbfa6f75ab002b60c2164fbb350c1d3"
|
||||
dependencies = [
|
||||
"binrw",
|
||||
"bitflags",
|
||||
"half",
|
||||
"libz-ng-sys",
|
||||
"modular-bitfield",
|
||||
"system-deps",
|
||||
"texture2ddecoder",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.3.0"
|
||||
|
@ -263,6 +418,18 @@ version = "0.4.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a3d689654af89bdfeba29a914ab6ac0236d382eb3b764f7454dde052f2821f8"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
@ -285,6 +452,34 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "7.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005"
|
||||
dependencies = [
|
||||
"cfg-expr",
|
||||
"heck",
|
||||
"pkg-config",
|
||||
"toml",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "texture2ddecoder"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54f0e5ca5dceb9b44d0f376de51782277c25fb42ffe1dad08d847f3a156d26d9"
|
||||
dependencies = [
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.20"
|
||||
|
@ -319,6 +514,25 @@ dependencies = [
|
|||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
|
@ -331,6 +545,12 @@ version = "1.0.18"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
|
|
|
@ -14,6 +14,8 @@ windows = { version = "0.61", features = ["Win32_Foundation", "Win32_UI_WindowsA
|
|||
serde = { version = "1.0", features = ["derive"], default-features = false }
|
||||
toml = { version = "0.8", features = ["parse"], default-features = false }
|
||||
retour = { version = "0.3", features = ["static-detour"], default-features = false }
|
||||
physis = { version = "0.3" }
|
||||
base64 = "0.22"
|
||||
|
||||
[replace]
|
||||
"mmap-fixed-fixed:0.1.3" = { git = "https://github.com/redstrate/rust-mmap-fixed-fixed" } # my fork which removes the winapi dependency
|
||||
|
|
|
@ -10,6 +10,7 @@ Tweaks for the official FFXIV launcher.
|
|||
* Force the launcher/boot executable to always communicate over HTTP instead of HTTPS, to make it easier to replace with local services.
|
||||
* Bypasses the (soft) WebView2 requirement introduced in Patch 7.21.
|
||||
* Disable the boot version check.
|
||||
* Add extra arguments when launching the game.
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
50
src/blowfish.rs
Normal file
50
src/blowfish.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
const checksum_table: [char; 16] = [
|
||||
'f', 'X', '1', 'p', 'G', 't', 'd', 'S', '5', 'C', 'A', 'P', '4', '_', 'V', 'L',
|
||||
];
|
||||
|
||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use physis::blowfish::Blowfish;
|
||||
use windows::Win32::System::SystemInformation::*;
|
||||
|
||||
fn calculate_checksum(key: u32) -> char {
|
||||
let value = key & 0x000F0000;
|
||||
checksum_table[(value >> 16) as usize]
|
||||
}
|
||||
|
||||
fn calculate_blowfish_key() -> u32 {
|
||||
let tick_count;
|
||||
unsafe {
|
||||
tick_count = GetTickCount();
|
||||
}
|
||||
|
||||
let ticks = tick_count & 0xFFFFFFFFu32;
|
||||
ticks & 0xFFFF0000u32
|
||||
}
|
||||
|
||||
fn initialize_blowfish() -> Blowfish {
|
||||
let buffer = format!("{:08x}", calculate_blowfish_key());
|
||||
Blowfish::new(buffer.as_bytes())
|
||||
}
|
||||
|
||||
pub fn decrypt_arguments(commandline: &str) -> String {
|
||||
let index = commandline.find("sqex").unwrap();
|
||||
|
||||
let base64 = &commandline[index + 8..commandline.len() - 6];
|
||||
let blowfish = initialize_blowfish();
|
||||
let decoded = URL_SAFE_NO_PAD.decode(base64.as_bytes()).unwrap();
|
||||
|
||||
let result = blowfish.decrypt(&decoded).unwrap();
|
||||
|
||||
let str = String::from_utf8(result).unwrap();
|
||||
str.trim_matches(char::from(0)).to_string()
|
||||
}
|
||||
|
||||
pub fn encrypt_arguments(commandline: &str) -> String {
|
||||
let blowfish = initialize_blowfish();
|
||||
let encrypted = blowfish.encrypt(commandline.as_bytes()).unwrap();
|
||||
|
||||
let encoded = URL_SAFE_NO_PAD.encode(encrypted);
|
||||
let checksum = calculate_checksum(calculate_blowfish_key());
|
||||
|
||||
format!("//**sqex0003{}{}**//", encoded, checksum)
|
||||
}
|
|
@ -12,6 +12,7 @@ pub struct Config {
|
|||
pub force_http: bool,
|
||||
pub game_patch_server: Option<String>,
|
||||
pub boot_patch_server: Option<String>,
|
||||
pub extra_game_arguments: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
|
103
src/lib.rs
103
src/lib.rs
|
@ -1,5 +1,8 @@
|
|||
#![allow(static_mut_refs)]
|
||||
|
||||
mod blowfish;
|
||||
use blowfish::{decrypt_arguments, encrypt_arguments};
|
||||
|
||||
mod config;
|
||||
use config::get_config;
|
||||
|
||||
|
@ -323,6 +326,105 @@ fn disable_boot_version_check() {
|
|||
}
|
||||
}
|
||||
|
||||
static_detour! {
|
||||
static CreateProcessW: fn(PCWSTR, PWSTR, *mut c_void, *mut c_void, bool, u32, *mut c_void, PCWSTR, *mut c_void, *mut c_void) -> bool;
|
||||
}
|
||||
|
||||
fn createprocessw_detour(
|
||||
lpapplicationname: PCWSTR,
|
||||
lpcommandline: PWSTR,
|
||||
lpprocessattributes: *mut c_void,
|
||||
lpthreadattributes: *mut c_void,
|
||||
binherithandles: bool,
|
||||
dwcreationflags: u32,
|
||||
lpenvironment: *mut c_void,
|
||||
lpcurrentdirectory: PCWSTR,
|
||||
lpstartupinfo: *mut c_void,
|
||||
lpprocessinformation: *mut c_void,
|
||||
) -> bool {
|
||||
let config = get_config();
|
||||
|
||||
unsafe {
|
||||
let old_commandline = lpcommandline.to_string().unwrap();
|
||||
if !old_commandline.contains("ffxiv_dx11.exe") {
|
||||
return CreateProcessW.call(
|
||||
lpapplicationname,
|
||||
lpcommandline,
|
||||
lpprocessattributes,
|
||||
lpthreadattributes,
|
||||
binherithandles,
|
||||
dwcreationflags,
|
||||
lpenvironment,
|
||||
lpcurrentdirectory,
|
||||
lpstartupinfo,
|
||||
lpprocessinformation,
|
||||
);
|
||||
}
|
||||
|
||||
let decrypted = decrypt_arguments(&old_commandline);
|
||||
|
||||
let mut commandline = decrypted.to_string();
|
||||
commandline.push_str(&config.extra_game_arguments.unwrap());
|
||||
|
||||
let new_commandline = format!(
|
||||
"{} \"{}\"",
|
||||
&old_commandline[..old_commandline.find(" \"//**sqex").unwrap()],
|
||||
encrypt_arguments(&commandline)
|
||||
);
|
||||
|
||||
let new_commandline: Vec<u16> = new_commandline
|
||||
.encode_utf16()
|
||||
.chain(std::iter::once(0))
|
||||
.collect();
|
||||
|
||||
CreateProcessW.call(
|
||||
lpapplicationname,
|
||||
PWSTR(new_commandline.as_ptr() as _),
|
||||
lpprocessattributes,
|
||||
lpthreadattributes,
|
||||
binherithandles,
|
||||
dwcreationflags,
|
||||
lpenvironment,
|
||||
lpcurrentdirectory,
|
||||
lpstartupinfo,
|
||||
lpprocessinformation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_game_args() {
|
||||
let config = get_config();
|
||||
if !config.extra_game_arguments.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let createprocessw_addr = find_symbol("CreateProcessW", "Kernel32.dll")
|
||||
.expect("Failed to find CreateProcessW address");
|
||||
let createprocessw_fn = std::mem::transmute::<
|
||||
*mut u8,
|
||||
fn(
|
||||
PCWSTR,
|
||||
PWSTR,
|
||||
*mut c_void,
|
||||
*mut c_void,
|
||||
bool,
|
||||
u32,
|
||||
*mut c_void,
|
||||
PCWSTR,
|
||||
*mut c_void,
|
||||
*mut c_void,
|
||||
) -> bool,
|
||||
>(createprocessw_addr);
|
||||
CreateProcessW
|
||||
.initialize(createprocessw_fn, createprocessw_detour)
|
||||
.expect("Failed to initialize CreateProcessW hook");
|
||||
CreateProcessW
|
||||
.enable()
|
||||
.expect("Failed to hook into CreateProcessW");
|
||||
}
|
||||
}
|
||||
|
||||
#[proxy]
|
||||
fn main() {
|
||||
// Emit panic messages with message boxes
|
||||
|
@ -352,6 +454,7 @@ fn main() {
|
|||
overwrite_launcher_url();
|
||||
overwrite_patch_url();
|
||||
force_http();
|
||||
add_game_args();
|
||||
}
|
||||
BOOT_FILENAME => {
|
||||
use_system_proxy();
|
||||
|
|
Loading…
Add table
Reference in a new issue