Skip to content

Commit

Permalink
add trash block generator docs
Browse files Browse the repository at this point in the history
  • Loading branch information
pagran authored and mvdan committed Feb 11, 2024
1 parent f3f57e3 commit d76bc2e
Showing 1 changed file with 93 additions and 1 deletion.
94 changes: 93 additions & 1 deletion docs/CONTROLFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Control flow obfuscation works in several stages:
4) Generates [junk jumps](#junk-jumps)
5) Applies [control flow flattening](#control-flow-flattening)
6) Applies (if enabled) [control flow hardening](#control-flow-hardening)
7) Converts go/ssa back into go/ast
7) Generates [trash blocks](#trash-blocks)
8) Converts go/ssa back into go/ast

### Example usage

Expand Down Expand Up @@ -272,6 +273,7 @@ _s2a_l12:
```

#### Control flow hardening

Parameter: `flatten_hardening` (default: empty, supported: `xor,delegate_table`)

Dispatcher is the main and most vulnerable part of control flow flattening. By static analysis of the dispatcher, it is possible to reconstruct the original control flow ([example](https://research.openanalysis.net/angr/symbolic%20execution/deobfuscation/research/2022/03/26/angr_notes.html)). Hardening can be used to make this analysis more difficult by adding an extra layer of obfuscation and moving some of the computation to runtime
Expand Down Expand Up @@ -299,6 +301,7 @@ func main() {
}
```

Result:

```go
var _garble2ec9r7n6t4d7f = (func(key [15]byte) [4]func(int) int {
Expand Down Expand Up @@ -501,6 +504,95 @@ func main() {

```

#### Trash blocks

Parameter: `trash_blocks` (default: `0`, maximum: `1024`)

> Warning: this param affects resulting binary only when used in combination with [flattening](#control-flow-flattening)
Trash blocks generator generates blocks that will never be called. Trash blocks contain random function calls and random variable assignments. The purpose of this is to create a large number of references to different methods and local variables and in combination with other controlflow obfuscation parameters it helps to effectively hide the real code.

The generator does not add new dependencies to the project, it uses only existing direct or indirect dependencies. In the following example, the `fmt` package implicitly imports the `io` and `os` packages
Input:

```go
package main

import "fmt"

//garble:controlflow block_splits=0 junk_jumps=0 flatten_passes=0 trash_blocks=1
func main() {
if true {
fmt.Println("hello world")
}
}
```

Result:

```go
package main

import (
"fmt"
"io"
"os"
)

func main() {
var (
_s2a_4 int
_s2a_5 bool
)
{
if true {
goto _s2a_l1
} else {
goto _s2a_l2
}
}
_s2a_l1:
{
_s2a_0 := new([1]interface {
})
_s2a_1 := &_s2a_0[(int)(0)]
_s2a_2 := (interface {
})("hello world")
*_s2a_1 = _s2a_2
_s2a_3 := _s2a_0[:]
_, _ = fmt.Println(_s2a_3...)
_s2a_4 = (int)(1375793722)
goto _s2a_l3
}
_s2a_l2:
{
return
}
_s2a_l3:
{
_s2a_5 = _s2a_4 == (int)(1414729372)
if _s2a_5 {
goto _s2a_l4
} else {
goto _s2a_l2
}
}
_s2a_l4:
{
_s2a_5, _s2a_4 = true, _s2a_4
_garble1v7i062eba5j0, _ := fmt.Printf((string)(_s2a_4), _s2a_4, _s2a_5)
_garble27oahvink0hig, _ := fmt.Println(_garble1v7i062eba5j0)
_ = fmt.Errorf((string)(_garble27oahvink0hig), os.Stdout, 714272279, _garble27oahvink0hig, io.EOF)
_garble27oahvink0hig, _s2a_4, _garble1v7i062eba5j0, _s2a_5 = _s2a_4, (int)(77), _s2a_4, _s2a_5
_, _garble6oknljnlggutn := fmt.Printf((string)(_garble1v7i062eba5j0))
_, _garble8ne429queuq8n := fmt.Scanf((string)(751648516), os.Stdin, 0.17251639929485216, "UAN4E===")
_garble1qt8quedh1fo9, _ := fmt.Scanf((string)(_s2a_4), _garble8ne429queuq8n, _s2a_5, _garble6oknljnlggutn)
_, _ = fmt.Scanf((string)(_garble1qt8quedh1fo9))
goto _s2a_l4
}
}
```

### Caveats

* Obfuscation breaks the lazy iteration over maps. See: [ssa2ast/polyfill.go](../internal/ssa2ast/polyfill.go)
Expand Down

0 comments on commit d76bc2e

Please sign in to comment.