From cdc250fca1c7c105de20fa595b908d85347f04a7 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 8 Mar 2025 16:08:25 -0500 Subject: [PATCH] Begin decrypting packets, add IPC segment type --- src/bin/kawari-lobby.rs | 6 ++-- src/packet.rs | 65 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/bin/kawari-lobby.rs b/src/bin/kawari-lobby.rs index 90aa57c..05c4410 100644 --- a/src/bin/kawari-lobby.rs +++ b/src/bin/kawari-lobby.rs @@ -1,4 +1,4 @@ -use kawari::packet::parse_packet; +use kawari::packet::{parse_packet, State}; use tokio::io::AsyncReadExt; use tokio::net::TcpListener; @@ -14,13 +14,15 @@ async fn main() { let (socket, _) = listener.accept().await.unwrap(); let (mut read, mut write) = tokio::io::split(socket); + let mut state = State { client_key: None }; + tokio::spawn(async move { let mut buf = [0; 2056]; loop { let n = read.read(&mut buf).await.expect("Failed to read data!"); if n != 0 { - parse_packet(&mut write, &buf[..n]).await; + parse_packet(&mut write, &buf[..n], &mut state).await; } } }); diff --git a/src/packet.rs b/src/packet.rs index 1d81899..d780f97 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,6 +1,6 @@ use std::{fs::write, io::Cursor, time::{SystemTime, UNIX_EPOCH}}; -use binrw::{binrw, helpers::until_eof, BinRead, BinWrite}; +use binrw::{binrw, helpers::until_eof, BinRead, BinResult, BinWrite}; use physis::blowfish::Blowfish; use tokio::{io::{AsyncWriteExt, WriteHalf}, net::TcpStream}; @@ -29,7 +29,37 @@ enum ConnectionType { #[binrw] #[derive(Debug, Clone)] +struct IPCSegment { + unk: u32 +} + +#[binrw::parser(reader, endian)] +pub(crate) fn decrypt(size: u32, encryption_key: Option<&[u8]>) -> BinResult +where + for<'a> T: BinRead = ()> + 'a +{ + let Some(encryption_key) = encryption_key else { + panic!("This segment type is encrypted and no key was provided!"); + }; + + let size = size - 16; // 16 = header size + + let mut data = Vec::new(); + data.resize(size as usize, 0x0); + reader.read_exact(&mut data)?; + + let blowfish = Blowfish::new(encryption_key); + let decrypted_data = blowfish.decrypt(&data).unwrap(); + + let mut cursor = Cursor::new(&decrypted_data); + T::read_options(&mut cursor, endian, ()) +} + +#[binrw] +#[br(import(size: u32, encryption_key: Option<&[u8]>))] +#[derive(Debug, Clone)] enum SegmentType { + // Client->Server Packets #[brw(magic = 0x9u32)] InitializeEncryption { #[brw(pad_before = 36)] // empty @@ -41,11 +71,19 @@ enum SegmentType { #[brw(pad_after = 512)] // empty key: [u8; 4], }, + #[brw(magic = 0x3u32)] + IPC { + #[br(parse_with = decrypt, args(size, encryption_key))] + #[bw(ignore)] + data: IPCSegment, + }, + + // Server->Client Packets #[brw(magic = 0x0Au32)] InitializationEncryptionResponse { #[br(count = 0x280)] data: Vec - } + }, } #[binrw] @@ -66,12 +104,14 @@ struct PacketHeader { } #[binrw] +#[br(import(encryption_key: Option<&[u8]>))] #[derive(Debug, Clone)] struct PacketSegment { #[bw(calc = self.calc_size())] size: u32, source_actor: u32, target_actor: u32, + #[br(args(size, encryption_key))] segment_type: SegmentType, } @@ -81,15 +121,17 @@ impl PacketSegment { return header as u32 + match &self.segment_type { SegmentType::InitializeEncryption { .. } => 616, SegmentType::InitializationEncryptionResponse { .. } => 640, + SegmentType::IPC { .. } => todo!(), }; } } #[binrw] +#[br(import(encryption_key: Option<&[u8]>))] #[derive(Debug)] struct Packet { header: PacketHeader, - #[br(count = header.segment_count)] + #[br(count = header.segment_count, args { inner: (encryption_key,) })] segments: Vec, } @@ -143,11 +185,15 @@ async fn send_packet(socket: &mut WriteHalf, segments: &[PacketSegmen .expect("Failed to write packet!"); } -pub async fn parse_packet(socket: &mut WriteHalf, data: &[u8]) { +// temporary +pub struct State { + pub client_key: Option<[u8; 16]> +} + +pub async fn parse_packet(socket: &mut WriteHalf, data: &[u8], state: &mut State) { let mut cursor = Cursor::new(data); - - match Packet::read_le(&mut cursor) { + match Packet::read_le_args(&mut cursor, (state.client_key.as_ref().map(|s: &[u8; 16]| s.as_slice()),)) { Ok(packet) => { println!("{:#?}", packet); @@ -162,9 +208,9 @@ pub async fn parse_packet(socket: &mut WriteHalf, data: &[u8]) { match &segment.segment_type { SegmentType::InitializeEncryption { phrase, key } => { // Generate an encryption key for this client - let client_key = generate_encryption_key(key, phrase); + state.client_key = Some(generate_encryption_key(key, phrase)); - let blowfish = Blowfish::new(&client_key); + let blowfish = Blowfish::new(&state.client_key.unwrap()); let mut data = blowfish.encrypt(&0xE0003C2Au32.to_le_bytes()).unwrap(); data.resize(0x280, 0); @@ -178,6 +224,9 @@ pub async fn parse_packet(socket: &mut WriteHalf, data: &[u8]) { send_packet(socket, &[response_packet]).await; }, SegmentType::InitializationEncryptionResponse { .. } => panic!("The server is recieving a response packet!"), + SegmentType::IPC { .. } => { + // decrypt + }, } }