1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#![recursion_limit = "1024"]
#![feature(range_contains, offset_to)]
#![cfg_attr(feature = "static", feature(const_fn, unboxed_closures))]
#![cfg_attr(test, feature(naked_functions, core_intrinsics, asm))]

//! A cross-platform detour library written in Rust.
//!
//! ## Intro
//!
//! This library provides thread-safe, inline detouring functionality by
//! disassembling and patching functions during runtime, using assembly opcodes
//! allocated within executable memory. It modifies the target functions and
//! replaces their prolog with an unconditional jump.
//!
//! Beyond the basic functionality this library handles several different edge
//! cases:
//!
//! - Relative branches.
//! - RIP relative operands.
//! - Detects NOP-padding.
//! - Relay for large offsets (>2GB)
//! - Supports hot patching.
//!
//! ## Detours
//!
//! Three different types of detours are provided:
//!
//! - [Generic](./struct.GenericDetour.html): A type-safe interface — the same
//!   prototype is enforced for both the target and the detour.  
//!   It is also enforced when invoking the original target.
//!
//! - [Static](./struct.StaticDetour.html): A static & type-safe interface.
//!   Thanks to its static nature it can accept a closure as its second
//!   argument, but on the other hand, it can only have one detour active at a
//!   time.
//!
//! - [Raw](./struct.RawDetour.html): The underlying building block that
//!   the others types abstract upon. It has no type-safety and interacts with
//!   raw pointers.  
//!   It should be avoided unless the types used aren't known until runtime.
//!
//! All detours implement the [Detour](./trait.Detour.html) trait, which exposes
//! several methods, and enforces `Send + Sync`. Therefore you must also include
//! it into your scope whenever you are using a detour.
//!
//! ## Features
//!
//! - **static**: Enabled by default. Includes the static detour functionality,
//!   but requires the nightly features *const_fn* & *unboxed_closures*.
//!
//! ## Procedure
//!
//! To illustrate on an x86 platform:
//!
//! ```c
//! 0 int return_five() {
//! 1     return 5;
//! 00400020 [b8 05 00 00 00] mov eax, 5
//! 00400025 [c3]             ret
//! 2 }
//! 3
//! 4 int detour_function() {
//! 5     return 10;
//! 00400040 [b8 0A 00 00 00] mov eax, 10
//! 00400045 [c3]             ret
//! 6 }
//! ```
//!
//! To detour `return_five` the library by default tries to replace five bytes
//! with a relative jump (the optimal scenario), which works in this case.
//! Executable memory will be allocated for the instruction and the function's
//! prolog will be replaced.
//!
//! ```c
//! 0 int return_five() {
//! 1     return detour_function();
//! 00400020 [e9 16 00 00 00] jmp 1b <detour_function>
//! 00400025 [c3]             ret
//! 2 }
//! 3
//! 4 int detour_function() {
//! 5     return 10;
//! 00400040 [b8 0A 00 00 00] mov eax, 10
//! 00400045 [c3]             ret
//! 6 }
//! ```
//!
//! Beyond what is shown here, a trampoline is also generated so the original
//! function can be called regardless whether the function is hooked or not.
//!
//! *NOTE: Currently x86 & x64 is supported on all major platforms.*

#[macro_use] extern crate cfg_if;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate matches;
extern crate boolinator;
extern crate generic_array;
extern crate mmap;
extern crate region;
extern crate slice_pool;

// Re-exports
pub use variant::*;
pub use traits::*;

#[macro_use]
mod macros;

// Modules
pub mod error;
mod traits;
mod alloc;
mod pic;
mod util;
mod variant;

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        mod x86;
        use self::x86 as arch;
    } else {
        // Implement ARM support!
    }
}