MacOS stuff

This commit is contained in:
Michael Wain 2025-02-11 05:08:05 +03:00
parent 39d9e14ddb
commit 8c51b1c20f
8 changed files with 126 additions and 79 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

9
Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "Inflector"
@ -753,9 +753,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.3"
version = "1.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
dependencies = [
"jobserver",
"libc",
@ -1617,12 +1617,11 @@ name = "frida_core"
version = "0.2.0"
dependencies = [
"base64 0.22.1",
"cc",
"chrono",
"filedescriptor",
"futures",
"libc",
"log",
"nix",
"rand",
"serde",
"serde_derive",

View File

@ -205,10 +205,18 @@ pub mod desktop {
use log::info;
use tokio::net::UdpSocket;
#[cfg(target_os = "linux")]
#[cfg(any(target_os = "linux", target_os = "macos"))]
use regex::Regex;
fn cmd(cmd: &str, args: &[&str]) -> String {
let ecode = std::process::Command::new(cmd)
.args(args)
.output();
assert!(ecode.is_ok(), "Failed to execte {}", cmd);
std::str::from_utf8(&ecode.as_ref().unwrap().stdout).unwrap().to_string()
}
#[cfg(target_os = "linux")]
fn configure_routes(endpoint_ip: &str) {
let mut if_out = std::process::Command::new("ip")
@ -306,6 +314,37 @@ pub mod desktop {
}
}
#[cfg(target_os = "macos")]
fn configure_routes(endpoint_ip: &str) {
let mut if_out = cmd("route", &["-n", "get", "default"]);
let r = std::str::from_utf8(&if_out.as_bytes()).unwrap();
let mut gateway = None;
let mut if_name = None;
let ui = r.find("gateway: ").unwrap() + 9;
let s = &r[ui..];
let ei = s.find("\n").unwrap();
gateway = Some(&s[..ei]);
let ui = r.find("interface: ").unwrap() + 11;
let s = &r[ui..];
let ei = s.find("\n").unwrap();
if_name = Some(&s[..ei]);
info!("Main interface: {:?}", &if_name.unwrap());
let inter_name = if_name.unwrap();
info!("Main network interface: {:?}", &gateway.unwrap());
cmd("route", &["add", "-host", endpoint_ip, &gateway.unwrap()]);
cmd("route", &["change", "default", "-interface", "utun3"]); // todo: change that
cmd("route", &["add", "-host", endpoint_ip, &gateway.unwrap()]);
}
pub struct DesktopClient {
pub client_config: ClientConfiguration
}
@ -330,12 +369,15 @@ pub mod desktop {
let mut client = CoreVpnClient{ client_config: self.client_config.clone(), close_token: tokio_util::sync::CancellationToken::new()};
info!("Platform specific code");
#[cfg(target_os = "linux")]
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
let s_a: std::net::SocketAddr = self.client_config.server.endpoint.parse().unwrap();
configure_routes(&s_a.ip().to_string());
}
#[cfg(target_os = "macos")]
sock.connect(&self.client_config.server.endpoint).await.unwrap();
client.start(sock, dev_reader, dev_writer, mtu).await;
}
}

View File

@ -25,12 +25,11 @@ tokio = { workspace = true }
[target.'cfg(target_os="windows")'.dependencies]
wintun = "0.5.0"
[target.'cfg(target_os="macos")'.dependencies]
nix = { version = "0.29.0", features = ["socket"] }
[target.'cfg(target_os="linux")'.dependencies]
tokio-tun = "0.12.1"
[target.'cfg(target_os="android")'.dependencies]
libc = "0.2"
filedescriptor = "0.8.2"
filedescriptor = "0.8.2"
[target.'cfg(target_os="macos")'.build-dependencies]
cc = "1.2.13"

7
frida_core/build.rs Normal file
View File

@ -0,0 +1,7 @@
use cc;
fn main() {
if cfg!(target_os = "macos") {
cc::Build::new().file("src/c/utun.c").compile("utun");
}
}

View File

@ -1,4 +1,3 @@
//use tokio::fs::File;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use std::error::Error;
use std::os::fd::FromRawFd;
@ -6,7 +5,6 @@ use std::os::fd::FromRawFd;
use std::fs::File;
use std::io::{Write, Read};
use libc::fdopen;
use std::ffi::CString;
pub fn create(cfg: i32) -> (DeviceReader, DeviceWriter) {

43
frida_core/src/c/utun.c Normal file
View File

@ -0,0 +1,43 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/kern_control.h>
#include <net/if_utun.h>
#include <sys/ioctl.h>
#include <sys/kern_event.h>
int32_t open_utun(uint64_t num) {
int err;
int fd;
struct sockaddr_ctl addr;
struct ctl_info info;
fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (fd < 0) {
return fd;
}
memset(&info, 0, sizeof (info));
strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME));
err = ioctl(fd, CTLIOCGINFO, &info);
if (err < 0) {
close(fd);
return err;
}
addr.sc_id = info.ctl_id;
addr.sc_len = sizeof(addr);
addr.sc_family = AF_SYSTEM;
addr.ss_sysaddr = AF_SYS_CONTROL;
addr.sc_unit = num + 1; // utunX where X is sc.sc_unit -1
err = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if (err < 0) {
// this utun is in use
close(fd);
return err;
}
return fd;
}

View File

@ -3,80 +3,39 @@ use std::{ffi::CString, process::Command};
use std::sync::Arc;
use std::error::Error;
use log::info;
use nix::errno::Errno;
use nix::libc::{connect, sockaddr_ctl, CTLIOCGINFO};
use nix::sys::socket::{SockaddrLike, SockaddrStorage, UnixAddr};
use nix::{libc::{ctl_info, PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL}, sys::socket::{socket, AddressFamily, SockFlag, SockProtocol, SockType, sockaddr}};
use tokio::fs::File;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use crate::device::AbstractDevice;
fn cmd(cmd: &str, args: &[&str]) {
let ecode = Command::new("ip")
extern "C" {
fn open_utun(num: u64) -> i32;
}
fn cmd(cmd: &str, args: &[&str]) -> String {
let ecode = Command::new(cmd)
.args(args)
.spawn()
.unwrap()
.wait()
.unwrap();
assert!(ecode.success(), "Failed to execte {}", cmd);
.output();
assert!(ecode.is_ok(), "Failed to execte {}", cmd);
std::str::from_utf8(&ecode.as_ref().unwrap().stdout).unwrap().to_string()
}
fn get_utun() -> (i32, String) {
for utun_n in 0..255 {
let fd = unsafe { open_utun(utun_n) };
if fd >= 0 {
let name = format!("utun{}", utun_n);
return (fd, name);
}
}
panic!("{}", std::io::Error::last_os_error())
}
pub fn create(cfg: AbstractDevice) -> (DeviceReader, DeviceWriter) {
let fd = socket(
AddressFamily::System,
SockType::Datagram,
SockFlag::empty(),
Some(SockProtocol::KextControl)
);
if let Err(e) = fd {
panic!("Unable to open socket! Error: {:?}", e);
}
let fd = fd.unwrap();
let mut info: ctl_info = unsafe { std::mem::zeroed() };
let ctl_name = CString::new("com.apple.net.utun_control").unwrap();
ctl_name.as_bytes_with_nul()
.iter()
.enumerate()
.for_each(|(i, &c)| info.ctl_name[i] = c as i8);
if unsafe { nix::libc::ioctl(fd.as_raw_fd(), CTLIOCGINFO, &mut info) } < 0 {
let err = Errno::last();
panic!("ioctl CTLIOCGINFO failed: {}", err);
}
let mut sc = sockaddr_ctl {
sc_len: std::mem::size_of::<sockaddr_ctl>() as u8,
sc_family: nix::libc::AF_SYSTEM as u8,
ss_sysaddr: nix::libc::AF_SYS_CONTROL as u16,
sc_id: info.ctl_id,
sc_unit: 0,
sc_reserved: [0; 5]
};
let asc = &sc as *const sockaddr_ctl as *const sockaddr;
let f = unsafe { connect(fd.as_raw_fd(), asc, size_of::<sockaddr_ctl>() as u32 ) };
info!("utun interface created successfully, fd: {:?}", f);
let mut reader = unsafe { File::from_raw_fd(f) };
let mut writer = unsafe { File::from_raw_fd(f) };
let mut address = cfg.address.unwrap().to_string();
address.push_str("/24");
/*
cmd("ip", &["addr", "add", "dev", iface.name(), &address]);
cmd("ip", &["link", "set", "up", "dev", iface.name()]);
let iface = Arc::new(iface);
let writer = Arc::clone(&iface);
let reader = Arc::clone(&iface);*/
let (fd, if_name) = get_utun();
let reader = unsafe { File::from_raw_fd(fd) };
let writer = unsafe { File::from_raw_fd(fd) };
cmd("ifconfig", &[&if_name, &cfg.address.unwrap().to_string(), &cfg.destination.unwrap().to_string(), "netmask", &cfg.netmask.unwrap().to_string(), "up"]);
(DeviceReader {reader}, DeviceWriter {writer})
}