├── .gitattributes ├── LICENSE ├── README.md └── gofuscator.go /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 artemixer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gofuscator 2 | **gofuscator** is an obfuscator/polymorphic engine for Golang code. 3 | 4 | 5 | ## Installation 6 | Make sure you have Golang installed by running ```go version``` 7 | ``` 8 | git clone https://github.com/artemixer/gofuscator 9 | cd gofuscator 10 | go build gofuscator.go 11 | ``` 12 | 13 | ## Usage 14 | ``` 15 | ./gofuscator -i input_file.go -o output_file.go 16 | ``` 17 | Here is a sample before and after the obfuscation process: 18 | 19 | Screenshot 2024-02-07 at 23 56 30 20 | 21 |
22 |
23 | 24 | Screenshot 2024-02-07 at 23 57 23 1 25 | 26 | ## Functionality 27 | Currently gofuscator is able to process **strings, integers, floats, bools, hex values, imports and function/variable names** 28 | 29 | Function and variable names, as well as imports, are changed to a random string consisting of the ASCII ```a``` and the cyrilic ```а```, which end up looking visually identical: 30 |
```str1``` -> ```аaааааaaaaаaaaaaааaa``` 31 |
```rand.Read``` -> ```аaааааaaaaаaaaaaааaa.Read``` 32 | 33 | Bools are changed to a random lesser or greater statement: 34 |
```false``` -> ```(948 >= 6995)``` 35 | 36 | Strings are decrypted from a base64 sequence of bytes : 37 |
```"test"``` -> ```aesDecrypt((string(49) + string(78) + string(57) + ...)``` 38 | 39 | Hexes are changed into declarations of corresponding bytes : 40 |
```0x48, 0x65``` -> ```(byte(72)), (byte(101))``` 41 | 42 | And all of the above methods are reinforced by the way integers and floats are obfuscated, which is the main feature of this tool. 43 | Integers and floats are converted into a random sequence of mathematical operations, such as ```math.Sqrt```, ```math.Tan``` and others. 44 | The corresponding math functions are called using ```reflect``` to avoid optimisations at compile-time. And finally, all relevant math functions 45 | are called through a randomly generated function array. This is the result: 46 |

```-3``` -> ```-(int(aaaaаaаaaaaааaааааaа.Round(aааaaaaаaааaaаааaaаа.ValueOf(aаaаaaaaаaaаaааaааaa[(int( aaaaаaаaaaaааaааааaа.Round(aааaaaaаaааaaаааaaаа.ValueOf(aaaaаaаaaaaааaааааaа.Cos).Call([]aааaaaaаaааaaаааaaаа.Value{aааaaaaаaааaaаааaaаа.ValueOf(5.415309898908408)})[0].Interface().(float64)/(0.6464489776185214*aaaaаaаaaaaааaааааaа.Pow(2, float64(-2))))))]).Call([]aааaaaaаaааaaаааaaаа.Value{aааaaaaаaааaaаааaaаа.ValueOf(5.8042675186492145)})[0].Interface().(float64)/aаaаaaaaаaaаaааaааaa[(int(aaaaаaаaaaaааaааааaа.Round(aааaaaaаaааaaаааaaаа.ValueOf(aaaaаaаaaaaааaааааaа.Sqrt).Call([]aааaaaaаaааaaаааaaаа.Value{aааaaaaаaааaaаааaaаа.ValueOf(7.908218581580884)})[0].Interface().(float64)*aaaaаaаaaaaааaааааaа.Tan(0))))](0.6766090278466431))))``` 47 | 48 | This processing also applies to integers generated at all previous steps. 49 | 50 | 51 | ## Notes 52 | As ```const``` types cannot have values set by functions, they are converted to ```var``` upon processing. 53 |
54 |
55 | If you are using non-default numeric variable types, make sure to explicitly declare them when passing to functions (ex. ```uint8(5)```), as the parser has no way of knowing the real variable type and assumes ```int```/```float64``` 56 | 57 | 58 |
59 |
60 | Feel free to open pull requests and issues, I will do my best to resolve or at least answer all of them 61 | -------------------------------------------------------------------------------- /gofuscator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "go/ast" 7 | "go/parser" 8 | "go/token" 9 | "go/printer" 10 | "os" 11 | "strings" 12 | "strconv" 13 | "math/rand" 14 | "math" 15 | "time" 16 | "io/ioutil" 17 | "bytes" 18 | "crypto/aes" 19 | "crypto/cipher" 20 | "encoding/base64" 21 | "encoding/hex" 22 | "unicode" 23 | "hash/fnv" 24 | ) 25 | var input_file = flag.String("i", "", "the path to the input file") 26 | var output_file = flag.String("o", "", "the path to the output file") 27 | var seed = flag.String("seed", "", "seed to use for code generation") 28 | 29 | var ignore_ints_bool = flag.Bool("no-ints", false, "disables int/float obfuscation") 30 | var ignore_strings_obfuscation_bool = flag.Bool("no-strings-obf", false, "disables string obfuscation") 31 | var ignore_strings_encryption_bool = flag.Bool("no-strings-enc", false, "disables string encryption") 32 | var ignore_vars_bool = flag.Bool("no-vars", false, "disables variable name obfuscation") 33 | var ignore_functions_bool = flag.Bool("no-functions", false, "disables function name/call obfuscation") 34 | var ignore_bools_bool = flag.Bool("no-bools", false, "disables bool obfuscation") 35 | var ignore_hexes_bool = flag.Bool("no-hexes", false, "disables hex value obfuscation") 36 | var ignore_imports_bool = flag.Bool("no-imports", false, "disables import obfuscation") 37 | 38 | 39 | var names_dictionary map[string]string = make(map[string]string) 40 | var unicode_chars = []rune("аa") 41 | var int_seed = int64(0) 42 | 43 | var aes_key_obf string 44 | var iv_obf string 45 | 46 | // Workflow 47 | // Replace 'const' with 'var' 48 | // Write and read 49 | // Add import 'math' 50 | // Write and read 51 | // Obfuscate variable names 52 | // Get imports list 53 | // Obfuscate bools 54 | // Obfuscate function decls 55 | // Obfuscate function calls 56 | // Obfuscate strings 57 | // Write and read 58 | // Obfuscate ints 59 | // Obfuscate floats 60 | // Obfuscate import aliases 61 | // Write and read 62 | // Add math operations array 63 | // Replace referrences to math operations 64 | // Replace import refferences 65 | 66 | func main() { 67 | flag.Parse() 68 | if (len(*input_file) < 1) { 69 | fmt.Println("Please provide an input file with '--i'") 70 | } 71 | if (len(*output_file) < 1) { 72 | fmt.Println("Please provide an output file with '--i'") 73 | } 74 | 75 | string_seed := *seed 76 | if (len(string_seed) > 0) { 77 | int_seed = int64(hashString(string_seed)) 78 | } else { 79 | int_seed = time.Now().UnixNano() 80 | } 81 | rand.Seed(int_seed) 82 | 83 | aes_key_obf_byte := make([]byte, 16) 84 | _, err := rand.Read(aes_key_obf_byte) 85 | aes_key_obf = hex.EncodeToString(aes_key_obf_byte) 86 | 87 | iv_obf_byte := make([]byte, 8) 88 | _, err = rand.Read(iv_obf_byte) 89 | iv_obf = hex.EncodeToString(iv_obf_byte) 90 | 91 | 92 | // Parse the file 93 | fset := token.NewFileSet() 94 | file, err := parser.ParseFile(fset, *input_file, nil, 0) 95 | if err != nil { 96 | fmt.Println("Error parsing file:", err) 97 | os.Exit(1) 98 | } 99 | 100 | // Replace all consts with var 101 | ast.Inspect(file, func(n ast.Node) bool { 102 | if genDecl, ok := n.(*ast.GenDecl); ok && genDecl.Tok == token.CONST { 103 | genDecl.Tok = token.VAR 104 | } 105 | return true 106 | }) 107 | 108 | writeToOutputFile(*output_file, file, fset) 109 | fset = token.NewFileSet() 110 | file, err = parser.ParseFile(fset, *output_file, nil, parser.ParseComments) 111 | 112 | // Adding AES functions 113 | if (!*ignore_strings_encryption_bool) { 114 | file, fset = addAESFunctions(file, fset) 115 | file, fset = addImport(file, fset, "crypto/aes") 116 | file, fset = addImport(file, fset, "crypto/cipher") 117 | file, fset = addImport(file, fset, "encoding/base64") 118 | } 119 | 120 | if (!*ignore_ints_bool) { 121 | file, fset = addImport(file, fset, "math") 122 | file, fset = addImport(file, fset, "reflect") 123 | } 124 | 125 | writeToOutputFile(*output_file, file, fset) 126 | fset = token.NewFileSet() 127 | file, err = parser.ParseFile(fset, *output_file, nil, parser.ParseComments) 128 | 129 | // Find variable names 130 | ast.Inspect(file, func(n ast.Node) bool { 131 | if ident, ok := n.(*ast.Ident); ok { 132 | // Check if it is a variable (not a type, function, etc.) 133 | if ident.Obj != nil && (ident.Obj.Kind == ast.Var) && ident.Name != "_" && !*ignore_vars_bool { 134 | ident.Name = obfuscateVariableName(ident.Name) 135 | } 136 | } 137 | return true 138 | }) 139 | 140 | // Write import paths to array 141 | var importPaths []string 142 | for _, decl := range file.Decls { 143 | if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.IMPORT { 144 | // Found an import declaration 145 | for _, spec := range genDecl.Specs { 146 | if importSpec, ok := spec.(*ast.ImportSpec); ok { 147 | // Extract the import path 148 | importPath := removeChar(importSpec.Path.Value, "\""[0]) 149 | importPaths = append(importPaths, importPath) 150 | } 151 | } 152 | } 153 | } 154 | 155 | ast.Inspect(file, func(n ast.Node) bool { 156 | if ident, ok := n.(*ast.Ident); ok { 157 | if ident.Obj == nil && (ident.Name == "true" || ident.Name == "false") && !*ignore_bools_bool { 158 | ident.Name = obfuscateBool(ident.Name) 159 | } 160 | } 161 | return true 162 | }) 163 | 164 | var functions_list []string 165 | ast.Inspect(file, func(n ast.Node) bool { 166 | switch node := n.(type) { 167 | case *ast.FuncDecl: 168 | // Check if it is the old function name and declared in the current file 169 | if node.Name.Name != "main" && node.Recv == nil && node.Name.Obj != nil && node.Name.Obj.Pos().IsValid() && fset.Position(node.Name.Obj.Pos()).Filename == *output_file && !*ignore_functions_bool { 170 | functions_list = append(functions_list, node.Name.Name) 171 | node.Name.Name = obfuscateFunctionName(node.Name.Name) 172 | } 173 | 174 | case *ast.CallExpr: 175 | // Check if it is a function call 176 | if ident, ok := node.Fun.(*ast.Ident); ok { 177 | // Check if it is the old function name and declared in the current file 178 | if ((ident.Name != "main" && ident.Obj != nil && ident.Obj.Pos().IsValid() && fset.Position(ident.Obj.Pos()).Filename == *output_file) || isInArray(ident.Name, functions_list)) && !*ignore_functions_bool { 179 | ident.Name = obfuscateFunctionName(ident.Name) 180 | } 181 | } 182 | case *ast.BasicLit: 183 | // Check if it is a string literal 184 | if node.Kind == token.STRING && !isInArray(trimFirstLastChars(node.Value), importPaths) { 185 | if (trimFirstLastChars(node.Value) != aes_key_obf && trimFirstLastChars(node.Value) != string(iv_obf) && !*ignore_strings_encryption_bool) { 186 | node.Value = string(obfuscateFunctionName("aesDecrypt") + "(" + obfuscateString(aesEncrypt(trimFirstLastChars(node.Value))) + ")") 187 | } else { 188 | node.Value = obfuscateString(trimFirstLastChars(node.Value)) 189 | } 190 | } 191 | 192 | } 193 | return true 194 | }) 195 | 196 | debug(functions_list) 197 | 198 | 199 | writeToOutputFile(*output_file, file, fset) 200 | fset = token.NewFileSet() 201 | file, err = parser.ParseFile(fset, *output_file, nil, parser.ParseComments) 202 | 203 | ast.Inspect(file, func(n ast.Node) bool { 204 | switch node := n.(type) { 205 | 206 | case *ast.BasicLit: 207 | if node.Kind == token.INT { 208 | if (containsNonNumericChars(node.Value)) { 209 | node.Value = obfuscateHex(node.Value) 210 | } else { 211 | integer_value, _ := strconv.Atoi(node.Value) 212 | node.Value = obfuscateIntFloat(float64(integer_value)) 213 | } 214 | } 215 | if node.Kind == token.FLOAT { 216 | float_value, _ := strconv.ParseFloat(node.Value, 64) 217 | node.Value = obfuscateIntFloat(float64(float_value)) 218 | //debug(node.Value) 219 | } 220 | 221 | } 222 | return true 223 | }) 224 | 225 | var imports_array []string 226 | for _, decl := range file.Decls { 227 | genDecl, ok := decl.(*ast.GenDecl) 228 | if !ok || genDecl.Tok != token.IMPORT || *ignore_imports_bool { 229 | continue 230 | } 231 | 232 | for _, spec := range genDecl.Specs { 233 | importSpec, ok := spec.(*ast.ImportSpec) 234 | if !ok { 235 | continue 236 | } 237 | 238 | importSpec.Name = &ast.Ident{Name: obfuscateFunctionName(strings.Split(strings.Trim(importSpec.Path.Value, "\""), "/")[len(strings.Split(strings.Trim(importSpec.Path.Value, "\""), "/"))-1])} 239 | imports_array = append(imports_array, strings.Split(strings.Trim(importSpec.Path.Value, "\""), "/")[len(strings.Split(strings.Trim(importSpec.Path.Value, "\""), "/"))-1]) 240 | } 241 | } 242 | 243 | 244 | writeToOutputFile(*output_file, file, fset) 245 | fset = token.NewFileSet() 246 | file, err = parser.ParseFile(fset, *output_file, nil, parser.ParseComments) 247 | 248 | // Adding math operation array 249 | if (!*ignore_ints_bool) { 250 | file = addGlobalVar(file, obfuscateVariableName("operations_array_obf"), "string", token.STRING, "operations_array_here") 251 | } 252 | 253 | writeToOutputFile(*output_file, file, fset) 254 | 255 | // Read the file contents 256 | content, err := ioutil.ReadFile(*output_file) 257 | if err != nil { 258 | fmt.Println("Error reading file:", err) 259 | os.Exit(1) 260 | } 261 | 262 | modifiedContent := string(content) 263 | for i := 0; i < len(imports_array); i++ { 264 | modifiedContent = strings.ReplaceAll(modifiedContent, imports_array[i] + ".", obfuscateFunctionName(imports_array[i]) + ".") 265 | } 266 | 267 | operations_str := []interface{}{ 268 | "math.Sqrt", 269 | "math.Sin", 270 | "math.Cos", 271 | "math.Log", 272 | "math.Tan", 273 | "math.Cbrt", 274 | } 275 | operations_str = shuffle(operations_str) 276 | 277 | if (!*ignore_ints_bool) { 278 | operations_array_str := "[]func(x float64)(float64){" 279 | for i := 0; i < len(operations_str); i++ { 280 | operations_array_str = operations_array_str + operations_str[i].(string) + "," 281 | } 282 | operations_array_str = operations_array_str + "}" 283 | if (!*ignore_imports_bool) { 284 | operations_array_str = strings.ReplaceAll(operations_array_str, `math`, obfuscateFunctionName("math")) 285 | } 286 | 287 | modifiedContent = strings.ReplaceAll(modifiedContent, `string = operations_array_here`, `= ` + operations_array_str) 288 | 289 | for i := 0; i < len(operations_str); i++ { 290 | real_operation := "" 291 | if (!*ignore_imports_bool) { 292 | real_operation = strings.ReplaceAll(operations_str[i].(string), `math`, obfuscateFunctionName("math")) 293 | } else { 294 | real_operation = operations_str[i].(string) 295 | } 296 | modifiedContent = strings.ReplaceAll(modifiedContent, real_operation + "(", obfuscateVariableName("operations_array_obf") + "[" + obfuscateIntFloat(float64(i)) + "](") 297 | modifiedContent = strings.ReplaceAll(modifiedContent, real_operation + ")", obfuscateVariableName("operations_array_obf") + "[" + obfuscateIntFloat(float64(i)) + "])") 298 | } 299 | 300 | if (!*ignore_imports_bool) { 301 | modifiedContent = strings.ReplaceAll(modifiedContent, `math.`, obfuscateFunctionName("math") + ".") 302 | modifiedContent = strings.ReplaceAll(modifiedContent, `reflect.`, obfuscateFunctionName("reflect") + ".") 303 | } 304 | } 305 | 306 | // Write the modified content back to the file 307 | err = ioutil.WriteFile(*output_file, []byte(modifiedContent), 0644) 308 | if err != nil { 309 | fmt.Println("Error writing to file:", err) 310 | os.Exit(1) 311 | } 312 | 313 | 314 | 315 | } 316 | 317 | 318 | 319 | func obfuscateIntFloat(real_value float64) string { 320 | if (*ignore_ints_bool) { 321 | return strconv.FormatFloat(real_value, 'f', -1, 64) 322 | } 323 | 324 | var terms_array []string 325 | var terms_value_array []float64 326 | var operations_array []string 327 | 328 | terms_amount := rand.Intn(1) + 2 329 | 330 | possible_operations_array := []string{"*", "/"} 331 | possible_modifiers_array := []string{"Sqrt", "Sin", "Cos", "Log", "Tan", "Frexp", "Hypot", "Cbrt"} 332 | possible_reversible_modifiers_array := []string{"Tan", "Frexp", "Cbrt"} 333 | 334 | // Generate random numbers and operations 335 | i := 0 336 | for { 337 | i = i + 1 338 | if (i > terms_amount) { 339 | break 340 | } 341 | 342 | var value float64 = float64(rand.Intn(100000000000000000) + 1) / 10000000000000000 343 | terms_value_array = append(terms_value_array, float64(value)) 344 | terms_array = append(terms_array, strconv.FormatFloat(value, 'f', -1, 64)) 345 | operations_array = append(operations_array, possible_operations_array[rand.Intn(len(possible_operations_array))]) 346 | 347 | } 348 | operations_array = operations_array[:len(operations_array)-1] 349 | 350 | i = 0 351 | for { 352 | if (i >= terms_amount) { 353 | break 354 | } 355 | 356 | // If the term is not the last in the string, just select a random modifier for it 357 | // TODO Add randomisation between reflect and normal 358 | if (i+1 < terms_amount) { 359 | modifier := possible_modifiers_array[rand.Intn(len(possible_modifiers_array))] 360 | if (modifier == "Sqrt") { 361 | terms_value_array[i] = math.Sqrt(terms_value_array[i]) 362 | terms_array[i] = "reflect.ValueOf(math.Sqrt).Call([]reflect.Value{reflect.ValueOf(" + terms_array[i] + ")})[0].Interface().(float64)" 363 | } else if (modifier == "Sin") { 364 | terms_value_array[i] = math.Sin(terms_value_array[i]) 365 | terms_array[i] = "reflect.ValueOf(math.Sin).Call([]reflect.Value{reflect.ValueOf(" + terms_array[i] + ")})[0].Interface().(float64)" 366 | } else if (modifier == "Cos") { 367 | terms_value_array[i] = math.Cos(terms_value_array[i]) 368 | terms_array[i] = "reflect.ValueOf(math.Cos).Call([]reflect.Value{reflect.ValueOf(" + terms_array[i] + ")})[0].Interface().(float64)" 369 | } else if (modifier == "Log") { 370 | terms_value_array[i] = math.Log(terms_value_array[i]) 371 | terms_array[i] = "reflect.ValueOf(math.Log).Call([]reflect.Value{reflect.ValueOf(" + terms_array[i] + ")})[0].Interface().(float64)" 372 | } else if (modifier == "Tan") { 373 | terms_value_array[i] = math.Tan(terms_value_array[i]) 374 | terms_array[i] = "reflect.ValueOf(math.Tan).Call([]reflect.Value{reflect.ValueOf(" + terms_array[i] + ")})[0].Interface().(float64)" 375 | } else if (modifier == "Cbrt") { 376 | terms_value_array[i] = math.Cbrt(terms_value_array[i]) 377 | terms_array[i] = "reflect.ValueOf(math.Cbrt).Call([]reflect.Value{reflect.ValueOf(" + terms_array[i] + ")})[0].Interface().(float64)" 378 | } else if (modifier == "Frexp") { 379 | exponent := float64((rand.Intn(100000000000000000) + 1) - 50000000000000000) / 10000000000000000 380 | terms_value_array[i] = terms_value_array[i]*math.Pow(3, float64(exponent)) 381 | terms_array[i] = "(" +terms_array[i] + "*reflect.ValueOf(math.Pow).Call([]reflect.Value{reflect.ValueOf(float64(2)), reflect.ValueOf(float64(" + strconv.FormatFloat(exponent, 'f', -1, 64) + ") )})[0].Interface().(float64))" 382 | } else if (modifier == "Hypot") { 383 | exponent := float64((rand.Intn(100000000000000000) + 1) - 50000000000000000) / 10000000000000000 384 | terms_value_array[i] = math.Hypot(terms_value_array[i], exponent) 385 | terms_array[i] = "(reflect.ValueOf(math.Hypot).Call([]reflect.Value{reflect.ValueOf(float64(" + terms_array[i] + ")), reflect.ValueOf(float64(" + strconv.FormatFloat(exponent, 'f', -1, 64) + ") )})[0].Interface().(float64))" 386 | } 387 | 388 | } else { 389 | x := 0 390 | total := terms_value_array[0] 391 | for { 392 | if (x+2 >= terms_amount) { 393 | break 394 | } 395 | 396 | if (operations_array[x] == "*") { 397 | total = total * terms_value_array[x+1] 398 | } else if (operations_array[x] == "/") { 399 | total = total / terms_value_array[x+1] 400 | } 401 | 402 | x = x + 1 403 | } 404 | 405 | target_num := 0.0 406 | if (operations_array[len(operations_array)-1] == "*") { 407 | target_num = real_value / total 408 | } else if (operations_array[len(operations_array)-1] == "/") { 409 | target_num = total / real_value 410 | } 411 | 412 | modifier := possible_reversible_modifiers_array[rand.Intn(len(possible_reversible_modifiers_array))] 413 | var exponent int 414 | var target_modified_num float64 415 | for { 416 | if (modifier == "Tan") { 417 | target_modified_num = math.Atan(target_num) 418 | terms_value_array[i] = target_num 419 | terms_array[i] = "math.Tan(" + strconv.FormatFloat(target_modified_num, 'f', -1, 64) + ")" 420 | } else if (modifier == "Frexp") { 421 | target_modified_num, exponent = math.Frexp(target_num) 422 | terms_value_array[i] = target_num 423 | terms_array[i] = "(" + strconv.FormatFloat(target_modified_num, 'f', -1, 64) + "*math.Pow(3, float64(" + strconv.Itoa(exponent) + ")))" 424 | } else if (modifier == "Cbrt") { 425 | target_modified_num = math.Pow(target_num, 3) 426 | terms_value_array[i] = target_num 427 | terms_array[i] = "math.Cbrt(" + strconv.FormatFloat(target_modified_num, 'f', -1, 64) + ")" 428 | } 429 | 430 | // Checking for infinity overflows 431 | if strings.Contains(strconv.FormatFloat(target_modified_num, 'f', -1, 64), "Inf") { 432 | modifier = "Tan" 433 | continue 434 | } else { 435 | break 436 | } 437 | } 438 | 439 | } 440 | 441 | i = i + 1 442 | } 443 | 444 | 445 | // Append the arrays to form the output string 446 | result_string := "" 447 | x := 0 448 | for { 449 | if (x >= terms_amount) { 450 | break 451 | } 452 | 453 | result_string = result_string + terms_array[x] 454 | if (x + 1 < terms_amount) { 455 | result_string = result_string + operations_array[x] 456 | } 457 | 458 | x = x + 1 459 | } 460 | 461 | // Find the decimal places of the input and round the output to those decimal places 462 | str := strconv.FormatFloat(real_value, 'f', -1, 64) 463 | parts := strings.Split(str, ".") 464 | decimal_places := 0 465 | if len(parts) == 2 { 466 | decimal_places = len(parts[1]) 467 | } else { 468 | decimal_places = 0 469 | } 470 | divider := int(math.Pow(float64(10), float64(decimal_places))) 471 | 472 | if (divider > 1) { 473 | result_string = "((math.Round((" + result_string + "*" + strconv.Itoa(divider) + ")))/" + strconv.Itoa(divider) + ")" 474 | } else { 475 | result_string = "(int(math.Round(" + result_string + ")))" 476 | 477 | } 478 | 479 | 480 | //fmt.Println(result_string) 481 | return result_string 482 | } 483 | 484 | func obfuscateVariableName(real_value string) string { 485 | if (*ignore_vars_bool) { 486 | return real_value 487 | } 488 | 489 | if _, exists := names_dictionary[real_value]; !exists { 490 | var result []rune 491 | for i := 0; i < 20; i++ { 492 | result = append(result, unicode_chars[rand.Intn(len(unicode_chars))]) 493 | } 494 | if valueExists(names_dictionary, string(result)) { 495 | debug("again") 496 | return obfuscateFunctionName(real_value) 497 | } 498 | names_dictionary[real_value] = string(result) 499 | } 500 | return names_dictionary[real_value] 501 | } 502 | 503 | func obfuscateFunctionName(real_value string) string { 504 | if (*ignore_functions_bool) { 505 | return real_value 506 | } 507 | 508 | if _, exists := names_dictionary[real_value]; !exists { 509 | var result []rune 510 | for i := 0; i < 20; i++ { 511 | result = append(result, unicode_chars[rand.Intn(len(unicode_chars))]) 512 | } 513 | if valueExists(names_dictionary, string(result)) { 514 | return obfuscateFunctionName(real_value) 515 | } 516 | names_dictionary[real_value] = string(result) 517 | } 518 | return names_dictionary[real_value] 519 | } 520 | 521 | func obfuscateString(real_value string) string { 522 | if (*ignore_strings_obfuscation_bool) { 523 | return `"` + real_value + `"` 524 | } 525 | 526 | real_value, _ = strconv.Unquote(`"` + real_value + `"`) 527 | byte_array := []byte(real_value) 528 | result_string := "" 529 | i := 0 530 | 531 | if (real_value == "") { 532 | return `""` 533 | } 534 | 535 | if (len(byte_array) != len(real_value)) { 536 | // TODO Add support for multiple-byte encodings 537 | return real_value 538 | } 539 | 540 | for _, b := range byte_array { 541 | // Convert byte to int 542 | int_value := int(b) 543 | 544 | result_string = result_string + "string(" + strconv.Itoa(int_value) + ")" 545 | 546 | if (i != len(byte_array)-1) { 547 | result_string = result_string + "+" 548 | } 549 | 550 | i = i + 1 551 | } 552 | 553 | result_string = "(" + result_string + ")" 554 | return result_string 555 | } 556 | 557 | func obfuscateBool(real_value string) string { 558 | if (*ignore_bools_bool) { 559 | return real_value 560 | } 561 | 562 | int1 := rand.Intn(10000) 563 | 564 | int2 := rand.Intn(10000) 565 | operator := "" 566 | 567 | if (real_value == "true") { 568 | if (int1 > int2) { 569 | operator = ">" 570 | } else { 571 | operator = "<=" 572 | } 573 | } else { 574 | if (int1 > int2) { 575 | operator = "<" 576 | } else { 577 | operator = ">=" 578 | } 579 | } 580 | 581 | result_string := strconv.Itoa(int1) + operator + strconv.Itoa(int2) 582 | result_string = "(" + result_string + ")" 583 | return result_string 584 | } 585 | 586 | func obfuscateHex(real_value string) string { 587 | if (*ignore_hexes_bool) { 588 | return real_value 589 | } 590 | 591 | if strings.HasPrefix(real_value, "0x") { 592 | real_value = real_value[2:] 593 | } 594 | 595 | byteArray, err := hex.DecodeString(real_value) 596 | if err != nil { 597 | fmt.Println("Error decoding hex:", err) 598 | return real_value 599 | } 600 | 601 | result_string := "(" 602 | for i := 0; i < len(byteArray); i++ { 603 | if (i+1 < len(byteArray)) { 604 | result_string = result_string + "," 605 | } 606 | byte_int := int(byteArray[i]) 607 | result_string = result_string + "byte(" + obfuscateIntFloat(float64(byte_int)) + ")" 608 | } 609 | result_string = result_string + ")" 610 | 611 | return result_string 612 | } 613 | 614 | func isInArray(target string, arr []string) bool { 615 | for _, item := range arr { 616 | if item == target { 617 | return true 618 | } 619 | } 620 | return false 621 | } 622 | 623 | func removeChar(input string, charToRemove byte) string { 624 | result := "" 625 | for i := 0; i < len(input); i++ { 626 | if input[i] != charToRemove { 627 | result += string(input[i]) 628 | } 629 | } 630 | return result 631 | } 632 | 633 | func debug(str interface{}, debug_level ...int) { 634 | if (debug_level != 0) { 635 | if (debug_level >= global_debug_level) { 636 | fmt.Printf("[?] ") 637 | fmt.Println(str) 638 | } 639 | } 640 | } 641 | 642 | func hasImport(file *ast.File, importPath string) bool { 643 | for _, imp := range file.Imports { 644 | if imp.Path != nil && imp.Path.Value == fmt.Sprintf(`"%s"`, importPath) { 645 | return true 646 | } 647 | } 648 | return false 649 | } 650 | 651 | func addImport(file *ast.File, fset *token.FileSet, import_str string) (*ast.File, *token.FileSet) { 652 | // Add the imports 653 | for i := 0; i < len(file.Decls); i++ { 654 | d := file.Decls[i] 655 | 656 | switch d.(type) { 657 | case *ast.FuncDecl: 658 | // No action 659 | case *ast.GenDecl: 660 | dd := d.(*ast.GenDecl) 661 | 662 | // IMPORT Declarations 663 | if dd.Tok == token.IMPORT { 664 | // Add the new import 665 | iSpec := &ast.ImportSpec{Path: &ast.BasicLit{Value: strconv.Quote(import_str)}} 666 | dd.Specs = append(dd.Specs, iSpec) 667 | } 668 | } 669 | } 670 | 671 | // Sort the imports 672 | ast.SortImports(fset, file) 673 | 674 | return file, fset 675 | } 676 | 677 | func valueExists(dict map[string]string, value string) bool { 678 | for _, v := range dict { 679 | if v == value { 680 | return true 681 | } 682 | } 683 | return false 684 | } 685 | 686 | 687 | 688 | func writeToOutputFile(file string, contents *ast.File, fset *token.FileSet) { 689 | os.Remove(file) 690 | outputFile, err := os.Create(file) 691 | if err != nil { 692 | fmt.Println("Error creating output file:", err) 693 | os.Exit(1) 694 | } 695 | defer outputFile.Close() 696 | 697 | err = printer.Fprint(outputFile, fset, contents) 698 | if err != nil { 699 | fmt.Println("Error writing to output file:", err) 700 | os.Exit(1) 701 | } 702 | } 703 | 704 | func addFunction(file *ast.File, fset *token.FileSet, function_name string, function_content string, inputs []string, input_types []string, outputs []string, output_types []string) (*ast.File, *token.FileSet) { 705 | 706 | inputs_parsed := parseFieldList(inputs, input_types) 707 | outputs_parsed := parseFieldList(outputs, output_types) 708 | 709 | // The function body as a string. 710 | funcBody := ` 711 | package main 712 | 713 | import ( 714 | "fmt" 715 | ) 716 | 717 | func myfunc() { 718 | ` + function_content + ` 719 | } 720 | ` 721 | 722 | // Parse the function body string into an AST. 723 | body, err := parser.ParseFile(fset, "", funcBody, parser.ParseComments) 724 | if err != nil { 725 | fmt.Println("Error parsing function body:", err) 726 | } 727 | 728 | // Extract the body from the parsed AST. 729 | var funcBodyStmts []ast.Stmt 730 | for _, decl := range body.Decls { 731 | if fn, ok := decl.(*ast.FuncDecl); ok { 732 | if fn.Body != nil { 733 | funcBodyStmts = fn.Body.List 734 | } 735 | } 736 | } 737 | 738 | // Create the AST nodes representing the new function. 739 | newFunc := &ast.FuncDecl{ 740 | Name: ast.NewIdent(function_name), 741 | Type: &ast.FuncType{ 742 | Params: inputs_parsed, 743 | Results: outputs_parsed, 744 | }, 745 | Body: &ast.BlockStmt{ 746 | List: funcBodyStmts, 747 | }, 748 | } 749 | 750 | // Add the new function declaration to the end of the file. 751 | file.Decls = append(file.Decls, newFunc) 752 | return file, fset 753 | } 754 | 755 | func addGlobalVar(file *ast.File, var_name string, var_type string, var_type_token token.Token, var_content string) *ast.File { 756 | globalVar := &ast.GenDecl{ 757 | Tok: token.VAR, 758 | Specs: []ast.Spec{ 759 | &ast.ValueSpec{ 760 | Names: []*ast.Ident{ 761 | ast.NewIdent(var_name), 762 | }, 763 | Type: ast.NewIdent(var_type), // Type of the variable 764 | Values: []ast.Expr{ 765 | &ast.BasicLit{ 766 | Kind: var_type_token, 767 | Value: var_content, // Initial value of the variable 768 | }, 769 | }, 770 | }, 771 | }, 772 | } 773 | 774 | // Add the new global variable declaration to the AST 775 | file.Decls = append(file.Decls, globalVar) 776 | 777 | return file 778 | } 779 | 780 | func parseFieldList(fields []string, field_types []string) *ast.FieldList { 781 | fields_parsed := []*ast.Field{} 782 | i := 0 783 | for _, name := range fields { 784 | fields_parsed = append(fields_parsed, &ast.Field{ 785 | Names: []*ast.Ident{ast.NewIdent(name)}, 786 | Type: ast.NewIdent(field_types[i]), 787 | }) 788 | i = i + 1 789 | } 790 | return &ast.FieldList{List: fields_parsed} 791 | } 792 | 793 | func addAESFunctions(file *ast.File, fset *token.FileSet) (*ast.File, *token.FileSet) { 794 | 795 | file = addGlobalVar(file, "aes_key_obf", "string", token.STRING, "\"" + string(aes_key_obf) + "\"") 796 | file = addGlobalVar(file, "iv_obf", "string", token.STRING, "\"" + string(iv_obf) + "\"") 797 | 798 | funcBody := "" 799 | funcBody = ` 800 | length := len(src) 801 | unpadding := int(src[length-1]) 802 | return src[:(length - unpadding)] 803 | ` 804 | file, fset = addFunction(file, fset, "PKCS5UnPadding", funcBody, strings.Split("src", " "), strings.Split("[]byte", " "), strings.Split("", " "), strings.Split("[]byte", " ")) 805 | 806 | funcBody = ` 807 | ciphertext, _ := base64.StdEncoding.DecodeString(encrypted) 808 | block, _ := aes.NewCipher([]byte(aes_key_obf)) 809 | mode := cipher.NewCBCDecrypter(block, []byte(iv_obf)) 810 | mode.CryptBlocks(ciphertext, ciphertext) 811 | ciphertext = PKCS5UnPadding(ciphertext) 812 | return string(ciphertext) 813 | ` 814 | file, fset = addFunction(file, fset, "aesDecrypt", funcBody, strings.Split("encrypted", " "), strings.Split("string", " "), strings.Split("", " "), strings.Split("string", " ")) 815 | 816 | 817 | 818 | return file, fset 819 | } 820 | 821 | func aesEncrypt(plaintext string) (string) { 822 | if (plaintext == "") { 823 | return `""` 824 | } 825 | 826 | plaintext, _ = strconv.Unquote(`"` + plaintext + `"`) 827 | 828 | var plainTextBlock []byte 829 | length := len(plaintext) 830 | 831 | if length%16 != 0 { 832 | extendBlock := 16 - (length % 16) 833 | plainTextBlock = make([]byte, length+extendBlock) 834 | copy(plainTextBlock[length:], bytes.Repeat([]byte{uint8(extendBlock)}, extendBlock)) 835 | } else { 836 | plainTextBlock = make([]byte, length) 837 | } 838 | 839 | copy(plainTextBlock, plaintext) 840 | block, err := aes.NewCipher([]byte(aes_key_obf)) 841 | 842 | if err != nil { 843 | debug(err) 844 | return "" 845 | } 846 | 847 | ciphertext := make([]byte, len(plainTextBlock)) 848 | mode := cipher.NewCBCEncrypter(block, []byte(iv_obf)) 849 | mode.CryptBlocks(ciphertext, plainTextBlock) 850 | 851 | str := base64.StdEncoding.EncodeToString(ciphertext) 852 | 853 | return str 854 | } 855 | 856 | func shuffle(arr []interface{}) []interface{} { 857 | // Make a copy of the slice to avoid modifying the original 858 | shuffled := make([]interface{}, len(arr)) 859 | copy(shuffled, arr) 860 | 861 | // Shuffle the elements 862 | for i := len(shuffled) - 1; i > 0; i-- { 863 | j := rand.Intn(i + 1) 864 | shuffled[i], shuffled[j] = shuffled[j], shuffled[i] 865 | } 866 | 867 | return shuffled 868 | } 869 | 870 | func trimFirstLastChars(input string) string { 871 | if len(input) <= 2 { 872 | return "" 873 | } 874 | 875 | trimmedString := input[1 : len(input)-1] 876 | 877 | return trimmedString 878 | } 879 | 880 | func containsNonNumericChars(str string) bool { 881 | for _, char := range str { 882 | if !unicode.IsDigit(char) { 883 | return true 884 | } 885 | } 886 | return false 887 | } 888 | 889 | func hashString(s string) uint64 { 890 | h := fnv.New64a() 891 | h.Write([]byte(s)) 892 | return h.Sum64() 893 | } --------------------------------------------------------------------------------