From 3c7f088eed2d522dd4e029b39e6b12bc7eafa207 Mon Sep 17 00:00:00 2001 From: Antkites Date: Tue, 13 Aug 2024 18:25:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=AE=8C=E5=96=84js?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/unpack/ujs.go | 244 +++++++++++++++++++++++------------------ main.go | 2 +- 2 files changed, 137 insertions(+), 109 deletions(-) diff --git a/internal/unpack/ujs.go b/internal/unpack/ujs.go index 70de4c9..5548417 100644 --- a/internal/unpack/ujs.go +++ b/internal/unpack/ujs.go @@ -5,11 +5,14 @@ import ( "log" "os" "path/filepath" + "regexp" + "strings" + + "github.com/dop251/goja" "github.com/Ackites/KillWxapkg/internal/enum" "github.com/Ackites/KillWxapkg/internal/config" - "github.com/dop251/goja" ) // JavaScriptParser JavaScript 解析器 @@ -17,60 +20,72 @@ type JavaScriptParser struct { OutputDir string } -// removeWrapper 移除函数包装器 -func removeWrapper(jsCode string) (string, error) { - vm := goja.New() - script := ` - (function(code) { - let match = code.match(/^function\s*\(.*?\)\s*\{([\s\S]*)\}$/); - if (match && match[1]) { - // 每一行缩进减少一个空格 - match[1] = match[1].trim(); - code = match[1].replace(/^\s{4}/gm, ''); - } - return code; - })(code); - ` - // 设置 JavaScript 变量 - err := vm.Set("code", jsCode) - if err != nil { - return "", err - } - value, err := vm.RunString(script) - if err != nil { - return "", fmt.Errorf("JavaScript execution error: %w", err) - } - return value.String(), nil +// DefineParams 存储从 define 函数中提取的参数 +type DefineParams struct { + ModuleName string + FuncBody string } -// 是否为分包 -func isSubpackage(wxapkg *config.WxapkgInfo) bool { - switch wxapkg.WxapkgType { - case enum.APP_SUBPACKAGE_V1, enum.APP_SUBPACKAGE_V2, enum.GAME_SUBPACKAGE: - return true - default: - return false +func cleanDefineFunc(jsCode string) string { + // 正则表达式匹配 define 函数的头部 + reHead := regexp.MustCompile(`^define\s*\(\s*["'].*?["']\s*,\s*function\s*\([^)]*\)\s*\{`) + + // 正则表达式匹配 define 函数的尾部 + reTail := regexp.MustCompile(`\}\s*,\s*\{[^}]*isPage\s*:\s*[^}]*\}\s*\)\s*;$`) + + // 移除头部 + cleanedCode := reHead.ReplaceAllString(jsCode, "") + + // 移除尾部 + cleanedCode = reTail.ReplaceAllString(cleanedCode, "") + + // 去除开头和结尾的空白字符 + cleanedCode = strings.TrimSpace(cleanedCode) + + // 去除"严格模式"声明 + if strings.HasPrefix(cleanedCode, `"use strict";`) || strings.HasPrefix(cleanedCode, `'use strict';`) { + cleanedCode = cleanedCode[13:] + cleanedCode = strings.TrimSpace(cleanedCode) } + + return cleanedCode } -// Parse 解析和分割 JavaScript 文件 -func (p *JavaScriptParser) Parse(option config.WxapkgInfo) error { +// extractDefineParams 提取所有 define 函数的第一个和第二个参数 +func extractDefineParams(jsCode string) ([]DefineParams, error) { + // 正则表达式提取 define 函数的第一个和第二个参数 + re := regexp.MustCompile(`define\s*\(\s*["']([^"']+)["']\s*,\s*function\s*\(([^)]*)\)\s*\{([\s\S]*?)\}\s*,\s*\{[^}]*isPage\s*:\s*[^}]*\}\s*\)\s*;`) + matches := re.FindAllStringSubmatch(jsCode, -1) - dir := option.SourcePath - if isSubpackage(&option) { - dir = p.OutputDir + if len(matches) == 0 { + results, err := run(jsCode) + if err != nil { + return nil, err + } + return results, nil } - code, err := os.ReadFile(option.Option.ServiceSource) - if err != nil { - return fmt.Errorf("failed to read file: %w", err) + var results = make([]DefineParams, 0) + for _, match := range matches { + if len(match) >= 3 { + params := DefineParams{ + ModuleName: match[1], + FuncBody: cleanDefineFunc(match[0]), + } + results = append(results, params) + } } + return results, nil +} +func run(code string) ([]DefineParams, error) { + var results = make([]DefineParams, 0) // 防止报错 patch := `var window={};var navigator={};navigator.userAgent="iPhone";window.screen={}; -document={getElementsByTagName:()=>{}};function require(){};` +document={getElementsByTagName:()=>{}};function require(){};var global={};var __wxAppCode__={};var __wxConfig={}; +var __vd_version_info__={};var $gwx=function(){};var __g={};` - scriptcode := patch + string(code) + scriptcode := patch + code // 包裹 try...catch 语句以捕获 JavaScript 错误 safeScript := ` @@ -109,42 +124,8 @@ document={getElementsByTagName:()=>{}};function require(){};` }) _ = vm.Set("console", console) - //// 提供 __g 变量的默认实现 - //err = vm.Set("__g", make(map[string]interface{})) - //if err != nil { - // return err - //} - // - // 提供 __wxConfig 变量的默认实现 - err = vm.Set("__wxConfig", make(map[string]interface{})) - if err != nil { - return err - } - - //// 提供 global 变量的默认实现 - //err = vm.Set("global", make(map[string]interface{})) - //if err != nil { - // return err - //} - // - //err = vm.Set("__vd_version_info__", map[string]interface{}{ - // "version": "1.0.0", - // "build": "default", - //}) - //if err != nil { - // return err - //} - // - //wxAppCode := make(map[string]func()) - //// 设置 __wxAppCode__ - //err = vm.Set("__wxAppCode__", wxAppCode) - //if err != nil { - // log.Printf("Error setting __wxAppCode__: %v\n", err) - // return err - //} - // 设置 define 函数和 require 函数的行为 - err = vm.Set("define", func(call goja.FunctionCall) goja.Value { + err := vm.Set("define", func(call goja.FunctionCall) goja.Value { moduleName := call.Argument(0).String() funcBody := call.Argument(1).String() @@ -154,46 +135,93 @@ document={getElementsByTagName:()=>{}};function require(){};` cleanedCode = funcBody } - //bcode := cleanedCode - // 检查是否包含 "use strict" 并处理 - //if strings.HasPrefix(cleanedCode, `"use strict";`) || strings.HasPrefix(cleanedCode, `'use strict';`) { - // cleanedCode = cleanedCode[13:] - //} else if (strings.HasPrefix(cleanedCode, `(function(){"use strict";`) || strings.HasPrefix(cleanedCode, `(function(){'use strict';`)) && - // strings.HasSuffix(cleanedCode, `})();`) { - // cleanedCode = cleanedCode[25 : len(cleanedCode)-5] - //} + //检查是否包含 "use strict" 并处理 + if strings.HasPrefix(cleanedCode, `"use strict";`) || strings.HasPrefix(cleanedCode, `'use strict';`) { + cleanedCode = cleanedCode[13:] + } else if (strings.HasPrefix(cleanedCode, `(function(){"use strict";`) || strings.HasPrefix(cleanedCode, `(function(){'use strict';`)) && + strings.HasSuffix(cleanedCode, `})();`) { + cleanedCode = cleanedCode[25 : len(cleanedCode)-5] + } - err = save(filepath.Join(dir, moduleName), []byte(cleanedCode)) - if err != nil { - log.Printf("Error saving file: %v\n", err) + params := DefineParams{ + ModuleName: moduleName, + FuncBody: cleanedCode, } + results = append(results, params) + return goja.Undefined() }) if err != nil { - return err + return nil, err } - //err = vm.Set("require", func(call goja.FunctionCall) goja.Value { - // // 返回一个空对象,表示对 require 的任何调用都将返回这个空对象 - // result := vm.NewObject() - // return result - //}) - //if err != nil { - // return err - //} - // - //// 设置 $gwx 变量 - //err = vm.Set("$gwx", func(call goja.FunctionCall) goja.Value { - // // $gwx function implementation here - // return goja.Undefined() - //}) - //if err != nil { - // return err - //} - _, err = vm.RunString(safeScript) if err != nil { - return fmt.Errorf("failed to run JavaScript: %w", err) + return nil, fmt.Errorf("failed to run JavaScript: %w", err) + } + + return results, nil +} + +// removeWrapper 移除函数包装器 +func removeWrapper(jsCode string) (string, error) { + vm := goja.New() + script := ` + (function(code) { + let match = code.match(/^function\s*\(.*?\)\s*\{([\s\S]*)\}$/); + if (match && match[1]) { + // 每一行缩进减少一个空格 + match[1] = match[1].trim(); + code = match[1].replace(/^\s{4}/gm, ''); + } + return code; + })(code); + ` + // 设置 JavaScript 变量 + err := vm.Set("code", jsCode) + if err != nil { + return "", err + } + value, err := vm.RunString(script) + if err != nil { + return "", fmt.Errorf("JavaScript execution error: %w", err) + } + return value.String(), nil +} + +// 是否为分包 +func isSubpackage(wxapkg *config.WxapkgInfo) bool { + switch wxapkg.WxapkgType { + case enum.APP_SUBPACKAGE_V1, enum.APP_SUBPACKAGE_V2, enum.GAME_SUBPACKAGE: + return true + default: + return false + } +} + +// Parse 解析和分割 JavaScript 文件 +func (p *JavaScriptParser) Parse(option config.WxapkgInfo) error { + + dir := option.SourcePath + if isSubpackage(&option) { + dir = p.OutputDir + } + + code, err := os.ReadFile(option.Option.ServiceSource) + if err != nil { + return fmt.Errorf("failed to read file: %w", err) + } + + params, err := extractDefineParams(string(code)) + if err != nil { + return err + } + + for _, param := range params { + err = save(filepath.Join(dir, param.ModuleName), []byte(param.FuncBody)) + if err != nil { + log.Printf("Error saving file: %v\n", err) + } } log.Printf("Splitting \"%s\" done.", option.Option.ServiceSource) diff --git a/main.go b/main.go index 249d84d..6ae7509 100644 --- a/main.go +++ b/main.go @@ -50,7 +50,7 @@ func main() { | |\ \| | | | \ / / /_/ / (_| \__ \ <| | | | \_| \_/_|_|_| \/ \__,_|\__,_|___/_|\_\_| |_| - Wxapkg Decompiler Tool v2.3.0 + Wxapkg Decompiler Tool v2.3.1 ` fmt.Println(banner)