Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String pattern mitigation #930

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

pagran
Copy link
Member

@pagran pagran commented Mar 16, 2025

WIP

Now implemented “external keys”, with random bit count (8/16/32/64). One key can be used many times and using bit shifting each key can be used differently

Roadmap:

  1. Add global keys, which would make deobfuscation even more complicated. Any ideas are welcome @lu4p
  2. Eliminate hardcoded constants (or add docs :) )
  3. Add string([]byte("")) pattern hiding (via proxy)
  4. Add documentation
Code examples
// no obfuscation
func main() {
	fmt.Println("Hello world")
}

// simple
func main() {
	fmt.Println(func(__ek_11725047838393011298 uint16, _ uint16, _ uint64, __ek_15442629010710282703 uint8, _ uint16, __ek_15133517871929446378 uint32, _ uint8, __ek_12796333468252078615 uint64) string {
		key := func() []byte {
			data := []byte("Plҥ\xa3[\x12v\x11\x97K")
			data[7] = data[7] - byte(__ek_15133517871929446378>>24)
			data[10] = data[10] ^ byte(__ek_11725047838393011298>>8)
			data[2] = data[2] ^ byte(__ek_12796333468252078615>>48)
			data[6] = data[6] - byte(__ek_15442629010710282703>>0)
			data[1] = data[1] - byte(__ek_15133517871929446378>>24)
			return data
		}()
		data := []byte("\x18*\x0e\xc9\xcc{06c\xfb%")
		for i, b := range key {
			data[i] = data[i] ^ b
		}
		return string(data)
	}(2568, 2634, 3921319057942851920, 203, 59873, 496871930, 243, 13452259376514879379))
}

// swap
func main() {
	fmt.Println(func(_ uint16, __ek_16698843071197877907 uint16, _ uint8, __ek_14615007820358085783 uint8, __ek_2660186290119384114 uint64, _ uint32, _ uint32, __ek_6765966717164870364 uint64) string {
		data := func() []byte {
			data := []byte("rr\xc0\xd4\xc6tNor\xa8\x10")
			data[0] = data[0] ^ byte(__ek_6765966717164870364>>0)
			data[10] = data[10] - byte(__ek_2660186290119384114>>16)
			data[6] = data[6] + byte(__ek_16698843071197877907>>8)
			data[1] = data[1] - byte(__ek_2660186290119384114>>24)
			data[5] = data[5] - byte(__ek_14615007820358085783>>0)
			return data
		}()
		positions := [...]byte{10, 10, 0, 9, 10, 3, 5, 10, 10, 3, 4, 3, 9, 2}
		for i := 0; i < 14; i += 2 {
			localKey := byte(i) + byte(positions[i]^positions[i+1]) + (byte(28) ^ byte(__ek_2660186290119384114>>16))
			data[positions[i]], data[positions[i+1]] = data[positions[i+1]]+localKey, data[positions[i]]+localKey
		}
		return string(data)
	}(10893, 10545, 179, 251, 10106724231502467345, 2153608741, 2424127044, 16266419076034768210))
}

// split
func main() {
	fmt.Println(func(_ uint64, _ uint32, __ek_10553311422834509489 uint32, _ uint32, __ek_10597153128353794973 uint8, _ uint32, _ uint8) string {
		data := make([]byte, 0, 12)
		i := 1
		decryptKey := int(byte(145) ^ byte(__ek_10553311422834509489>>16))
		for counter := 0; i != 3; counter++ {
			decryptKey ^= i * counter
			switch i {
			case 9:
				for y := range data {
					data[y] = data[y] ^ byte(decryptKey^y)
				}
				i = 3
			case 2:
				i = 5
				data = append(data, 19)
			case 6:
				i = 7
				data = append(data, 9)
			case 7:
				data = append(data, byte(52)+byte(__ek_10597153128353794973>>0))
				i = 11
			case 0:
				i = 12
				data = append(data, 28)
			case 4:
				data = append(data, 23)
				i = 2
			case 5:
				i = 6
				data = append(data, 93)
			case 10:
				data = append(data, byte(202)^byte(__ek_10597153128353794973>>0))
				i = 9
			case 8:
				i = 10
				data = append(data, 29)
			case 11:
				data = append(data, 2)
				i = 8
			case 12:
				i = 4
				data = append(data, 22)
			case 1:
				data = append(data, 48)
				i = 0
			}
		}
		return string(data)
	}(9767650945150019100, 3538353787, 720247858, 670129593, 220, 2230471821, 151))
}

// shuffle
func main() {
	fmt.Println(func(__ek_10329494355374689123 uint32, __ek_14941566625470174949 uint32, __ek_12646083717148524100 uint32, __ek_133237833610477955 uint32, _ uint8, __ek_16820180909362607653 uint8, __ek_16851294987403251015 uint16, _ uint8) string {
		fullData := func() []byte {
			data := []byte("TܠB$\xeb\xd9\xc1!0s\x9c\xccݤ\xbd\x80\x94\x99\xbe-\xa0")
			data[8] = data[8] + byte(__ek_133237833610477955>>16)
			data[7] = data[7] + byte(__ek_10329494355374689123>>24)
			data[10] = data[10] ^ byte(__ek_16851294987403251015>>8)
			data[7] = data[7] + byte(__ek_14941566625470174949>>24)
			data[6] = data[6] ^ byte(__ek_12646083717148524100>>24)
			data[18] = data[18] ^ byte(__ek_16820180909362607653>>0)
			data[16] = data[16] + byte(__ek_16820180909362607653>>0)
			data[21] = data[21] - byte(__ek_16820180909362607653>>0)
			data[16] = data[16] + byte(__ek_16820180909362607653>>0)
			data[17] = data[17] - byte(__ek_10329494355374689123>>0)
			data[1] = data[1] - byte(__ek_12646083717148524100>>24)
			return data
		}()
		idxKey := func() []byte {
			data := []byte("\xf0\x87j\xf1D\xf0\x97:")
			data[3] = data[3] + byte(__ek_133237833610477955>>16)
			data[2] = data[2] - byte(__ek_10329494355374689123>>16)
			data[2] = data[2] - byte(__ek_14941566625470174949>>16)
			data[0] = data[0] - byte(__ek_16820180909362607653>>0)
			return data
		}()
		data := make([]byte, 0, 12)
		data = append(data, fullData[246^int(idxKey[5])]^fullData[254^int(idxKey[5])], fullData[89^int(idxKey[0])]+fullData[75^int(idxKey[0])], fullData[71^int(idxKey[0])]^fullData[66^int(idxKey[0])], fullData[131^int(idxKey[1])]+fullData[141^int(idxKey[1])], fullData[77^int(idxKey[2])]+fullData[90^int(idxKey[2])], fullData[129^int(idxKey[3])]+fullData[141^int(idxKey[3])], fullData[75^int(idxKey[2])]^fullData[69^int(idxKey[2])], fullData[226^int(idxKey[5])]+fullData[249^int(idxKey[5])], fullData[69^int(idxKey[0])]-fullData[91^int(idxKey[0])], fullData[70^int(idxKey[4])]+fullData[84^int(idxKey[4])], fullData[130^int(idxKey[6])]^fullData[144^int(idxKey[6])])
		return string(data)
	}(618585161, 3107849982, 896102478, 3163618181, 184, 166, 15221, 232))
}

// seed
func main() {
	fmt.Println(func(__ek_7881529660392696364 uint8, _ uint64, _ uint32, _ uint16, _ uint16, __ek_4913274346185192430 uint32, _ uint32) string {
		seed := byte(90)
		var data []byte
		type decFunc func(byte) decFunc
		var fnc decFunc
		fnc = func(x byte) decFunc { data = append(data, x+seed); seed += x; return fnc }
		fnc(byte(205) - byte(__ek_4913274346185192430>>0))(byte(133) + byte(__ek_4913274346185192430>>8))(7)(0)(3)(177)(byte(0) + byte(__ek_7881529660392696364>>0))(248)(3)(250)(byte(79) - byte(__ek_7881529660392696364>>0))
		return string(data)
	}(87, 8047631583729643452, 1083076900, 4058, 54871, 1385863391, 1401467317))
}

Closes #926

@pagran pagran self-assigned this Mar 16, 2025
Copy link
Member

@lu4p lu4p left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit message shouldn't say "fixes" (as we want to do more) but "updates"

@@ -59,6 +59,22 @@ func LambdaCall(resultType ast.Expr, block *ast.BlockStmt) *ast.CallExpr {
return CallExpr(funcLit)
}

// LambdaCallParams "func(params) resultType {block}(args)"
func LambdaCallParams(params *ast.FieldList, resultType ast.Expr, block *ast.BlockStmt, args []ast.Expr) *ast.CallExpr {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lambda call should just use this with nil params

Comment on lines 16 to 54
type extKeyRarity int

const (
Rare extKeyRarity = 40
Normal = 60
Common = 80
)

func (r extKeyRarity) Try(rand *mathrand.Rand) bool {
return rand.Intn(100) < int(r)
}

type extKey struct {
name, typ string
value uint64
bits int
refs int
}

func (k *extKey) Byte() byte {
return byte(k.value)
}

func (k *extKey) Type() *ast.Ident {
return ast.NewIdent(k.typ)
}

func (k *extKey) Name() *ast.Ident {
return ast.NewIdent(k.name)
}

func (k *extKey) AddRef() {
k.refs++
}

func (k *extKey) Used() bool {
return k.refs > 0
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs more docs

Comment on lines 124 to 258
return keys
}

func addTrashExternalKeys(obfRand *mathrand.Rand, keys []*extKey) []*extKey {
if len(keys) >= maxExternalKeyCount {
return keys
}

trashCount := maxExternalKeyCount - len(keys)
if trashCount > 1 {
trashCount = 1 + obfRand.Intn(trashCount)
}
for i := 0; i < trashCount; i++ {
keys = append(keys, randExternalKey(obfRand))
}

obfRand.Shuffle(len(keys), func(i, j int) {
keys[i], keys[j] = keys[j], keys[i]
})

return keys
}

func externalKeysToParams(obfRand *mathrand.Rand, keys []*extKey) (params *ast.FieldList, args []ast.Expr) {
params = &ast.FieldList{}
for _, key := range addTrashExternalKeys(obfRand, keys) {
name := key.Name()
if !key.Used() {
name.Name = "_"
}
params.List = append(params.List, &ast.Field{
Names: []*ast.Ident{name},
Type: key.Type(),
})
args = append(args, &ast.BasicLit{
Kind: token.INT,
Value: fmt.Sprint(key.value),
})
}
return
}

func dataToByteSliceWithExternalKeys(obfRand *mathrand.Rand, data []byte, externalKeys []*extKey, rarity extKeyRarity) ast.Expr {
if !rarity.Try(obfRand) {
return ah.DataToByteSlice(data)
}

count := len(data) / 2
if count > maxExternalKeyCount*2 {
count = maxExternalKeyCount * 2
}

var stmts []ast.Stmt
for i := 0; i < count; i++ {
key := externalKeys[obfRand.Intn(len(externalKeys))]
key.AddRef()
idx, op, b := obfRand.Intn(len(data)), randOperator(obfRand), obfRand.Intn(key.bits/8)
data[idx] = evalOperator(op, data[idx], byte(key.value>>(b*8)))
stmts = append(stmts, &ast.AssignStmt{
Lhs: []ast.Expr{ah.IndexExpr("data", ah.IntLit(idx))},
Tok: token.ASSIGN,
Rhs: []ast.Expr{
operatorToReversedBinaryExpr(op,
ah.IndexExpr("data", ah.IntLit(idx)),
ah.CallExprByName("byte", &ast.BinaryExpr{
X: key.Name(),
Op: token.SHR,
Y: ah.IntLit(b * 8),
}),
),
},
})
}

slices.Reverse(stmts)

stmts = append([]ast.Stmt{ah.AssignDefineStmt(ast.NewIdent("data"), ah.DataToByteSlice(data))}, append(stmts, ah.ReturnStmt(ast.NewIdent("data")))...)
return ah.LambdaCall(&ast.ArrayType{Elt: ast.NewIdent("byte")}, ah.BlockStmt(stmts...))
}

func byteLitWithExternalKeys(obfRand *mathrand.Rand, val byte, externalKeys []*extKey, rarity extKeyRarity) ast.Expr {
if !rarity.Try(obfRand) {
return ah.IntLit(int(val))
}

key := externalKeys[obfRand.Intn(len(externalKeyRanges))]
key.AddRef()

op, b := randOperator(obfRand), obfRand.Intn(key.bits/8)
newVal := evalOperator(op, val, byte(key.value>>(b*8)))
return operatorToReversedBinaryExpr(op,
ah.CallExprByName("byte", ah.IntLit(int(newVal))),
ah.CallExprByName("byte", &ast.BinaryExpr{
X: key.Name(),
Op: token.SHR,
Y: ah.IntLit(b * 8),
}),
)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs more docs, whenever you generate code please add a comment with how the generated code looks like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Mitigate string encryption deobfuscation
2 participants