首页
社区
课程
招聘
7
[分享]Rust内存工具库 hackit
发表于: 2021-5-12 21:25 10950

[分享]Rust内存工具库 hackit

2021-5-12 21:25
10950

https://gitee.com/udbg/hackit 是笔者开发的一个memory hack之类的库,中文我不知道咋翻译比较优雅,暂且叫内存工具库

如果想运行下面的示例代码,需要在 Cargo.toml 中加入 hackit 依赖,使用nightly版本的rust编译器(rust内联汇编需要nightly版本的编译器),我的rustc版本是rustc 1.52.0-nightly (a8486b64b 2021-02-24)

枚举进程

利用rust的迭代器trait,可以很方便地过滤出自己想要枚举的进程,
更多迭代器方法可参考官方文档 https://doc.rust-lang.org/core/iter/trait.Iterator.html

通过进程名过滤进程,被单独封装成了一个函数 enum_process_filter_name(name: &str)
获得第一个名为 explorer.exe 的进程信息

遍历模块:枚举 explorer 进程中的模块

更多读内存的方法参考 trait ReadMemUtil https://gitee.com/udbg/hackit/blob/master/src/mem.rs#L21

rust的String是utf8编码,如果需要调用一些Windows原生接口,需要转Unicode字符串

直接贴了测试用例,Hook库是自己实现的,理论上是可以Hook任意地址的(有跳转指令的除外,处理jmp和call的逻辑还有点问题)

主要是实现了shellcode!这个宏,通过这个宏直接编写汇编代码,并能返回一个指向这段汇编的&[u8](字节数组引用)

https://gitee.com/udbg/hackit/blob/master/src/util.rs#L95

用法参考Hook库的实现 https://gitee.com/udbg/hackit/blob/master/src/win/hook.rs#L143

主要是实现了sig!这个宏,可以直接写BinaryPattern,搜索算法使用了最简单的顺序匹配

宏实现: https://gitee.com/udbg/hackit/blob/master/src/util.rs#L152

算法实现: https://gitee.com/udbg/hackit/blob/master/src/util.rs#L118

还有一些功能就不一一介绍了,感兴趣的朋友自然会去看源码了解,如果用着有啥问题,也欢迎给我提issue,再推荐一些搞memory hack常用的第三方库

[dependencies]
hackit = {git = 'https://gitee.com/udbg/hackit', features = ['std', 'csutil']}
[dependencies]
hackit = {git = 'https://gitee.com/udbg/hackit', features = ['std', 'csutil']}
use hackit::*;
 
for ps in enum_process() {
    println!("{} {}", ps.pid(), ps.name());
}
use hackit::*;
 
for ps in enum_process() {
    println!("{} {}", ps.pid(), ps.name());
}
for ps in enum_process().filter(|p| p.name().eq_ignore_ascii_case("svchost.exe")) {
    println!("{} {}", ps.pid(), ps.name());
}
for ps in enum_process().filter(|p| p.name().eq_ignore_ascii_case("svchost.exe")) {
    println!("{} {}", ps.pid(), ps.name());
}
let ps = enum_process_filter_name("explorer.exe").next().unwrap();
println!("{} {}", ps.pid(), ps.name());
let ps = enum_process_filter_name("explorer.exe").next().unwrap();
println!("{} {}", ps.pid(), ps.name());
for m in enum_module(ps.pid()) {
    println!("{:x} {:x} {}", m.base(), m.size(), m.path());
}
for m in enum_module(ps.pid()) {
    println!("{:x} {:x} {}", m.base(), m.size(), m.path());
}
// 打开进程对象,第二个参数为访问权限,默认为 PROCESS_ALL_ACCESS
let p = Process::open(ps.pid(), None).expect("open explorer");
// 定位到模块基址
let base = p.enum_module().next().unwrap().base();
// 读取内存
let buf = p.read_bytes(base, 2);
assert_eq!(buf, b"MZ");
// 泛型读取,泛型参数可以是 u16 u32 float double ...
let word = p.read_value::<u16>(base).unwrap();
println!("read u16: 0x{:x}", word);
// 读字符串
let s = p.read_cstring(base, 2);
println!("read string: {:?}", s);
// 打开进程对象,第二个参数为访问权限,默认为 PROCESS_ALL_ACCESS
let p = Process::open(ps.pid(), None).expect("open explorer");
// 定位到模块基址
let base = p.enum_module().next().unwrap().base();
// 读取内存
let buf = p.read_bytes(base, 2);
assert_eq!(buf, b"MZ");
// 泛型读取,泛型参数可以是 u16 u32 float double ...
let word = p.read_value::<u16>(base).unwrap();
println!("read u16: 0x{:x}", word);
// 读字符串
let s = p.read_cstring(base, 2);
println!("read string: {:?}", s);
// 枚举驱动模块
for m in system_module_list().unwrap() {
    println!("{:p} {:x} {}", m.ImageBase, m.ImageSize, m.full_path_str());
}
 
// 枚举 explorer 的进程线程信息
for pi in system_process_information().unwrap().filter(|pi| pi.UniqueProcessId as u32 == p.pid) {
    println!("pid: {} image: {} handle-count: {}", pi.UniqueProcessId as u32, pi.ImageName.to_string(), pi.HandleCount);
    for ti in pi.threads() {
        println!(
            "  tid: {} priority: {} wait-time: {} entry: {:p}",
            ti.ClientId.UniqueThread as u32,
            ti.Priority,
            ti.WaitTime,
            ti.StartAddress,
        );
    }
}
// 枚举驱动模块
for m in system_module_list().unwrap() {
    println!("{:p} {:x} {}", m.ImageBase, m.ImageSize, m.full_path_str());
}
 
// 枚举 explorer 的进程线程信息
for pi in system_process_information().unwrap().filter(|pi| pi.UniqueProcessId as u32 == p.pid) {
    println!("pid: {} image: {} handle-count: {}", pi.UniqueProcessId as u32, pi.ImageName.to_string(), pi.HandleCount);
    for ti in pi.threads() {
        println!(
            "  tid: {} priority: {} wait-time: {} entry: {:p}",
            ti.ClientId.UniqueThread as u32,
            ti.Priority,
            ti.WaitTime,
            ti.StartAddress,
        );
    }
}
// utf8转Unicode
let abc = "abc";
unsafe {
    use core::ptr::*;
    use winapi::um::winuser::MessageBoxW;
 
    MessageBoxW(null_mut(), abc.to_unicode_with_null().as_ptr(), null_mut(), 0);
}
// Unicdoe转utf8
let wstr = abc.to_unicode();
assert_eq!(wstr.to_utf8(), "abc");
// Unicode转ANSI编码
assert_eq!(wstr.to_ansi(), b"abc");
// utf8转Unicode
let abc = "abc";
unsafe {
    use core::ptr::*;
    use winapi::um::winuser::MessageBoxW;
 
    MessageBoxW(null_mut(), abc.to_unicode_with_null().as_ptr(), null_mut(), 0);
}
// Unicdoe转utf8
let wstr = abc.to_unicode();
assert_eq!(wstr.to_utf8(), "abc");
// Unicode转ANSI编码
assert_eq!(wstr.to_ansi(), b"abc");
#[cfg(test)]
mod hook_test {
    use super::*;
    use std::println;
 
    use winapi::um::winuser::*;
    use winapi::um::libloaderapi::*;
 
    const MAGIC_VALUE: u64 = 1001234;
 
    #[test]
    fn inline_hook() {
        let tp = this_process();
        tp.sym_init(None, true).ok();
 
        type FnRtlQueryPerformanceCounter = extern "system" fn(&mut u64) -> usize;
        let m = unsafe { GetProcAddress(GetModuleHandleA(b"ntdll\0".as_ptr() as *const i8), b"RtlQueryPerformanceCounter\0".as_ptr() as *const i8) };
        assert!(!m.is_null());
        HookManager::instance().inline_hook(m as usize, |args: &mut HookArgs| unsafe {
            let RtlQueryPerformanceCounter = transmute::<_, FnRtlQueryPerformanceCounter>(args.trampoline());
            let regs = &mut args.regs;
            let arg1 = regs.arg(1);
            *regs.ax() = RtlQueryPerformanceCounter(transmute(arg1));
            *(arg1 as *mut u64) = MAGIC_VALUE;
            args.reject = Some(if size_of::<usize>() == 8 { 0 } else { 1 });
        }, true).expect("RtlQueryPerformanceCounter");
 
        let mut counter: u64 = 0;
        unsafe {
            let RtlQueryPerformanceCounter: FnRtlQueryPerformanceCounter = transmute(m);
            RtlQueryPerformanceCounter(transmute(&mut counter));
            assert_eq!(MAGIC_VALUE, counter);
        }
 
        let m = unsafe { GetProcAddress(LoadLibraryA(b"user32\0".as_ptr() as *const i8), b"MessageBoxA\0".as_ptr() as *const i8) };
        assert!(!m.is_null());
 
        static mut CHECK_MSG: u64 = 0;
        unsafe extern "C" fn callback(args: &mut HookArgs) {
            // let msg: extern "system" fn(usize, *const u8, *const u8, u32) = transmute(args.ret);
            // msg(0, b"Hooked\0".as_ptr(), "\0".as_ptr(), 0);
            CHECK_MSG = MAGIC_VALUE;
            args.reject = Some(if cfg!(target_arch = "x86_64") { 0 } else { 4 });
        }
        HookManager::instance().inline_hook(m as usize, callback as HookCallbackFn, true).expect("MessageBoxA");
        unsafe {
            MessageBoxA(std::ptr::null_mut(), b"error\0".as_ptr() as *const i8, b"\0".as_ptr() as *const i8, 0);
            assert_eq!(MAGIC_VALUE, CHECK_MSG);
        }
    }
 
    #[test]
    fn table_hook() {
        static mut CHECK_HOOK: u64 = 0;
 
        unsafe {
            let m = GetProcAddress(LoadLibraryA(b"kernel32\0".as_ptr() as *const i8), b"OutputDebugStringW\0".as_ptr() as *const i8);
            let output_debug_string: extern "win64" fn(LPCWSTR) = transmute(m);
            let address: usize = transmute(&output_debug_string);
 
            HookManager::instance().table_hook(address, |_arg: &mut HookArgs| {
                println!("TableHook success");
                CHECK_HOOK = MAGIC_VALUE;
            }, true).expect("table hook");
 
            let s = "OutputDebugString".to_wide();
            output_debug_string(s.as_ptr());
            assert_eq!(MAGIC_VALUE, CHECK_HOOK);
        }
    }
}
#[cfg(test)]
mod hook_test {
    use super::*;
    use std::println;
 
    use winapi::um::winuser::*;
    use winapi::um::libloaderapi::*;
 
    const MAGIC_VALUE: u64 = 1001234;
 
    #[test]
    fn inline_hook() {
        let tp = this_process();
        tp.sym_init(None, true).ok();
 
        type FnRtlQueryPerformanceCounter = extern "system" fn(&mut u64) -> usize;
        let m = unsafe { GetProcAddress(GetModuleHandleA(b"ntdll\0".as_ptr() as *const i8), b"RtlQueryPerformanceCounter\0".as_ptr() as *const i8) };
        assert!(!m.is_null());
        HookManager::instance().inline_hook(m as usize, |args: &mut HookArgs| unsafe {
            let RtlQueryPerformanceCounter = transmute::<_, FnRtlQueryPerformanceCounter>(args.trampoline());
            let regs = &mut args.regs;
            let arg1 = regs.arg(1);
            *regs.ax() = RtlQueryPerformanceCounter(transmute(arg1));
            *(arg1 as *mut u64) = MAGIC_VALUE;
            args.reject = Some(if size_of::<usize>() == 8 { 0 } else { 1 });
        }, true).expect("RtlQueryPerformanceCounter");
 
        let mut counter: u64 = 0;
        unsafe {
            let RtlQueryPerformanceCounter: FnRtlQueryPerformanceCounter = transmute(m);
            RtlQueryPerformanceCounter(transmute(&mut counter));
            assert_eq!(MAGIC_VALUE, counter);
        }
 
        let m = unsafe { GetProcAddress(LoadLibraryA(b"user32\0".as_ptr() as *const i8), b"MessageBoxA\0".as_ptr() as *const i8) };
        assert!(!m.is_null());
 
        static mut CHECK_MSG: u64 = 0;

[注意]看雪招聘,专注安全领域的专业人才平台!

最后于 2021-5-17 19:44 被metaworm编辑 ,原因:
收藏
免费 7
支持
分享
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2023-1-13 09:13
sfzhi
为你点赞~
2023-1-9 09:57
SharsDela
为你点赞~
2022-4-15 23:25
呓语。
为你点赞~
2022-1-27 21:59
同志们好啊
为你点赞~
2021-5-12 22:40
微启宇
为你点赞~
2021-5-12 22:33
metaworm
为你点赞~
2021-5-12 21:30
最新回复 (2)
雪    币: 453
活跃值: (134)
能力值: (RANK:0 )
在线值:
发帖
回帖
粉丝
2
好东西,加油.
2021-5-12 22:40
0
雪    币: 1143
活跃值: (3056)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
牛逼,感谢分享
2021-5-12 23:17
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册