Personal commit
This commit is contained in:
parent
ba567d1bba
commit
bdaa48defd
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.idea/
|
||||
target/
|
||||
Cargo.lock
|
27
Cargo.toml
Normal file
27
Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"app",
|
||||
"shellcode",
|
||||
"codeloader",
|
||||
"shellcode-util",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
region = "3.0.2"
|
||||
utf16_lit = "2.0.2"
|
||||
|
||||
[workspace.dependencies.windows-sys]
|
||||
version = "0.59.0"
|
||||
features = [
|
||||
"Win32",
|
||||
"Win32_Foundation",
|
||||
"Win32_System",
|
||||
"Win32_System_Diagnostics",
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
"Win32_System_Kernel",
|
||||
"Win32_System_SystemInformation",
|
||||
"Win32_System_SystemServices",
|
||||
"Win32_System_Threading",
|
||||
"Win32_System_WindowsProgramming"
|
||||
]
|
9
app/Cargo.toml
Normal file
9
app/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
shellcode-util = { path = "../shellcode-util" }
|
||||
utf16_lit = { workspace = true }
|
||||
windows-sys = { workspace = true }
|
57
app/src/main.rs
Normal file
57
app/src/main.rs
Normal file
@ -0,0 +1,57 @@
|
||||
extern crate core;
|
||||
|
||||
use core::{ffi::c_void, mem, ptr};
|
||||
use shellcode_util::{get_module_handle_from_peb, get_procedure_from_edt};
|
||||
use utf16_lit::utf16;
|
||||
use windows_sys::{
|
||||
core::PCSTR,
|
||||
Win32::Foundation::{BOOL, HANDLE, HMODULE, HWND},
|
||||
};
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
unsafe { shellcode() }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn shellcode() {
|
||||
// Initial Imports
|
||||
let kernel32 = get_module_handle_from_peb(&utf16!("KERNEL32.DLL")).unwrap();
|
||||
let LoadLibraryA: extern "system" fn(PCSTR) -> HMODULE =
|
||||
get_procedure_from_edt(kernel32, "LoadLibraryA\0").unwrap();
|
||||
let GetProcAddress: extern "system" fn(HMODULE, PCSTR) -> *const () =
|
||||
get_procedure_from_edt(kernel32, "GetProcAddress\0").unwrap();
|
||||
|
||||
// Console output
|
||||
let GetStdHandle: extern "system" fn(u32) -> HANDLE =
|
||||
mem::transmute(GetProcAddress(kernel32, "GetStdHandle\0".as_ptr()));
|
||||
let output_handle = GetStdHandle(u32::MAX - 11);
|
||||
let WriteConsoleA: extern "system" fn(HANDLE, PCSTR, u32, *mut u32, *mut c_void) -> BOOL =
|
||||
mem::transmute(GetProcAddress(kernel32, "WriteConsoleA\0".as_ptr()));
|
||||
|
||||
let text = "Hello from Console!\n\0";
|
||||
WriteConsoleA(
|
||||
output_handle,
|
||||
text.as_ptr(),
|
||||
text.len() as u32,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
);
|
||||
|
||||
// Messagebox
|
||||
let user32 = LoadLibraryA("user32.dll\0".as_ptr());
|
||||
let MessageBoxA: extern "system" fn(HWND, PCSTR, PCSTR, u32) -> i32 =
|
||||
mem::transmute(GetProcAddress(user32, "MessageBoxA\0".as_ptr()));
|
||||
|
||||
let text = "Hello World!\0";
|
||||
MessageBoxA(ptr::null_mut(), text.as_ptr(), text.as_ptr(), 0);
|
||||
|
||||
let text = "Bye World\0";
|
||||
MessageBoxA(ptr::null_mut(), text.as_ptr(), text.as_ptr(), 0);
|
||||
|
||||
// Exit
|
||||
let ExitProcess: extern "system" fn(u32) =
|
||||
mem::transmute(GetProcAddress(kernel32, "ExitProcess\0".as_ptr()));
|
||||
ExitProcess(5);
|
||||
}
|
5
codeloader/.cargo/config.toml
Normal file
5
codeloader/.cargo/config.toml
Normal file
@ -0,0 +1,5 @@
|
||||
[build]
|
||||
target = "i686-pc-windows-msvc"
|
||||
|
||||
[alias]
|
||||
runcode = "run -- ../target/i686-unknown-none/release/code.bin"
|
7
codeloader/Cargo.toml
Normal file
7
codeloader/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "codeloader"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
region = { workspace = true }
|
20
codeloader/src/main.rs
Normal file
20
codeloader/src/main.rs
Normal file
@ -0,0 +1,20 @@
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + 'static>>;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let file = std::env::args().nth(1).unwrap_or("code.bin".to_string());
|
||||
|
||||
let code = std::fs::read(file)?;
|
||||
|
||||
let code: extern "C" fn() = unsafe {
|
||||
region::protect(
|
||||
code.as_ptr(),
|
||||
code.len(),
|
||||
region::Protection::READ_WRITE_EXECUTE,
|
||||
)?;
|
||||
std::mem::transmute(code.as_ptr())
|
||||
};
|
||||
|
||||
code();
|
||||
|
||||
Ok(())
|
||||
}
|
8
shellcode-util/Cargo.toml
Normal file
8
shellcode-util/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "shellcode-util"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
utf16_lit = { workspace = true }
|
||||
windows-sys = {workspace = true }
|
128
shellcode-util/src/lib.rs
Normal file
128
shellcode-util/src/lib.rs
Normal file
@ -0,0 +1,128 @@
|
||||
#![no_std]
|
||||
#![feature(core_intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use core::{arch::asm, ffi::CStr, intrinsics, slice};
|
||||
use windows_sys::{
|
||||
core::PCSTR,
|
||||
Win32::{
|
||||
Foundation::{HMODULE, UNICODE_STRING},
|
||||
System::{
|
||||
Diagnostics::Debug::{
|
||||
IMAGE_DIRECTORY_ENTRY_EXPORT, IMAGE_NT_HEADERS32, IMAGE_NT_HEADERS64,
|
||||
},
|
||||
SystemServices::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY},
|
||||
Threading::TEB,
|
||||
WindowsProgramming::LDR_DATA_TABLE_ENTRY,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub unsafe fn get_module_handle_from_peb(module_name: &[u16]) -> Option<HMODULE> {
|
||||
// Start at the top boys
|
||||
let mut teb: *mut TEB;
|
||||
#[cfg(target_arch = "x86")]
|
||||
asm!(
|
||||
"mov {}, fs:[0x18]",
|
||||
out(reg) teb
|
||||
);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
asm!(
|
||||
"mov {}, gs:[0x30]",
|
||||
out(reg) teb
|
||||
);
|
||||
|
||||
// I will dereference every pointer
|
||||
let teb = *teb;
|
||||
let peb = *(teb.ProcessEnvironmentBlock);
|
||||
let ldr_data = *(peb.Ldr);
|
||||
|
||||
// Hidden fields of PEB_LDR_DATA and LDR_DATA_TABLE_ENTRY abound
|
||||
// Reserved2[0] = SsHandle, Reserved[1] = InLoadOrderLinks.Flink, Reserved[2] = InLoadOrderLinks.Blink
|
||||
let mut module_list = *(ldr_data.Reserved2[1] as *mut LDR_DATA_TABLE_ENTRY);
|
||||
|
||||
while !module_list.DllBase.is_null() {
|
||||
// BaseDllName
|
||||
let base_dll_name = *(module_list.Reserved4.as_ptr() as *mut UNICODE_STRING);
|
||||
let base_dll_name = slice::from_raw_parts(
|
||||
base_dll_name.Buffer,
|
||||
base_dll_name.Length as usize / size_of::<u16>(),
|
||||
);
|
||||
|
||||
if module_name == base_dll_name {
|
||||
return Some(module_list.DllBase as HMODULE);
|
||||
}
|
||||
|
||||
// Reserved1[0] = InLoadOrderLinks.Flink, Reserved1[1] = InLoadOrderLinks.Blink
|
||||
module_list = *(module_list.Reserved1[0] as *mut LDR_DATA_TABLE_ENTRY);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub unsafe fn get_procedure_from_edt<F>(module: HMODULE, proc_name: &str) -> Option<F> {
|
||||
let module = module as usize;
|
||||
let proc_name = CStr::from_ptr(proc_name.as_ptr() as *const _);
|
||||
|
||||
let dos_headers = *(module as *const IMAGE_DOS_HEADER);
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
let nt_headers = *((module + dos_headers.e_lfanew as usize) as *const IMAGE_NT_HEADERS32);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let nt_headers = *((module + dos_headers.e_lfanew as usize) as *const IMAGE_NT_HEADERS64);
|
||||
|
||||
let export_directory = *((module
|
||||
+ nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT as usize]
|
||||
.VirtualAddress as usize)
|
||||
as *const IMAGE_EXPORT_DIRECTORY);
|
||||
|
||||
let functions_table_ptr =
|
||||
(module + export_directory.AddressOfFunctions as usize) as *const usize;
|
||||
let names_table_ptr = (module + export_directory.AddressOfNames as usize) as *const usize;
|
||||
let ordinals_table_ptr =
|
||||
(module + export_directory.AddressOfNameOrdinals as usize) as *const u16;
|
||||
|
||||
let functions_table = slice::from_raw_parts(
|
||||
functions_table_ptr,
|
||||
export_directory.NumberOfFunctions as usize,
|
||||
);
|
||||
let names_table =
|
||||
slice::from_raw_parts(names_table_ptr, export_directory.NumberOfNames as usize);
|
||||
let ordinals_table =
|
||||
slice::from_raw_parts(ordinals_table_ptr, export_directory.NumberOfNames as usize);
|
||||
|
||||
for i in 0..names_table.len() {
|
||||
let name = CStr::from_ptr((module + names_table[i]) as *const _);
|
||||
let ordinal = ordinals_table[i];
|
||||
let address = functions_table[ordinal as usize];
|
||||
|
||||
if name == proc_name {
|
||||
return Some(intrinsics::transmute_unchecked(module + address));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use utf16_lit::utf16;
|
||||
|
||||
fn get_module_test() {
|
||||
let module = unsafe { get_module_handle_from_peb(&utf16!("KERNEL32.DLL")) };
|
||||
assert!(!module.is_some());
|
||||
}
|
||||
|
||||
fn get_procedure_test() {
|
||||
let module = unsafe { get_module_handle_from_peb(&utf16!("KERNEL32.DLL")) };
|
||||
assert!(module.is_some());
|
||||
|
||||
let procedure = unsafe {
|
||||
get_procedure_from_edt::<extern "system" fn() -> u32>(module.unwrap(), "GetProcessId\0")
|
||||
};
|
||||
assert!(procedure.is_some());
|
||||
|
||||
let procedure = procedure.unwrap();
|
||||
assert_ne!(procedure(), 0)
|
||||
}
|
||||
}
|
29
shellcode.ld
Normal file
29
shellcode.ld
Normal file
@ -0,0 +1,29 @@
|
||||
/* has a header still? objcopy -O binary output is accurate */
|
||||
/* OUTPUT_FORMAT("binary") */
|
||||
|
||||
ENTRY(_start);
|
||||
SECTIONS
|
||||
{
|
||||
. = SIZEOF_HEADERS;
|
||||
.text :
|
||||
{
|
||||
*(.text._start)
|
||||
*(.text .text.*)
|
||||
*(.rodata .rodata.*)
|
||||
|
||||
}
|
||||
.data :
|
||||
{
|
||||
*(.got .got.*)
|
||||
*(.data .data.*)
|
||||
*(.bss .bss.*)
|
||||
}
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment)
|
||||
*(.debug_frame)
|
||||
*(.interp)
|
||||
*(.note .note.*)
|
||||
}
|
||||
}
|
22
shellcode/.cargo/config.toml
Normal file
22
shellcode/.cargo/config.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[build]
|
||||
target = "i686-unknown-none.json"
|
||||
rustflags = [
|
||||
"-Z", "no-unique-section-names=yes",
|
||||
"-C", "link-args=--script=shellcode.ld --build-id=none"
|
||||
]
|
||||
|
||||
[unstable]
|
||||
build-std-features = ["compiler-builtins-mem"]
|
||||
build-std = ["core", "compiler_builtins", "alloc"]
|
||||
trim-paths = true
|
||||
|
||||
[profile.release]
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
strip = true
|
||||
lto = "fat"
|
||||
opt-level = "z"
|
||||
panic = "abort"
|
||||
trim-paths = "all"
|
||||
|
15
shellcode/Cargo.toml
Normal file
15
shellcode/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
cargo-features = ["different-binary-name"]
|
||||
|
||||
[package]
|
||||
name = "code"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "code"
|
||||
filename = "code.bin"
|
||||
|
||||
[dependencies]
|
||||
shellcode-util = { path = "../shellcode-util" }
|
||||
utf16_lit = { workspace = true }
|
||||
windows-sys = { workspace = true }
|
32
shellcode/i686-unknown-none.json
Normal file
32
shellcode/i686-unknown-none.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"arch": "x86",
|
||||
"code-model": "kernel",
|
||||
"cpu": "i686",
|
||||
"crt-objects-fallback": "false",
|
||||
"data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
|
||||
"disable-redzone": true,
|
||||
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "gnu-lld",
|
||||
"llvm-target": "i686-unknown-none-elf",
|
||||
"max-atomic-width": 32,
|
||||
"metadata": {
|
||||
"description": "Freestanding/bare-metal i686 softfloat",
|
||||
"host_tools": false,
|
||||
"std": false,
|
||||
"tier": 2
|
||||
},
|
||||
"panic-strategy": "abort",
|
||||
"plt-by-default": false,
|
||||
"position-independent-executables": true,
|
||||
"relro-level": "full",
|
||||
"stack-probes": {
|
||||
"kind": "inline"
|
||||
},
|
||||
"static-position-independent-executables": true,
|
||||
"supported-sanitizers": [
|
||||
"kcfi",
|
||||
"kernel-address"
|
||||
],
|
||||
"target-pointer-width": "32"
|
||||
}
|
62
shellcode/src/main.rs
Normal file
62
shellcode/src/main.rs
Normal file
@ -0,0 +1,62 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
extern crate core;
|
||||
|
||||
use core::{
|
||||
arch::asm,
|
||||
ffi::c_void,
|
||||
mem,
|
||||
ptr
|
||||
};
|
||||
use shellcode_util::{get_module_handle_from_peb, get_procedure_from_edt};
|
||||
use utf16_lit::utf16;
|
||||
use windows_sys::{
|
||||
core::PCSTR,
|
||||
Win32::Foundation::{BOOL, HANDLE, HMODULE, HWND},
|
||||
};
|
||||
|
||||
#[panic_handler]
|
||||
pub fn panic(_panic: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
// Always ensure _start() is at beginning of .text, despite what the linker thinks it should do.
|
||||
// Placed at top of .text section in shellcode.ld, may not be needed since wildcard matches alphabetically
|
||||
#[no_mangle]
|
||||
#[link_section = ".text._start"]
|
||||
unsafe extern "C" fn _start() {
|
||||
let kernel32 = get_module_handle_from_peb(&utf16!("KERNEL32.DLL")).unwrap();
|
||||
let LoadLibraryA: extern "system" fn(PCSTR) -> HMODULE =
|
||||
get_procedure_from_edt(kernel32, "LoadLibraryA\0").unwrap();
|
||||
let GetProcAddress: extern "system" fn(HMODULE, PCSTR) -> *const () =
|
||||
get_procedure_from_edt(kernel32, "GetProcAddress\0").unwrap();
|
||||
|
||||
let user32 = LoadLibraryA("user32.dll\0".as_ptr());
|
||||
let MessageBoxA: extern "system" fn(HWND, PCSTR, PCSTR, u32) -> i32 =
|
||||
mem::transmute(GetProcAddress(user32, "MessageBoxA\0".as_ptr()));
|
||||
|
||||
let GetStdHandle: extern "system" fn(u32) -> HANDLE =
|
||||
mem::transmute(GetProcAddress(kernel32, "GetStdHandle\0".as_ptr()));
|
||||
let output_handle = GetStdHandle(u32::MAX - 11);
|
||||
let WriteConsoleA: extern "system" fn(HANDLE, PCSTR, u32, *mut u32, *mut c_void) -> BOOL =
|
||||
mem::transmute(GetProcAddress(kernel32, "WriteConsoleA\0".as_ptr()));
|
||||
|
||||
let text = "Hello from Console!\n\0";
|
||||
WriteConsoleA(
|
||||
output_handle,
|
||||
text.as_ptr(),
|
||||
text.len() as u32,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
);
|
||||
|
||||
let text1 = "Hello World!\0";
|
||||
MessageBoxA(ptr::null_mut(), text1.as_ptr(), text1.as_ptr(), 0);
|
||||
|
||||
let text2 = "Bye World\0";
|
||||
MessageBoxA(ptr::null_mut(), text2.as_ptr(), text2.as_ptr(), 0);
|
||||
|
||||
let ExitProcess: extern "system" fn(u32) =
|
||||
mem::transmute(GetProcAddress(kernel32, "ExitProcess\0".as_ptr()));
|
||||
ExitProcess(4);
|
||||
}
|
Loading…
Reference in New Issue
Block a user