1
- detour-rs
2
- =========
3
- [ ![ Travis build status] [ travis-shield ]] [ travis ]
4
- [ ![ Appveyor build status] [ appveyor-shield ]] [ appveyor ]
1
+ <div align =" center " >
2
+
3
+ # ` detour-rs `
4
+
5
+ [ ![ Azure build Status] [ azure-shield ]] [ azure ]
5
6
[ ![ crates.io version] [ crate-shield ]] [ crate ]
6
7
[ ![ Documentation] [ docs-shield ]] [ docs ]
7
8
[ ![ Language (Rust)] [ rust-shield ]] [ rust ]
8
9
10
+ </div >
11
+
9
12
This is a cross-platform detour library developed in Rust. Beyond the basic
10
13
functionality, this library handles branch redirects, RIP-relative
11
14
instructions, hot-patching, NOP-padded functions, and allows the original
@@ -16,68 +19,87 @@ maintain this feature, not all desired functionality can be supported due to
16
19
lack of cross-platform APIs. Therefore [ EIP relocation] ( #appendix ) is not
17
20
supported.
18
21
19
- ** NOTE** : Nightly is currently required for ` static_detours! ` .
22
+ ** NOTE** : Nightly is currently required for ` static_detour! ` and is enabled by
23
+ default.
20
24
21
25
## Platforms
22
26
23
- - ` x86/x64 ` : Windows, Linux & macOS.
24
- - ` ARM ` : Not implemented, but foundation exists.
27
+ This library provides CI for these targets:
28
+
29
+ - Linux
30
+ * ` i686-unknown-linux-gnu `
31
+ * ` x86_64-unknown-linux-gnu `
32
+ * ` x86_64-unknown-linux-musl `
33
+ - Windows
34
+ * ` i686-pc-windows-gnu `
35
+ * ` i686-pc-windows-msvc `
36
+ * ` x86_64-pc-windows-gnu `
37
+ * ` x86_64-pc-windows-msvc `
38
+ - macOS
39
+ * ~~ ` i686-apple-darwin ` ~~
40
+ * ` x86_64-apple-darwin `
25
41
26
42
## Installation
27
43
28
44
Add this to your ` Cargo.toml ` :
29
45
30
46
``` toml
31
47
[dependencies ]
32
- detour = " 0.5.0"
33
- ```
34
-
35
- ... and this to your crate root:
36
-
37
- ``` rust
38
- #[macro_use]
39
- extern crate detour;
48
+ detour = " 0.8.0"
40
49
```
41
50
42
51
## Example
43
52
44
53
- A static detour (one of * three* different detours):
45
54
46
55
``` rust
47
- #[macro_use] extern crate detour;
56
+ use std :: error :: Error ;
57
+ use detour :: static_detour;
48
58
49
- extern " C " fn add ( x : i32 , y : i32 ) -> i32 {
50
- x + y
59
+ static_detour! {
60
+ static Test : /* extern "X" */ fn ( i32 ) -> i32 ;
51
61
}
52
62
53
- static_detours! {
54
- struct DetourAdd : extern " C " fn ( i32 , i32 ) -> i32 ;
63
+ fn add5 ( val : i32 ) -> i32 {
64
+ val + 5
55
65
}
56
66
57
- fn main () {
58
- // Replaces the 'add' function with a closure that subtracts
59
- let mut hook = unsafe { DetourAdd . initialize (add , | x , y | x - y ). unwrap () };
67
+ fn add10 (val : i32 ) -> i32 {
68
+ val + 10
69
+ }
70
+
71
+ fn main () -> Result <(), Box <dyn Error >> {
72
+ // Reroute the 'add5' function to 'add10' (can also be a closure)
73
+ unsafe { Test . initialize (add5 , add10 )? };
74
+
75
+ assert_eq! (add5 (1 ), 6 );
76
+ assert_eq! (Test . call (1 ), 6 );
60
77
61
- assert_eq! ( add ( 1 , 5 ), 6 );
62
- assert_eq! ( hook . is_enabled (), false ) ;
78
+ // Hooks must be enabled to take effect
79
+ unsafe { Test . enable () ? } ;
63
80
64
- unsafe { hook . enable (). unwrap (); }
81
+ // The original function is detoured to 'add10'
82
+ assert_eq! (add5 (1 ), 11 );
65
83
66
- assert_eq! ( add ( 1 , 5 ), - 4 );
67
- assert_eq! (hook . call (1 , 5 ), 6 );
84
+ // The original function can still be invoked using 'call'
85
+ assert_eq! (Test . call (1 ), 6 );
68
86
69
- // Change the detour whilst hooked
70
- hook . set_detour (| x , y | x * y );
71
- assert_eq! (add ( 5 , 5 ), 25 );
87
+ // It is also possible to change the detour whilst hooked
88
+ Test . set_detour (| val | val - 5 );
89
+ assert_eq! (add5 ( 5 ), 0 );
72
90
73
- unsafe { hook . disable (). unwrap (); }
91
+ unsafe { Test . disable ()? };
74
92
75
- assert_eq! (hook . is_enabled (), false );
76
- assert_eq! (hook . call (1 , 5 ), 6 );
77
- assert_eq! (add (1 , 5 ), 6 );
93
+ assert_eq! (add5 (1 ), 6 );
94
+ Ok (())
78
95
}
79
96
```
80
97
98
+ - A Windows API hooking example is available [ here] ( ./examples/messageboxw_detour.rs ) ; build it by running:
99
+ ```
100
+ $ cargo build --example messageboxw_detour
101
+ ```
102
+
81
103
## Mentions
82
104
83
105
Part of the library's external user interface was inspired by
@@ -90,7 +112,7 @@ derivative code of his work.
90
112
91
113
* Should be performed whenever a function's prolog instructions
92
114
are being executed, simultaneously as the function itself is being
93
- detoured. This is done by halting all affected threads, copying the related
115
+ detoured. This is done by halting all affected threads, copying the affected
94
116
instructions and appending a ` JMP ` to return to the function. This is
95
117
barely ever an issue, and never in single-threaded environments, but YMMV.*
96
118
@@ -109,10 +131,8 @@ derivative code of his work.
109
131
trailing `NOP` instructions will be replaced, to make room for the detour.*
110
132
111
133
<!-- Links -->
112
- [travis-shield]: https://img.shields.io/travis/darfink/detour-rs.svg?style=flat-square&label=travis
113
- [travis]: https://travis-ci.org/darfink/detour-rs
114
- [appveyor-shield]: https://img.shields.io/appveyor/ci/darfink/detour-rs/master.svg?style=flat-square&label=appveyor
115
- [appveyor]: https://ci.appveyor.com/project/darfink/detour-rs
134
+ [azure-shield]: https://img.shields.io/azure-devops/build/darfink/detour-rs/2/master?label=Azure%20Pipelines&logo=azure-pipelines&style=flat-square
135
+ [azure]: https://dev.azure.com/darfink/detour-rs/_build/latest?definitionId=1&branchName=master
116
136
[crate-shield]: https://img.shields.io/crates/v/detour.svg?style=flat-square
117
137
[crate]: https://crates.io/crates/detour
118
138
[rust-shield]: https://img.shields.io/badge/powered%20by-rust-blue.svg?style=flat-square
0 commit comments