mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-04-30 17:39:58 -07:00
implement installer as library and use it in gui
This commit is contained in:
committed by
Markus Unterwaditzer
parent
9e9fe4d392
commit
3b44234ae1
@@ -1,19 +1,29 @@
|
||||
use anyhow::{Context, Error, bail};
|
||||
use anyhow::{Context, Error};
|
||||
use clap::{Parser, Subcommand};
|
||||
use env_logger::Env;
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use anyhow::bail;
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
mod orbic;
|
||||
mod orbic_auth;
|
||||
mod orbic_network;
|
||||
mod output;
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
mod pinephone;
|
||||
mod tmobile;
|
||||
mod tplink;
|
||||
mod util;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
mod uz801;
|
||||
mod wingtech;
|
||||
|
||||
pub static CONFIG_TOML: &str = include_str!("../../dist/config.toml.in");
|
||||
pub static RAYHUNTER_DAEMON_INIT: &str = include_str!("../../dist/scripts/rayhunter_daemon");
|
||||
use crate::output::eprintln;
|
||||
|
||||
static CONFIG_TOML: &str = include_str!("../../dist/config.toml.in");
|
||||
static RAYHUNTER_DAEMON_INIT: &str = include_str!("../../dist/scripts/rayhunter_daemon");
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about)]
|
||||
@@ -27,6 +37,7 @@ struct Args {
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Command {
|
||||
/// Install rayhunter on the Orbic RC400L using the legacy USB+ADB-based installer.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
OrbicUsb(InstallOrbic),
|
||||
/// Install rayhunter on the Orbic RC400L or Moxee Hotspot via network.
|
||||
#[clap(alias = "orbic-network")]
|
||||
@@ -34,8 +45,10 @@ enum Command {
|
||||
/// Install rayhunter on the TMobile TMOHS1.
|
||||
Tmobile(TmobileArgs),
|
||||
/// Install rayhunter on the Uz801.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
Uz801(Uz801Args),
|
||||
/// Install rayhunter on a PinePhone's Quectel modem.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
Pinephone(InstallPinephone),
|
||||
/// Install rayhunter on the TP-Link M7350.
|
||||
Tplink(InstallTpLink),
|
||||
@@ -98,14 +111,18 @@ struct Util {
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum UtilSubCommand {
|
||||
/// Send a serial command to the Orbic.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
Serial(Serial),
|
||||
/// Start an ADB shell
|
||||
#[cfg(not(target_os = "android"))]
|
||||
Shell,
|
||||
/// Root the Tmobile and launch adb.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
TmobileStartAdb(TmobileArgs),
|
||||
/// Root the Tmobile and launch telnetd.
|
||||
TmobileStartTelnet(TmobileArgs),
|
||||
/// Root the Uz801 and launch adb.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
Uz801StartAdb(Uz801Args),
|
||||
/// Root the tplink and launch telnetd.
|
||||
TplinkStartTelnet(TplinkStartTelnet),
|
||||
@@ -114,8 +131,10 @@ enum UtilSubCommand {
|
||||
/// Root the Wingtech and launch adb.
|
||||
WingtechStartAdb(WingtechArgs),
|
||||
/// Unlock the Pinephone's modem and start adb.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
PinephoneStartAdb,
|
||||
/// Lock the Pinephone's modem and stop adb.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
PinephoneStopAdb,
|
||||
/// Root the Orbic and launch telnetd.
|
||||
OrbicStartTelnet(OrbicNetworkArgs),
|
||||
@@ -196,20 +215,24 @@ struct Serial {
|
||||
command: Vec<String>,
|
||||
}
|
||||
|
||||
async fn run() -> Result<(), Error> {
|
||||
async fn run(args: Args) -> Result<(), Error> {
|
||||
env_logger::Builder::from_env(Env::default().default_filter_or("off")).init();
|
||||
let Args { command } = Args::parse();
|
||||
|
||||
match command {
|
||||
match args.command {
|
||||
Command::Tmobile(args) => tmobile::install(args).await.context("Failed to install rayhunter on the Tmobile TMOHS1. Make sure your computer is connected to the hotspot using USB tethering or WiFi.")?,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
Command::Uz801(args) => uz801::install(args).await.context("Failed to install rayhunter on the Uz801. Make sure your computer is connected to the hotspot using USB.")?,
|
||||
Command::Tplink(tplink) => tplink::main_tplink(tplink).await.context("Failed to install rayhunter on the TP-Link M7350. Make sure your computer is connected to the hotspot using USB tethering or WiFi.")?,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
Command::Pinephone(_) => pinephone::install().await
|
||||
.context("Failed to install rayhunter on the Pinephone's Quectel modem")?,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
Command::OrbicUsb(_) => orbic::install().await.context("\nFailed to install rayhunter on the Orbic RC400L (USB installer)")?,
|
||||
Command::Orbic(args) => orbic_network::install(args.admin_ip, args.admin_username, args.admin_password).await.context("\nFailed to install rayhunter on the Orbic RC400L")?,
|
||||
Command::Wingtech(args) => wingtech::install(args).await.context("\nFailed to install rayhunter on the Wingtech CT2MHS01")?,
|
||||
Command::Util(subcommand) => match subcommand.command {
|
||||
Command::Util(subcommand) => {
|
||||
match subcommand.command {
|
||||
#[cfg(not(target_os = "android"))]
|
||||
UtilSubCommand::Serial(serial_cmd) => {
|
||||
if serial_cmd.root {
|
||||
if !serial_cmd.command.is_empty() {
|
||||
@@ -228,9 +251,12 @@ async fn run() -> Result<(), Error> {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
UtilSubCommand::Shell => orbic::shell().await.context("\nFailed to open shell on Orbic RC400L")?,
|
||||
UtilSubCommand::TmobileStartTelnet(args) => wingtech::start_telnet(&args.admin_ip, &args.admin_password).await.context("\nFailed to start telnet on the Tmobile TMOHS1")?,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
UtilSubCommand::TmobileStartAdb(args) => wingtech::start_adb(&args.admin_ip, &args.admin_password).await.context("\nFailed to start adb on the Tmobile TMOHS1")?,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
UtilSubCommand::Uz801StartAdb(args) => uz801::activate_usb_debug(&args.admin_ip).await.context("\nFailed to activate USB debug on the Uz801")?,
|
||||
UtilSubCommand::TplinkStartTelnet(options) => {
|
||||
tplink::start_telnet(&options.admin_ip).await?;
|
||||
@@ -243,19 +269,75 @@ async fn run() -> Result<(), Error> {
|
||||
}
|
||||
UtilSubCommand::WingtechStartTelnet(args) => wingtech::start_telnet(&args.admin_ip, &args.admin_password).await.context("\nFailed to start telnet on the Wingtech CT2MHS01")?,
|
||||
UtilSubCommand::WingtechStartAdb(args) => wingtech::start_adb(&args.admin_ip, &args.admin_password).await.context("\nFailed to start adb on the Wingtech CT2MHS01")?,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
UtilSubCommand::PinephoneStartAdb => pinephone::start_adb().await.context("\nFailed to start adb on the PinePhone's modem")?,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
UtilSubCommand::PinephoneStopAdb => pinephone::stop_adb().await.context("\nFailed to stop adb on the PinePhone's modem")?,
|
||||
UtilSubCommand::OrbicStartTelnet(args) => orbic_network::start_telnet(&args.admin_ip, &args.admin_username, args.admin_password.as_deref()).await.context("\\nFailed to start telnet on the Orbic RC400L")?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
if let Err(e) = run().await {
|
||||
eprintln!("{e:?}");
|
||||
std::process::exit(1);
|
||||
/// Type alias for output callback function
|
||||
pub type OutputCallback = Box<dyn Fn(&str) + Send + Sync>;
|
||||
|
||||
/// Run the installer with CLI arguments and optional output callback
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `args` - Command-line arguments (including program name as `args[0]`)
|
||||
/// * `callback` - Optional function to receive stdout/stderr output
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(())` on success
|
||||
/// * `Err(anyhow::Error)` on failure with full error context
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// use installer;
|
||||
///
|
||||
/// // if the callback is None, stdout/stderr is going to be used
|
||||
/// let result = installer::run_with_callback(
|
||||
/// vec!["installer".to_string(), "orbic-network".to_string(), "--admin-password".to_string(), "12345".to_string()],
|
||||
/// Some(Box::new(|output| {
|
||||
/// print!("{}", output);
|
||||
/// }))
|
||||
/// );
|
||||
/// ```
|
||||
pub fn run_with_callback(args: Vec<String>, callback: Option<OutputCallback>) -> Result<(), Error> {
|
||||
// Set up the callback if provided
|
||||
let _guard;
|
||||
if let Some(cb) = callback {
|
||||
_guard = output::set_output_callback(move |s: &str| cb(s));
|
||||
}
|
||||
|
||||
// Create a Tokio runtime and run the installer
|
||||
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.context("Failed to create Tokio runtime")?
|
||||
.block_on(async {
|
||||
// Parse arguments
|
||||
let parsed_args = Args::try_parse_from(&args).context("Failed to parse arguments")?;
|
||||
|
||||
// Run the installer
|
||||
run(parsed_args).await
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the version of the installer
|
||||
pub fn version() -> &'static str {
|
||||
env!("CARGO_PKG_VERSION")
|
||||
}
|
||||
|
||||
/// Run the CLI installer
|
||||
///
|
||||
/// This function is public so the binary can call it, but library users
|
||||
/// should use the typed functions like `run_with_callback` instead.
|
||||
pub async fn main_cli() -> Result<(), Error> {
|
||||
let args = Args::parse();
|
||||
run(args).await
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::io::stdin;
|
||||
|
||||
use std::io::{ErrorKind, Write};
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -12,7 +12,8 @@ use nusb::transfer::{Control, ControlType, Recipient, RequestBuffer};
|
||||
use sha2::{Digest, Sha256};
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::util::{echo, open_usb_device};
|
||||
use crate::output::{print, println};
|
||||
use crate::util::open_usb_device;
|
||||
use crate::{CONFIG_TOML, RAYHUNTER_DAEMON_INIT};
|
||||
|
||||
pub const ORBIC_NOT_FOUND: &str = r#"No Orbic device found.
|
||||
@@ -54,7 +55,7 @@ const RNDIS_INTERFACE: u8 = 1;
|
||||
#[cfg(target_os = "windows")]
|
||||
async fn confirm() -> Result<bool> {
|
||||
println!("{}", WINDOWS_WARNING);
|
||||
echo!("Do you wish to proceed? Enter 'yes' to install> ");
|
||||
print!("Do you wish to proceed? Enter 'yes' to install> ");
|
||||
let mut input = String::new();
|
||||
stdin().read_line(&mut input)?;
|
||||
Ok(input.trim() == "yes")
|
||||
@@ -75,13 +76,13 @@ pub async fn install() -> Result<()> {
|
||||
}
|
||||
|
||||
let mut adb_device = force_debug_mode().await?;
|
||||
echo!("Installing rootshell... ");
|
||||
print!("Installing rootshell... ");
|
||||
setup_rootshell(&mut adb_device).await?;
|
||||
println!("done");
|
||||
echo!("Installing rayhunter... ");
|
||||
print!("Installing rayhunter... ");
|
||||
let mut adb_device = setup_rayhunter(adb_device).await?;
|
||||
println!("done");
|
||||
echo!("Testing rayhunter... ");
|
||||
print!("Testing rayhunter... ");
|
||||
test_rayhunter(&mut adb_device).await?;
|
||||
println!("done");
|
||||
Ok(())
|
||||
@@ -101,11 +102,11 @@ pub async fn shell() -> Result<()> {
|
||||
async fn force_debug_mode() -> Result<ADBUSBDevice> {
|
||||
println!("Forcing a switch into the debug mode to enable ADB");
|
||||
enable_command_mode()?;
|
||||
echo!("ADB enabled, waiting for reboot... ");
|
||||
print!("ADB enabled, waiting for reboot... ");
|
||||
let mut adb_device = get_adb().await?;
|
||||
adb_setup_serial(&mut adb_device).await?;
|
||||
println!("it's alive!");
|
||||
echo!("Waiting for atfwd_daemon to startup... ");
|
||||
print!("Waiting for atfwd_daemon to startup... ");
|
||||
adb_command(&mut adb_device, &["pgrep", "atfwd_daemon"])?;
|
||||
println!("done");
|
||||
Ok(adb_device)
|
||||
@@ -159,7 +160,7 @@ async fn setup_rayhunter(mut adb_device: ADBUSBDevice) -> Result<ADBUSBDevice> {
|
||||
adb_at_syscmd(&mut adb_device, "chmod 755 /etc/init.d/rayhunter_daemon").await?;
|
||||
adb_at_syscmd(&mut adb_device, "chmod 755 /etc/init.d/misc-daemon").await?;
|
||||
println!("done");
|
||||
echo!("Waiting for reboot... ");
|
||||
print!("Waiting for reboot... ");
|
||||
adb_at_syscmd(&mut adb_device, "shutdown -r -t 1 now").await?;
|
||||
// first wait for shutdown (it can take ~10s)
|
||||
tokio::time::timeout(Duration::from_secs(30), async {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::io::Write;
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
@@ -9,7 +8,8 @@ use serde::Deserialize;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::orbic_auth::{LoginInfo, LoginRequest, LoginResponse, encode_password};
|
||||
use crate::util::{echo, telnet_send_command, telnet_send_file};
|
||||
use crate::output::{eprintln, print, println};
|
||||
use crate::util::{telnet_send_command, telnet_send_file};
|
||||
use crate::{CONFIG_TOML, RAYHUNTER_DAEMON_INIT};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
@@ -128,7 +128,7 @@ pub async fn start_telnet(
|
||||
anyhow::bail!("--admin-password is required");
|
||||
};
|
||||
|
||||
echo!("Logging in and starting telnet... ");
|
||||
print!("Logging in and starting telnet... ");
|
||||
login_and_exploit(admin_ip, admin_username, admin_password).await?;
|
||||
println!("done");
|
||||
|
||||
@@ -154,11 +154,11 @@ pub async fn install(
|
||||
anyhow::bail!("exiting");
|
||||
};
|
||||
|
||||
echo!("Logging in and starting telnet... ");
|
||||
print!("Logging in and starting telnet... ");
|
||||
login_and_exploit(&admin_ip, &admin_username, &admin_password).await?;
|
||||
println!("done");
|
||||
|
||||
echo!("Waiting for telnet to become available... ");
|
||||
print!("Waiting for telnet to become available... ");
|
||||
wait_for_telnet(&admin_ip).await?;
|
||||
println!("done");
|
||||
|
||||
|
||||
112
installer/src/output.rs
Normal file
112
installer/src/output.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
//! Output handling for the installer
|
||||
//!
|
||||
//! This module provides custom print macros that can be intercepted by setting
|
||||
//! a callback function. This is essential for FFI usage where stdout/stderr
|
||||
//! redirection doesn't work reliably (especially on Android).
|
||||
|
||||
use std::io::Write;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// Type for the output callback function
|
||||
type OutputCallbackFn = Box<dyn Fn(&str) + Send + Sync>;
|
||||
|
||||
/// Global output callback storage
|
||||
static OUTPUT_CALLBACK: Mutex<Option<OutputCallbackFn>> = Mutex::new(None);
|
||||
|
||||
/// Set the global output callback
|
||||
///
|
||||
/// All output from `println!` and `eprintln!` will be sent to this callback.
|
||||
/// If no callback is set, output goes to stdout/stderr as normal.
|
||||
///
|
||||
/// Returns a guard that when dropped, resets the callback.
|
||||
pub(crate) fn set_output_callback<F>(callback: F) -> OutputCallbackGuard
|
||||
where
|
||||
F: Fn(&str) + Send + Sync + 'static,
|
||||
{
|
||||
*OUTPUT_CALLBACK.lock().unwrap() = Some(Box::new(callback));
|
||||
OutputCallbackGuard
|
||||
}
|
||||
|
||||
pub struct OutputCallbackGuard;
|
||||
|
||||
impl Drop for OutputCallbackGuard {
|
||||
fn drop(&mut self) {
|
||||
clear_output_callback();
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the global output callback
|
||||
pub(crate) fn clear_output_callback() {
|
||||
*OUTPUT_CALLBACK.lock().unwrap() = None;
|
||||
}
|
||||
|
||||
/// Write a line to the output (either callback or stdout)
|
||||
pub(crate) fn write_output_line(s: &str) {
|
||||
if let Ok(guard) = OUTPUT_CALLBACK.lock()
|
||||
&& let Some(ref callback) = *guard
|
||||
{
|
||||
callback(s);
|
||||
callback("\n");
|
||||
return;
|
||||
}
|
||||
// Fallback to stdout if no callback or lock failed
|
||||
std::println!("{}", s);
|
||||
let _ = std::io::stdout().flush();
|
||||
}
|
||||
|
||||
/// Write an error line to the output (either callback or stderr)
|
||||
pub(crate) fn write_error_line(s: &str) {
|
||||
if let Ok(guard) = OUTPUT_CALLBACK.lock()
|
||||
&& let Some(ref callback) = *guard
|
||||
{
|
||||
callback(s);
|
||||
callback("\n");
|
||||
return;
|
||||
}
|
||||
// Fallback to stderr if no callback or lock failed
|
||||
std::eprintln!("{}", s);
|
||||
let _ = std::io::stderr().flush();
|
||||
}
|
||||
|
||||
/// Write raw output without newline (either callback or stdout)
|
||||
pub(crate) fn write_output_raw(s: &str) {
|
||||
if let Ok(guard) = OUTPUT_CALLBACK.lock()
|
||||
&& let Some(ref callback) = *guard
|
||||
{
|
||||
callback(s);
|
||||
return;
|
||||
}
|
||||
// Fallback to stdout if no callback or lock failed
|
||||
std::print!("{}", s);
|
||||
let _ = std::io::stdout().flush();
|
||||
}
|
||||
|
||||
/// Shadow println! macro to respect the output callback
|
||||
macro_rules! println {
|
||||
() => {
|
||||
$crate::output::write_output_line("")
|
||||
};
|
||||
($($arg:tt)*) => {{
|
||||
$crate::output::write_output_line(&format!($($arg)*))
|
||||
}};
|
||||
}
|
||||
pub(crate) use println;
|
||||
|
||||
/// Shadow eprintln! macro to respect the output callback
|
||||
macro_rules! eprintln {
|
||||
() => {
|
||||
$crate::output::write_error_line("")
|
||||
};
|
||||
($($arg:tt)*) => {{
|
||||
$crate::output::write_error_line(&format!($($arg)*))
|
||||
}};
|
||||
}
|
||||
pub(crate) use eprintln;
|
||||
|
||||
/// Shadow print! macro to respect the output callback
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => {{
|
||||
$crate::output::write_output_raw(&format!($($arg)*))
|
||||
}};
|
||||
}
|
||||
pub(crate) use print;
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -11,7 +10,8 @@ use nusb::transfer::{Control, ControlType, Recipient, RequestBuffer};
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::orbic::test_rayhunter;
|
||||
use crate::util::{echo, open_usb_device};
|
||||
use crate::output::{print, println};
|
||||
use crate::util::open_usb_device;
|
||||
use crate::{CONFIG_TOML, RAYHUNTER_DAEMON_INIT};
|
||||
|
||||
const USB_VENDOR_ID: u16 = 0x2C7C;
|
||||
@@ -19,7 +19,7 @@ const USB_PRODUCT_ID: u16 = 0x125;
|
||||
const USB_INTERFACE_NUMBER: u8 = 2;
|
||||
|
||||
pub async fn install() -> Result<()> {
|
||||
echo!("Unlocking modem ... ");
|
||||
print!("Unlocking modem ... ");
|
||||
start_adb().await?;
|
||||
sleep(Duration::from_secs(3)).await;
|
||||
let mut adb = ADBUSBDevice::new(USB_VENDOR_ID, USB_PRODUCT_ID).unwrap();
|
||||
@@ -54,13 +54,13 @@ pub async fn install() -> Result<()> {
|
||||
adb.run_command(&["shutdown -r -t 1 now"], "exit code 0")?;
|
||||
sleep(Duration::from_secs(30)).await;
|
||||
|
||||
echo!("Unlocking modem ... ");
|
||||
print!("Unlocking modem ... ");
|
||||
start_adb().await?;
|
||||
sleep(Duration::from_secs(3)).await;
|
||||
let mut adb = ADBUSBDevice::new(USB_VENDOR_ID, USB_PRODUCT_ID).unwrap();
|
||||
println!("ok");
|
||||
|
||||
echo!("Testing rayhunter ... ");
|
||||
print!("Testing rayhunter ... ");
|
||||
test_rayhunter(&mut adb).await?;
|
||||
println!("ok");
|
||||
println!("rayhunter is running on the modem. Use adb to access the web interface.");
|
||||
@@ -198,7 +198,7 @@ impl Install for ADBUSBDevice {
|
||||
/// Transfer a file to the modem's filesystem with adb push.
|
||||
/// Validates the file sends successfully to /tmp before overwriting the destination.
|
||||
fn install_file(&mut self, dest: &str, mut payload: &[u8]) -> Result<()> {
|
||||
echo!("Sending file {dest} ... ");
|
||||
print!("Sending file {dest} ... ");
|
||||
let file_name = Path::new(dest)
|
||||
.file_name()
|
||||
.ok_or_else(|| anyhow!("{dest} does not have a file name"))?
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
/// WT_INNER_VERSION=SW_Q89527AA1_V045_M11_TMO_USR_MP
|
||||
/// WT_PRODUCTION_VERSION=TMOHS1_00.05.20
|
||||
/// WT_HARDWARE_VERSION=89527_1_11
|
||||
use std::io::Write;
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
@@ -13,7 +12,8 @@ use anyhow::Result;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::TmobileArgs as Args;
|
||||
use crate::util::{echo, http_ok_every, telnet_send_command, telnet_send_file};
|
||||
use crate::output::{print, println};
|
||||
use crate::util::{http_ok_every, telnet_send_command, telnet_send_file};
|
||||
use crate::wingtech::start_telnet;
|
||||
|
||||
pub async fn install(
|
||||
@@ -26,12 +26,12 @@ pub async fn install(
|
||||
}
|
||||
|
||||
async fn run_install(admin_ip: String, admin_password: String) -> Result<()> {
|
||||
echo!("Starting telnet ... ");
|
||||
print!("Starting telnet ... ");
|
||||
start_telnet(&admin_ip, &admin_password).await?;
|
||||
sleep(Duration::from_millis(200)).await;
|
||||
println!("ok");
|
||||
|
||||
echo!("Connecting via telnet to {admin_ip} ... ");
|
||||
print!("Connecting via telnet to {admin_ip} ... ");
|
||||
let addr = SocketAddr::from_str(&format!("{admin_ip}:23")).unwrap();
|
||||
telnet_send_command(addr, "mkdir -p /data/rayhunter", "exit code 0", true).await?;
|
||||
println!("ok");
|
||||
@@ -96,7 +96,7 @@ async fn run_install(admin_ip: String, admin_password: String) -> Result<()> {
|
||||
telnet_send_command(addr, "reboot", "exit code 0", true).await?;
|
||||
sleep(Duration::from_secs(30)).await;
|
||||
|
||||
echo!("Testing rayhunter ... ");
|
||||
print!("Testing rayhunter ... ");
|
||||
let max_failures = 10;
|
||||
http_ok_every(
|
||||
format!("http://{admin_ip}:8080/index.html"),
|
||||
|
||||
@@ -18,6 +18,7 @@ use serde::Deserialize;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::InstallTpLink;
|
||||
use crate::output::println;
|
||||
use crate::util::{telnet_send_command, telnet_send_file};
|
||||
|
||||
type HttpProxyClient = hyper_util::client::legacy::Client<HttpConnector, Body>;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::io::Write;
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
@@ -10,13 +9,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::time::{sleep, timeout};
|
||||
|
||||
macro_rules! echo {
|
||||
($($arg:tt)*) => {
|
||||
print!($($arg)*);
|
||||
let _ = std::io::stdout().flush();
|
||||
};
|
||||
}
|
||||
pub(crate) use echo;
|
||||
use crate::output::{print, println};
|
||||
|
||||
pub async fn telnet_send_command_with_output(
|
||||
addr: SocketAddr,
|
||||
@@ -91,7 +84,7 @@ pub async fn telnet_send_file(
|
||||
payload: &[u8],
|
||||
wait_for_prompt: bool,
|
||||
) -> Result<()> {
|
||||
echo!("Sending file {filename}... ");
|
||||
print!("Sending file {filename} ... ");
|
||||
let nc_output = {
|
||||
let filename = filename.to_owned();
|
||||
let handle = tokio::spawn(async move {
|
||||
@@ -122,7 +115,7 @@ pub async fn telnet_send_file(
|
||||
break;
|
||||
}
|
||||
|
||||
echo!("attempt {attempts}... ");
|
||||
print!("attempt {attempts}... ");
|
||||
}
|
||||
|
||||
{
|
||||
@@ -216,6 +209,7 @@ pub async fn http_ok_every(
|
||||
}
|
||||
|
||||
/// General function to open a USB device
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub fn open_usb_device(vid: u16, pid: u16) -> Result<Option<Device>> {
|
||||
let devices = match nusb::list_devices() {
|
||||
Ok(d) => d,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
/// Installer for the Uz801 hotspot.
|
||||
///
|
||||
@@ -15,30 +14,30 @@ use md5::compute as md5_compute;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::Uz801Args as Args;
|
||||
use crate::util::echo;
|
||||
use crate::output::{print, println};
|
||||
|
||||
pub async fn install(Args { admin_ip }: Args) -> Result<()> {
|
||||
run_install(admin_ip).await
|
||||
}
|
||||
|
||||
async fn run_install(admin_ip: String) -> Result<()> {
|
||||
echo!("Activating USB debugging backdoor... ");
|
||||
print!("Activating USB debugging backdoor... ");
|
||||
activate_usb_debug(&admin_ip).await?;
|
||||
println!("ok");
|
||||
|
||||
echo!("Waiting for device reboot and ADB connection... ");
|
||||
print!("Waiting for device reboot and ADB connection... ");
|
||||
let mut adb_device = wait_for_adb().await?;
|
||||
println!("ok");
|
||||
|
||||
echo!("Installing rayhunter files... ");
|
||||
print!("Installing rayhunter files... ");
|
||||
install_rayhunter_files(&mut adb_device).await?;
|
||||
println!("ok");
|
||||
|
||||
echo!("Modifying startup script... ");
|
||||
print!("Modifying startup script... ");
|
||||
modify_startup_script(&mut adb_device).await?;
|
||||
println!("ok");
|
||||
|
||||
echo!("Rebooting the device... ");
|
||||
print!("Rebooting the device... ");
|
||||
let _ = adb_device.reboot(adb_client::RebootType::System);
|
||||
println!("ok");
|
||||
|
||||
@@ -55,7 +54,7 @@ pub async fn activate_usb_debug(admin_ip: &str) -> Result<()> {
|
||||
let origin = format!("http://{admin_ip}");
|
||||
|
||||
// Check if device is online
|
||||
echo!("Checking if device is online... ");
|
||||
print!("Checking if device is online... ");
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(5))
|
||||
.build()?;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
/// WT_INNER_VERSION=SW_Q89323AA1_V057_M10_CRICKET_USR_MP
|
||||
/// WT_PRODUCTION_VERSION=CT2MHS01_0.04.55
|
||||
/// WT_HARDWARE_VERSION=89323_1_20
|
||||
use std::io::Write;
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
@@ -19,7 +18,8 @@ use serde::Deserialize;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::WingtechArgs as Args;
|
||||
use crate::util::{echo, http_ok_every, telnet_send_command, telnet_send_file};
|
||||
use crate::output::{print, println};
|
||||
use crate::util::{http_ok_every, telnet_send_command, telnet_send_file};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct LoginResponse {
|
||||
@@ -89,11 +89,11 @@ pub async fn run_command(admin_ip: &str, admin_password: &str, cmd: &str) -> Res
|
||||
}
|
||||
|
||||
async fn wingtech_run_install(admin_ip: String, admin_password: String) -> Result<()> {
|
||||
echo!("Starting telnet ... ");
|
||||
print!("Starting telnet ... ");
|
||||
start_telnet(&admin_ip, &admin_password).await?;
|
||||
println!("ok");
|
||||
|
||||
echo!("Connecting via telnet to {admin_ip} ... ");
|
||||
print!("Connecting via telnet to {admin_ip} ... ");
|
||||
let addr = SocketAddr::from_str(&format!("{admin_ip}:23")).unwrap();
|
||||
telnet_send_command(addr, "mkdir -p /data/rayhunter", "exit code 0", true).await?;
|
||||
println!("ok");
|
||||
@@ -149,7 +149,7 @@ async fn wingtech_run_install(admin_ip: String, admin_password: String) -> Resul
|
||||
telnet_send_command(addr, "shutdown -r -t 1 now", "exit code 0", true).await?;
|
||||
sleep(Duration::from_secs(30)).await;
|
||||
|
||||
echo!("Testing rayhunter ... ");
|
||||
print!("Testing rayhunter ... ");
|
||||
let max_failures = 10;
|
||||
http_ok_every(
|
||||
format!("http://{admin_ip}:8080/index.html"),
|
||||
|
||||
Reference in New Issue
Block a user