├── README.md └── fix.js /README.md: -------------------------------------------------------------------------------- 1 | # 微信小程序逆向修复脚本 2 | 3 | 这是一个 Node.js 脚本,旨在快速修复微信小程序逆向工程后常见的一些配置和路径问题。 4 | 5 | ## 功能 6 | 7 | 1. **`usingComponents` 路径修复**: 8 | * 自动扫描项目内所有的 `.json` 文件。 9 | * 识别出 `usingComponents` 中不正确的组件路径(通常是由于逆向工具错误地将文件所在目录作为前缀)。 10 | * 将错误的路径修正为小程序要求的项目绝对路径(以 `/` 开头)。 11 | * 例如,将 `pages/home/components/comp` 修正为 `/components/comp`。 12 | 13 | 2. **项目配置修复**: 14 | * 自动修改 `project.config.json` 和 `project.private.config.json` 文件。 15 | * 将 `setting` 对象中的 `urlCheck` 字段设置为 `true`,以关闭URL合法域名检查,解决部分逆向项目无法在本地预览的问题。 16 | 17 | 3. **自动备份**: 18 | * 在修改任何文件之前,脚本会自动在同级目录下创建一个 `.bak` 后缀的备份文件,方便回滚和比对。 19 | * 如果某个文件经过检查后无需修改,脚本会自动删除为其创建的临时备份。 20 | 21 | ## 使用方法 22 | 23 | ### 环境要求 24 | 25 | - [Node.js](https://nodejs.org/) (建议使用LTS版本) 26 | 27 | ### 操作步骤 28 | 29 | 1. 将此脚本(`fix.js`)和 `README.md` 放置在一个独立的目录中。 30 | 2. 打开你的终端(Terminal)或命令提示符(Command Prompt)。 31 | 3. 进入该脚本所在的目录。 32 | 4. 运行以下命令,并将 `<你的小程序项目路径>`替换为实际的小程序项目根目录路径: 33 | 34 | ```bash 35 | node fix.js <你的小程序项目路径> 36 | ``` 37 | 38 | **示例:** 39 | 40 | ```bash 41 | node fix.js /Users/username/Desktop/my-miniprogram-project 42 | ``` 43 | 44 | 5. 脚本将自动执行所有修复操作,并在终端输出详细的处理日志。 -------------------------------------------------------------------------------- /fix.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | // 1. Get the mini program path from command line arguments 5 | const miniAppPath = process.argv[2]; 6 | 7 | if (!miniAppPath) { 8 | console.error('错误:请提供小程序项目的根目录路径作为参数。'); 9 | console.log('用法: node fix.js '); 10 | process.exit(1); 11 | } 12 | 13 | const absoluteMiniAppPath = path.resolve(miniAppPath); 14 | 15 | if (!fs.existsSync(absoluteMiniAppPath) || !fs.statSync(absoluteMiniAppPath).isDirectory()) { 16 | console.error(`错误:提供的路径 "${absoluteMiniAppPath}" 不存在或不是一个目录。`); 17 | process.exit(1); 18 | } 19 | 20 | console.log(`正在扫描项目: ${absoluteMiniAppPath}`); 21 | 22 | // 2. Recursively find all files in the directory 23 | function findFilesRecursively(dir, fileList = []) { 24 | const files = fs.readdirSync(dir); 25 | 26 | files.forEach(file => { 27 | const filePath = path.join(dir, file); 28 | const stat = fs.statSync(filePath); 29 | 30 | if (stat.isDirectory()) { 31 | if (['node_modules', 'miniprogram_npm', '.git'].includes(file)) { 32 | console.log(`- 跳过目录: ${filePath}`); 33 | return; 34 | } 35 | findFilesRecursively(filePath, fileList); 36 | } else { 37 | fileList.push(filePath); 38 | } 39 | }); 40 | 41 | return fileList; 42 | } 43 | 44 | const allFiles = findFilesRecursively(absoluteMiniAppPath); 45 | const jsonFiles = allFiles.filter(file => path.extname(file) === '.json'); 46 | 47 | console.log(` 48 | 找到了 ${jsonFiles.length} 个 JSON 文件,开始处理 usingComponents...`); 49 | 50 | // 3. Process each JSON file for usingComponents 51 | let processedUsingComponentsCount = 0; 52 | jsonFiles.forEach(jsonFilePath => { 53 | try { 54 | const fileContent = fs.readFileSync(jsonFilePath, 'utf8'); 55 | // Skip empty files 56 | if (!fileContent.trim()) { 57 | return; 58 | } 59 | const jsonObject = JSON.parse(fileContent); 60 | 61 | if (jsonObject && typeof jsonObject === 'object' && jsonObject.usingComponents) { 62 | console.log(` 63 | -> 正在处理 usingComponents: ${path.relative(absoluteMiniAppPath, jsonFilePath)}`); 64 | processedUsingComponentsCount++; 65 | let isModified = false; 66 | 67 | // Create a backup before modification 68 | const backupPath = `${jsonFilePath}.bak`; 69 | fs.copyFileSync(jsonFilePath, backupPath); 70 | console.log(` 备份至: ${path.relative(absoluteMiniAppPath, backupPath)}`); 71 | 72 | const components = jsonObject.usingComponents; 73 | // Get the directory of the current JSON file, relative to the project root. 74 | const jsonFileDir = path.dirname(path.relative(absoluteMiniAppPath, jsonFilePath)); 75 | 76 | // Handle root case where dirname is '.' 77 | // If the json file is in the root, its relative path is 'file.json', dirname is '.' 78 | // If the component path is already absolute (starts with /), no need to modify 79 | if (jsonFileDir === '.') { 80 | // Check if any component path starts with '.' and fix it 81 | for (const key in components) { 82 | const originalPath = components[key]; 83 | if (originalPath.startsWith('./')) { 84 | const newPath = '/' + originalPath.substring(2); 85 | if (newPath !== originalPath) { 86 | console.log(` - [${key}]: "${originalPath}" => "${newPath}"`); 87 | components[key] = newPath; 88 | isModified = true; 89 | } 90 | } 91 | } 92 | } else { 93 | for (const key in components) { 94 | const originalPath = components[key]; 95 | let newPath = originalPath; 96 | 97 | // Check if the component path starts with the incorrect directory prefix 98 | if (originalPath.startsWith(jsonFileDir)) { 99 | newPath = originalPath.substring(jsonFileDir.length); 100 | 101 | // Ensure the new path starts with a '/' 102 | if (!newPath.startsWith('/')) { 103 | newPath = '/' + newPath; 104 | } 105 | 106 | if (newPath !== originalPath) { 107 | console.log(` - [${key}]: "${originalPath}" => "${newPath}"`); 108 | components[key] = newPath; 109 | isModified = true; 110 | } 111 | } 112 | } 113 | } 114 | 115 | 116 | if (isModified) { 117 | // Write the updated JSON object back to the file 118 | const updatedContent = JSON.stringify(jsonObject, null, 2); // Pretty print JSON 119 | fs.writeFileSync(jsonFilePath, updatedContent, 'utf8'); 120 | console.log(` 文件已更新。`); 121 | } else { 122 | console.log(` 无需修改。`); 123 | // If no modification, remove the backup 124 | fs.unlinkSync(backupPath); 125 | console.log(` 备份已删除。`); 126 | } 127 | } 128 | } catch (error) { 129 | if (error instanceof SyntaxError) { 130 | // console.warn(` 警告: 解析JSON失败,已跳过 ${path.relative(absoluteMiniAppPath, jsonFilePath)}`); 131 | } else { 132 | console.error(` 处理文件时出错 ${path.relative(absoluteMiniAppPath, jsonFilePath)}:`, error); 133 | } 134 | } 135 | }); 136 | 137 | console.log(` 138 | 处理 usingComponents 完成!总共检查了 ${jsonFiles.length} 个JSON文件,处理了 ${processedUsingComponentsCount} 个包含 usingComponents 的文件。`); 139 | 140 | 141 | // 4. Process project config files for urlCheck 142 | console.log(` 143 | 开始处理项目配置文件 (project.config.json, project.private.config.json) 中的 urlCheck...`); 144 | 145 | function processProjectConfigFile(filePath) { 146 | const fullPath = path.join(absoluteMiniAppPath, filePath); 147 | if (fs.existsSync(fullPath)) { 148 | try { 149 | const fileContent = fs.readFileSync(fullPath, 'utf8'); 150 | const jsonObject = JSON.parse(fileContent); 151 | let isModified = false; 152 | 153 | // Ensure setting object exists 154 | if (!jsonObject.setting) { 155 | jsonObject.setting = {}; 156 | } 157 | 158 | if (jsonObject && typeof jsonObject === 'object' && jsonObject.setting && jsonObject.setting.urlCheck === false) { 159 | console.log(`-> 正在处理: ${filePath}`); 160 | // Create a backup 161 | const backupPath = `${fullPath}.bak`; 162 | fs.copyFileSync(fullPath, backupPath); 163 | console.log(` 备份至: ${path.relative(absoluteMiniAppPath, backupPath)}`); 164 | 165 | jsonObject.setting.urlCheck = true; 166 | isModified = true; 167 | console.log(` urlCheck 已设置为 true。`); 168 | } else { 169 | console.log(`-> ${filePath}: urlCheck 已是 true 或不存在,无需修改。`); 170 | } 171 | 172 | if (isModified) { 173 | const updatedContent = JSON.stringify(jsonObject, null, 2); 174 | fs.writeFileSync(fullPath, updatedContent, 'utf8'); 175 | console.log(` 文件已更新。`); 176 | } else { 177 | // If no modification, and a backup was created (which it would be if urlCheck was false), remove it. 178 | // This logic needs to be careful. If urlCheck was already true, no backup was made. 179 | // If urlCheck was false and changed, backup is kept. 180 | // If urlCheck was false and no change was made (e.g. error), backup should be removed. 181 | // For simplicity, if isModified is false, no backup was created, nothing to remove. 182 | } 183 | 184 | } catch (error) { 185 | console.error(`处理文件时出错 ${filePath}:`, error); 186 | } 187 | } else { 188 | console.log(`-> 文件 ${filePath} 不存在,已跳过。`); 189 | } 190 | } 191 | 192 | processProjectConfigFile('project.config.json'); 193 | processProjectConfigFile('project.private.config.json'); 194 | 195 | console.log('\n所有处理完成!'); --------------------------------------------------------------------------------