mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-14 05:48:22 +00:00
.
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
// Fake function signature injection.
|
||||
//
|
||||
// Injects realistic-looking but dead function definitions into the source
|
||||
// file. These functions are never called and serve to confuse disassemblers
|
||||
// by polluting the symbol table with plausible function boundaries, making
|
||||
// it harder to identify real functions and their purposes.
|
||||
package transform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/lukaszraczylo/go-obfuscation/pkg/stringcrypt"
|
||||
)
|
||||
|
||||
type fakeFuncTemplate struct {
|
||||
namePattern string
|
||||
params string
|
||||
returnType string
|
||||
bodyGen func(rng *rand.Rand, argName string) string
|
||||
}
|
||||
|
||||
var fakeFuncTemplates = []fakeFuncTemplate{
|
||||
{
|
||||
namePattern: "_initAuth_obf",
|
||||
params: "token string",
|
||||
returnType: "bool",
|
||||
bodyGen: func(rng *rand.Rand, arg string) string {
|
||||
v1 := stringcrypt.RandomIdent("_v", 3)
|
||||
v2 := stringcrypt.RandomIdent("_v", 3)
|
||||
return fmt.Sprintf("\t_ = %s\n\t%s := len(%s)\n\t%s := %s & 0xFF\n\treturn %s > 100 && %s < 0",
|
||||
arg, v1, arg, v2, arg, v1, v2)
|
||||
},
|
||||
},
|
||||
{
|
||||
namePattern: "_parseConfig_obf",
|
||||
params: "data []byte",
|
||||
returnType: "int",
|
||||
bodyGen: func(rng *rand.Rand, arg string) string {
|
||||
v1 := stringcrypt.RandomIdent("_c", 3)
|
||||
v2 := stringcrypt.RandomIdent("_c", 3)
|
||||
return fmt.Sprintf("\t_ = %s\n\t%s := len(%s)\n\t%s := %s * 3\n\t_ = %s\n\treturn %s - %s",
|
||||
arg, v1, arg, v2, v1, v2, v1, v2)
|
||||
},
|
||||
},
|
||||
{
|
||||
namePattern: "_validateKey_obf",
|
||||
params: "key string, size int",
|
||||
returnType: "bool",
|
||||
bodyGen: func(rng *rand.Rand, arg string) string {
|
||||
v1 := stringcrypt.RandomIdent("_k", 3)
|
||||
v2 := stringcrypt.RandomIdent("_k", 3)
|
||||
return fmt.Sprintf("\t%s := len(key)\n\t%s := size ^ 0xDEAD\n\t_ = %s\n\treturn %s == %s && %s != %s",
|
||||
v1, v2, v2, v1, v2, v1, v2)
|
||||
},
|
||||
},
|
||||
{
|
||||
namePattern: "_hashData_obf",
|
||||
params: "input []byte",
|
||||
returnType: "[32]byte",
|
||||
bodyGen: func(rng *rand.Rand, arg string) string {
|
||||
v1 := stringcrypt.RandomIdent("_h", 3)
|
||||
return fmt.Sprintf("\tvar %s [32]byte\n\t_ = %s\n\tfor _i := range %s {\n\t\t%s[_i] = byte(_i)\n\t}\n\treturn %s",
|
||||
v1, arg, arg, v1, v1)
|
||||
},
|
||||
},
|
||||
{
|
||||
namePattern: "_encodePayload_obf",
|
||||
params: "buf []byte, offset int",
|
||||
returnType: "int",
|
||||
bodyGen: func(rng *rand.Rand, arg string) string {
|
||||
v1 := stringcrypt.RandomIdent("_e", 3)
|
||||
return fmt.Sprintf("\t_ = buf\n\t_ = offset\n\t%s := len(buf) + offset\n\treturn %s ^ %s",
|
||||
v1, v1, v1)
|
||||
},
|
||||
},
|
||||
{
|
||||
namePattern: "_checkPerms_obf",
|
||||
params: "uid int, gid int",
|
||||
returnType: "bool",
|
||||
bodyGen: func(rng *rand.Rand, arg string) string {
|
||||
v1 := stringcrypt.RandomIdent("_p", 3)
|
||||
return fmt.Sprintf("\t%s := uid ^ gid\n\treturn %s > 0 && %s < 0 && uid == gid && uid != gid",
|
||||
v1, v1, v1)
|
||||
},
|
||||
},
|
||||
{
|
||||
namePattern: "_readStream_obf",
|
||||
params: "path string",
|
||||
returnType: "[]byte",
|
||||
bodyGen: func(rng *rand.Rand, arg string) string {
|
||||
v1 := stringcrypt.RandomIdent("_r", 3)
|
||||
v2 := stringcrypt.RandomIdent("_r", 3)
|
||||
return fmt.Sprintf("\t_ = %s\n\t%s := len(%s)\n\t%s := make([]byte, %s)\n\tfor _i := range %s {\n\t\t%s[_i] = 0\n\t}\n\treturn %s",
|
||||
arg, v1, arg, v2, v1, v2, v2, v2)
|
||||
},
|
||||
},
|
||||
{
|
||||
namePattern: "_formatLog_obf",
|
||||
params: "level int, msg string",
|
||||
returnType: "string",
|
||||
bodyGen: func(rng *rand.Rand, arg string) string {
|
||||
v1 := stringcrypt.RandomIdent("_l", 3)
|
||||
return fmt.Sprintf("\t_ = level\n\t%s := len(msg)\n\tif %s > 1000000 {\n\t\treturn \"\"\n\t}\n\treturn msg[:%s]",
|
||||
v1, v1, v1)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// InjectFakeSignatures inserts 2-5 fake function definitions per file
|
||||
// that look realistic but are never called.
|
||||
func InjectFakeSignatures(src string) string {
|
||||
rng := rand.New(rand.NewSource(rand.Int63()))
|
||||
|
||||
numFake := rng.Intn(4) + 2 // 2-5 fake functions
|
||||
var fakeFuncs strings.Builder
|
||||
|
||||
// Select random templates without replacement
|
||||
perm := rng.Perm(len(fakeFuncTemplates))
|
||||
for i := 0; i < numFake && i < len(fakeFuncTemplates); i++ {
|
||||
tmpl := fakeFuncTemplates[perm[i]]
|
||||
suffix := fmt.Sprintf("%04X", rng.Intn(0xFFFF))
|
||||
funcName := tmpl.namePattern + suffix
|
||||
|
||||
argName := extractFirstArgName(tmpl.params)
|
||||
|
||||
fakeFuncs.WriteString("\n//go:noinline\n")
|
||||
fakeFuncs.WriteString(fmt.Sprintf("func %s(%s) %s {\n", funcName, tmpl.params, tmpl.returnType))
|
||||
fakeFuncs.WriteString(tmpl.bodyGen(rng, argName))
|
||||
fakeFuncs.WriteString("\n}\n")
|
||||
}
|
||||
|
||||
// Inject at package level, after imports
|
||||
insertAt := findImportBlockEnd(src)
|
||||
if insertAt == -1 {
|
||||
pkgIdx := strings.Index(src, "package ")
|
||||
if pkgIdx != -1 {
|
||||
lineEnd := strings.Index(src[pkgIdx:], "\n")
|
||||
if lineEnd != -1 {
|
||||
insertAt = pkgIdx + lineEnd + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if insertAt != -1 && insertAt < len(src) {
|
||||
src = src[:insertAt] + fakeFuncs.String() + src[insertAt:]
|
||||
}
|
||||
|
||||
return src
|
||||
}
|
||||
|
||||
func extractFirstArgName(params string) string {
|
||||
params = strings.TrimSpace(params)
|
||||
if params == "" {
|
||||
return "_"
|
||||
}
|
||||
parts := strings.SplitN(params, ",", 2)
|
||||
first := strings.TrimSpace(parts[0])
|
||||
fields := strings.Fields(first)
|
||||
if len(fields) >= 1 {
|
||||
return fields[0]
|
||||
}
|
||||
return "_"
|
||||
}
|
||||
|
||||
// InjectMoreFakeSignatures generates additional fake functions with
|
||||
// random realistic names and bodies for deeper obfuscation.
|
||||
func InjectMoreFakeSignatures(src string, count int) string {
|
||||
rng := rand.New(rand.NewSource(rand.Int63()))
|
||||
|
||||
prefixes := []string{
|
||||
"_resolveAddr", "_buildRequest", "_handleResp", "_writeLog",
|
||||
"_parseHeader", "_checkAuth", "_compressData", "_decompressBuf",
|
||||
"_verifySig", "_loadCache", "_flushBuffer", "_retryConn",
|
||||
"_closeSocket", "_allocMem", "_releaseLock", "_acquireLock",
|
||||
"_serializeMsg", "_deserializeMsg", "_encodeURL", "_decodeURL",
|
||||
}
|
||||
|
||||
paramSets := []struct {
|
||||
params string
|
||||
returnType string
|
||||
}{
|
||||
{"addr string, port int", "error"},
|
||||
{"data []byte", "int"},
|
||||
{"key string", "bool"},
|
||||
{"src, dst string", "string"},
|
||||
{"n int", "int64"},
|
||||
{"buf []byte, offset int", "[]byte"},
|
||||
{"flag bool, name string", "string"},
|
||||
{"x, y int64", "int64"},
|
||||
}
|
||||
|
||||
var fakeFuncs strings.Builder
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
prefix := prefixes[rng.Intn(len(prefixes))]
|
||||
suffix := fmt.Sprintf("%04X", rng.Intn(0xFFFF))
|
||||
funcName := prefix + "_obf" + suffix
|
||||
|
||||
pset := paramSets[rng.Intn(len(paramSets))]
|
||||
argName := extractFirstArgName(pset.params)
|
||||
|
||||
body := generateRandomBody(rng, argName, pset.returnType)
|
||||
|
||||
fakeFuncs.WriteString("\n//go:noinline\n")
|
||||
fakeFuncs.WriteString(fmt.Sprintf("func %s(%s) %s {\n", funcName, pset.params, pset.returnType))
|
||||
fakeFuncs.WriteString(body)
|
||||
fakeFuncs.WriteString("\n}\n")
|
||||
}
|
||||
|
||||
insertAt := findImportBlockEnd(src)
|
||||
if insertAt == -1 {
|
||||
pkgIdx := strings.Index(src, "package ")
|
||||
if pkgIdx != -1 {
|
||||
lineEnd := strings.Index(src[pkgIdx:], "\n")
|
||||
if lineEnd != -1 {
|
||||
insertAt = pkgIdx + lineEnd + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if insertAt != -1 && insertAt < len(src) {
|
||||
src = src[:insertAt] + fakeFuncs.String() + src[insertAt:]
|
||||
}
|
||||
|
||||
return src
|
||||
}
|
||||
|
||||
// generateRandomBody creates a plausible-looking function body that computes
|
||||
// something meaningless but looks legitimate.
|
||||
func generateRandomBody(rng *rand.Rand, argName, returnType string) string {
|
||||
var sb strings.Builder
|
||||
numStmts := rng.Intn(6) + 3 // 3-8 statements
|
||||
|
||||
vars := make([]string, numStmts)
|
||||
for i := range vars {
|
||||
vars[i] = stringcrypt.RandomIdent("_x", 3)
|
||||
}
|
||||
|
||||
// Always start with consuming the argument
|
||||
sb.WriteString(fmt.Sprintf("\t_ = %s\n", argName))
|
||||
|
||||
for i := 0; i < numStmts; i++ {
|
||||
switch rng.Intn(5) {
|
||||
case 0:
|
||||
// Assignment from arithmetic
|
||||
val := rng.Intn(0xFFFF) + 1
|
||||
sb.WriteString(fmt.Sprintf("\t%s := %d ^ 0x%X\n", vars[i], val, rng.Intn(0xFFFF)))
|
||||
case 1:
|
||||
// Boolean expression
|
||||
sb.WriteString(fmt.Sprintf("\t%s := %d > %d && %d < %d\n",
|
||||
vars[i], rng.Intn(100), rng.Intn(100)+200, rng.Intn(100), rng.Intn(100)+200))
|
||||
case 2:
|
||||
// Self-referencing computation
|
||||
if i > 0 {
|
||||
sb.WriteString(fmt.Sprintf("\t%s = %s + %d\n", vars[i-1], vars[i-1], rng.Intn(1000)))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("\t%s := %d\n", vars[i], rng.Intn(0xFFFF)))
|
||||
}
|
||||
case 3:
|
||||
// Dead code branch
|
||||
sb.WriteString(fmt.Sprintf("\tif false { %s = %s }\n", vars[i], vars[max(0, i-1)]))
|
||||
case 4:
|
||||
// Bitwise operation
|
||||
sb.WriteString(fmt.Sprintf("\t%s := int64(%d) << %d\n", vars[i], rng.Intn(256), rng.Intn(8)))
|
||||
}
|
||||
}
|
||||
|
||||
// Return something based on the return type
|
||||
switch returnType {
|
||||
case "bool":
|
||||
sb.WriteString(fmt.Sprintf("\treturn %s && !%s\n", vars[0], vars[0]))
|
||||
case "int", "int64":
|
||||
sb.WriteString(fmt.Sprintf("\treturn %s - %s\n", vars[0], vars[0]))
|
||||
case "string":
|
||||
sb.WriteString("\treturn \"\"\n")
|
||||
case "[]byte":
|
||||
sb.WriteString("\treturn nil\n")
|
||||
case "[32]byte":
|
||||
sb.WriteString(fmt.Sprintf("\tvar %s [32]byte\n\treturn %s\n", vars[numStmts-1], vars[numStmts-1]))
|
||||
case "error":
|
||||
sb.WriteString("\treturn nil\n")
|
||||
default:
|
||||
sb.WriteString(fmt.Sprintf("\treturn %s\n", vars[0]))
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
Reference in New Issue
Block a user