以 SpringBoardServices
为例。
方法1
从越狱的ios设备中提取 SpringBoardServices.tbd
文件,也可以在网上找别人提取过的,也可以自己对着 SpringBoardServices
二进制文件符号表手写(。
tbd 全称是 text-based stub libraries
用于记录链接动态库的必要信息,包括动态库导出的符号、架构信息、依赖信息、链接路径等。
放在 PrivateFrameworks/SpringBoardServices.framework
文件夹中。
在 build.rs
中加入:
1
2
3
|
fn main() {
println!("cargo::rustc-link-search=framework=PrivateFrameworks");
}
|
目录结构:
1
2
3
4
5
6
7
|
├── PrivateFrameworks
│ └── SpringBoardServices.framework
│ └── SpringBoardServices.tbd
├── src
│ └── main.rs
├── build.rs
├── Cargo.toml
|
然后就可以正常写 binding 代码了,例如:
1
2
3
4
5
6
7
|
#[allow(non_snake_case)]
#[link(name = "SpringBoardServices", kind = "framework")]
extern "C" {
fn SBSCopyDisplayIdentifierForProcessID(p1: i32) -> CFStringRef;
fn SBSCopyLocalizedApplicationNameForDisplayIdentifier(p1: CFStringRef) -> CFStringRef;
fn SBSCopyIconImagePNGDataForDisplayIdentifier(p1: CFStringRef) -> CFDataRef;
}
|
方法2
使用 dlopen、dlsym
动态加载符号
dlopen 以指定模式打开指定的动态链接库文件,并返回一个句柄给 dlsym,dlsym 根据动态链接库操作句柄与符号,返回符号对应的地址
这里偷懒使用 https://github.com/nagisa/rust_libloading 库,它做了一层使用起来比较方便并且安全的包装。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
let lib = Library::new(
"/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices",
)?;
#[allow(non_snake_case)]
let SBSCopyDisplayIdentifierForProcessID: Symbol<extern "C" fn(i32) -> CFStringRef> =
lib.get(b"SBSCopyDisplayIdentifierForProcessID")?;
#[allow(non_snake_case)]
let SBSCopyLocalizedApplicationNameForDisplayIdentifier: Symbol<
extern "C" fn(CFStringRef) -> CFStringRef,
> = lib.get(b"SBSCopyLocalizedApplicationNameForDisplayIdentifier")?;
#[allow(non_snake_case)]
let SBSCopyIconImagePNGDataForDisplayIdentifier: Symbol<
extern "C" fn(CFStringRef) -> CFDataRef,
> = lib.get(b"SBSCopyIconImagePNGDataForDisplayIdentifier")?;
|
区别
方法1是编译时链接的,方法2是运行时去调用
另外别忘了签名对应权限