From 5035dcab825106bb8e0b607cf97c374f7b6ea231 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Thu, 3 Jul 2025 17:00:55 -0400 Subject: [PATCH] Begin implementing more packet obsfucation It's not complete yet, notably the correct model IDs don't show up. See #9 --- src/packet/compression.rs | 15 +++---- src/world/mod.rs | 4 +- src/world/scrambler.rs | 86 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/packet/compression.rs b/src/packet/compression.rs index 9a14c22..1caa8a6 100644 --- a/src/packet/compression.rs +++ b/src/packet/compression.rs @@ -6,7 +6,7 @@ use binrw::{BinRead, BinResult}; use crate::{ config::get_config, packet::{PacketHeader, PacketSegment}, - world::ScramblerKeys, + world::{ScramblerKeys, scramble_packet}, }; use super::{IPC_HEADER_SIZE, PacketState, ReadWriteIpcSegment, SegmentData, oodle::OodleNetwork}; @@ -102,14 +102,11 @@ pub(crate) fn compress( let opcode = data.get_opcode(); let base_key = keys.get_base_key(opcode); - if data.get_name() == "PlayerSpawn" { - let name_offset = 610; - for i in 0..32 { - buffer[(IPC_HEADER_SIZE + name_offset + i) as usize] = buffer - [(IPC_HEADER_SIZE + name_offset + i) as usize] - .wrapping_add(base_key); - } - } + scramble_packet( + data.get_name(), + base_key, + &mut buffer[IPC_HEADER_SIZE as usize..], + ); } } diff --git a/src/world/mod.rs b/src/world/mod.rs index da73c5f..d7e6a72 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -32,4 +32,6 @@ mod common; pub use common::{ClientHandle, ClientId, FromServer, ServerHandle, ToServer}; mod scrambler; -pub use scrambler::{OBFUSCATION_ENABLED_MODE, ScramblerKeyGenerator, ScramblerKeys}; +pub use scrambler::{ + OBFUSCATION_ENABLED_MODE, ScramblerKeyGenerator, ScramblerKeys, scramble_packet, +}; diff --git a/src/world/scrambler.rs b/src/world/scrambler.rs index 85ba355..9eeaaf2 100644 --- a/src/world/scrambler.rs +++ b/src/world/scrambler.rs @@ -94,3 +94,89 @@ impl ScramblerKeys { self.keys[(opcode % 3) as usize] } } + +/// Scrambles the packet in just the right ways. +/// Not the greatest thing I ever implemented, it just copies what Unscrambler does. There might be a better way of doing this. +pub fn scramble_packet(opcode_name: &str, base_key: u8, data: &mut [u8]) { + // NOTE: All offsets begin after the IPC segment header + + unsafe { + match opcode_name { + "PlayerSpawn" => { + // content id + *std::mem::transmute::<&mut [u8; 8], &mut u64>( + &mut data[24..32].try_into().unwrap(), + ) += base_key as u64; + // home world + *std::mem::transmute::<&mut [u8; 2], &mut u16>( + &mut data[36..38].try_into().unwrap(), + ) += base_key as u16; + // current world + *std::mem::transmute::<&mut [u8; 2], &mut u16>( + &mut data[38..40].try_into().unwrap(), + ) += base_key as u16; + + // name + let name_offset = 610; + for i in 0..32 { + data[(name_offset + i) as usize] = + data[(name_offset + i) as usize].wrapping_add(base_key); + } + + // equipment + let equip_offset = 556; + let int_key_to_use = base_key as u32 + 118426275; + for i in 0..10 { + let offset = equip_offset + i * 4; + *std::mem::transmute::<&mut [u8; 4], &mut u32>( + &mut data[offset as usize..offset as usize + 4] + .try_into() + .unwrap(), + ) ^= int_key_to_use; + } + } + "NpcSpawn" => { + // TODO: note what these fields are + *std::mem::transmute::<&mut [u8; 4], &mut u32>( + &mut data[80..84].try_into().unwrap(), + ) += base_key as u32; + *std::mem::transmute::<&mut [u8; 4], &mut u32>( + &mut data[84..88].try_into().unwrap(), + ) += base_key as u32; + *std::mem::transmute::<&mut [u8; 4], &mut u32>( + &mut data[88..92].try_into().unwrap(), + ) += base_key as u32; + *std::mem::transmute::<&mut [u8; 4], &mut u32>( + &mut data[96..100].try_into().unwrap(), + ) += base_key as u32; + *std::mem::transmute::<&mut [u8; 4], &mut u32>( + &mut data[100..104].try_into().unwrap(), + ) += base_key as u32; + let weird_const = 0xF1E2D9C8; + *std::mem::transmute::<&mut [u8; 4], &mut u32>( + &mut data[108..112].try_into().unwrap(), + ) ^= weird_const; + + // ops? + /*let op_offset = 168; + for i in 0..30 { + let offset = op_offset + i * 22; + *std::mem::transmute::<&mut [u8; 2], &mut u16>(&mut data[offset as usize..offset as usize + 2].try_into().unwrap()) += base_key as u16; + }*/ + } + "Equip" => { + let op_offset = 36; + let int_key_to_use = base_key as i32 - 863169860; + for i in 0..10 { + let offset = op_offset + i * 4; + *std::mem::transmute::<&mut [u8; 4], &mut i32>( + &mut data[offset as usize..offset as usize + 4] + .try_into() + .unwrap(), + ) ^= int_key_to_use; + } + } + _ => {} + } + } +}