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"
);
mod hook_test {
use
super
::
*
;
use std::println;
use winapi::um::winuser::
*
;
use winapi::um::libloaderapi::
*
;
const MAGIC_VALUE: u64
=
1001234
;
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);
}
}
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);
}
}
}
mod hook_test {
use
super
::
*
;
use std::println;
use winapi::um::winuser::
*
;
use winapi::um::libloaderapi::
*
;
const MAGIC_VALUE: u64
=
1001234
;
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编辑
,原因: