Skip to content

Commit

Permalink
fix: 修复完善js解析
Browse files Browse the repository at this point in the history
  • Loading branch information
Ackites committed Aug 13, 2024
1 parent 69e3bc2 commit 3c7f088
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 109 deletions.
244 changes: 136 additions & 108 deletions internal/unpack/ujs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,72 +5,87 @@ 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 解析器
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 := `
Expand Down Expand Up @@ -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()

Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func main() {
| |\ \| | | | \ / / /_/ / (_| \__ \ <| | | |
\_| \_/_|_|_| \/ \__,_|\__,_|___/_|\_\_| |_|
Wxapkg Decompiler Tool v2.3.0
Wxapkg Decompiler Tool v2.3.1
`
fmt.Println(banner)

Expand Down

0 comments on commit 3c7f088

Please sign in to comment.