diff --git a/Cargo.lock b/Cargo.lock index 0077895..b720e2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -197,21 +197,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "diag" -version = "0.1.0" -dependencies = [ - "bytes", - "chrono", - "crc", - "deku", - "env_logger", - "libc", - "log", - "pcap-file", - "thiserror", -] - [[package]] name = "env_logger" version = "0.10.1" @@ -596,6 +581,21 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +[[package]] +name = "wavehunter" +version = "0.1.0" +dependencies = [ + "bytes", + "chrono", + "crc", + "deku", + "env_logger", + "libc", + "log", + "pcap-file", + "thiserror", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 38eabfd..10c1465 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,22 @@ [package] -name = "diag" +name = "wavehunter" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "wavehunter" +path = "src/lib.rs" + +[[bin]] +name = "wavehunter-reader" +path = "src/bin/wavehunter_reader.rs" + +[[bin]] +name = "wavehunter" +path = "src/bin/wavehunter.rs" + [dependencies] bytes = "1.5.0" chrono = "0.4.31" diff --git a/README.md b/README.md index 26a8172..d10ff20 100644 --- a/README.md +++ b/README.md @@ -1 +1,27 @@ +# Wave Hunter + +``` +@@@ @@@ @@@ @@@@@@ @@@ @@@ @@@@@@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@@@@@ @@@@@@@@ @@@@@@@ +@@! @@! @@! @@! @@@ @@! @@@ @@! @@! @@@ @@! @@@ @@!@!@@@ @!! @@! @@! @@@ +@!! !!@ @!@ @!@!@!@! @!@ !@! @!!!:! @!@!@!@! @!@ !@! @!@@!!@! @!! @!!!:! @!@!!@! + !: !!: !! !!: !!! !: .:! !!: !!: !!! !!: !!! !!: !!! !!: !!: !!: :!! + ::.: ::: : : : :: : :: :: : : : :.:: : :: : : : :: :: : : : + +_ _ _ _ _ _ _ _ +)`'-.,_)`'-.,_)`'-.,_)`'-.,_)`'-.,_)`'-.,_)`'-.,_)`'-.,_ + + O . + O ' ' + o ' . + o .' + __________.-' '...___ + .-' ### '''...__ + / a### ## ''--.._ ______ + '. # ######## ' .-' + '-._ ..**********#### ___...---'''\ ' + '-._ __________...---''' \ l + \ | apc '._| + \__; +``` + diag helper binary for the Orbic mobile hotspot. Based on code from [QCSuper](https://github.com/P1sec/QCSuper) diff --git a/src/main.rs b/src/bin/wavehunter.rs similarity index 66% rename from src/main.rs rename to src/bin/wavehunter.rs index 1d56fa4..c0e8b66 100644 --- a/src/main.rs +++ b/src/bin/wavehunter.rs @@ -1,11 +1,7 @@ -mod hdlc; -mod diag; -mod diag_device; -mod log_codes; +use wavehunter::diag_device::{DiagDevice, DiagResult}; +use wavehunter::diag_reader::DiagReader; -use crate::diag_device::DiagDevice; - -fn main() -> diag_device::DiagResult<()> { +fn main() -> DiagResult<()> { // this should eventually be removed for prod env_logger::init(); @@ -14,6 +10,7 @@ fn main() -> diag_device::DiagResult<()> { .write(true) .open("/dev/diag")?; let mut dev = DiagDevice::new(&file)?; + dev.enable_debug_mode("/data/wavehunter-debug")?; dev.config_logs()?; loop { diff --git a/src/bin/wavehunter_reader.rs b/src/bin/wavehunter_reader.rs new file mode 100644 index 0000000..cbb99c1 --- /dev/null +++ b/src/bin/wavehunter_reader.rs @@ -0,0 +1,20 @@ +use wavehunter::debug_file::DebugFileReader; +use wavehunter::diag_reader::DiagReader; +use wavehunter::diag_device::DiagResult; + +fn main() -> DiagResult<()> { + // this should eventually be removed for prod + env_logger::init(); + let args: Vec = std::env::args().collect(); + if args.len() != 2 { + println!("Usage: {} /path/to/debug/file", args[0]); + std::process::exit(1); + } + let mut debug_reader = DebugFileReader::new(&args[1])?; + + loop { + for msg in debug_reader.read_response()? { + println!("msg: {:?}", msg); + } + } +} diff --git a/src/debug_file.rs b/src/debug_file.rs new file mode 100644 index 0000000..3dd2c2a --- /dev/null +++ b/src/debug_file.rs @@ -0,0 +1,50 @@ +use crate::diag_reader::DiagReader; +use crate::diag_device::DiagResult; +use crate::diag::*; + +use deku::prelude::*; +use std::fs::File; +use std::io::Read; + +#[derive(Debug, DekuRead, DekuWrite)] +#[deku(endian = "little")] +pub struct DebugFileBlock<'a> { + pub size: u32, + #[deku(count = "size")] + pub data: &'a [u8], +} + +pub struct DebugFileReader { + file: File, +} + +impl DebugFileReader { + pub fn new

(path: P) -> DiagResult where P: AsRef { + let file = std::fs::File::options() + .read(true) + .open(path)?; + Ok(DebugFileReader { file }) + } +} + + +impl DiagReader for DebugFileReader { + fn get_next_messages_container(&mut self) -> DiagResult { + let mut bytes_read_buf = [0; 4]; + if let Err(e) = self.file.read_exact(&mut bytes_read_buf) { + if e.kind() == std::io::ErrorKind::UnexpectedEof { + println!("reached end of debug file, exiting..."); + std::process::exit(0); + } + return Err(e.into()); + } + let bytes_read = u32::from_le_bytes(bytes_read_buf) as usize; + let mut data = vec![0; bytes_read as usize]; + self.file.read_exact(&mut data)?; + let ((leftover_bytes, _), container) = MessagesContainer::from_bytes((&data, 0))?; + if leftover_bytes.len() > 0 { + println!("warning: {} leftover bytes when parsing MessagesContainer", leftover_bytes.len()); + } + Ok(container) + } +} diff --git a/src/diag.rs b/src/diag.rs index 4eb19c3..fd8136b 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -391,11 +391,4 @@ mod test { }, }); } - - #[test] - fn test_fuck() { - env_logger::init(); - let data = vec![32, 0, 0, 0, 1, 0, 0, 0, 122, 1, 0, 0, 16, 0, 38, 0, 38, 0, 192, 176, 153, 128, 249, 211, 218, 62, 2, 1, 20, 14, 48, 0, 160, 0, 14, 6, 1, 0, 217, 39, 5, 0, 0, 0, 0, 7, 0, 64, 2, 14, 213, 72, 153, 192, 168, 216, 126]; - dbg!(MessagesContainer::from_bytes((&data, 0)).unwrap()); - } } diff --git a/src/diag_device.rs b/src/diag_device.rs index 9989fd3..b697e96 100644 --- a/src/diag_device.rs +++ b/src/diag_device.rs @@ -1,12 +1,13 @@ -use crate::hdlc::{hdlc_encapsulate, hdlc_decapsulate, HdlcError}; +use crate::hdlc::{hdlc_encapsulate, HdlcError}; use crate::diag::{Message, ResponsePayload, Request, LogConfigRequest, LogConfigResponse, build_log_mask_request, RequestContainer, DataType, MessagesContainer}; +use crate::diag_reader::{DiagReader, CRC_CCITT}; +use crate::debug_file::DebugFileBlock; use crate::log_codes; use std::fs::File; -use std::io::Read; +use std::io::{Read, Write}; use std::os::fd::AsRawFd; use thiserror::Error; -use crc::{Crc, Algorithm}; use deku::prelude::*; pub type DiagResult = Result; @@ -29,19 +30,6 @@ pub enum DiagDeviceError { DekuError(#[from] DekuError), } -// this is sorta based on the params qcsuper uses, plus what seems to be used in -// https://github.com/fgsect/scat/blob/f1538b397721df3ab8ba12acd26716abcf21f78b/util.py#L47 -pub const CRC_CCITT_ALG: Algorithm = Algorithm { - poly: 0x1021, - init: 0xffff, - refin: true, - refout: true, - width: 16, - xorout: 0xffff, - check: 0x2189, - residue: 0x0000, -}; - pub const LOG_CODES_FOR_RAW_PACKET_LOGGING: [u32; 11] = [ // Layer 2: log_codes::LOG_GPRS_MAC_SIGNALLING_MESSAGE_C, // 0x5226 @@ -70,9 +58,30 @@ const DIAG_IOCTL_SWITCH_LOGGING: u32 = 7; pub struct DiagDevice<'a> { file: &'a File, + debug_file: Option, read_buf: Vec, use_mdm: i32, - crc: Crc, +} + + + +impl<'a> DiagReader for DiagDevice<'a> { + fn get_next_messages_container(&mut self) -> DiagResult { + let bytes_read = self.file.read(&mut self.read_buf).unwrap(); + if let Some(debug_file) = self.debug_file.as_mut() { + let debug_block = DebugFileBlock { + size: bytes_read as u32, + data: &self.read_buf[0..bytes_read], + }; + let debug_block_bytes = debug_block.to_bytes().unwrap(); + debug_file.write_all(&debug_block_bytes).unwrap(); + } + let ((leftover_bytes, _), container) = MessagesContainer::from_bytes((&self.read_buf[0..bytes_read], 0))?; + if leftover_bytes.len() > 0 { + println!("warning: {} leftover bytes when parsing MessagesContainer", leftover_bytes.len()); + } + Ok(container) + } } impl<'a> DiagDevice<'a> { @@ -85,51 +94,21 @@ impl<'a> DiagDevice<'a> { Ok(DiagDevice { read_buf: vec![0; BUFFER_LEN], file, - crc: Crc::::new(&CRC_CCITT_ALG), + debug_file: None, use_mdm, }) } - fn parse_response_container(&self, container: MessagesContainer) -> DiagResult> { - let mut result = Vec::new(); - for msg in container.messages { - for sub_msg in msg.data.split_inclusive(|&b| b == 0x7e) { - match hdlc_decapsulate(&sub_msg, &self.crc) { - Ok(data) => match Message::from_bytes((&data, 0)) { - Ok(((leftover_bytes, _), res)) => { - if leftover_bytes.len() > 0 { - println!("warning: {} leftover bytes when parsing Message", leftover_bytes.len()); - } - result.push(res); - }, - Err(e) => { - println!("error parsing response: {:?}", e); - println!("{:?}", data); - }, - }, - Err(err) => { - println!("error decapsulating response: {:?}", err); - println!("{:?}", &sub_msg); - } - } - } - } - Ok(result) - } - - pub fn read_response(&mut self) -> DiagResult> { - loop { - let bytes_read = self.file.read(&mut self.read_buf).unwrap(); - let ((leftover_bytes, _), res_container) = MessagesContainer::from_bytes((&self.read_buf[0..bytes_read], 0))?; - if leftover_bytes.len() > 0 { - println!("warning: {} leftover bytes when parsing MessagesContainer", leftover_bytes.len()); - } - if res_container.data_type == DataType::UserSpace { - return self.parse_response_container(res_container); - } else { - println!("skipping non-userspace message...") - } - } + // Creates a file at the given path where all binary output from /dev/diag + // will be recorded. + pub fn enable_debug_mode

(&mut self, path: P) -> DiagResult<()> where P: AsRef { + let debug_file = std::fs::File::options() + .create(true) + .write(true) + .open(path)?; + println!("enabling debug mode, writing debug output to {:?}", debug_file); + self.debug_file = Some(debug_file); + Ok(()) } pub fn write_request(&mut self, req: &Request) -> DiagResult<()> { @@ -137,7 +116,7 @@ impl<'a> DiagDevice<'a> { data_type: DataType::UserSpace, use_mdm: self.use_mdm > 0, mdm_field: -1, - hdlc_encapsulated_request: hdlc_encapsulate(&req.to_bytes().unwrap(), &self.crc), + hdlc_encapsulated_request: hdlc_encapsulate(&req.to_bytes().unwrap(), &CRC_CCITT), }.to_bytes().unwrap(); unsafe { let fd = self.file.as_raw_fd(); diff --git a/src/diag_reader.rs b/src/diag_reader.rs new file mode 100644 index 0000000..00ded53 --- /dev/null +++ b/src/diag_reader.rs @@ -0,0 +1,61 @@ +use crate::{diag::*, hdlc::hdlc_decapsulate}; +use crate::diag_device::DiagResult; + +use crc::{Crc, Algorithm}; +use deku::prelude::*; + +// this is sorta based on the params qcsuper uses, plus what seems to be used in +// https://github.com/fgsect/scat/blob/f1538b397721df3ab8ba12acd26716abcf21f78b/util.py#L47 +pub const CRC_CCITT_ALG: Algorithm = Algorithm { + poly: 0x1021, + init: 0xffff, + refin: true, + refout: true, + width: 16, + xorout: 0xffff, + check: 0x2189, + residue: 0x0000, +}; +pub const CRC_CCITT: Crc = Crc::::new(&CRC_CCITT_ALG); + +pub trait DiagReader { + fn get_next_messages_container(&mut self) -> DiagResult; + + fn read_response(&mut self) -> DiagResult> { + loop { + let container = self.get_next_messages_container()?; + if container.data_type == DataType::UserSpace { + return self.parse_response_container(container); + } else { + println!("skipping non-userspace message...") + } + } + } + + fn parse_response_container(&self, container: MessagesContainer) -> DiagResult> { + let mut result = Vec::new(); + for msg in container.messages { + for sub_msg in msg.data.split_inclusive(|&b| b == 0x7e) { + match hdlc_decapsulate(&sub_msg, &CRC_CCITT) { + Ok(data) => match Message::from_bytes((&data, 0)) { + Ok(((leftover_bytes, _), res)) => { + if leftover_bytes.len() > 0 { + println!("warning: {} leftover bytes when parsing Message", leftover_bytes.len()); + } + result.push(res); + }, + Err(e) => { + println!("error parsing response: {:?}", e); + println!("{:?}", data); + }, + }, + Err(err) => { + println!("error decapsulating response: {:?}", err); + println!("{:?}", &sub_msg); + } + } + } + } + Ok(result) + } +} diff --git a/src/hdlc.rs b/src/hdlc.rs index 78dc663..7813e5b 100644 --- a/src/hdlc.rs +++ b/src/hdlc.rs @@ -87,7 +87,7 @@ mod tests { #[test] fn test_hdlc_encapsulate() { - let crc = Crc::::new(&crate::diag_device::CRC_CCITT_ALG); + let crc = Crc::::new(&crate::diag_reader::CRC_CCITT_ALG); let data = vec![0x01, 0x02, 0x03, 0x04]; let expected = vec![1, 2, 3, 4, 145, 57, 126]; let encapsulated = hdlc_encapsulate(&data, &crc); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e288db4 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,6 @@ +pub mod hdlc; +pub mod diag; +pub mod diag_device; +pub mod diag_reader; +pub mod debug_file; +pub mod log_codes;