Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/0xor0ne/debugoff

Linux anti-debugging and anti-analysis rust library
https://github.com/0xor0ne/debugoff

anti-analysis anti-debugging antianalysis antidebug antidebugging debugging dynamic-analysis obfuscation rust static-analysis

Last synced: about 2 months ago
JSON representation

Linux anti-debugging and anti-analysis rust library

Awesome Lists containing this project

README

        

# DebugOff Library

## Linux anti-analysis Rust library

The goal of this library is to make both static and dynamic (debugging) analysis
more difficult.

> **The library targets Linux environments.**

It is currently based on `ptrace` anti-analysis trick and provides the following
main features:

* Direct syscall invocation without relying on libc (this makes LD_PRELOAD
bypass mechanism ineffective);

* System call obfuscation which makes static reverse engineering more difficult
(this feature is currently supported only in `x86_64`);

* Multiple `ptrace` syscall invocations. Each call to `ptrace` must return the
expected value (i.e., 0 at the first invocation and -1 thereafter) and
contributes to the computation of an "`offset`" value that, at the end of the
`ptrace` call chain, must match an expected value (see
[here](https://seblau.github.io/posts/linux-anti-debugging)). If ptrace
returns an unexpcted value or the "`offset`" value does not match, the process
is terminated;

* 'ptrace' is called in nested loops. The loops are unrolled and the number of
iterations is randomized at each compilation. Moreover, also the "`offset`"
value is radomized at each iteration;

* The generated code can be obfuscated even more by enabling the `obfuscate`
feature which relies on [goldberg crate](https://crates.io/crates/goldberg);

To use the crate, add it to your dependencies:

```text
[dependencies]
debugoff = { version = "0.2.1, features = ["obfuscate"] }
```

For enabling also system call obfuscation, use the `syscallobf` feature (this is
an experimental feature and affect only binaries targeting `x86_64`
architecture):

```text
[dependencies]
debugoff = { version = "0.2.1, features = ["obfuscate", "syscallobf"] }
```

Given that the library generates random code at each compilation, be sure to
rebuild everything each time. Something like this:

```text
cargo clean
cargo build --release
```

Stripping symbols from the release build is also a good idea:

```text
[profile.release]
debug = false
strip = "symbols"
panic = "abort"
```

## Usage Example

In the example below, `debugoff` is used only when the target OS is Linux and
only for release builds (in this way when the code is compiled in debug mode it
can be debugged without the need to bypass `debugoff`).

```rust
// Include only for Linux and when building in release mode
#[cfg(target_os = "linux")]
#[cfg(not(debug_assertions))]
use debugoff;
use std::time::SystemTime;

fn main() {
// Call only for Linux and when building in release mode
#[cfg(target_os = "linux")]
#[cfg(not(debug_assertions))]
debugoff::multi_ptraceme_or_die();

println!(
"Time: {}",
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis()
);

// Call only for Linux and when building in release mode
#[cfg(target_os = "linux")]
#[cfg(not(debug_assertions))]
debugoff::multi_ptraceme_or_die();

println!("Example complete!");
}
```

See other examples in the [examples directory](./examples) which can be built
with:

```bash
cargo build --release --features obfuscate,syscallobf --examples
```

## Obfuscation example

If we build the following code (which does not use `DebugOff`) in release mode:

```rust
use std::time::SystemTime;

fn main() {
println!(
"Time: {}",
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis()
);

println!("Example complete!");
}
```

This is the corresponding function graph of the `main` function:

![Executable build without
DebugOff](./docs/images/function_graph_no_debugoff.png).

If we build the same code using `DebugOff` with `obfuscate` feature:

```rust
#[cfg(target_os = "linux")]
#[cfg(not(debug_assertions))]
use debugoff;
use std::time::SystemTime;

fn main() {
#[cfg(target_os = "linux")]
#[cfg(not(debug_assertions))]
debugoff::multi_ptraceme_or_die();

println!(
"Time: {}",
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis()
);

#[cfg(target_os = "linux")]
#[cfg(not(debug_assertions))]
debugoff::multi_ptraceme_or_die();

println!("Example complete!");
}
```

This is the obfuscated function graph of the `main` function:

![Executable build with
DebugOff](./docs/images/function_graph_obfuscate.png).

In this particular example, all the code generated by `DebugOff` was inlined in
the `main` function. This is not guaranteed to be always the case because the
functions inlining can be influenced by many factors like the locations where
`DebugOff` is called and the toolchain version used for building the project. In
other cases the resulting function graph could be simpler than the one reported
in the example but, in any case, more complex than the one generated when
`DebugOff` is not used.

## License

Licensed under:

* GPL-3.0 when `obfuscate` feature is enabled;
* MIT when `obfuscate` feature **IS NOT** enabled;

## TODOs

* Implement syscall obfuscation for other architectures (for not syscall
obfuscation is supported only for `x86_64`);
* Deterministic builds;
* Remove dependency from goldberg by implemeing internal obfuscation
functionalities in order to remove GPL-3.0 license requirement;