diff --git a/.cargo/config b/.cargo/config index f66f8e3..0b6928e 100644 --- a/.cargo/config +++ b/.cargo/config @@ -15,8 +15,13 @@ rustflags = [ #"-C", "link-arg=/OPT:REF,ICF", "-C", "link-arg=/MERGE:.edata=.rdata", "-C", "link-arg=/MERGE:.rustc=.data", + "-C", "link-arg=/MERGE:.rdata=.text", + "-C", "link-arg=/MERGE:.pdata=.text", #"-C", "link-arg=/INTEGRITYCHECK" + "-C", "link-arg=/DEBUG:NONE", + "-C", "link-arg=/EMITPOGOPHASEINFO", + "-C", "target-feature=-mmx,-sse,+soft-float" - "-C", "target-feature=-mmx,-sse,+soft-float" + -] +] \ No newline at end of file diff --git a/README.md b/README.md index f8958f5..d4c2420 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,7 @@ https://github.com/johnthagen/min-sized-rust edit -https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4acc288a658ce23cb2c3da66aa818b8d \ No newline at end of file +https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4acc288a658ce23cb2c3da66aa818b8d + + +https://stackoverflow.com/questions/46134477/how-can-i-call-a-raw-address-from-rust diff --git a/src/binds.rs b/src/binds.rs index 5564b39..f93912d 100644 --- a/src/binds.rs +++ b/src/binds.rs @@ -1,5 +1,6 @@ #![allow(non_snake_case)] #![allow(non_camel_case_types)] +#![allow(dead_code)] pub enum c_void {} pub type BOOLEAN = u8; @@ -28,6 +29,7 @@ pub struct PEB_LDR_DATA { // ... } +pub type PLDR_DATA_TABLE_ENTRY = *const LDR_DATA_TABLE_ENTRY; #[repr(C)] pub struct LDR_DATA_TABLE_ENTRY { pub InLoadOrderModuleList: LIST_ENTRY, diff --git a/src/main.rs b/src/main.rs index e68ccf1..4eee7d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,263 +1,136 @@ #![allow(non_snake_case)] #![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] #![allow(overflowing_literals)] #![no_std] #![no_main] #![feature(asm)] #![feature(link_args)] -use core::{ptr::null_mut, slice, usize}; - +use core::ptr::null_mut; mod binds; mod utils; -use arrayvec::ArrayString; use binds::*; use utils::*; #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } -// use winapi::um::libloaderapi::LoadLibraryA; -// pub type LLA = extern "stdcall" LoadLibraryA; +// const KERNEL32_DLL: &str = concat!("KERNEL32.DLL", "\0"); +const USER32_DLL: &str = concat!("user32.dll", "\0"); +const OutputDebugStringA_: &str = concat!("OutputDebugStringA", "\0"); +const LoadLibraryA_: &str = concat!("LoadLibraryA", "\0"); +const GetProcAddress_: &str = concat!("GetProcAddress", "\0"); +const MessageBoxA_: &str = concat!("MessageBoxA", "\0"); + +pub type LoadLibraryAFn = extern "system" fn(lpFileName: LPCSTR) -> PVOID; +pub type GetProcAddressFn = extern "system" fn(hmodule: PVOID, name: LPCSTR) -> PVOID; +pub type MessageBoxAFn = extern "system" fn(h: PVOID, text: LPCSTR, cation: LPCSTR, t: u32) -> u32; +pub type OutputDebugStringAFn = extern "C" fn(*const i8); +pub type DbgPrintFn = extern "C" fn(Format: *const u8, ...) -> NTSTATUS; #[no_mangle] -// #[link_section = ".text.prologue"] pub extern "C" fn main() -> ! { - // "KERNEL32.DLL" unsafe { + // clean argc and argv asm!("mov rcx, 0", "mov rdx, 0",); } let KERNEL32_STR: [u16; 13] = [75, 69, 82, 78, 69, 76, 51, 50, 46, 68, 76, 76, 0]; - // let KERNEL32_STR = "KERNEL32.DLL"; - // username: Username::try_from_str("user")?, - // let KERNEL32_STR = KK20::try_from_str("KERNEL32.DLL"); - let kk = get_module_by_name(KERNEL32_STR.as_ptr()); - // println!("kernel32: {:p}", kk); - // let kk = get_module_by_name(12); - let OutputDebugStringA_STR: [u8; 19] = [ - 79, 117, 116, 112, 117, 116, 68, 101, 98, 117, 103, 83, 116, 114, 105, 110, 103, 65, 0, - ]; - let dbg_addr = get_func_by_name(kk, OutputDebugStringA_STR.as_ptr()); - // "LoadLibraryA" - let LoadLibraryA_STR: [u8; 13] = [76, 111, 97, 100, 76, 105, 98, 114, 97, 114, 121, 65, 0]; - let load_library = get_func_by_name(kk, LoadLibraryA_STR.as_ptr()); + let kernel32_ptr = get_module_by_name(KERNEL32_STR.as_ptr()); + let dbg_addr = get_func_by_name(kernel32_ptr, OutputDebugStringA_.as_ptr()); + let load_library_ptr = get_func_by_name(kernel32_ptr, LoadLibraryA_.as_ptr()); + let get_proc = get_func_by_name(kernel32_ptr, GetProcAddress_.as_ptr()); + let LoadLibraryA: LoadLibraryAFn = unsafe { core::mem::transmute(load_library_ptr) }; - // "GetProcAddress" - let GetProcAddress_STR: [u8; 15] = [ - 71, 101, 116, 80, 114, 111, 99, 65, 100, 100, 114, 101, 115, 115, 0, - ]; - let get_proc = get_func_by_name(kk, GetProcAddress_STR.as_ptr()); - // println!("dbg_addr: {:p}", dbg_addr); - // println!("load_library: {:p}", load_library); - - let LoadLibraryA: extern "system" fn(lpFileName: LPCSTR) -> PVOID = - unsafe { core::mem::transmute(load_library) }; - // let LoadLibraryA_ :LoadLibraryA = unsafe { core::mem::transmute(load_library) }; - // let a = "user32.dll"; - // let c_str = CString::new("user32.dll").unwrap(); - // let c_world: *const c_char = c_str.as_ptr() as *const c_char; - let c_world = b"user32.dll\0".as_ptr() as *const i8; - // let c_world: [i8; 11] = [117, 115, 101, 114, 51, 50, 46, 100, 108, 108, 0]; - - unsafe { - asm!("push rax"); + // make stack align + unsafe { asm!("push rax") }; + let u32_dll = LoadLibraryA(USER32_DLL.as_ptr() as *const i8); + let GetProcAddress: GetProcAddressFn = unsafe { core::mem::transmute(get_proc) }; + let message_box_ptr = GetProcAddress(u32_dll, MessageBoxA_.as_ptr() as *const i8); + let MessageBoxA: MessageBoxAFn = unsafe { core::mem::transmute(message_box_ptr) }; + MessageBoxA( + null_mut(), + MessageBoxA_.as_ptr() as *const i8, + MessageBoxA_.as_ptr() as _, + 0x30, + ); + let OutputDebugStringA: OutputDebugStringAFn = unsafe { core::mem::transmute(dbg_addr) }; + #[macro_export] + macro_rules! debug_print { + ($msg:expr) => { + OutputDebugStringA(concat!($msg, "\0").as_ptr() as _) + }; } - let u32_dll = LoadLibraryA(c_world); - // println!("u32_dll: {:p}", u32_dll); - - // pub unsafe extern "system" fn GetProcAddress( - // hModule: HMODULE, - // lpProcName: LPCSTR - // ) -> FARPROC - - let GetProcAddress: extern "system" fn(hmodule: PVOID, name: LPCSTR) -> PVOID = - unsafe { core::mem::transmute(get_proc) }; - - // let c_str = CString::new("MessageBoxA").unwrap(); - // let c_world: *const c_char = c_str.as_ptr() as *const c_char; - let c_world = b"MessageBoxA\0".as_ptr() as *const i8; - // let c_world: [i8; 12] = [77, 101, 115, 115, 97, 103, 101, 66, 111, 120, 65, 0]; - // let c_world1 = b"xxx"; - let c_world1 = "title\0"; - // let c_world1 = aa + "123"; - // c_world1.to_uppercase(); - // let mut u = ArrayString::from_byte_string(b"hello world").unwrap(); - // u.push_str("abc"); - let message_box_ptr = GetProcAddress(u32_dll, c_world); - - // println!("message_box_ptr: {:p}", message_box_ptr); - - let MessageBoxA: extern "system" fn(h: PVOID, text: LPCSTR, cation: LPCSTR, t: u32) -> u32 = - unsafe { core::mem::transmute(message_box_ptr) }; - - MessageBoxA(null_mut(), c_world, c_world1.as_ptr() as _, 0x30); - // https://stackoverflow.com/questions/46134477/how-can-i-call-a-raw-address-from-rust - let OutputDebugStringA: extern "C" fn(*const i8) = unsafe { core::mem::transmute(dbg_addr) }; - // let c_str = CString::new("helloxx").unwrap(); - // let c_world: *const c_char = c_str.as_ptr() as *const c_char; - // let c_str = "helloxxx123"; - // let c_str:[u8;3] = [0x41,0x42,0x0]; - // let c_world = c_str.as_ptr(); - // // // // println!("1: {:?}", c_world); - // let msg = b"mmmmsg"; - // let msg: &[u8] = [b'a', b'b']; - //let a = "abc"; - - // OutputDebugStringA(msg.as_ptr() as _); + debug_print!("we made it! see me in DebugView or Debugger"); loop {} } fn get_module_by_name(module_name: *const u16) -> PVOID { + let peb: *mut PEB; unsafe { - let peb: *mut PEB; asm!( "mov {}, gs:[0x60]", out(reg) peb, ); let ldr = (*peb).Ldr; - let mut list = &((*ldr).InLoadOrderModuleList); - let mut curr_module: *mut LDR_DATA_TABLE_ENTRY = &mut list as *mut _ as *mut _; + let list_entry = &((*ldr).InLoadOrderModuleList); + let mut cur_module: *const LDR_DATA_TABLE_ENTRY = &list_entry as *const _ as *const _; loop { - // println!("loop start"); - if curr_module.is_null() || (*curr_module).BaseAddress.is_null() { - // println!( - // "gg, {}, {}", - // curr_module.is_null(), - // (*curr_module).BaseAddress.is_null() - // ); - // break; + if cur_module.is_null() || (*cur_module).BaseAddress.is_null() { + // TODO: when to break } - let mut curr_name = (*curr_module).BaseDllName.Buffer; - if curr_name.is_null() { - // continue; - } - // curr_name = curr_name.offset(1) - // // println!("1"); - let mut i: isize = 0; - // // println!("2"); - // // println!("curr_name: {:?}", curr_name); - - if curr_name.is_null() { - } else { - // let name = u16_ptr_to_string(curr_name); - // let name = ""; - // // // println!("name===: {} {:?}", name.len(), name); - // if name_len == module_name.len() { - if compare_raw_str(module_name, curr_name) { - // println!("base: {:?}", (*curr_module).BaseAddress); - // break; - return (*curr_module).BaseAddress; + let cur_name = (*cur_module).BaseDllName.Buffer; + if !cur_name.is_null() { + if compare_raw_str(module_name, cur_name) { + return (*cur_module).BaseAddress; } } - // for - // break; - let flink = (*curr_module).InLoadOrderModuleList.Flink; - curr_module = flink as *mut LDR_DATA_TABLE_ENTRY; + let flink = (*cur_module).InLoadOrderModuleList.Flink; + cur_module = flink as *const LDR_DATA_TABLE_ENTRY; } - // // // println!("") } } -// type LoadLibraryA - fn get_func_by_name(module: PVOID, func_name: *const u8) -> PVOID { let idh: *const IMAGE_DOS_HEADER = module as *const _; unsafe { if (*idh).e_magic != IMAGE_DOS_SIGNATURE { - // // println!("e_magic eror"); - } else { + return null_mut(); } let e_lfanew = (*idh).e_lfanew; - // dbg!(e_lfanew); let nt_headers: *const IMAGE_NT_HEADERS = (module as *const u8).offset(e_lfanew as isize) as *const _; let op_header = &(*nt_headers).OptionalHeader; - let exp_dir = &op_header.DataDirectory[0]; + let virtual_addr = (&op_header.DataDirectory[0]).VirtualAddress; + let export_dir: *const IMAGE_EXPORT_DIRECTORY = + (module as *const u8).offset(virtual_addr as _) as _; + let number_of_names = (*export_dir).NumberOfNames; + let addr_of_funcs = (*export_dir).AddressOfFunctions; + let addr_of_names = (*export_dir).AddressOfNames; + let addr_of_ords = (*export_dir).AddressOfNameOrdinals; + for i in 0..number_of_names { + let name_rva_p: *const DWORD = + (module as *const u8).offset((addr_of_names + i * 4) as isize) as *const _; + let name_index_p: *const WORD = + (module as *const u8).offset((addr_of_ords + i * 2) as isize) as *const _; + let name_index = name_index_p.as_ref().unwrap(); + let mut off: u32 = (4 * name_index) as u32; + off = off + addr_of_funcs; + let func_rva: *const DWORD = (module as *const u8).offset(off as _) as *const _; - let exp_addr = exp_dir.VirtualAddress; - if exp_addr == 0 { - // // println!("virtualaddr error"); - } else { - // // println!("virtualAddr: 0x{:x} {}", exp_addr, exp_addr); - } - // let exp_dir_raw = exp_dir as *const _ as *const u8; - let exp: *const IMAGE_EXPORT_DIRECTORY = (module as *const u8).offset(exp_addr as _) as _; // this case error? - let names_count = (*exp).NumberOfNames; - let funcs_rva = (*exp).AddressOfFunctions; - let func_names_rva = (*exp).AddressOfNames; - let names_ords_rva = (*exp).AddressOfNameOrdinals; - - // // println!("names_count: {}", names_count); - for i in 0..names_count { - // // // println!("=== {} ===", i); - let name_rva: *const DWORD = - (module as *const u8).offset((func_names_rva + i * 4) as isize) as *const _; - let name_index: *const WORD = - (module as *const u8).offset((names_ords_rva + i * 2) as isize) as *const _; - let name_i = name_index.as_ref().unwrap(); - let mut off1: u32 = (4 * name_i) as u32; - off1 = off1 + funcs_rva; - let func_rva: *const DWORD = (module as *const u8).offset(off1 as isize) as *const _; - - let mut rav_i = name_rva.as_ref().unwrap(); - let curr_name = (module as *const u8).offset(*rav_i as isize); + let name_rva = name_rva_p.as_ref().unwrap(); + let curr_name = (module as *const u8).offset(*name_rva as isize); if *curr_name == 0 { continue; - // let bla= CString::from_raw(curr_name as _); } - // let len = (0..).take_while(|&i| *curr_name.offset(i) != 0).count(); - // let slice = core::slice::from_raw_parts(curr_name, len); - // // // println!("cur_name: {:?}",slice); - // OutputDebugStringA - // if slice[0] == 'O' as u8 && slice[6] == 'D' as u8 { if compare_raw_str(func_name, curr_name) { - // for i in slice { - //print!("{}", *i as char); - // } - // // println!(""); - // break; - let mo = (module as *const u8).offset(*func_rva as isize); - // return 0; - return mo as _; + let res = (module as *const u8).offset(*func_rva as isize); + return res as _; } - // let c_string = CString::new("LoadLibraryA").expect("CString::new failed"); - // let load_library = c_string.as_bytes(); - - // for i in 0..load_library.len() { - // if load_library[i] == slice[i] { - // continue - // } else { - // // // println!("{} => {}", i, load_library.len()); - // if load_library.len() - i < 2 { - // // // println!("got it: {:?}", slice); - // } - // break; - - // } - // } - - // i } } - return 0 as _; + return null_mut(); } - -// pub unsafe extern "system" fn LoadLibraryA(lp_lib_file_name: *const i8) -> isize; -// pub unsafe extern "system" fn OutputDebugStringA(lpOutputString: LPCSTR) - -#[allow(unused_attributes)] -#[cfg(target_env = "msvc")] -#[link_args = "/GS- /MERGE:.rdata=.text /MERGE:.pdata=.text /NODEFAULTLIB /EMITPOGOPHASEINFO /DEBUG:NONE"] -extern "C" {} -/// NT Status type. - -extern "C" { - // /// `DbgPrint` routine sends a message to the kernel debugger. - // pub fn DbgPrint(Format: *const u8, ...) -> NTSTATUS; - // /// The `DbgPrintEx` routine sends a string to the kernel debugger if certain conditions are met. - // pub fn DbgPrintEx(ComponentId: u32, Level: u32, Format: *const u8, ...) -> NTSTATUS; -} - -// #[macro_export] -// macro_rules! KdPrint { -// ($msg:expr $(, $arg:expr)*) => { unsafe { DbgPrint( concat!($msg, "\0").as_ptr() $(, $arg )* )} }; -// } +// #[allow(unused_attributes)] +// #[cfg(target_env = "msvc")] +// #[link_args = "/GS- /MERGE:.rdata=.text /MERGE:.pdata=.text /NODEFAULTLIB /EMITPOGOPHASEINFO /DEBUG:NONE"] +// extern "C" {} \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index 26bbc75..d81f705 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,6 @@ +#![allow(dead_code)] + + unsafe fn u16_ptr_len(ptr: *const u16) -> usize { let len = (0..).take_while(|&i| *ptr.offset(i) != 0).count(); return len; @@ -21,7 +24,22 @@ fn compare_str_u16(s: &str, u: *const u16) -> bool { } } -use core::cmp::PartialEq; +// TODO: use alloc +pub fn str_to_u16_ptr(s: &str, buf: &mut [u16]) { + let s_len = s.len(); + let s_bytes = s.as_bytes(); + + // for i in 0..255 { + + // } + // let buf = vec![0u16;s_len+1]; + for i in 0..s_len { + buf[i] = s_bytes[i] as _; + } + buf[s_len] = 0; + // buf.as_ptr() +} + use num_traits::Num; pub fn compare_raw_str(s: *const T, u: *const T) -> bool @@ -68,11 +86,3 @@ fn compare_str_u8(s: &str, u: *const u8) -> bool { fn str_to_i8(s: &str) -> *const i8 { s.as_bytes().as_ptr() as *const i8 } - -// https://stackoverflow.com/questions/48586816/converting-raw-pointer-to-16-bit-unicode-character-to-file-path-in-rust -// unsafe fn u16_ptr_to_string(ptr: *const u16) -> OsString { -// let len = (0..).take_while(|&i| *ptr.offset(i) != 0).count(); -// let slice = std::slice::from_raw_parts(ptr, len); - -// OsString::from_wide(slice) -// }