9个版本 (4个重大变更)
0.5.1 | 2024年5月8日 |
---|---|
0.5.0 | 2023年11月11日 |
0.4.1 | 2023年11月10日 |
0.3.1 | 2023年11月9日 |
0.1.0 | 2023年11月7日 |
#204 在 开发工具
24KB
393 行
proxygen
用Rust编写的DLL代理生成器。轻松代理任何DLL。
功能
- 生成代理DLL Rust项目
- 使用宏
#[proxy]
、#[pre_hook]
和#[post_hook]
轻松调用原始函数 - 将新DLL导出合并到现有代理DLL项目中
- 更新现有DLL项目的导出(自动生成的代理已被拦截)
安装
假设你已经安装了 Rust,只需运行
cargo install proxygen
编辑生成的项目
你通常只需要编辑 src/intercepted_exports.rs
。
只需将你想要拦截的任何函数添加到 src/intercepted_exports.rs
中(确保与 src/proxied_exports
中的名称匹配)。
在项目根目录中运行 proxygen update .
以自动更新生成的导出。
然后构建项目。
宏/钩子
#[forward]
#[export_name="SomeFunction"]
pub extern "C" fn SomeFunction() {
// The call is forwarded directly to the original function
// Also note: we cannot place anything in the function body when forwarding the call this way
}
#[pre_hook(sig="known")]
#[export_name="SomeFunction"]
pub extern "C" fn SomeFunction(some_arg_1: usize, some_arg_2: u32) -> bool {
println!("Pre-hooked SomeFunction. Args: {}, {}", some_arg_1, some_arg_2);
// After all our code in this pre-hook runs, if we don't return, the original function will be called
// and its result will be returned
}
#[pre_hook(sig="unknown")]
#[export_name="SomeFunction"]
pub extern "C" fn SomeFunction() {
println!("Pre-hooked SomeFunction. Unknown signature");
// The original function will then run afterwards
}
#[proxy(sig="known")]
#[export_name="SomeFunction"]
pub extern "C" fn SomeFunction(some_arg_1: usize, some_arg_2: u32) -> bool {
let orig_result = orig_func(some_arg_1, some_arg_2);
println!("Manually proxied SomeFunction. Args: {}, {}. Result: {}", some_arg_1, some_arg_2, orig_result);
// This is just a normal/manual proxy. It is up to us to return a value.
// Also note that the original function `orig_func` will not be run in this case unless we explicitly call it
true
}
#[post_hook(sig="known")]
#[export_name="SomeFunction"]
pub extern "C" fn SomeFunction(some_arg_1: usize, some_arg_2: u32) -> bool {
// `orig_func` got run just before our code. Its result is stored in `orig_result`
println!("In post-hook for SomeFunction. Args: {}, {}. Result: {}", some_arg_1, some_arg_2, orig_result);
// We could manually return something here if we didn't want `orig_result` returned
}
用法
A DLL export dumper and proxy generator
Usage: proxygen <COMMAND>
Commands:
dump-exports Prints out the exported functions from a given PE file
generate Generate a new proxy DLL project for the given DLL file
merge Merges the given DLL's new exports into an existing DLL proxy project
update Updates an exisitng DLL proxy project's exports based on the intercepted exports
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
工具链和构建
由于我们依赖于裸函数,因此需要使用nightly rust构建此项目。
注意,生成的项目中有一个 toolchain.toml
文件,它将通道设置为 nightly
。
一般构建
通常,你可以运行以下命令并针对项目默认的目标构建项目。
cargo build --release
这显然需要你安装正确的工具链,以及为i686 DLLs安装msys2(见下文)。
为x86_64构建
默认情况下,64位DLL将以 x86_64-pc-windows-msvc
目标构建。
如果你想要使用GNU工具链构建,请别忘了 安装msys2、更新你的路径,并安装 mingw-w64-x86_64-toolchain
。
然后,只需运行
cargo build --release --target=x86_64-pc-windows-gnu
为i686构建
当为i686-pc-windows-msvc
构建时,可能会遇到一些名称混淆问题,你可能会遇到链接错误。
因此,如果您遇到问题,我建议您为i686-pc-windows-gnu
构建
设置构建为i686-pc-windows-gnu
安装nightly-i686-pc-windows-gnu
工具链
rustup toolchain install nightly-i686-pc-windows-gnu
添加i686-pc-windows-gnu
目标
rustup target add i686-pc-windows-gnu
将您的msys2/mingw32/bin文件夹添加到系统路径中。
然后,打开mingw64终端,安装mingw-w64-i686-toolchain
pacman -S mingw-w64-i686-toolchain
在代理项目中新开一个终端,并构建它
cargo build --release --target=i686-pc-windows-gnu
示例用法
proxygen generate path/to/some_library.dll my_some_library_proxy
就这样,您已经准备好编译的DLL代理Rust项目。
然后,将您想替换的导出添加到intercepted_exports.rs
中。
例如,您可以拦截/代理_SomeMangledFunctionName@12
函数。假设它有一个void*
(指针大小类型)后面跟着一个int*
(通常是32位),并返回一个布尔值
我们可以通过在intercepted_exports.rs
中添加以下内容来代理它
#[proxy(sig="known")]
#[export_name = "_SomeMangledFunctionName@12"]
pub extern "C" fn SomeFunctionName(
some_arg_1: usize,
some_arg_2: u32,
) -> bool {
let original_result: bool = orig_func(some_arg_1, some_arg_2);
println!(
"Proxied SomeFunctionName. Original result: {}. Returning true instead",
original_result
);
true
}
在构建之前,在项目的根目录中运行此命令来更新您的导出
proxygen update .
构建DLL
cargo build --release
接下来,将原始DLL重命名,并在末尾添加一个下划线。将目标文件夹中的dll复制到与原始DLL相同的文件夹中。
运行程序,您应该会看到一个控制台出现。您发送到stdout或stderr的任何内容都将显示在那个控制台。
依赖项
~10-20MB
~273K SLoC