Skip to content

Commit

Permalink
fix shuffle obfuscation compiler optimization
Browse files Browse the repository at this point in the history
In some cases, compiler could optimize the shuffle obfuscator,
causing exposing the obfuscated literal.
As a fix, added xor encryption of array indexes.
  • Loading branch information
pagran authored and mvdan committed Dec 7, 2023
1 parent 96d2d8b commit 3a9c9aa
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
28 changes: 26 additions & 2 deletions internal/literals/shuffle.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ func (shuffle) obfuscate(obfRand *mathrand.Rand, data []byte) *ast.BlockStmt {
key := make([]byte, len(data))
obfRand.Read(key)

const (
minIdxKeySize = 2
maxIdxKeySize = 16
)

idxKeySize := minIdxKeySize
if tmp := obfRand.Intn(len(data)); tmp > idxKeySize {
idxKeySize = tmp
}
if idxKeySize > maxIdxKeySize {
idxKeySize = maxIdxKeySize
}

idxKey := make([]byte, idxKeySize)
obfRand.Read(idxKey)

fullData := make([]byte, len(data)+len(key))
operators := make([]token.Token, len(fullData))
for i := range operators {
Expand All @@ -39,10 +55,13 @@ func (shuffle) obfuscate(obfRand *mathrand.Rand, data []byte) *ast.BlockStmt {

args := []ast.Expr{ast.NewIdent("data")}
for i := range data {
keyIdx := obfRand.Intn(idxKeySize)
k := int(idxKey[keyIdx])

args = append(args, operatorToReversedBinaryExpr(
operators[i],
ah.IndexExpr("fullData", ah.IntLit(shuffledIdxs[i])),
ah.IndexExpr("fullData", ah.IntLit(shuffledIdxs[len(data)+i])),
ah.IndexExpr("fullData", &ast.BinaryExpr{X: ah.IntLit(shuffledIdxs[i] ^ k), Op: token.XOR, Y: ah.CallExprByName("int", ah.IndexExpr("idxKey", ah.IntLit(keyIdx)))}),
ah.IndexExpr("fullData", &ast.BinaryExpr{X: ah.IntLit(shuffledIdxs[len(data)+i] ^ k), Op: token.XOR, Y: ah.CallExprByName("int", ah.IndexExpr("idxKey", ah.IntLit(keyIdx)))}),
))
}

Expand All @@ -52,6 +71,11 @@ func (shuffle) obfuscate(obfRand *mathrand.Rand, data []byte) *ast.BlockStmt {
Tok: token.DEFINE,
Rhs: []ast.Expr{ah.DataToByteSlice(shuffledFullData)},
},
&ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("idxKey")},
Tok: token.DEFINE,
Rhs: []ast.Expr{ah.DataToByteSlice(idxKey)},
},
&ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("data")},
Tok: token.DEFINE,
Expand Down
4 changes: 2 additions & 2 deletions testdata/script/literals.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ grep '^\s+\w+ := \[\.{3}\](byte|uint16|uint32|uint64)\{[0-9\s,]+\}$' debug1/test
# Split obfuscator. Detect decryptKey ^= i * counter
grep '^\s+\w+ \^= \w+ \* \w+$' debug1/test/main/extra_literals.go

# XorShuffle obfuscator. Detect data = append(data, x (^|-|+) y...).
# XorShuffle obfuscator. Detect data = append(data, x[? ^ idxKey[?]] (^|-|+) y[? ^ idxKey[?]]...).
# Note that the line obfuscator adds an inline comment before the call.
grep '^\s+\w+ = .*\bappend\(\w+,(\s+\w+\[\d+\][\^\-+]\w+\[\d+\],?)+\)$' debug1/test/main/extra_literals.go
grep '^(\s+)?\w+ = .*\bappend\(\w+,(\s+\w+\[\d+\^\s.+\][\^\-+]\w+\[\d+\^\s.+\],?)+\)$' debug1/test/main/extra_literals.go

# XorSeed obfuscator. Detect type decFunc func(byte) decFunc
grep '^\s+type \w+ func\(byte\) \w+$' debug1/test/main/extra_literals.go
Expand Down

0 comments on commit 3a9c9aa

Please sign in to comment.