├── .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 |
20 |
21 |
22 |
23 |
24 |
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 | }
--------------------------------------------------------------------------------