diff --git a/internal/literals/obfuscators.go b/internal/literals/obfuscators.go index bd86bf6..80a8747 100644 --- a/internal/literals/obfuscators.go +++ b/internal/literals/obfuscators.go @@ -19,6 +19,7 @@ var ( // obfuscators contains all types which implement the obfuscator Interface obfuscators = []obfuscator{ xor{}, + swap{}, } envGarbleSeed = os.Getenv("GARBLE_SEED") ) @@ -58,3 +59,15 @@ func genRandBytes(buffer []byte) { func genRandInt() int { return mathrand.Int() } + +func genRandIntn(max int) int { + return mathrand.Intn(max) +} + +func generateIntSlice(max, count int) []int { + indexes := make([]int, count) + for i := 0; i < count; i++ { + indexes[i] = genRandIntn(max) + } + return indexes +} diff --git a/internal/literals/swap.go b/internal/literals/swap.go new file mode 100644 index 0000000..2e24070 --- /dev/null +++ b/internal/literals/swap.go @@ -0,0 +1,149 @@ +package literals + +import ( + "go/ast" + "go/token" + "math" + "strconv" +) + +type swap struct{} + +// check that the obfuscator interface is implemented +var _ obfuscator = swap{} + +func getIndexType(dataLen int) string { + switch { + case dataLen <= math.MaxUint8: + return "byte" + case dataLen <= math.MaxUint16: + return "uint16" + case dataLen <= math.MaxUint32: + return "uint32" + default: + return "uint64" + } +} + +func positionsToSlice(data []int) *ast.CompositeLit { + arr := &ast.CompositeLit{ + Type: &ast.ArrayType{ + Len: &ast.Ellipsis{}, // Performance optimization + Elt: ident(getIndexType(len(data))), + }, + Elts: []ast.Expr{}, + } + for _, data := range data { + arr.Elts = append(arr.Elts, intLiteral(strconv.Itoa(data))) + } + return arr +} + +// Generates a random even swap count based on the length of data +func generateSwapCount(dataLen int) int { + swapCount := dataLen + + maxExtraPositions := dataLen / 2 // Limit the number of extra positions to half the data length + if maxExtraPositions > 1 { + swapCount += genRandIntn(maxExtraPositions) + } + if swapCount%2 != 0 { // Swap count must be even + swapCount++ + } + return swapCount +} + +func (x swap) obfuscate(data []byte) *ast.BlockStmt { + swapCount := generateSwapCount(len(data)) + shiftKey := byte(genRandIntn(math.MaxUint8)) + + positions := generateIntSlice(len(data), swapCount) + for i := len(positions) - 2; i >= 0; i -= 2 { + localKey := byte(i) + byte(positions[i]^positions[i+1]) + shiftKey // Generate local key for xor based on random key and byte position + data[positions[i]], data[positions[i+1]] = data[positions[i+1]]^localKey, data[positions[i]]^localKey // Swap bytes from i+1 to i and xor using local key + } + + return &ast.BlockStmt{List: []ast.Stmt{ + &ast.AssignStmt{ + Lhs: []ast.Expr{ident("data")}, + Tok: token.DEFINE, + Rhs: []ast.Expr{dataToByteSlice(data)}, + }, + &ast.AssignStmt{ + Lhs: []ast.Expr{ident("positions")}, + Tok: token.DEFINE, + Rhs: []ast.Expr{positionsToSlice(positions)}, + }, + &ast.ForStmt{ + Init: &ast.AssignStmt{ + Lhs: []ast.Expr{ident("i")}, + Tok: token.DEFINE, + Rhs: []ast.Expr{intLiteral("0")}, + }, + Cond: &ast.BinaryExpr{ + X: ident("i"), + Op: token.LSS, + Y: intLiteral(strconv.Itoa(len(positions))), + }, + Post: &ast.AssignStmt{ + Lhs: []ast.Expr{ident("i")}, + Tok: token.ADD_ASSIGN, + Rhs: []ast.Expr{intLiteral("2")}, + }, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.AssignStmt{ + Lhs: []ast.Expr{ident("localKey")}, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.BinaryExpr{ + X: &ast.BinaryExpr{ + X: callExpr(ident("byte"), ident("i")), + Op: token.ADD, + Y: callExpr(ident("byte"), &ast.BinaryExpr{ + X: indexExpr("positions", ident("i")), + Op: token.XOR, + Y: indexExpr("positions", &ast.BinaryExpr{ + X: ident("i"), + Op: token.ADD, + Y: intLiteral("1"), + }), + }), + }, + Op: token.ADD, + Y: intLiteral(strconv.Itoa(int(shiftKey))), + }, + }, + }, + &ast.AssignStmt{ + Lhs: []ast.Expr{ + indexExpr("data", indexExpr("positions", ident("i"))), + indexExpr("data", indexExpr("positions", &ast.BinaryExpr{ + X: ident("i"), + Op: token.ADD, + Y: intLiteral("1"), + })), + }, + Tok: token.ASSIGN, + Rhs: []ast.Expr{ + &ast.BinaryExpr{ + X: indexExpr("data", indexExpr("positions", &ast.BinaryExpr{ + X: ident("i"), + Op: token.ADD, + Y: intLiteral("1"), + })), + Op: token.XOR, + Y: ident("localKey"), + }, + &ast.BinaryExpr{ + X: indexExpr("data", indexExpr("positions", ident("i"))), + Op: token.XOR, + Y: ident("localKey"), + }, + }, + }, + }, + }, + }, + }} +}