This commit is contained in:
Paul Scheduikat
2025-06-03 02:03:16 +02:00
parent 0b8de06a09
commit edcdaf3e35
8 changed files with 172 additions and 138 deletions

View File

@@ -140,6 +140,63 @@ func IndexExprByExpr(xExpr, indexExpr ast.Expr) *ast.IndexExpr {
return &ast.IndexExpr{X: xExpr, Index: indexExpr} return &ast.IndexExpr{X: xExpr, Index: indexExpr}
} }
// UnaryExpr creates a unary expression with the given operator and operand
func UnaryExpr(op token.Token, x ast.Expr) *ast.UnaryExpr {
return &ast.UnaryExpr{
Op: op,
X: x,
}
}
// StarExpr creates a pointer type expression "*x"
func StarExpr(x ast.Expr) *ast.StarExpr {
return &ast.StarExpr{X: x}
}
// ArrayType creates an array type expression "[len]eltType"
func ArrayType(len ast.Expr, eltType ast.Expr) *ast.ArrayType {
return &ast.ArrayType{
Len: len,
Elt: eltType,
}
}
// ByteArrayType creates a byte array type "[len]byte"
func ByteArrayType(len int64) *ast.ArrayType {
lenLit := IntLit(int(len))
return ArrayType(lenLit, ast.NewIdent("byte"))
}
// ByteSliceType creates a byte slice type "[]byte"
func ByteSliceType() *ast.ArrayType {
return &ast.ArrayType{Elt: ast.NewIdent("byte")}
}
// BinaryExpr creates a binary expression "x op y"
func BinaryExpr(x ast.Expr, op token.Token, y ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: x,
Op: op,
Y: y,
}
}
// UintLit returns an ast.BasicLit of kind INT for uint64 values
func UintLit(value uint64) *ast.BasicLit {
return &ast.BasicLit{
Kind: token.INT,
Value: fmt.Sprint(value),
}
}
// Field creates a field with names and type for function parameters or struct fields
func Field(typ ast.Expr, names ...*ast.Ident) *ast.Field {
return &ast.Field{
Names: names,
Type: typ,
}
}
func ConstToAst(val constant.Value) ast.Expr { func ConstToAst(val constant.Value) ast.Expr {
switch val.Kind() { switch val.Kind() {
case constant.Bool: case constant.Bool:

View File

@@ -226,9 +226,10 @@ func withPos(node ast.Node, pos token.Pos) ast.Node {
func obfuscateString(obfRand *obfRand, data string) *ast.CallExpr { func obfuscateString(obfRand *obfRand, data string) *ast.CallExpr {
obf := getNextObfuscator(obfRand, len(data)) obf := getNextObfuscator(obfRand, len(data))
// Generate junk bytes to to prepend and append to the data.
// This is to prevent the obfuscated string from being easily fingerprintable.
junkBytes := make([]byte, obfRand.Intn(maxStringJunkBytes-minStringJunkBytes)+minStringJunkBytes) junkBytes := make([]byte, obfRand.Intn(maxStringJunkBytes-minStringJunkBytes)+minStringJunkBytes)
obfRand.Read(junkBytes) obfRand.Read(junkBytes)
splitIdx := obfRand.Intn(len(junkBytes)) splitIdx := obfRand.Intn(len(junkBytes))
extKeys := randExtKeys(obfRand.Rand) extKeys := randExtKeys(obfRand.Rand)
@@ -246,7 +247,7 @@ func obfuscateString(obfRand *obfRand, data string) *ast.CallExpr {
// } // }
funcTyp := &ast.FuncType{ funcTyp := &ast.FuncType{
Params: &ast.FieldList{List: []*ast.Field{{ Params: &ast.FieldList{List: []*ast.Field{{
Type: &ast.ArrayType{Elt: ast.NewIdent("byte")}, Type: ah.ByteSliceType(),
}}}, }}},
Results: &ast.FieldList{List: []*ast.Field{{ Results: &ast.FieldList{List: []*ast.Field{{
Type: ast.NewIdent("string"), Type: ast.NewIdent("string"),
@@ -256,26 +257,23 @@ func obfuscateString(obfRand *obfRand, data string) *ast.CallExpr {
Type: &ast.FuncType{ Type: &ast.FuncType{
Params: &ast.FieldList{List: []*ast.Field{{ Params: &ast.FieldList{List: []*ast.Field{{
Names: []*ast.Ident{ast.NewIdent("x")}, Names: []*ast.Ident{ast.NewIdent("x")},
Type: &ast.ArrayType{Elt: ast.NewIdent("byte")}, Type: ah.ByteSliceType(),
}}}, }}},
Results: &ast.FieldList{List: []*ast.Field{{ Results: &ast.FieldList{List: []*ast.Field{{
Type: ast.NewIdent("string"), Type: ast.NewIdent("string"),
}}}, }}},
}, },
Body: &ast.BlockStmt{List: []ast.Stmt{ Body: ah.BlockStmt(
&ast.ReturnStmt{Results: []ast.Expr{ ah.ReturnStmt(
&ast.CallExpr{ ah.CallExprByName("string",
Fun: ast.NewIdent("string"), &ast.SliceExpr{
Args: []ast.Expr{ X: ast.NewIdent("x"),
&ast.SliceExpr{ Low: ah.IntLit(splitIdx),
X: ast.NewIdent("x"), High: ah.IntLit(splitIdx + len(plainData)),
Low: ah.IntLit(splitIdx),
High: ah.IntLit(splitIdx + len(plainData)),
},
}, },
}, ),
}}, ),
}}, ),
} }
block.List = append(block.List, ah.ReturnStmt(ah.CallExpr(obfRand.proxyDispatcher.HideValue(funcVal, funcTyp), ast.NewIdent("data")))) block.List = append(block.List, ah.ReturnStmt(ah.CallExpr(obfRand.proxyDispatcher.HideValue(funcVal, funcTyp), ast.NewIdent("data"))))
return ah.LambdaCall(params, ast.NewIdent("string"), block, args) return ah.LambdaCall(params, ast.NewIdent("string"), block, args)
@@ -289,17 +287,14 @@ func obfuscateByteSlice(obfRand *obfRand, isPointer bool, data []byte) *ast.Call
params, args := extKeysToParams(obfRand, extKeys) params, args := extKeysToParams(obfRand, extKeys)
if isPointer { if isPointer {
block.List = append(block.List, ah.ReturnStmt(&ast.UnaryExpr{ block.List = append(block.List, ah.ReturnStmt(
Op: token.AND, ah.UnaryExpr(token.AND, ast.NewIdent("data")),
X: ast.NewIdent("data"), ))
})) return ah.LambdaCall(params, ah.StarExpr(ah.ByteSliceType()), block, args)
return ah.LambdaCall(params, &ast.StarExpr{
X: &ast.ArrayType{Elt: ast.NewIdent("byte")},
}, block, args)
} }
block.List = append(block.List, ah.ReturnStmt(ast.NewIdent("data"))) block.List = append(block.List, ah.ReturnStmt(ast.NewIdent("data")))
return ah.LambdaCall(params, &ast.ArrayType{Elt: ast.NewIdent("byte")}, block, args) return ah.LambdaCall(params, ah.ByteSliceType(), block, args)
} }
func obfuscateByteArray(obfRand *obfRand, isPointer bool, data []byte, length int64) *ast.CallExpr { func obfuscateByteArray(obfRand *obfRand, isPointer bool, data []byte, length int64) *ast.CallExpr {
@@ -309,10 +304,7 @@ func obfuscateByteArray(obfRand *obfRand, isPointer bool, data []byte, length in
block := obf.obfuscate(obfRand.Rand, data, extKeys) block := obf.obfuscate(obfRand.Rand, data, extKeys)
params, args := extKeysToParams(obfRand, extKeys) params, args := extKeysToParams(obfRand, extKeys)
arrayType := &ast.ArrayType{ arrayType := ah.ByteArrayType(length)
Len: ah.IntLit(int(length)),
Elt: ast.NewIdent("byte"),
}
sliceToArray := []ast.Stmt{ sliceToArray := []ast.Stmt{
&ast.DeclStmt{ &ast.DeclStmt{
@@ -328,26 +320,25 @@ func obfuscateByteArray(obfRand *obfRand, isPointer bool, data []byte, length in
Key: ast.NewIdent("i"), Key: ast.NewIdent("i"),
Tok: token.DEFINE, Tok: token.DEFINE,
X: ast.NewIdent("data"), X: ast.NewIdent("data"),
Body: &ast.BlockStmt{List: []ast.Stmt{ Body: ah.BlockStmt(
&ast.AssignStmt{ ah.AssignStmt(
Lhs: []ast.Expr{ah.IndexExpr("newdata", ast.NewIdent("i"))}, ah.IndexExprByExpr(ast.NewIdent("newdata"), ast.NewIdent("i")),
Tok: token.ASSIGN, ah.IndexExprByExpr(ast.NewIdent("data"), ast.NewIdent("i")),
Rhs: []ast.Expr{ah.IndexExpr("data", ast.NewIdent("i"))}, ),
}, ),
}},
}, },
} }
var retexpr ast.Expr = ast.NewIdent("newdata") var retexpr ast.Expr = ast.NewIdent("newdata")
if isPointer { if isPointer {
retexpr = &ast.UnaryExpr{X: retexpr, Op: token.AND} retexpr = ah.UnaryExpr(token.AND, retexpr)
} }
sliceToArray = append(sliceToArray, ah.ReturnStmt(retexpr)) sliceToArray = append(sliceToArray, ah.ReturnStmt(retexpr))
block.List = append(block.List, sliceToArray...) block.List = append(block.List, sliceToArray...)
if isPointer { if isPointer {
return ah.LambdaCall(params, &ast.StarExpr{X: arrayType}, block, args) return ah.LambdaCall(params, ah.StarExpr(arrayType), block, args)
} }
return ah.LambdaCall(params, arrayType, block, args) return ah.LambdaCall(params, arrayType, block, args)

View File

@@ -15,48 +15,48 @@ import (
ah "mvdan.cc/garble/internal/asthelper" ah "mvdan.cc/garble/internal/asthelper"
) )
// extKeyRarity probability of using an external key. // externalKeyProbability probability of using an external key.
// Larger value, greater probability of using an external key. // Larger value, greater probability of using an external key.
// Must be between 0 and 1 // Must be between 0 and 1
type extKeyRarity float32 type externalKeyProbability float32
const ( const (
rareRarity extKeyRarity = 0.4 lowProb externalKeyProbability = 0.4
normalRarity extKeyRarity = 0.6 normalProb externalKeyProbability = 0.6
commonRarity extKeyRarity = 0.8 highProb externalKeyProbability = 0.8
) )
func (r extKeyRarity) Try(rand *mathrand.Rand) bool { func (r externalKeyProbability) Try(rand *mathrand.Rand) bool {
return rand.Float32() < float32(r) return rand.Float32() < float32(r)
} }
// extKey contains all information about the external key // externalKey contains all information about the external key
type extKey struct { type externalKey struct {
name, typ string name, typ string
value uint64 value uint64
bits int bits int
refs int refs int
} }
func (k *extKey) Type() *ast.Ident { func (k *externalKey) Type() *ast.Ident {
return ast.NewIdent(k.typ) return ast.NewIdent(k.typ)
} }
func (k *extKey) Name() *ast.Ident { func (k *externalKey) Name() *ast.Ident {
return ast.NewIdent(k.name) return ast.NewIdent(k.name)
} }
func (k *extKey) AddRef() { func (k *externalKey) AddRef() {
k.refs++ k.refs++
} }
func (k *extKey) IsUsed() bool { func (k *externalKey) IsUsed() bool {
return k.refs > 0 return k.refs > 0
} }
// obfuscator takes a byte slice and converts it to a ast.BlockStmt // obfuscator takes a byte slice and converts it to a ast.BlockStmt
type obfuscator interface { type obfuscator interface {
obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *ast.BlockStmt obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*externalKey) *ast.BlockStmt
} }
var ( var (
@@ -107,20 +107,18 @@ func evalOperator(t token.Token, x, y byte) byte {
} }
func operatorToReversedBinaryExpr(t token.Token, x, y ast.Expr) *ast.BinaryExpr { func operatorToReversedBinaryExpr(t token.Token, x, y ast.Expr) *ast.BinaryExpr {
expr := &ast.BinaryExpr{X: x, Y: y} var op token.Token
switch t { switch t {
case token.XOR: case token.XOR:
expr.Op = token.XOR op = token.XOR
case token.ADD: case token.ADD:
expr.Op = token.SUB op = token.SUB
case token.SUB: case token.SUB:
expr.Op = token.ADD op = token.ADD
default: default:
panic(fmt.Sprintf("unknown operator: %s", t)) panic(fmt.Sprintf("unknown operator: %s", t))
} }
return ah.BinaryExpr(x, op, y)
return expr
} }
const ( const (
@@ -149,44 +147,38 @@ var extKeyRanges = []struct {
} }
// randExtKey generates a random external key with a unique name, type, value, and bitnesses // randExtKey generates a random external key with a unique name, type, value, and bitnesses
func randExtKey(obfRand *mathrand.Rand, idx int) *extKey { func randExtKey(rand *mathrand.Rand, idx int) *externalKey {
r := extKeyRanges[obfRand.Intn(len(extKeyRanges))] r := extKeyRanges[rand.Intn(len(extKeyRanges))]
return &extKey{ return &externalKey{
name: "garbleExternalKey" + strconv.Itoa(idx), name: "garbleExternalKey" + strconv.Itoa(idx),
typ: r.typ, typ: r.typ,
value: obfRand.Uint64() & r.max, value: rand.Uint64() & r.max,
bits: r.bits, bits: r.bits,
} }
} }
func randExtKeys(obfRand *mathrand.Rand) []*extKey { func randExtKeys(rand *mathrand.Rand) []*externalKey {
count := minExtKeyCount + obfRand.Intn(maxExtKeyCount-minExtKeyCount) count := minExtKeyCount + rand.Intn(maxExtKeyCount-minExtKeyCount)
keys := make([]*extKey, count) keys := make([]*externalKey, count)
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
keys[i] = randExtKey(obfRand, i) keys[i] = randExtKey(rand, i)
} }
return keys return keys
} }
// extKeysToParams converts a list of extKeys into a parameter list and argument expressions for function calls. // extKeysToParams converts a list of extKeys into a parameter list and argument expressions for function calls.
// It ensures unused keys have placeholder names and sometimes use proxyDispatcher.HideValue for key values // It ensures unused keys have placeholder names and sometimes use proxyDispatcher.HideValue for key values
func extKeysToParams(objRand *obfRand, keys []*extKey) (params *ast.FieldList, args []ast.Expr) { func extKeysToParams(objRand *obfRand, keys []*externalKey) (params *ast.FieldList, args []ast.Expr) {
params = &ast.FieldList{} params = &ast.FieldList{}
for _, key := range keys { for _, key := range keys {
name := key.Name() name := key.Name()
if !key.IsUsed() { if !key.IsUsed() {
name.Name = "_" name.Name = "_"
} }
params.List = append(params.List, &ast.Field{ params.List = append(params.List, ah.Field(key.Type(), name))
Names: []*ast.Ident{name},
Type: key.Type(),
})
var extKeyExpr ast.Expr = &ast.BasicLit{ var extKeyExpr ast.Expr = ah.UintLit(key.value)
Kind: token.INT, if lowProb.Try(objRand.Rand) {
Value: fmt.Sprint(key.value),
}
if rareRarity.Try(objRand.Rand) {
extKeyExpr = objRand.proxyDispatcher.HideValue(extKeyExpr, ast.NewIdent(key.typ)) extKeyExpr = objRand.proxyDispatcher.HideValue(extKeyExpr, ast.NewIdent(key.typ))
} }
args = append(args, extKeyExpr) args = append(args, extKeyExpr)
@@ -196,15 +188,11 @@ func extKeysToParams(objRand *obfRand, keys []*extKey) (params *ast.FieldList, a
// extKeyToExpr converts an external key into an AST expression like: // extKeyToExpr converts an external key into an AST expression like:
// //
// uint8(key >> b) // uint8(key >> b)
func extKeyToExpr(key *extKey, b int) ast.Expr { func (key *externalKey) ToExpr(b int) ast.Expr {
var x ast.Expr = key.Name() var x ast.Expr = key.Name()
if b > 0 { if b > 0 {
x = &ast.BinaryExpr{ x = ah.BinaryExpr(x, token.SHR, ah.IntLit(b*8))
X: x,
Op: token.SHR,
Y: ah.IntLit(b * 8),
}
} }
if key.typ != "uint8" { if key.typ != "uint8" {
x = ah.CallExprByName("byte", x) x = ah.CallExprByName("byte", x)
@@ -219,26 +207,23 @@ func extKeyToExpr(key *extKey, b int) ast.Expr {
// data[<index>] = data[<index>] <random operator> byte(<external key> >> <random shift>) // repeated random times // data[<index>] = data[<index>] <random operator> byte(<external key> >> <random shift>) // repeated random times
// return data // return data
// }() // }()
func dataToByteSliceWithExtKeys(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) ast.Expr { func dataToByteSliceWithExtKeys(rand *mathrand.Rand, data []byte, extKeys []*externalKey) ast.Expr {
extKeyOpCount := minByteSliceExtKeyOps + obfRand.Intn(maxByteSliceExtKeyOps-minByteSliceExtKeyOps) extKeyOpCount := minByteSliceExtKeyOps + rand.Intn(maxByteSliceExtKeyOps-minByteSliceExtKeyOps)
var stmts []ast.Stmt var stmts []ast.Stmt
for i := 0; i < extKeyOpCount; i++ { for i := 0; i < extKeyOpCount; i++ {
key := extKeys[obfRand.Intn(len(extKeys))] key := extKeys[rand.Intn(len(extKeys))]
key.AddRef() key.AddRef()
idx, op, b := obfRand.Intn(len(data)), randOperator(obfRand), obfRand.Intn(key.bits/8) idx, op, b := rand.Intn(len(data)), randOperator(rand), rand.Intn(key.bits/8)
data[idx] = evalOperator(op, data[idx], byte(key.value>>(b*8))) data[idx] = evalOperator(op, data[idx], byte(key.value>>(b*8)))
stmts = append(stmts, &ast.AssignStmt{ stmts = append(stmts, ah.AssignStmt(
Lhs: []ast.Expr{ah.IndexExpr("data", ah.IntLit(idx))}, ah.IndexExpr("data", ah.IntLit(idx)),
Tok: token.ASSIGN, operatorToReversedBinaryExpr(op,
Rhs: []ast.Expr{ ah.IndexExpr("data", ah.IntLit(idx)),
operatorToReversedBinaryExpr(op, key.ToExpr(b),
ah.IndexExpr("data", ah.IntLit(idx)), ),
extKeyToExpr(key, b), ))
),
},
})
} }
// External keys can be applied several times to the same array element, // External keys can be applied several times to the same array element,
@@ -246,26 +231,26 @@ func dataToByteSliceWithExtKeys(obfRand *mathrand.Rand, data []byte, extKeys []*
slices.Reverse(stmts) slices.Reverse(stmts)
stmts = append([]ast.Stmt{ah.AssignDefineStmt(ast.NewIdent("data"), ah.DataToByteSlice(data))}, append(stmts, ah.ReturnStmt(ast.NewIdent("data")))...) stmts = append([]ast.Stmt{ah.AssignDefineStmt(ast.NewIdent("data"), ah.DataToByteSlice(data))}, append(stmts, ah.ReturnStmt(ast.NewIdent("data")))...)
return ah.LambdaCall(nil, &ast.ArrayType{Elt: ast.NewIdent("byte")}, ah.BlockStmt(stmts...), nil) return ah.LambdaCall(nil, ah.ByteSliceType(), ah.BlockStmt(stmts...), nil)
} }
// dataToByteSliceWithExtKeys scramble and turns a byte into an AST expression like: // dataToByteSliceWithExtKeys scramble and turns a byte into an AST expression like:
// //
// byte(<obfuscated value>) <random operator> byte(<external key> >> <random shift>) // byte(<obfuscated value>) <random operator> byte(<external key> >> <random shift>)
func byteLitWithExtKey(obfRand *mathrand.Rand, val byte, extKeys []*extKey, rarity extKeyRarity) ast.Expr { func byteLitWithExtKey(rand *mathrand.Rand, val byte, extKeys []*externalKey, extKeyProb externalKeyProbability) ast.Expr {
if !rarity.Try(obfRand) { if !extKeyProb.Try(rand) {
return ah.IntLit(int(val)) return ah.IntLit(int(val))
} }
key := extKeys[obfRand.Intn(len(extKeys))] key := extKeys[rand.Intn(len(extKeys))]
key.AddRef() key.AddRef()
op, b := randOperator(obfRand), obfRand.Intn(key.bits/8) op, b := randOperator(rand), rand.Intn(key.bits/8)
newVal := evalOperator(op, val, byte(key.value>>(b*8))) newVal := evalOperator(op, val, byte(key.value>>(b*8)))
return operatorToReversedBinaryExpr(op, return operatorToReversedBinaryExpr(op,
ah.CallExprByName("byte", ah.IntLit(int(newVal))), ah.CallExprByName("byte", ah.IntLit(int(newVal))),
extKeyToExpr(key, b), key.ToExpr(b),
) )
} }

View File

@@ -16,7 +16,7 @@ type seed struct{}
// check that the obfuscator interface is implemented // check that the obfuscator interface is implemented
var _ obfuscator = seed{} var _ obfuscator = seed{}
func (seed) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *ast.BlockStmt { func (seed) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*externalKey) *ast.BlockStmt {
seed := byte(obfRand.Uint32()) seed := byte(obfRand.Uint32())
originalSeed := seed originalSeed := seed
@@ -27,18 +27,18 @@ func (seed) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *a
seed += encB seed += encB
if i == 0 { if i == 0 {
callExpr = ah.CallExpr(ast.NewIdent("fnc"), byteLitWithExtKey(obfRand, encB, extKeys, commonRarity)) callExpr = ah.CallExpr(ast.NewIdent("fnc"), byteLitWithExtKey(obfRand, encB, extKeys, highProb))
continue continue
} }
callExpr = ah.CallExpr(callExpr, byteLitWithExtKey(obfRand, encB, extKeys, rareRarity)) callExpr = ah.CallExpr(callExpr, byteLitWithExtKey(obfRand, encB, extKeys, lowProb))
} }
return ah.BlockStmt( return ah.BlockStmt(
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("seed")}, Lhs: []ast.Expr{ast.NewIdent("seed")},
Tok: token.DEFINE, Tok: token.DEFINE,
Rhs: []ast.Expr{ah.CallExprByName("byte", byteLitWithExtKey(obfRand, originalSeed, extKeys, commonRarity))}, Rhs: []ast.Expr{ah.CallExprByName("byte", byteLitWithExtKey(obfRand, originalSeed, extKeys, highProb))},
}, },
&ast.DeclStmt{ &ast.DeclStmt{
Decl: &ast.GenDecl{ Decl: &ast.GenDecl{

View File

@@ -16,9 +16,9 @@ type shuffle struct{}
// check that the obfuscator interface is implemented // check that the obfuscator interface is implemented
var _ obfuscator = shuffle{} var _ obfuscator = shuffle{}
func (shuffle) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *ast.BlockStmt { func (shuffle) obfuscate(rand *mathrand.Rand, data []byte, extKeys []*externalKey) *ast.BlockStmt {
key := make([]byte, len(data)) key := make([]byte, len(data))
obfRand.Read(key) rand.Read(key)
const ( const (
minIdxKeySize = 2 minIdxKeySize = 2
@@ -26,7 +26,7 @@ func (shuffle) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey)
) )
idxKeySize := minIdxKeySize idxKeySize := minIdxKeySize
if tmp := obfRand.Intn(len(data)); tmp > idxKeySize { if tmp := rand.Intn(len(data)); tmp > idxKeySize {
idxKeySize = tmp idxKeySize = tmp
} }
if idxKeySize > maxIdxKeySize { if idxKeySize > maxIdxKeySize {
@@ -34,19 +34,19 @@ func (shuffle) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey)
} }
idxKey := make([]byte, idxKeySize) idxKey := make([]byte, idxKeySize)
obfRand.Read(idxKey) rand.Read(idxKey)
fullData := make([]byte, len(data)+len(key)) fullData := make([]byte, len(data)+len(key))
operators := make([]token.Token, len(fullData)) operators := make([]token.Token, len(fullData))
for i := range operators { for i := range operators {
operators[i] = randOperator(obfRand) operators[i] = randOperator(rand)
} }
for i, b := range key { for i, b := range key {
fullData[i], fullData[i+len(data)] = evalOperator(operators[i], data[i], b), b fullData[i], fullData[i+len(data)] = evalOperator(operators[i], data[i], b), b
} }
shuffledIdxs := obfRand.Perm(len(fullData)) shuffledIdxs := rand.Perm(len(fullData))
shuffledFullData := make([]byte, len(fullData)) shuffledFullData := make([]byte, len(fullData))
for i, b := range fullData { for i, b := range fullData {
@@ -55,7 +55,7 @@ func (shuffle) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey)
args := []ast.Expr{ast.NewIdent("data")} args := []ast.Expr{ast.NewIdent("data")}
for i := range data { for i := range data {
keyIdx := obfRand.Intn(idxKeySize) keyIdx := rand.Intn(idxKeySize)
k := int(idxKey[keyIdx]) k := int(idxKey[keyIdx])
args = append(args, operatorToReversedBinaryExpr( args = append(args, operatorToReversedBinaryExpr(
@@ -69,12 +69,12 @@ func (shuffle) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey)
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("fullData")}, Lhs: []ast.Expr{ast.NewIdent("fullData")},
Tok: token.DEFINE, Tok: token.DEFINE,
Rhs: []ast.Expr{dataToByteSliceWithExtKeys(obfRand, shuffledFullData, extKeys)}, Rhs: []ast.Expr{dataToByteSliceWithExtKeys(rand, shuffledFullData, extKeys)},
}, },
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("idxKey")}, Lhs: []ast.Expr{ast.NewIdent("idxKey")},
Tok: token.DEFINE, Tok: token.DEFINE,
Rhs: []ast.Expr{dataToByteSliceWithExtKeys(obfRand, idxKey, extKeys)}, Rhs: []ast.Expr{dataToByteSliceWithExtKeys(rand, idxKey, extKeys)},
}, },
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("data")}, Lhs: []ast.Expr{ast.NewIdent("data")},

View File

@@ -7,6 +7,7 @@ import (
"go/ast" "go/ast"
"go/token" "go/token"
mathrand "math/rand" mathrand "math/rand"
ah "mvdan.cc/garble/internal/asthelper" ah "mvdan.cc/garble/internal/asthelper"
) )
@@ -15,11 +16,11 @@ type simple struct{}
// check that the obfuscator interface is implemented // check that the obfuscator interface is implemented
var _ obfuscator = simple{} var _ obfuscator = simple{}
func (simple) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *ast.BlockStmt { func (simple) obfuscate(rand *mathrand.Rand, data []byte, extKeys []*externalKey) *ast.BlockStmt {
key := make([]byte, len(data)) key := make([]byte, len(data))
obfRand.Read(key) rand.Read(key)
op := randOperator(obfRand) op := randOperator(rand)
for i, b := range key { for i, b := range key {
data[i] = evalOperator(op, data[i], b) data[i] = evalOperator(op, data[i], b)
} }
@@ -28,12 +29,12 @@ func (simple) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey)
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("key")}, Lhs: []ast.Expr{ast.NewIdent("key")},
Tok: token.DEFINE, Tok: token.DEFINE,
Rhs: []ast.Expr{dataToByteSliceWithExtKeys(obfRand, key, extKeys)}, Rhs: []ast.Expr{dataToByteSliceWithExtKeys(rand, key, extKeys)},
}, },
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("data")}, Lhs: []ast.Expr{ast.NewIdent("data")},
Tok: token.DEFINE, Tok: token.DEFINE,
Rhs: []ast.Expr{dataToByteSliceWithExtKeys(obfRand, data, extKeys)}, Rhs: []ast.Expr{dataToByteSliceWithExtKeys(rand, data, extKeys)},
}, },
&ast.RangeStmt{ &ast.RangeStmt{
Key: ast.NewIdent("i"), Key: ast.NewIdent("i"),

View File

@@ -66,33 +66,33 @@ func encryptChunks(chunks [][]byte, op token.Token, key byte) {
} }
} }
func (split) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *ast.BlockStmt { func (split) obfuscate(rand *mathrand.Rand, data []byte, extKeys []*externalKey) *ast.BlockStmt {
var chunks [][]byte var chunks [][]byte
// Short arrays should be divided into single-byte fragments // Short arrays should be divided into single-byte fragments
if len(data)/maxChunkSize < minCaseCount { if len(data)/maxChunkSize < minCaseCount {
chunks = splitIntoOneByteChunks(data) chunks = splitIntoOneByteChunks(data)
} else { } else {
chunks = splitIntoRandomChunks(obfRand, data) chunks = splitIntoRandomChunks(rand, data)
} }
// Generate indexes for cases chunk count + 1 decrypt case + 1 exit case // Generate indexes for cases chunk count + 1 decrypt case + 1 exit case
indexes := obfRand.Perm(len(chunks) + 2) indexes := rand.Perm(len(chunks) + 2)
decryptKeyInitial := byte(obfRand.Uint32()) decryptKeyInitial := byte(rand.Uint32())
decryptKey := decryptKeyInitial decryptKey := decryptKeyInitial
// Calculate decrypt key based on indexes and position. Ignore exit index // Calculate decrypt key based on indexes and position. Ignore exit index
for i, index := range indexes[:len(indexes)-1] { for i, index := range indexes[:len(indexes)-1] {
decryptKey ^= byte(index * i) decryptKey ^= byte(index * i)
} }
op := randOperator(obfRand) op := randOperator(rand)
encryptChunks(chunks, op, decryptKey) encryptChunks(chunks, op, decryptKey)
decryptIndex := indexes[len(indexes)-2] decryptIndex := indexes[len(indexes)-2]
exitIndex := indexes[len(indexes)-1] exitIndex := indexes[len(indexes)-1]
switchCases := []ast.Stmt{&ast.CaseClause{ switchCases := []ast.Stmt{&ast.CaseClause{
List: []ast.Expr{ah.IntLit(decryptIndex)}, List: []ast.Expr{ah.IntLit(decryptIndex)},
Body: shuffleStmts(obfRand, Body: shuffleStmts(rand,
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("i")}, Lhs: []ast.Expr{ast.NewIdent("i")},
Tok: token.ASSIGN, Tok: token.ASSIGN,
@@ -131,15 +131,15 @@ func (split) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *
} }
if len(chunk) != 1 { if len(chunk) != 1 {
appendCallExpr.Args = append(appendCallExpr.Args, dataToByteSliceWithExtKeys(obfRand, chunk, extKeys)) appendCallExpr.Args = append(appendCallExpr.Args, dataToByteSliceWithExtKeys(rand, chunk, extKeys))
appendCallExpr.Ellipsis = 1 appendCallExpr.Ellipsis = 1
} else { } else {
appendCallExpr.Args = append(appendCallExpr.Args, byteLitWithExtKey(obfRand, chunk[0], extKeys, rareRarity)) appendCallExpr.Args = append(appendCallExpr.Args, byteLitWithExtKey(rand, chunk[0], extKeys, lowProb))
} }
switchCases = append(switchCases, &ast.CaseClause{ switchCases = append(switchCases, &ast.CaseClause{
List: []ast.Expr{ah.IntLit(index)}, List: []ast.Expr{ah.IntLit(index)},
Body: shuffleStmts(obfRand, Body: shuffleStmts(rand,
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("i")}, Lhs: []ast.Expr{ast.NewIdent("i")},
Tok: token.ASSIGN, Tok: token.ASSIGN,
@@ -168,7 +168,7 @@ func (split) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("decryptKey")}, Lhs: []ast.Expr{ast.NewIdent("decryptKey")},
Tok: token.DEFINE, Tok: token.DEFINE,
Rhs: []ast.Expr{ah.CallExprByName("int", byteLitWithExtKey(obfRand, decryptKeyInitial, extKeys, normalRarity))}, Rhs: []ast.Expr{ah.CallExprByName("int", byteLitWithExtKey(rand, decryptKeyInitial, extKeys, normalProb))},
}, },
&ast.ForStmt{ &ast.ForStmt{
Init: &ast.AssignStmt{ Init: &ast.AssignStmt{
@@ -199,7 +199,7 @@ func (split) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *
}, },
&ast.SwitchStmt{ &ast.SwitchStmt{
Tag: ast.NewIdent("i"), Tag: ast.NewIdent("i"),
Body: ah.BlockStmt(shuffleStmts(obfRand, switchCases...)...), Body: ah.BlockStmt(shuffleStmts(rand, switchCases...)...),
}), }),
}, },
) )

View File

@@ -58,13 +58,13 @@ func generateSwapCount(obfRand *mathrand.Rand, dataLen int) int {
return swapCount return swapCount
} }
func (swap) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *ast.BlockStmt { func (swap) obfuscate(rand *mathrand.Rand, data []byte, extKeys []*externalKey) *ast.BlockStmt {
swapCount := generateSwapCount(obfRand, len(data)) swapCount := generateSwapCount(rand, len(data))
shiftKey := byte(obfRand.Uint32()) shiftKey := byte(rand.Uint32())
op := randOperator(obfRand) op := randOperator(rand)
positions := genRandIntSlice(obfRand, len(data), swapCount) positions := genRandIntSlice(rand, len(data), swapCount)
for i := len(positions) - 2; i >= 0; i -= 2 { for i := len(positions) - 2; i >= 0; i -= 2 {
// Generate local key for xor based on random key and byte position // Generate local key for xor based on random key and byte position
localKey := byte(i) + byte(positions[i]^positions[i+1]) + shiftKey localKey := byte(i) + byte(positions[i]^positions[i+1]) + shiftKey
@@ -76,7 +76,7 @@ func (swap) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *a
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("data")}, Lhs: []ast.Expr{ast.NewIdent("data")},
Tok: token.DEFINE, Tok: token.DEFINE,
Rhs: []ast.Expr{dataToByteSliceWithExtKeys(obfRand, data, extKeys)}, Rhs: []ast.Expr{dataToByteSliceWithExtKeys(rand, data, extKeys)},
}, },
&ast.AssignStmt{ &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("positions")}, Lhs: []ast.Expr{ast.NewIdent("positions")},
@@ -118,7 +118,7 @@ func (swap) obfuscate(obfRand *mathrand.Rand, data []byte, extKeys []*extKey) *a
}), }),
}, },
Op: token.ADD, Op: token.ADD,
Y: byteLitWithExtKey(obfRand, shiftKey, extKeys, commonRarity), Y: byteLitWithExtKey(rand, shiftKey, extKeys, highProb),
}}, }},
}, },
&ast.AssignStmt{ &ast.AssignStmt{