├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── .vscode ├── extensions.json ├── global.code-snippets └── settings.json ├── README.md ├── WechatOpenDevTools └── __init__.py ├── __init__.py ├── configs ├── address_11159_x64.json ├── address_11205_x64.json ├── address_11253_x64.json ├── address_11275_x64.json ├── address_13080811_x64.json ├── address_13080812_x64.json ├── address_8447_x64.json ├── address_8461_x64.json ├── address_8501_x64.json ├── address_8519_x64.json ├── address_8529_x64.json ├── address_8531_x64.json ├── address_8555_x64.json ├── address_9079_x64.json ├── address_9105_x64.json ├── address_9115_x64.json ├── address_9129_x64.json └── address_9193_x64.json ├── docs ├── api.md ├── authors.md ├── contributing.md ├── history.md ├── images │ ├── 1 │ ├── MG38.jpg │ ├── demo1.png │ ├── demo2.png │ ├── run.jpg │ ├── version0.jpg │ ├── version1.jpg │ └── version2.jpg ├── index.md ├── installation.md └── usage.md ├── main.py ├── requirements.txt ├── scripts ├── WechatWin.dll │ └── hook.js └── hook.js ├── utils ├── __init__.py ├── banner.py ├── colors.py ├── commons.py └── wechatutils.py └── workflows ├── README.md ├── __init__.py ├── dev.yml ├── release.yml └── requirements.txt /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "# 问题标题:简洁且具有描述性的问题标题" 5 | labels: bug 6 | assignees: JaveleyQAQ 7 | 8 | --- 9 | # 🙋提问智力得分表 10 | | 智力得分|提问方式 11 | | -------| ------ 12 | | 100分 | 我在xxx遇到了一个问题,在翻阅文档和视频后,这里是报错截图,我参考了百度或谷歌中xxx文章进行解决,但仍不能解决! 13 | | 90分 | 我遇到了xxx问题,我翻阅了文档和视频,没有找到解决方案,完整的报错截图如下。。。。。。 14 | | 60分 | 这里是完整的报错截图,请问应该怎么解决 15 | | 10分 | 这咋回事啊(手机拍屏幕) 16 | | 0分 | 这怎么办啊(不完整的报错截图) 17 | | sb | 大神求带、这怎么不能用了我打不开了、你们这个正常吗、文件在哪啊、怎么学啊我是小白能帮我吗 18 | 19 | 20 | ## 问题描述 21 | - 请在这里提供问题的详细描述,包括您遇到的具体问题和任何相关的背景信息。 22 | 23 | ## 环境信息 24 | - **操作系统及版本**:例如 Windows 10, macOS Big Sur 11.1 25 | - **编程语言和版本**:例如 Python 3.8.5 26 | - **相关库或框架及版本**:例如 Django 3.1.7 27 | - **GitHub 仓库名称和问题相关的代码分支**:如果有的话,提供仓库链接和分支信息。 28 | 29 | ## 复现步骤 30 | 1. 步骤一:描述第一步操作。 31 | 2. 步骤二:描述第二步操作。 32 | 3. 以此类推,直到步骤 N。 33 | 34 | ## 预期结果 35 | - 描述您期望的结果或行为。 36 | 37 | ## 实际结果 38 | - 描述实际发生的结果或行为。 39 | - 如果有错误信息,请提供完整的错误日志或截图。 40 | 41 | ## 其他信息 42 | - 提供任何可能有助于解决问题的其他信息,例如您尝试过的解决方案或相关工作的链接。 43 | 44 | ## 附加文件 45 | - 如果需要附加文件,请确保它们是必要的,并且不会泄露任何敏感信息。可以使用 GitHub 的上传功能或提供文件的下载链接。 46 | 47 | --- 48 | 49 | 请在提交问题之前,检查您的描述是否清晰、准确,并且提供了足够的信息以便他人理解您的问题。感谢您的合作! 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | frida-example 2 | .DS_Store 3 | **/__pycache__ 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | // my extensions, ofc :P 4 | "antfu.browse-lite", 5 | "antfu.iconify", 6 | "antfu.slidev", 7 | "antfu.unocss", 8 | "antfu.vite", 9 | "antfu.where-am-i", 10 | "antfu.open-in-github-button", 11 | "lokalise.i18n-ally", 12 | 13 | // themes & icons 14 | "antfu.icons-carbon", 15 | "antfu.theme-vitesse", 16 | "file-icons.file-icons", 17 | "sainnhe.gruvbox-material", 18 | 19 | // life savers! 20 | "dbaeumer.vscode-eslint", 21 | "Vue.volar", 22 | "GitHub.copilot", 23 | "usernamehw.errorlens", 24 | "streetsidesoftware.code-spell-checker", 25 | 26 | // up to you 27 | "eamodio.gitlens", 28 | "EditorConfig.EditorConfig", 29 | "github.vscode-github-actions", 30 | "GitHub.vscode-pull-request-github", 31 | "johnsoncodehk.vscode-tsconfig-helper", 32 | "mpontus.tab-cycle", 33 | "naumovs.color-highlight", 34 | "WakaTime.vscode-wakatime", 35 | "znck.grammarly" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /.vscode/global.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "import": { 3 | "scope": "javascript,typescript", 4 | "prefix": "im", 5 | "body": [ 6 | "import { $1 } from '$2';" 7 | ], 8 | "description": "Import a module" 9 | }, 10 | "export-all": { 11 | "scope": "javascript,typescript", 12 | "prefix": "ex", 13 | "body": [ 14 | "export * from '$2';" 15 | ], 16 | "description": "Export a module" 17 | }, 18 | "vue-script-setup": { 19 | "scope": "vue", 20 | "prefix": "", 23 | "const props = defineProps<{", 24 | " modelValue?: boolean,", 25 | "}>()", 26 | "$1", 27 | "", 28 | "", 29 | "", 34 | ] 35 | }, 36 | "vue-template-ref": { 37 | "scope": "javascript,typescript,vue", 38 | "prefix": "tref", 39 | "body": [ 40 | "const ${1:el} = shallowRef()", 41 | ] 42 | }, 43 | "vue-computed": { 44 | "scope": "javascript,typescript,vue", 45 | "prefix": "com", 46 | "body": [ 47 | "computed(() => { $1 })" 48 | ] 49 | }, 50 | "vue-watch-effect": { 51 | "scope": "javascript,typescript,vue", 52 | "prefix": "watchE", 53 | "body": [ 54 | "watchEffect(() => {", 55 | " $1", 56 | "})" 57 | ] 58 | }, 59 | "if-vitest": { 60 | "scope": "javascript,typescript", 61 | "prefix": "ifv", 62 | "body": [ 63 | "if (import.meta.vitest) {", 64 | " const { describe, it, expect } = import.meta.vitest", 65 | " ${1}", 66 | "}" 67 | ] 68 | }, 69 | "markdown-api-table": { 70 | "scope": "markdown", 71 | "prefix": "table", 72 | "body": [ 73 | "", 74 | "", 75 | "", 82 | "", 89 | "", 90 | "
", 76 | "", 77 | "### API", 78 | "", 79 | "Description", 80 | "", 81 | "
", 83 | "", 84 | "```ts", 85 | "// code block", 86 | "```", 87 | "", 88 | "
", 91 | ], 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // =========extension=========// 3 | 4 | 5 | // ========== Visuals ========== 6 | "editor.cursorBlinking":"smooth", 7 | "editor.cursorSmoothCaretAnimation":"on", 8 | "files.autoSave": "onFocusChange", 9 | "editor.fontFamily": "Input Mono, monospace", 10 | "editor.fontSize": 15, 11 | "editor.guides.bracketPairs": true, 12 | "editor.guides.bracketPairsHorizontal":true, 13 | "search.collapseResults": "auto", 14 | "editor.hover.delay":0, 15 | "editor.lineNumbers": "interval", 16 | "editor.renderWhitespace": "boundary", 17 | "editor.bracketPairColorization.independentColorPoolPerBracketType": true, 18 | "editor.columnSelection": true, 19 | "editor.padding.top":2, 20 | "editor.smoothScrolling":true, 21 | "editor.showFoldingControls":"always", 22 | "window.autoDetectColorScheme": true, 23 | "workbench.colorTheme": "Vitesse Light", 24 | "workbench.editor.tabActionLocation": "left", 25 | "workbench.fontAliasing": "antialiased", 26 | "workbench.iconTheme": "catppuccin-latte", 27 | "workbench.list.smoothScrolling": true, 28 | "workbench.preferredDarkColorTheme": "Vitesse Dark", 29 | "workbench.preferredLightColorTheme": "Vitesse Light", 30 | "workbench.productIconTheme": "icons-carbon", 31 | "workbench.sideBar.location": "left", 32 | "workbench.startupEditor": "newUntitledFile", 33 | "workbench.tree.expandMode": "singleClick", 34 | "workbench.tree.indent": 10, 35 | "search.showLineNumbers": true, 36 | "search.seedOnFocus": true, 37 | "workbench.quickOpen.preserveInput": true, 38 | 39 | // ========== Editor ========== 40 | "diffEditor.renderSideBySide": false, 41 | "debug.onTaskErrors": "debugAnyway", 42 | "diffEditor.ignoreTrimWhitespace": false, 43 | "editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\·\",.<>/?", 44 | "editor.find.addExtraSpaceOnTop": false, 45 | 46 | "editor.find.seedSearchStringFromSelection":"never", 47 | "editor.inlineSuggest.enabled": true, 48 | "editor.multiCursorModifier": "ctrlCmd", 49 | "editor.suggestSelection": "recentlyUsed", 50 | "editor.tabSize": 2, 51 | "editor.unicodeHighlight.invisibleCharacters": false, 52 | "editor.stickyScroll.enabled": true, 53 | "editor.hover.sticky": true, 54 | "editor.snippetSuggestions": "top", 55 | 56 | "editor.codeActionsOnSave": { 57 | "source.fixAll": "never", 58 | "source.fixAll.eslint": "explicit", 59 | "source.organizeImports": "never" 60 | }, 61 | "explorer.confirmDelete": false, 62 | "explorer.confirmDragAndDrop": false, 63 | "files.eol": "\n", 64 | "files.insertFinalNewline": true, 65 | "files.simpleDialog.enable": true, 66 | "git.autofetch": true, 67 | "git.confirmSync": false, 68 | "git.enableSmartCommit": true, 69 | "git.untrackedChanges": "separate", 70 | "scm.diffDecorationsGutterWidth": 2, 71 | "terminal.integrated.cursorBlinking": true, 72 | "terminal.integrated.cursorStyle": "line", 73 | "terminal.integrated.fontWeight": "300", 74 | "terminal.integrated.persistentSessionReviveProcess": "never", 75 | "terminal.integrated.tabs.enabled": true, 76 | "workbench.editor.closeOnFileDelete": true, 77 | "workbench.editor.highlightModifiedTabs": true, 78 | "workbench.editor.limit.enabled": true, 79 | "workbench.editor.limit.perEditorGroup": true, 80 | "workbench.editor.limit.value": 5, 81 | "search.exclude": { 82 | "**/*.snap": true, 83 | "**/*.svg": true, 84 | "**/.git": true, 85 | "**/.github": false, 86 | "**/.nuxt": true, 87 | "**/.output": true, 88 | "**/.pnpm": true, 89 | "**/.vscode": true, 90 | "**/.yarn": true, 91 | "**/assets": true, 92 | "**/bower_components": true, 93 | "**/dist/**": true, 94 | "**/logs": true, 95 | "**/node_modules": true, 96 | "**/out/**": true, 97 | "**/package-lock.json": true, 98 | "**/pnpm-lock.yaml": true, 99 | "**/public": true, 100 | "**/temp": true, 101 | "**/yarn.lock": true, 102 | "**/CHANGELOG*": true, 103 | "**/LICENSE*": true, 104 | }, 105 | 106 | 107 | //=====commands ===// 108 | "workbench.commandPalette.experimental.suggestCommands": true, 109 | "workbench.commandPalette.history": 50, 110 | "workbench.commandPalette.preserveInput": true, 111 | "workbench.reduceMotion": "auto", 112 | 113 | "search.useParentIgnoreFiles": true, 114 | 115 | 116 | // ========== Global Level Config, needs to put in User Settings ========== 117 | "window.dialogStyle": "custom", 118 | "window.nativeTabs": true, // this is great, macOS only 119 | "window.title": "${rootName}", // this make tabs more readable 120 | "window.titleBarStyle": "custom", 121 | "editor.defaultFormatter": "esbenp.prettier-vscode", 122 | "extensions.autoUpdate": "onlyEnabledExtensions", 123 | 124 | // ========== Extension configs ========== 125 | "emmet.showSuggestionsAsSnippets": true, 126 | "emmet.triggerExpansionOnTab": false, 127 | "errorLens.enabledDiagnosticLevels": [ 128 | "warning", 129 | "error" 130 | ], 131 | "errorLens.excludeBySource": [ 132 | "cSpell", 133 | "Grammarly", 134 | "eslint" 135 | ], 136 | 137 | // ESLint config: https://github.com/antfu/eslint-config 138 | "eslint.codeAction.showDocumentation": { 139 | "enable": true 140 | }, 141 | "eslint.quiet": true, 142 | // Silent the stylistic rules in you IDE, but still auto fix them 143 | "eslint.rules.customizations": [ 144 | { "rule": "style/*", "severity": "off" }, 145 | { "rule": "format/*", "severity": "off" }, 146 | { "rule": "*-indent", "severity": "off" }, 147 | { "rule": "*-spacing", "severity": "off" }, 148 | { "rule": "*-spaces", "severity": "off" }, 149 | { "rule": "*-order", "severity": "off" }, 150 | { "rule": "*-dangle", "severity": "off" }, 151 | { "rule": "*-newline", "severity": "off" }, 152 | { "rule": "*quotes", "severity": "off" }, 153 | { "rule": "*semi", "severity": "off" } 154 | ], 155 | "eslint.validate": [ 156 | "javascript", 157 | "javascriptreact", 158 | "typescript", 159 | "typescriptreact", 160 | "vue", 161 | "html", 162 | "markdown", 163 | "json", 164 | "jsonc", 165 | "yaml", 166 | "toml" 167 | ], 168 | 169 | "github.copilot.enable": { 170 | "*": true, 171 | "markdown": true, 172 | "plaintext": false, 173 | }, 174 | "cSpell.allowCompoundWords": true, 175 | "cSpell.language": "en,en-US", 176 | "css.lint.hexColorLength": "ignore", 177 | "githubIssues.workingIssueFormatScm": "#${issueNumberLabel}", 178 | "githubPullRequests.fileListLayout": "tree", 179 | "gitlens.codeLens.authors.enabled": false, 180 | "gitlens.codeLens.enabled": false, 181 | "gitlens.codeLens.recentChange.enabled": false, 182 | "gitlens.menus": { 183 | "editor": { 184 | "blame": false, 185 | "clipboard": true, 186 | "compare": true, 187 | "history": false, 188 | "remote": false 189 | }, 190 | "editorGroup": { 191 | "blame": true, 192 | "compare": false 193 | }, 194 | "editorTab": { 195 | "clipboard": true, 196 | "compare": true, 197 | "history": true, 198 | "remote": true 199 | }, 200 | "explorer": { 201 | "clipboard": true, 202 | "compare": true, 203 | "history": true, 204 | "remote": true 205 | }, 206 | "scm": { 207 | "authors": true 208 | }, 209 | "scmGroup": { 210 | "compare": true, 211 | "openClose": true, 212 | "stash": true 213 | }, 214 | "scmGroupInline": { 215 | "stash": true 216 | }, 217 | "scmItem": { 218 | "clipboard": true, 219 | "compare": true, 220 | "history": true, 221 | "remote": false, 222 | "stash": true 223 | } 224 | }, 225 | "i18n-ally.autoDetection": false, 226 | "i18n-ally.displayLanguage": "en", 227 | "i18n-ally.ignoredLocales": [], 228 | "iconify.annotations": true, 229 | "iconify.inplace": true, 230 | "svg.preview.mode": "svg", 231 | 232 | // I only use Prettier for manually formatting 233 | "prettier.enable": false, 234 | "prettier.printWidth": 200, 235 | "prettier.semi": false, 236 | "prettier.singleQuote": true, 237 | 238 | // ========== File Nesting ========== 239 | // this might not be up to date with the repo, please check yourself 240 | // https://github.com/antfu/vscode-file-nesting-config 241 | "explorer.fileNesting.enabled": true, 242 | "explorer.fileNesting.expand": false, 243 | "explorer.fileNesting.patterns": { 244 | "*.asax": "$(capture).*.cs, $(capture).*.vb", 245 | "*.ascx": "$(capture).*.cs, $(capture).*.vb", 246 | "*.ashx": "$(capture).*.cs, $(capture).*.vb", 247 | "*.aspx": "$(capture).*.cs, $(capture).*.vb", 248 | "*.bloc.dart": "$(capture).event.dart, $(capture).state.dart", 249 | "*.c": "$(capture).h", 250 | "*.cc": "$(capture).hpp, $(capture).h, $(capture).hxx", 251 | "*.cjs": "$(capture).cjs.map, $(capture).*.cjs, $(capture)_*.cjs", 252 | "*.component.ts": "$(capture).component.html, $(capture).component.spec.ts, $(capture).component.css, $(capture).component.scss, $(capture).component.sass, $(capture).component.less", 253 | "*.cpp": "$(capture).hpp, $(capture).h, $(capture).hxx", 254 | "*.cs": "$(capture).*.cs", 255 | "*.cshtml": "$(capture).cshtml.cs", 256 | "*.csproj": "*.config, *proj.user, appsettings.*, bundleconfig.json", 257 | "*.css": "$(capture).css.map, $(capture).*.css", 258 | "*.cxx": "$(capture).hpp, $(capture).h, $(capture).hxx", 259 | "*.dart": "$(capture).freezed.dart, $(capture).g.dart", 260 | "*.ex": "$(capture).html.eex, $(capture).html.heex, $(capture).html.leex", 261 | "*.go": "$(capture)_test.go", 262 | "*.java": "$(capture).class", 263 | "*.js": "$(capture).js.map, $(capture).*.js, $(capture)_*.js", 264 | "*.jsx": "$(capture).js, $(capture).*.jsx, $(capture)_*.js, $(capture)_*.jsx", 265 | "*.master": "$(capture).*.cs, $(capture).*.vb", 266 | "*.mjs": "$(capture).mjs.map, $(capture).*.mjs, $(capture)_*.mjs", 267 | "*.module.ts": "$(capture).resolver.ts, $(capture).controller.ts, $(capture).service.ts", 268 | "*.pubxml": "$(capture).pubxml.user", 269 | "*.resx": "$(capture).*.resx, $(capture).designer.cs, $(capture).designer.vb", 270 | "*.tex": "$(capture).acn, $(capture).acr, $(capture).alg, $(capture).aux, $(capture).bbl, $(capture).blg, $(capture).fdb_latexmk, $(capture).fls, $(capture).glg, $(capture).glo, $(capture).gls, $(capture).idx, $(capture).ind, $(capture).ist, $(capture).lof, $(capture).log, $(capture).lot, $(capture).out, $(capture).pdf, $(capture).synctex.gz, $(capture).toc, $(capture).xdv", 271 | "*.ts": "$(capture).js, $(capture).d.ts.map, $(capture).*.ts, $(capture)_*.js, $(capture)_*.ts", 272 | "*.tsx": "$(capture).ts, $(capture).*.tsx, $(capture)_*.ts, $(capture)_*.tsx", 273 | "*.vbproj": "*.config, *proj.user, appsettings.*, bundleconfig.json", 274 | "*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue", 275 | "*.xaml": "$(capture).xaml.cs", 276 | "+layout.svelte": "+layout.ts,+layout.ts,+layout.js,+layout.server.ts,+layout.server.js,+layout.gql", 277 | "+page.svelte": "+page.server.ts,+page.server.js,+page.ts,+page.js,+page.gql", 278 | ".clang-tidy": ".clang-format, .clangd, compile_commands.json", 279 | ".env": "*.env, .env.*, .envrc, env.d.ts", 280 | ".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*", 281 | ".project": ".classpath", 282 | "//": "Last update at 4/29/2023, 2:04:58 PM", 283 | "BUILD.bazel": "*.bzl, *.bazel, *.bazelrc, bazel.rc, .bazelignore, .bazelproject, WORKSPACE", 284 | "CMakeLists.txt": "*.cmake, *.cmake.in, .cmake-format.yaml, CMakePresets.json", 285 | "I*.cs": "$(capture).cs", 286 | "artisan": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, server.php, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, webpack.mix.js, windi.config.*", 287 | "astro.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 288 | "cargo.toml": ".clippy.toml, .rustfmt.toml, cargo.lock, clippy.toml, cross.toml, rust-toolchain.toml, rustfmt.toml", 289 | "composer.json": ".php*.cache, composer.lock, phpunit.xml*, psalm*.xml", 290 | "default.nix": "shell.nix", 291 | "deno.json*": "*.env, .env.*, .envrc, api-extractor.json, deno.lock, env.d.ts, import-map.json, import_map.json, jsconfig.*, tsconfig.*, tsdoc.*", 292 | "dockerfile": ".dockerignore, docker-compose.*, dockerfile*", 293 | "flake.nix": "flake.lock", 294 | "gatsby-config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, gatsby-browser.*, gatsby-node.*, gatsby-ssr.*, gatsby-transformer.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 295 | "gemfile": ".ruby-version, gemfile.lock", 296 | "go.mod": ".air*, go.sum", 297 | "go.work": "go.work.sum", 298 | "mix.exs": ".credo.exs, .dialyzer_ignore.exs, .formatter.exs, .iex.exs, .tool-versions, mix.lock", 299 | "next.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, next-env.d.ts, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 300 | "nuxt.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 301 | "package.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*", 302 | "pubspec.yaml": ".metadata, .packages, all_lint_rules.yaml, analysis_options.yaml, build.yaml, pubspec.lock, pubspec_overrides.yaml", 303 | "pyproject.toml": ".pdm.toml, pdm.lock, pyproject.toml", 304 | "quasar.conf.js": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, quasar.extensions.json, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 305 | "readme*": "authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying, credits, governance.md, history.md, license*, maintainers, readme*, security.md, sponsors*", 306 | "remix.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, remix.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 307 | "rush.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*", 308 | "shims.d.ts": "*.d.ts", 309 | "svelte.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, houdini.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, mdsvex.config.js, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vite.config.*, vitest.config.*, webpack.config.*, windi.config.*", 310 | "vite.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 311 | "vue.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*" 312 | }, 313 | 314 | } 315 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### **注意本库只能作为学习用途, 造成的任何问题与本库开发者无关, 如侵犯到你的权益,请联系删除。** 2 | 3 | ### **注意本库只能作为学习用途, 造成的任何问题与本库开发者无关, 如侵犯到你的权益,请联系删除。** 4 | 5 | ### **注意本库只能作为学习用途, 造成的任何问题与本库开发者无关, 如侵犯到你的权益,请联系删除。** 6 | 7 | --- 8 | 9 | # 目录 10 | [1. 支持版本列表](#%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8B%E5%BD%93%E5%89%8D%E8%BF%90%E8%A1%8C%E7%89%88%E6%9C%AC) 11 | 12 | [2. 如何查看当前运行版本?](#%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8B%E5%BD%93%E5%89%8D%E8%BF%90%E8%A1%8C%E7%89%88%E6%9C%AC) 13 | - [windows](#windows) 14 | - [mac](#mac) 15 | 16 | [3. 食用方法](#%E9%A3%9F%E7%94%A8%E6%96%B9%E6%B3%95) 17 | 18 | - [开启小程序F12](#%E9%A3%9F%E7%94%A8%E6%96%B9%E6%B3%95) 19 | 20 | - [开启微信内置浏览器F12](#%E5%BC%80%E5%90%AF%E5%BE%AE%E4%BF%A1%E5%86%85%E7%BD%AE%E6%B5%8F%E8%A7%88%E5%99%A8F12) 21 | 22 | [4. 常见问题](#%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98) 23 | 24 | 25 | --- 26 | 27 | 28 | 29 | ## 支持版本列表 30 | 31 | > 感谢志远大佬的WeChatOpenDevTool开源 代码只是把node改用python3重写,简单实现了一些自动化问题,重要代码都是原作者的。 32 | 33 | | Windows 微信版本 | 小程序版本 | 是否为最新版 | 34 | | ---------------- | ---------- | ------------ | 35 | | | 11275_x64 | ✅ | 36 | | | 11253_x64 | ✅ | 37 | | | 11205_x64 | ✅ | 38 | | | 11159_x64 | ✅ | 39 | | 3.9.10.19_x64 | 9129_x64 | ✅ | 40 | | 3.9.10.19_x64 | 9115_x64 | ✅ | 41 | | 3.9.10.19_x64 | 8555_x64 | ❌ | 42 | | 3.9.10.19_x64 | 9105_x64 | ❌ | 43 | | 3.9.9.43_x64 | 8555_x64 | ❌ | 44 | | 3.9.9.43_x64 | 9079_x64 | ❌ | 45 | | 3.9.8.25_x64 | 8531_x64 | ❌ | 46 | | 3.9.8.25_x64 | 8529_x64 | ❌ | 47 | | 3.9.8.25_x64 | 8519_x64 | ❌ | 48 | | 3.9.8.25_x64 | 8501_x64 | ❌ | 49 | | 3.9.8.25_x64 | 8461_x64 | ❌ | 50 | | 3.9.8.25_x64 | 8447_x64 | ❌ | 51 | 52 | --- 53 | 54 | 55 | | Mac x64微信版本 | 是否为最新版 | x 56 | | ---------------- | ------------ | ------------ 57 | | MacWechat/3.8.8(0x13080811) | ✅ | 源码运行 58 | | MacWechat/3.8.8(0x13080812) | ✅ | 源码运行 59 | 60 | 61 | ## 如何查看当前运行版本? 62 | ### windows 63 | 64 | ![image](./docs/images/version0.jpg) 65 | 66 | ![image](./docs/images/version1.jpg) 67 | ![image](./docs/images/version2.jpg) 68 | 69 | ### mac 70 | ```bash 71 | ps aux | grep 'WeChatAppEx' | grep -v 'grep' | grep "wmpf-mojo-handle" 72 | ``` 73 | 74 | 75 | ## 食用方法 76 | 77 | ### 开启小程序F12 78 | 79 | > ~~只支持windows版本微信~~,运行前先启动微信运行前先启动微信(建议小号,别被封了。。。) 80 | 81 | 1. 安装python3版本 82 | 2. 下载WeChatOpenDevTools-Python或直接下载编译好的exe 83 | [WeChatOpenDevTools_64.exe](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/releases/) 84 | 85 | 安装依赖 86 | 87 | ``` 88 | pip3 install -r requirements.txt 89 | ``` 90 | 91 | 运行✅ 92 | 93 | ``` 94 | python main.py -x 95 | ``` 96 | 97 | ![image](./docs/images/run.jpg) 98 | ![image](./docs/images/MG38.jpg) 99 | 100 | --- 101 | 102 | ### 开启微信内置浏览器F12 103 | 104 | ```python 105 | python main.py -c 106 | ``` 107 | 108 | ![1709657739316](./docs/images/demo1.png) 109 | 110 | ![1709657739316](./docs/images/demo2.png) 111 | 112 | ![image](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/assets/132129852/04053f33-3e88-437b-a5c6-48683c984641) 113 | 114 | --- 115 | 116 | ### 常见问题 117 | 118 | * 无法修改中文 119 | 120 | - yes 121 | * 提示找不到版本或微信未运行❌ 122 | 123 | - 1. 请先看支持的微信版本和小程序版本 124 | - 如果还有问题看:[微信版本和小程序版本都是符合要求的,但是仍然显示“未找到匹配版本的微信进程或微信未运行”](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/issues/38) 125 | 2. **如果微信版本相同小程序版本不同,就删除小程序版本目录并重启微信,直到刷出支持的小程序版本目录** 126 | 3. 最后回到上级目录,设置文件夹权限为只读,这样就能一直保持小程序版本一致 127 | [image](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/assets/132129852/c2b793c3-6d81-424e-a167-3b1e584cef6f) 128 | * 怎么回退版本? 129 | 130 | - https://weixin.qq.com/cgi-bin/readtemplate?lang=zh_CN&t=weixin_faq_list&head=true 131 | - https://github.com/tom-snow/wechat-windows-versions/releases 132 | 133 | 134 | * mac版本闪退 135 | - ~~[macOS版本](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/releases/)不能和windows版本一样随时hook小程序修改F12,只能先加载小程序后再hook(必须是有小程序缓存了,不然会闪退)~~ 136 | - 可以先启动多个需要调试的小程序后再运行软件然后再刷新小程序 137 | * mac版本提示 [ Error: Unable to access process with pid xxx from the current user account](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/issues/49) 138 | ## Star History 139 | 140 | [![Star History Chart](https://api.star-history.com/svg?repos=javeleyqaq/WeChatOpenDevTools-Python&type=Date)](https://star-history.com/#javeleyqaq/WeChatOpenDevTools-Python&Date) 141 | 142 | -------------------------------------------------------------------------------- /WechatOpenDevTools/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | -------------------------------------------------------------------------------- /configs/address_11159_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x2888A20", 3 | "MenuItemDevToolsString":"0x69461F8", 4 | "SwitchVersion":"0x26BA076", 5 | "Version":11159 6 | } 7 | -------------------------------------------------------------------------------- /configs/address_11205_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x28A070C", 3 | "MenuItemDevToolsString": "0x28AE121", 4 | "SwitchVersion": "0x26D1CE8", 5 | "Version": 11205 6 | } 7 | -------------------------------------------------------------------------------- /configs/address_11253_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x28A246B", 3 | "MenuItemDevToolsString": "0x2AC446F", 4 | "SwitchVersion": "0x26D3A38", 5 | "Version": 11253 6 | } -------------------------------------------------------------------------------- /configs/address_11275_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x28A255C", 3 | "MenuItemDevToolsString": "0x2AC456F", 4 | "SwitchVersion": "0x26D3B38", 5 | "Version": 11275 6 | } 7 | -------------------------------------------------------------------------------- /configs/address_13080811_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "WechatAppHtml": "0x2C86E2B", 3 | "WechatWebHtml": "0x8023935", 4 | "LaunchAppletBegin":"0x2E1D9A8", 5 | "MenuItemDevToolsString":"0x2E295AD", 6 | "Version":13080811 7 | } 8 | -------------------------------------------------------------------------------- /configs/address_13080812_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "WechatAppHtml": "0x2C86E2B", 3 | "WechatWebHtml": "0x8023935", 4 | "LaunchAppletBegin":"0x2E1D9A8", 5 | "MenuItemDevToolsString":"0x2E295AD", 6 | "Version":13080812 7 | } 8 | -------------------------------------------------------------------------------- /configs/address_8447_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x1B3FF48", 3 | "WechatAppHtml":"0x2EC9FBD", 4 | "WechatWebHtml":"0x7C0D6BD", 5 | "WechatAppExLog":"0x2F20022" 6 | } -------------------------------------------------------------------------------- /configs/address_8461_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x1B4013F", 3 | "WechatAppHtml":"0x2ECA1CD", 4 | "WechatWebHtml":"0x7C0D7AD", 5 | "WechatAppExLog":"0x2F20022" 6 | } -------------------------------------------------------------------------------- /configs/address_8501_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x2A4C18D", 3 | "WechatAppHtml":"0x28E1D66", 4 | "WechatWebHtml":"0x7A23D33" 5 | } -------------------------------------------------------------------------------- /configs/address_8519_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x02A4C21D", 3 | "WechatAppHtml":"0x28E1D66", 4 | "WechatWebHtml":"0x7A23D33", 5 | "WechatAppExLog":"0x2F20022" 6 | } -------------------------------------------------------------------------------- /configs/address_8529_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x02A4D29D", 3 | "WechatAppHtml":"0x28E1D66", 4 | "WechatWebHtml":"0x7A2D533", 5 | "WechatAppExLog":"0x2F20022" 6 | } -------------------------------------------------------------------------------- /configs/address_8531_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x02A4D3ED", 3 | "WechatAppHtml":"0x28E1DF6", 4 | "WechatWebHtml":"0x7A2E563", 5 | "WechatAppExLog":"0x2F20022" 6 | } -------------------------------------------------------------------------------- /configs/address_8555_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x02A4D52D", 3 | "WechatAppHtml":"0x28E1E36", 4 | "WechatWebHtml":"0x7A2E563", 5 | "WechatAppExLog":"0x2F20022", 6 | "MenuItemDevToolsString":"0x2BC92AE", 7 | "Version":8555 8 | 9 | } 10 | -------------------------------------------------------------------------------- /configs/address_9079_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x2649CA0", 3 | "WechatAppHtml":"0x24BF4EB", 4 | "WechatWebHtml":"0x24BF4E4", 5 | "WechatAppExLog":"0x2F20022", 6 | "WechatVersionSwitch": "0x24BF4F2", 7 | "MenuItemDevToolsString":"0x17C062" 8 | } 9 | -------------------------------------------------------------------------------- /configs/address_9105_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x2649CA0", 3 | "WechatAppHtml":"0x24BF4EB", 4 | "WechatWebHtml": "0x24BF4E4", 5 | "SwitchVersion":"0x24BF4F4", 6 | "MenuItemDevToolsString":"0x28776E5", 7 | "Version":9105 8 | } 9 | -------------------------------------------------------------------------------- /configs/address_9115_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x2649CA0", 3 | "MenuItemDevToolsString":"0x2877F65", 4 | "jscode":"0x26B154D", 5 | "SwitchVersion":"0x24BF4F4", 6 | "Version":9115 7 | } 8 | -------------------------------------------------------------------------------- /configs/address_9129_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x264A9E2", 3 | "MenuItemDevToolsString":"0x265A33A", 4 | "SwitchVersion":"0x24C0074", 5 | "Version":9129 6 | } 7 | -------------------------------------------------------------------------------- /configs/address_9193_x64.json: -------------------------------------------------------------------------------- 1 | { 2 | "LaunchAppletBegin": "0x26F1B50", 3 | "MenuItemDevToolsString":"0x290816C", 4 | "SwitchVersion":"0x2554A54", 5 | "Version":9193 6 | } 7 | -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | ::: wechatminidevhook 2 | -------------------------------------------------------------------------------- /docs/authors.md: -------------------------------------------------------------------------------- 1 | {% 2 | include-markdown "../AUTHORS.md" 3 | %} 4 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | {% 2 | include-markdown "../CONTRIBUTING.md" 3 | %} 4 | -------------------------------------------------------------------------------- /docs/history.md: -------------------------------------------------------------------------------- 1 | {% 2 | include-markdown "../HISTORY.md" 3 | %} 4 | -------------------------------------------------------------------------------- /docs/images/1: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/images/MG38.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaveleyQAQ/WeChatOpenDevTools-Python/9e6ef5db393a07c2efb4bfebbe46bbbe0d6ad98c/docs/images/MG38.jpg -------------------------------------------------------------------------------- /docs/images/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaveleyQAQ/WeChatOpenDevTools-Python/9e6ef5db393a07c2efb4bfebbe46bbbe0d6ad98c/docs/images/demo1.png -------------------------------------------------------------------------------- /docs/images/demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaveleyQAQ/WeChatOpenDevTools-Python/9e6ef5db393a07c2efb4bfebbe46bbbe0d6ad98c/docs/images/demo2.png -------------------------------------------------------------------------------- /docs/images/run.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaveleyQAQ/WeChatOpenDevTools-Python/9e6ef5db393a07c2efb4bfebbe46bbbe0d6ad98c/docs/images/run.jpg -------------------------------------------------------------------------------- /docs/images/version0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaveleyQAQ/WeChatOpenDevTools-Python/9e6ef5db393a07c2efb4bfebbe46bbbe0d6ad98c/docs/images/version0.jpg -------------------------------------------------------------------------------- /docs/images/version1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaveleyQAQ/WeChatOpenDevTools-Python/9e6ef5db393a07c2efb4bfebbe46bbbe0d6ad98c/docs/images/version1.jpg -------------------------------------------------------------------------------- /docs/images/version2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaveleyQAQ/WeChatOpenDevTools-Python/9e6ef5db393a07c2efb4bfebbe46bbbe0d6ad98c/docs/images/version2.jpg -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | {% 2 | include-markdown "../README.md" 3 | %} 4 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Stable release 4 | 5 | To install WeChatMiniDevHook, run this command in your 6 | terminal: 7 | 8 | ``` console 9 | pip install wechatminidevhook 10 | ``` 11 | 12 | This is the preferred method to install WeChatMiniDevHook, as it will always install the most recent stable release. 13 | 14 | If you don't have [pip][] installed, this [Python installation guide][] 15 | can guide you through the process. 16 | 17 | ## From source 18 | 19 | The source for WeChatMiniDevHook can be downloaded from 20 | the [Github repo][]. 21 | 22 | You can either clone the public repository: 23 | 24 | ``` console 25 | git clone git://github.com/javeley/wechatminidevhook 26 | ``` 27 | 28 | Or download the [tarball][]: 29 | 30 | ``` console 31 | curl -OJL https://github.com/javeley/wechatminidevhook/tarball/master 32 | ``` 33 | 34 | Once you have a copy of the source, you can install it with: 35 | 36 | ``` console 37 | pip install . 38 | ``` 39 | 40 | [pip]: https://pip.pypa.io 41 | [Python installation guide]: http://docs.python-guide.org/en/latest/starting/installation/ 42 | [Github repo]: https://github.com/%7B%7B%20cookiecutter.github_username%20%7D%7D/%7B%7B%20cookiecutter.project_slug%20%7D%7D 43 | [tarball]: https://github.com/%7B%7B%20cookiecutter.github_username%20%7D%7D/%7B%7B%20cookiecutter.project_slug%20%7D%7D/tarball/master 44 | -------------------------------------------------------------------------------- /docs/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | To use WeChatMiniDevHook in a project 4 | 5 | ``` 6 | import wechatminidevhook 7 | ``` 8 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | 2 | from argparse import RawTextHelpFormatter 3 | from utils.commons import Commons 4 | from utils.banner import generate_banner 5 | from utils.colors import Color 6 | import argparse 7 | 8 | 9 | 10 | def print_colored_message(message, color): 11 | print(color + message + Color.END) 12 | 13 | def main(): 14 | HELPALL = """ 15 | 请选择要执行的方法: 16 | [+] python main.py -h 查看帮助 17 | [+] python main.py -x 开启小程序F12 18 | [+] python main.py -c 开启内置浏览器F12 19 | [+] python main.py -all 开启内置浏览器F12与小程序F12 20 | 21 | """ 22 | parser = argparse.ArgumentParser(description=HELPALL, formatter_class=RawTextHelpFormatter) 23 | parser.add_argument('-x', action='store_true', help='开启小程序F12') 24 | parser.add_argument('-c', action='store_true', help='开启内置浏览器F12') 25 | parser.add_argument('-all', action='store_true', help='开启内置浏览器F12与小程序F12') 26 | args = parser.parse_args() 27 | 28 | if args.x: 29 | commons.load_wechatEx_configs() 30 | elif args.c: 31 | commons.load_wechatEXE_configs() 32 | elif args.all: 33 | commons.load_wechatEXE_and_wechatEx() 34 | else: 35 | 36 | print_colored_message(HELPALL, Color.RED) 37 | 38 | if __name__ == "__main__": 39 | generate_banner() 40 | commons = Commons() 41 | main() 42 | 43 | 44 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | frida==16.1.11 2 | psutil==5.9.7 3 | pyfiglet==1.0.2 4 | -------------------------------------------------------------------------------- /scripts/WechatWin.dll/hook.js: -------------------------------------------------------------------------------- 1 | function readStdString(s) { 2 | var flag = s.add(23).readU8() 3 | if (flag == 0x80) { 4 | // 从堆中读取 5 | var size = s.add(8).readUInt() 6 | return s.readPointer().readUtf8String(size) 7 | } else { 8 | // 从栈中读取 9 | return s.readUtf8String(flag) 10 | } 11 | } 12 | function writeStdString(s, content) { 13 | var flag = s.add(23).readU8() 14 | if (flag == 0x80) { 15 | // 从堆中写入 16 | var orisize = s.add(8).readUInt() 17 | if (content.length > orisize) { 18 | throw "must below orisize!" 19 | } 20 | s.readPointer().writeUtf8String(content) 21 | s.add(8).writeUInt(content.length) 22 | } else { 23 | // 从栈中写入 24 | if (content.length > 22) { 25 | throw "max 23 for stack str" 26 | } 27 | s.writeUtf8String(content) 28 | s.add(23).writeU8(content.length) 29 | } 30 | } 31 | 32 | 33 | 34 | // 创建一个函数,用于拦截CreateProcessW函数 35 | var cpsPtr = Module.findExportByName("kernel32.dll", "CreateProcessW"); 36 | var cps = new NativeFunction(cpsPtr,'bool', ['pointer', 'pointer', 'pointer', 'pointer', 'bool', 'uint32', 'pointer', 'pointer', 'pointer', 'pointer']); 37 | 38 | // 拦截CreateProcessW函数,在函数调用前和调用后分别执行onEnter和onLeave函数 39 | Interceptor.attach(cpsPtr, { 40 | onEnter: function (args) { 41 | // 获取CreateProcessW函数的参数 42 | this.pi = args[9]; 43 | this.exepath = args[0]; 44 | this.cmdline = args[1]; 45 | let aaa = this.cmdline.readUtf16String(); 46 | // 替换参数中的--log-level=2为--log-level=0 --xweb-enable-inspect=1 47 | aaa = aaa.replaceAll("--log-level=2", "--log-level=0 --xweb-enable-inspect=1"); 48 | this.cmdline.writeUtf16String(aaa); 49 | }, 50 | onLeave: function (retval) { 51 | // send("[+] 可执行路径:"+this.exepath.readUtf16String()) 52 | 53 | // 打印可执行路径 54 | // send("[+] 可执行路径:"+this.exepath.readUtf16String()) 55 | 56 | // // 打印命令行参数 57 | send("[+] 命令行参数:"+this.cmdline.readUtf16String()); 58 | //--xweb-enable-inspect 59 | // 打印进程id 60 | // send("[+] 进程id: "+this.cmdline.readUtf16String()); 61 | } 62 | } 63 | ); -------------------------------------------------------------------------------- /scripts/hook.js: -------------------------------------------------------------------------------- 1 | ; 2 | //获取WeChatAppEx.exe的基址 3 | var module = Process.findModuleByName("WeChatAppEx.exe") || Process.findModuleByName('WeChatAppEx Framework') 4 | var base = module.base; 5 | // console.log("模块名称:",module.name); 6 | // console.log("模块地址:",module.base); 7 | // console.log("大小:",module.size); 8 | 9 | 10 | Object.keys(address).forEach(key => { 11 | key != "Version" ? address[key] = base.add(address[key]) : false 12 | }); 13 | 14 | send("[+] WeChatAppEx 注入成功!"); 15 | send("[+] 当前小程序版本: " + address.Version); 16 | send("[+] 等待小程序加载..."); 17 | 18 | function readStdString(s) { 19 | var flag = s.add(23).readU8() 20 | if (flag == 0x80) { 21 | // 从堆中读取 22 | var size = s.add(8).readUInt() 23 | return s.readPointer().readUtf8String(size) 24 | } else { 25 | // 从栈中读取 26 | return s.readUtf8String(flag) 27 | } 28 | } 29 | function writeStdString(s, content) { 30 | var flag = s.add(23).readU8() 31 | if (flag == 0x80) { 32 | // 从堆中写入 33 | var orisize = s.add(8).readUInt() 34 | if (content.length > orisize) { 35 | throw "must below orisize!" 36 | } 37 | s.readPointer().writeUtf8String(content) 38 | s.add(8).writeUInt(content.length) 39 | } else { 40 | // 从栈中写入 41 | if (content.length > 22) { 42 | throw "max 23 for stack str" 43 | } 44 | s.writeUtf8String(content) 45 | s.add(23).writeU8(content.length) 46 | } 47 | } 48 | function sendMessage(msg) { 49 | msg === null || undefined ? send(msg) : send("[+] 已还原完整F12") 50 | // send("[+] 已还原完整F12") 51 | } 52 | 53 | 54 | function replaceParams() { 55 | Interceptor.attach(address.LaunchAppletBegin, { 56 | onEnter(args) { 57 | send("[+] HOOK到小程序加载! " + readStdString(args[1])) 58 | for (var i = 0; i < 0x1000; i += 8) { 59 | try { 60 | var s = readStdString(args[2].add(i)) 61 | var s1 = s.replaceAll('"enable_vconsole":false', '"enable_vconsole": true') 62 | // .replaceAll("md5", "md6") 63 | // .replaceAll('"frameset":false', '"frameset": true') 64 | //"frameset":false 65 | if (s !== s1) { 66 | writeStdString(args[2].add(i), s1) 67 | } 68 | } catch (a) { 69 | } 70 | } 71 | } 72 | }) 73 | 74 | } 75 | 76 | 77 | 78 | // 过新版8555检测 79 | if (address.MenuItemDevToolsString) { 80 | var menuItemDevToolsStringCr = new Uint8Array(address.MenuItemDevToolsString.readByteArray(7)); 81 | var intptr_ = (menuItemDevToolsStringCr[3] & 0xFF) | ((menuItemDevToolsStringCr[4] & 0xFF) << 8) | ((menuItemDevToolsStringCr[5] & 0xFF) << 16) | ((menuItemDevToolsStringCr[6] & 0xFF) << 24); 82 | var menuItemDevToolsStringPtrData = address.MenuItemDevToolsString.add(intptr_ + 7); 83 | Memory.protect(menuItemDevToolsStringPtrData, 8, 'rw-') 84 | menuItemDevToolsStringPtrData.writeUtf8String("DevTools"); 85 | replaceParams() 86 | setupInterceptor() 87 | } 88 | 89 | 90 | function setupInterceptor() { 91 | 92 | /** 93 | * 94 | */ 95 | 96 | switch (address.Version) { 97 | 98 | case 8555: 99 | Interceptor.attach(address.WechatAppHtml, { 100 | onEnter(args) { 101 | this.context.rdx = address.WechatWebHtml; 102 | sendMessage() 103 | } 104 | }); 105 | 106 | break; 107 | 108 | 109 | case 9105: 110 | Interceptor.attach(address.SwitchVersion, { 111 | onEnter(args) { 112 | this.context.r8 = this.context.rax 113 | sendMessage() 114 | } 115 | }) 116 | break; 117 | 118 | case 9079: 119 | Interceptor.attach(address.SwitchVersion, { 120 | onEnter(args) { 121 | this.context.r8 = this.context.rax 122 | sendMessage() 123 | } 124 | }) 125 | break; 126 | 127 | case 9115: 128 | Interceptor.attach(address.SwitchVersion, { 129 | onEnter(args) { 130 | this.context.r8 = this.context.rax 131 | sendMessage() 132 | } 133 | }) 134 | break; 135 | 136 | case 9129: 137 | Interceptor.attach(address.SwitchVersion, { 138 | onEnter(args) { 139 | this.context.r8 = this.context.rax 140 | sendMessage() 141 | } 142 | }) 143 | break; 144 | case 11159: 145 | Interceptor.attach(address.SwitchVersion, { 146 | onEnter(args) { 147 | this.context.r8 = this.context.rax 148 | sendMessage() 149 | } 150 | }) 151 | break; 152 | 153 | case 13080811: 154 | Interceptor.attach(address.WechatAppHtml, { 155 | onEnter(args) { 156 | this.context.rsi = address.WechatWebHtml 157 | sendMessage() 158 | } 159 | }) 160 | break; 161 | 162 | case 13080812: 163 | Interceptor.attach(address.WechatAppHtml, { 164 | onEnter(args) { 165 | this.context.rsi = address.WechatWebHtml 166 | sendMessage() 167 | } 168 | }) 169 | break; 170 | 171 | case 9193: 172 | Interceptor.attach(address.SwitchVersion, { 173 | onEnter(args) { 174 | this.context.r8 = this.context.rax 175 | sendMessage() 176 | } 177 | }) 178 | break; 179 | case 11205: 180 | Interceptor.attach(address.SwitchVersion, { 181 | onEnter(args) { 182 | this.context.r8 = this.context.rax 183 | sendMessage() 184 | } 185 | }) 186 | break; 187 | case 11275: 188 | Interceptor.attach(address.SwitchVersion, { 189 | onEnter(args) { 190 | this.context.r8 = this.context.rax 191 | sendMessage() 192 | } 193 | }) 194 | break; 195 | case 11253: 196 | Interceptor.attach(address.SwitchVersion, { 197 | onEnter(args) { 198 | this.context.r8 = this.context.rax 199 | sendMessage() 200 | } 201 | }) 202 | break; 203 | default: 204 | console.log(address.Version); 205 | Interceptor.attach(address.WechatAppHtml, { 206 | onEnter(args) { 207 | this.context.rdx = address.WechatWebHtml; 208 | sendMessage() 209 | } 210 | }); 211 | break; 212 | 213 | 214 | // case "null": 215 | // Interceptor.attach(address.WechatAppHtml, { 216 | // onEnter(args) { 217 | // const webhtml= "68 74 74 70 73 3A 2F 2F 61 70 70 6C 65 74 2D 64 65 62 75 67 2E 63 6F 6D 2F 64 65 76 74 6F 6F 6C 73 2F 77 65 63 68 61 74 5F 77 65 62 2E 68 74 6D 6C"; 218 | // var data; 219 | // Process.enumerateModules({ 220 | // onMatch: function(module){ 221 | // var ranges = module.enumerateRanges('r--'); 222 | // for (var i = 0; i < ranges.length; i++) { 223 | // var range = ranges[i]; 224 | // var scanResults = Memory.scanSync(range.base, range.size, webhtml); 225 | // if (scanResults.length > 0){ 226 | // data = scanResults[0].address 227 | // // console.log('Memory.scanSync() result for range ' + range.base + '-' + range.size + ':\n' + JSON.stringify(scanResults)); 228 | // } 229 | // } 230 | 231 | // }, 232 | // onComplete: function(){ 233 | 234 | // }}); 235 | 236 | // this.context.rdx = data 237 | // sendMessage() 238 | 239 | // } 240 | // }) 241 | 242 | // break; 243 | 244 | 245 | 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | -------------------------------------------------------------------------------- /utils/banner.py: -------------------------------------------------------------------------------- 1 | import pyfiglet 2 | import random 3 | from utils.colors import Color 4 | 5 | def colored_print(text, color_code): 6 | print(f"{color_code}{text}"+Color.END) 7 | 8 | def generate_banner(): 9 | name=""" 10 | 11 | 12 | 公众号: 一位不愿透露姓名的热心网友 13 | Github:https://github.com/JaveleyQAQ 14 | """ 15 | selected_fonts = ['standard', 'big', 'slant', 'small', 'shadow'] 16 | selected_font = random.choice(selected_fonts) 17 | font = pyfiglet.Figlet(font=selected_font) 18 | ascii_banner = font.renderText("WX DevTools") 19 | color_codes = [Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.CYAN, Color.PURPLE] 20 | selected_color = random.choice(color_codes) 21 | ascii_banner_with_author = ascii_banner.rstrip('\r\n') + f'\n\n\t'+name+f'\n' 22 | colored_print(ascii_banner_with_author, selected_color) -------------------------------------------------------------------------------- /utils/colors.py: -------------------------------------------------------------------------------- 1 | class Color: 2 | END = '\033[0m' 3 | RED = '\033[91m' 4 | GREEN = '\033[92m' 5 | YELLOW = '\033[93m' 6 | BLUE = '\033[94m' 7 | CYAN = '\033[96m' 8 | PURPLE = '\033[95m' 9 | -------------------------------------------------------------------------------- /utils/commons.py: -------------------------------------------------------------------------------- 1 | # commons.py 2 | from utils.colors import Color 3 | from utils.wechatutils import WechatUtils 4 | import frida 5 | import sys 6 | import time 7 | import platform 8 | 9 | class Commons: 10 | def __init__(self): 11 | self.wechatutils_instance = WechatUtils() 12 | self.device = frida.get_local_device() 13 | self.process = self.device.enumerate_processes() 14 | self.version_list = [] 15 | self.configs_path = "" 16 | self.active_sessions = [] 17 | 18 | def onMessage(self, message, data): 19 | if message['type'] == 'send': 20 | print(Color.GREEN + message['payload'], Color.END) 21 | elif message['type'] == 'error': 22 | print(Color.RED + message['stack'], Color.END) 23 | 24 | def inject_wechatEx(self, pid, code): 25 | try: 26 | session = frida.attach(pid) 27 | script = session.create_script(code) 28 | script.on("message", self.onMessage) 29 | script.load() 30 | print(Color.GREEN + f"[+] 成功注入微信PID: {pid}", Color.END) 31 | return session 32 | except Exception as e: 33 | print(Color.RED + f"[-] 注入微信失败PID {pid}: {e}", Color.END) 34 | return None 35 | 36 | def inject_wechatDLL(self, path, code): 37 | pid = self.device.spawn(path) 38 | session = frida.attach(pid) 39 | script = session.create_script(code) 40 | script.on("message", self.onMessage) 41 | script.load() 42 | self.device.resume(pid) 43 | time.sleep(10) 44 | session.detach() 45 | 46 | def load_wechatEx_configs(self): 47 | path = self.wechatutils_instance.get_configs_path() 48 | if get_cpu_architecture() == "MacOS x64": 49 | wechat_instances = self.wechatutils_instance.get_wechat_pids_and_versions_mac() 50 | else: 51 | wechat_instances = self.wechatutils_instance.get_wechat_pids_and_versions() 52 | 53 | if wechat_instances: 54 | for pid, version in wechat_instances: 55 | try: 56 | wechatEx_hookcode = open(path + "../scripts/hook.js", "r", encoding="utf-8").read() 57 | wechatEx_addresses = open(path + f"../configs/address_{version}_x64.json").read() 58 | wechatEx_hookcode = "var address=" + wechatEx_addresses + wechatEx_hookcode 59 | session = self.inject_wechatEx(pid, wechatEx_hookcode) 60 | if session: 61 | self.active_sessions.append(session) 62 | print(Color.GREEN +f"[+] 成功注入{version}小程序版本,PID: {pid}", Color.END) 63 | except Exception as e: 64 | print(Color.RED + f"[-] 注入{version}小程序版本失败!", Color.END) 65 | else: 66 | self.wechatutils_instance.print_process_not_found_message() 67 | 68 | # 管理会话 69 | while self.active_sessions: 70 | self.manage_sessions() 71 | time.sleep(5) # 每5秒检查一次 72 | 73 | def load_wechatEXE_configs(self): 74 | wechat_instances = self.wechatutils_instance.get_wechat_pids_and_versions() 75 | if wechat_instances: 76 | print(Color.RED + f"[-] 请退出所有微信实例后再执行该命令 " + Color.END) 77 | return 0 78 | 79 | wechatEXEpath = self.wechatutils_instance.find_installation_path("微信") 80 | path = self.wechatutils_instance.get_configs_path() 81 | wechatEXE_hookcode = open(path + "..\\scripts\\WechatWin.dll\\hook.js", "r", encoding="utf-8").read() 82 | self.inject_wechatDLL(wechatEXEpath, wechatEXE_hookcode) 83 | 84 | def load_wechatEXE_and_wechatEx(self): 85 | wechat_instances = self.wechatutils_instance.get_wechat_pids_and_versions() 86 | if wechat_instances: 87 | print(Color.RED + f"[-] 请关闭所有微信实例后再执行该命令 " + Color.END) 88 | return 0 89 | self.load_wechatEXE_configs() 90 | self.load_wechatEx_configs() 91 | 92 | def manage_sessions(self): 93 | for session in self.active_sessions[:]: # 使用切片创建副本以便在迭代时修改 94 | if session.is_detached: 95 | print(f"Session {session} detached, removing from active sessions.") 96 | self.active_sessions.remove(session) 97 | 98 | def get_cpu_architecture(): 99 | try: 100 | cpu_arch = platform.platform().lower() 101 | if "64bit" in cpu_arch and "macos" in cpu_arch: 102 | return "MacOS x64" 103 | return "Windows" # 默认返回Windows 104 | except Exception as e: 105 | print(Color.RED, f"[-] Error detecting CPU architecture: {e} ", Color.END) 106 | return "Windows" 107 | 108 | # 主函数示例 109 | if __name__ == "__main__": 110 | commons = Commons() 111 | commons.load_wechatEx_configs() 112 | -------------------------------------------------------------------------------- /utils/wechatutils.py: -------------------------------------------------------------------------------- 1 | import os,re,sys 2 | import psutil,subprocess 3 | from utils.colors import Color 4 | 5 | class WechatUtils: 6 | def __init__(self): 7 | self.configs_path = self.get_configs_path() 8 | self.version_list = self.get_version_list() 9 | 10 | # self.pid , self.version = self.get_wechat_pid_and_version() 11 | # if self.pid is None and self.version is None: 12 | # self.print_process_not_found_message() 13 | 14 | def get_configs_path(self): 15 | current_path = os.path.abspath(__file__) 16 | relative_path = '../configs/' 17 | return os.path.join(os.path.dirname(current_path), relative_path) 18 | 19 | def get_version_list(self): 20 | configs_path = self.configs_path 21 | version_list = os.listdir(configs_path) 22 | versions_list = [int(file.split('_')[1]) for file in version_list if file.startswith('address_')] 23 | return versions_list 24 | 25 | def is_wechatEx_process(self, cmdline): 26 | process_name = "WeChatAppEx" 27 | return cmdline and process_name in cmdline[0] and "--type=" not in ' '.join(cmdline) 28 | def get_wechat_pids_and_versions(self): 29 | processes = (proc.info for proc in psutil.process_iter(['pid', 'cmdline'])) 30 | wechatEx_processes = (p for p in processes if self.is_wechatEx_process(p['cmdline'])) 31 | wechat_instances = [] 32 | for process in wechatEx_processes: 33 | pid = process['pid'] 34 | version = self.extract_version_number(process['cmdline']) 35 | if version in self.version_list: 36 | wechat_instances.append((pid, version)) 37 | return wechat_instances 38 | 39 | def get_wechat_pid_and_version(self): 40 | wechat_instances = self.get_wechat_pids_and_versions() 41 | return wechat_instances[0] if wechat_instances else (None, None) 42 | 43 | def get_wechat_pids_and_versions_mac(self): 44 | try: 45 | pid_command = "ps aux | grep 'WeChatAppEx' | grep -v 'grep' | grep ' --client_version' | grep '-user-agent=' | awk '{print $2}'" 46 | version_command = "ps aux | grep 'WeChatAppEx' | grep -v 'grep' | grep ' --client_version' | grep '-user-agent=' | grep -oE 'MacWechat/([0-9]+\.)+[0-9]+\(0x\d+\)' | grep -oE '(0x\d+)' | sed 's/0x//g'" 47 | pids = subprocess.run(pid_command, shell=True, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.split() 48 | versions = subprocess.run(version_command, shell=True, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.split() 49 | return list(zip(map(int, pids), versions)) 50 | except subprocess.CalledProcessError as e: 51 | print(Color.RED + f"Error getting MacOS WeChat instances: {e.stderr}" + Color.END) 52 | return [] 53 | 54 | def print_process_not_found_message(self): 55 | print(Color.RED + "[-] 未找到匹配版本的微信进程或微信未运行" + Color.END) 56 | 57 | def find_installation_path(self, program_name): 58 | try: 59 | import winreg 60 | reg_path = r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" 61 | reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path) 62 | 63 | for i in range(1024): 64 | try: 65 | sub_key_name = winreg.EnumKey(reg_key, i) 66 | sub_key = winreg.OpenKey(reg_key, sub_key_name) 67 | display_name = winreg.QueryValueEx(sub_key, "DisplayName")[0] 68 | # 排除企业微信 和 适配英文区域安装的WeChat 69 | if program_name == display_name or display_name == 'WeChat': 70 | install_location = winreg.QueryValueEx(sub_key, "InstallLocation")[0]+"\\WeChat.exe" 71 | print(Color.GREEN + f"[+] 查找到{program_name}的安装路径是:{install_location}" + Color.END) 72 | print(Color.GREEN + f"[+] 正在尝试重启微信..."+ Color.END) 73 | return install_location 74 | except WindowsError: 75 | pass 76 | 77 | except Exception as e: 78 | print(Color.RED + f"[-] 查找安装路径时出错:{e}"+ Color.END) 79 | 80 | 81 | def extract_version_number(self, cmdline): 82 | str = ' '.join(cmdline) 83 | version_match = re.search(r'"version":(\d+)', str) 84 | return int(version_match.group(1)) if version_match else None 85 | 86 | def get_wechat_pid_and_version(self): 87 | processes = (proc.info for proc in psutil.process_iter(['pid', 'cmdline'])) 88 | wechatEx_processes = (p for p in processes if self.is_wechatEx_process(p['cmdline'])) 89 | for process in wechatEx_processes: 90 | pid = process['pid'] 91 | version = self.extract_version_number(process['cmdline']) 92 | if version in self.version_list: 93 | return pid, version 94 | 95 | return None, None 96 | 97 | def print_process_not_found_message(self): 98 | print(Color.RED + "[-] 未找到匹配版本的微信进程或微信未运行" + Color.END) 99 | 100 | def get_wechat_pid_and_version_mac(self): 101 | try: 102 | pid_command="ps aux | grep 'WeChatAppEx' | grep -v 'grep' | grep ' --client_version' | grep '-user-agent=' | awk '{print $2}' | tail -n 1" 103 | version_command = "ps aux | grep 'WeChatAppEx' | grep -v 'grep' | grep ' --client_version' | grep '-user-agent=' | grep -oE 'MacWechat/([0-9]+\.)+[0-9]+\(0x\d+\)' | grep -oE '(0x\d+)' | sed 's/0x//g' | head -n 1" 104 | pid = subprocess.run(pid_command, shell=True, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.replace("\n","") 105 | version = subprocess.run(version_command, shell=True, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.replace("\n","") 106 | return int(pid),version 107 | except subprocess.CalledProcessError as e: 108 | return e.stderr 109 | 110 | -------------------------------------------------------------------------------- /workflows/README.md: -------------------------------------------------------------------------------- 1 | # 感谢志远大佬的WeChatOpenDevTool开源 2 | 代码只是把node改用python3重写,简单实现了一些自动化问题,重要代码都是原作者的。 3 | 4 | ### **注意本库只能作为学习用途, 造成的任何问题与本库开发者无关, 如侵犯到你的权益,请联系删除。** 5 | ### **注意本库只能作为学习用途, 造成的任何问题与本库开发者无关, 如侵犯到你的权益,请联系删除。** 6 | ### **注意本库只能作为学习用途, 造成的任何问题与本库开发者无关, 如侵犯到你的权益,请联系删除。** 7 | --- 8 | 9 | ## 支持版本 10 | | Windows 微信版本 | 小程序版本 | 是否为最新版 | 11 | | ----------- | -------------- | ----- | 12 | | 3.9.9.43_x64| 8555_x64 | ✅ | 13 | | 3.9.8.25_x64| 8531_x64 | ❌ | 14 | | 3.9.8.25_x64| 8529_x64 | ❌ | 15 | | 3.9.8.25_x64| 8519_x64 | ❌ | 16 | | 3.9.8.25_x64| 8501_x64 | ❌ | 17 | | 3.9.8.25_x64| 8461_x64 | ❌ | 18 | | 3.9.8.25_x64| 8447_x64 | ❌ | 19 | 20 | 如何查看当前运行版本? 21 | 22 | ![image](./docs/images/version0.jpg) 23 | 24 | ![image](./docs/images/version1.jpg) 25 | ![image](./docs/images/version2.jpg) 26 | 27 | 28 | ## 目录 29 | [1. 开启小程序F12](#%E9%A3%9F%E7%94%A8%E6%96%B9%E6%B3%95) 30 | 31 | [2. 开启微信内置浏览器F12](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python#%E5%BC%80%E5%90%AF%E5%BE%AE%E4%BF%A1%E5%86%85%E7%BD%AE%E6%B5%8F%E8%A7%88%E5%99%A8F12) 32 | 33 | 34 | 35 | ## 食用方法 36 | 37 | 38 | ### 开启小程序F12 39 | > 只支持windows版本微信,运行前先启动微信运行前先启动微信(建议小号,别被封了。。。) 40 | 1. 安装python3版本 41 | 2. 下载WeChatOpenDevTools-Python或直接下载编译好的exe 42 | [WeChatOpenDevTools_64.exe](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/releases/) 43 | 44 | 安装依赖 45 | ``` 46 | pip3 install -r requirements.txt 47 | ``` 48 | 49 | 运行✅ 50 | ``` 51 | python main.py 52 | ``` 53 | 54 | 55 | 56 | ![image](./docs/images/run.jpg) 57 | ![image](./docs/images/MG38.jpg) 58 | 59 | ---- 60 | 61 | 62 | ### 开启微信内置浏览器F12 63 | 64 | 1. 关闭微信并找到微信安装目录 65 | 66 | ![image](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/assets/132129852/593ae1b7-274f-4b7b-a476-8d71fe26f621) 67 | 68 | 69 | 3. 把 [WeChatWin3.9.8.25_x64.zip](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/releases/download/0.1/WeChatWin3.9.8.25_x64.zip) 压缩包内容解压到对应的微信版本目录中,替换原文件(记得把原文件重命名备份一份) 70 | 71 | ![image](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/assets/132129852/08b68600-8323-4b63-a503-a9866533cacf) 72 | 73 | 5. 到网页调用 74 | ![image](https://github.com/JaveleyQAQ/WeChatOpenDevTools-Python/assets/132129852/04053f33-3e88-437b-a5c6-48683c984641) 75 | 76 | 77 | 78 | ----- 79 | 80 | ## Star History 81 | 82 | [![Star History Chart](https://api.star-history.com/svg?repos=javeleyqaq/WeChatOpenDevTools-Python&type=Date)](https://star-history.com/#javeleyqaq/WeChatOpenDevTools-Python&Date) 83 | 84 | 85 | -------------------------------------------------------------------------------- /workflows/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | -------------------------------------------------------------------------------- /workflows/dev.yml: -------------------------------------------------------------------------------- 1 | name: dev build CI 2 | 3 | # Controls when the action will run. 4 | on: 5 | # Triggers the workflow on push or pull request events 6 | push: 7 | branches: 8 | - '*' 9 | pull_request: 10 | branches: 11 | - '*' 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # contains 3 jobs: test, publish_dev_build and notification 16 | jobs: 17 | test: 18 | # The type of runner that the job will run on 19 | strategy: 20 | matrix: 21 | python-versions: ['3.8', '3.9', '3.10', '3.11'] 22 | # github action doesn't goes well with windows due to docker support 23 | # github action doesn't goes well with macos due to `no docker command` 24 | #os: [ubuntu-latest, windows-latest, macos-latest] 25 | os: [ubuntu-latest] 26 | runs-on: ${{ matrix.os }} 27 | # map step outputs to job outputs so they can be share among jobs 28 | outputs: 29 | package_version: ${{ steps.variables_step.outputs.package_version }} 30 | package_name: ${{ steps.variables_step.outputs.package_name }} 31 | repo_name: ${{ steps.variables_step.outputs.repo_name }} 32 | repo_owner: ${{ steps.variables_step.outputs.repo_owner }} 33 | build_number: ${{ steps.variables_step.outputs.build_number }} 34 | 35 | # uncomment the following to pickup services 36 | # services: 37 | # redis: 38 | # image: redis 39 | # options: >- 40 | # --health-cmd "redis-cli ping" 41 | # --health-interval 10s 42 | # --health-timeout 5s 43 | # --health-retries 5 44 | # ports: 45 | # - 6379:6379 46 | 47 | # Steps represent a sequence of tasks that will be executed as part of the job 48 | steps: 49 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 50 | - uses: actions/checkout@v4 51 | - uses: actions/setup-python@v4 52 | with: 53 | python-version: ${{ matrix.python-versions }} 54 | 55 | - name: Install dependencies 56 | run: | 57 | python -m pip install --upgrade pip 58 | pip install tox tox-gh-actions poetry 59 | 60 | # declare package_version, repo_owner, repo_name, package_name so you may use it in web hooks. 61 | - name: Declare variables for convenient use 62 | id: variables_step 63 | run: | 64 | echo "repo_owner=${GITHUB_REPOSITORY%/*}" >> $GITHUB_OUTPUT 65 | echo "repo_name=${GITHUB_REPOSITORY#*/}" >> $GITHUB_OUTPUT 66 | echo "package_name=`poetry version | awk '{print $1}'`" >> $GITHUB_OUTPUT 67 | echo "package_version=`poetry version --short`" >> $GITHUB_OUTPUT 68 | shell: bash 69 | 70 | - name: test with tox 71 | run: tox 72 | 73 | - uses: codecov/codecov-action@v3 74 | with: 75 | fail_ci_if_error: true 76 | 77 | publish_dev_build: 78 | # if test failed, we should not publish 79 | needs: test 80 | # you may need to change os below 81 | runs-on: ubuntu-latest 82 | steps: 83 | - uses: actions/checkout@v4 84 | - uses: actions/setup-python@v4 85 | with: 86 | python-version: '3.9' 87 | 88 | - name: Install dependencies 89 | run: | 90 | python -m pip install --upgrade pip 91 | pip install poetry tox tox-gh-actions 92 | 93 | - name: build documentation 94 | run: | 95 | poetry install -E doc 96 | mkdocs build 97 | git config --global user.name Docs deploy 98 | git config --global user.email docs@dummy.bot.com 99 | mike deploy -p -f --ignore "`poetry version --short`.dev" 100 | mike set-default -p "`poetry version --short`.dev" 101 | 102 | - name: Build wheels and source tarball 103 | run: | 104 | poetry version $(poetry version --short)-dev.$GITHUB_RUN_NUMBER 105 | poetry lock 106 | poetry build 107 | 108 | - name: publish to Test PyPI 109 | uses: pypa/gh-action-pypi-publish@release/v1 110 | with: 111 | user: __token__ 112 | password: ${{ secrets.TEST_PYPI_API_TOKEN}} 113 | repository_url: https://test.pypi.org/legacy/ 114 | skip_existing: true 115 | 116 | notification: 117 | needs: [test,publish_dev_build] 118 | if: always() 119 | runs-on: ubuntu-latest 120 | steps: 121 | - uses: martialonline/workflow-status@v2 122 | id: check 123 | 124 | - name: build success notification via email 125 | if: ${{ steps.check.outputs.status == 'success' }} 126 | uses: dawidd6/action-send-mail@v3 127 | with: 128 | server_address: ${{ secrets.BUILD_NOTIFY_MAIL_SERVER }} 129 | server_port: ${{ secrets.BUILD_NOTIFY_MAIL_PORT }} 130 | username: ${{ secrets.BUILD_NOTIFY_MAIL_FROM }} 131 | password: ${{ secrets.BUILD_NOTIFY_MAIL_PASSWORD }} 132 | from: build-bot 133 | to: ${{ secrets.BUILD_NOTIFY_MAIL_RCPT }} 134 | subject: ${{ needs.test.outputs.package_name }}.${{ needs.test.outputs.package_version}}.dev.${{ github.run_number }} build successfully 135 | convert_markdown: true 136 | html_body: | 137 | ## Build Success 138 | ${{ needs.test.outputs.package_name }}.${{ needs.test.outputs.package_version }}.dev.${{ github.run_number }} is built and published to test pypi 139 | 140 | ## Change Details 141 | ${{ github.event.head_commit.message }} 142 | 143 | For more information, please check change history at https://${{ needs.test.outputs.repo_owner }}.github.io/${{ needs.test.outputs.repo_name }}/${{ needs.test.outputs.package_version }}.dev/history 144 | 145 | ## Package Download 146 | The pacakge is available at: https://test.pypi.org/project/${{ needs.test.outputs.package_name }}/ 147 | 148 | - name: build failure notification via email 149 | if: ${{ steps.check.outputs.status == 'failure' }} 150 | uses: dawidd6/action-send-mail@v3 151 | with: 152 | server_address: ${{ secrets.BUILD_NOTIFY_MAIL_SERVER }} 153 | server_port: ${{ secrets.BUILD_NOTIFY_MAIL_PORT }} 154 | username: ${{ secrets.BUILD_NOTIFY_MAIL_FROM }} 155 | password: ${{ secrets.BUILD_NOTIFY_MAIL_PASSWORD }} 156 | from: build-bot 157 | to: ${{ secrets.BUILD_NOTIFY_MAIL_RCPT }} 158 | subject: ${{ needs.test.outputs.package_name }}.${{ needs.test.outputs.package_version}}.dev.${{ github.run_number }} build failure 159 | convert_markdown: true 160 | html_body: | 161 | ## Change Details 162 | ${{ github.event.head_commit.message }} 163 | 164 | ## View Log 165 | https://github.com/${{ needs.test.outputs.repo_owner }}/${{ needs.test.outputs.repo_name }}/actions 166 | 167 | 168 | # - name: Dingtalk Robot Notify 169 | # if: always() 170 | # uses: leafney/dingtalk-action@v1.0.0 171 | # env: 172 | # DINGTALK_ACCESS_TOKEN: ${{ secrets.DINGTALK_ACCESS_TOKEN }} 173 | # DINGTALK_SECRET: ${{ secrets.DINGTALK_SECRET }} 174 | # with: 175 | # msgtype: markdown 176 | # title: CI Notification | Success 177 | # text: | 178 | # ### Build Success 179 | # ${{ needs.test.outputs.package_version }}.dev.${{ github.run_number }}published to TEST pypi 180 | # ### Change History 181 | # Please check change history at https://${{ needs.test.outputs.repo_owner }}.github.io/${{ needs.test.outputs.repo_name }}/${{ needs.test.outputs.package_version }}.dev/history 182 | # ### Package Download 183 | # The pacakge is availabled at: https://test.pypi.org/project/${{ needs.test.outputs.repo_name }}/ 184 | -------------------------------------------------------------------------------- /workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Publish package on release branch if it's tagged with 'v*' 2 | 3 | name: build & release 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | push: 9 | branch: [main, master] 10 | tags: 11 | - 'v*' 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | release: 19 | runs-on: ubuntu-latest 20 | 21 | strategy: 22 | matrix: 23 | python-versions: ['3.9'] 24 | 25 | # map step outputs to job outputs so they can be share among jobs 26 | outputs: 27 | package_version: ${{ steps.variables_step.outputs.package_version }} 28 | package_name: ${{ steps.variables_step.outputs.package_name }} 29 | repo_name: ${{ steps.variables_step.outputs.repo_name }} 30 | repo_owner: ${{ steps.variables_step.outputs.repo_owner }} 31 | 32 | # Steps represent a sequence of tasks that will be executed as part of the job 33 | steps: 34 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 35 | - uses: actions/checkout@v4 36 | 37 | - name: build change log 38 | id: build_changelog 39 | uses: mikepenz/release-changelog-builder-action@v3.2.0 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | 43 | - uses: actions/setup-python@v4 44 | with: 45 | python-version: ${{ matrix.python-versions }} 46 | 47 | - name: Install dependencies 48 | run: | 49 | python -m pip install --upgrade pip 50 | pip install tox-gh-actions poetry 51 | 52 | # declare package_version, repo_owner, repo_name, package_name so you may use it in web hooks. 53 | - name: Declare variables for convenient use 54 | id: variables_step 55 | run: | 56 | echo "repo_owner=${GITHUB_REPOSITORY%/*}" >> $GITHUB_OUTPUT 57 | echo "repo_name=${GITHUB_REPOSITORY#*/}" >> $GITHUB_OUTPUT 58 | echo "package_name=`poetry version | awk '{print $1}'`" >> $GITHUB_OUTPUT 59 | echo "package_version=`poetry version --short`" >> $GITHUB_OUTPUT 60 | shell: bash 61 | 62 | - name: publish documentation 63 | run: | 64 | poetry install -E doc 65 | mkdocs build 66 | git config --global user.name Docs deploy 67 | git config --global user.email docs@dummy.bot.com 68 | mike deploy -p -f --ignore `poetry version --short` latest 69 | mike set-default -p `poetry version --short` 70 | 71 | - name: Build wheels and source tarball 72 | run: | 73 | poetry lock 74 | poetry build 75 | 76 | - name: Create Release 77 | id: create_release 78 | uses: actions/create-release@v1 79 | env: 80 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 81 | with: 82 | tag_name: ${{ github.ref_name }} 83 | release_name: Release ${{ github.ref_name }} 84 | body: ${{ steps.build_changelog.outputs.changelog }} 85 | draft: false 86 | prerelease: false 87 | 88 | - name: publish to PYPI 89 | uses: pypa/gh-action-pypi-publish@release/v1 90 | with: 91 | user: __token__ 92 | password: ${{ secrets.PYPI_API_TOKEN }} 93 | skip_existing: true 94 | 95 | notification: 96 | needs: release 97 | if: always() 98 | runs-on: ubuntu-latest 99 | steps: 100 | - uses: martialonline/workflow-status@v2 101 | id: check 102 | 103 | - name: build success notification via email 104 | if: ${{ steps.check.outputs.status == 'success' }} 105 | uses: dawidd6/action-send-mail@v3 106 | with: 107 | server_address: ${{ secrets.BUILD_NOTIFY_MAIL_SERVER }} 108 | server_port: ${{ secrets.BUILD_NOTIFY_MAIL_PORT }} 109 | username: ${{ secrets.BUILD_NOTIFY_MAIL_FROM }} 110 | password: ${{ secrets.BUILD_NOTIFY_MAIL_PASSWORD }} 111 | from: build-bot 112 | to: ${{ secrets.BUILD_NOTIFY_MAIL_RCPT }} 113 | subject: ${{ needs.release.outputs.package_name }}.${{ needs.release.outputs.package_version}} build successfully 114 | convert_markdown: true 115 | html_body: | 116 | ## Build Success 117 | ${{ needs.release.outputs.package_name }}.${{ needs.release.outputs.package_version }} has been published to PYPI 118 | 119 | ## Change Details 120 | ${{ github.event.head_commit.message }} 121 | 122 | For more information, please check change history at https://${{ needs.release.outputs.repo_owner }}.github.io/${{ needs.release.outputs.repo_name }}/${{ needs.release.outputs.package_version }}/history 123 | 124 | ## Package Download 125 | The pacakge is available at: https://pypi.org/project/${{ needs.release.outputs.package_name }}/ 126 | 127 | - name: build failure notification via email 128 | if: ${{ steps.check.outputs.status == 'failure' }} 129 | uses: dawidd6/action-send-mail@v3 130 | with: 131 | server_address: ${{ secrets.BUILD_NOTIFY_MAIL_SERVER }} 132 | server_port: ${{ secrets.BUILD_NOTIFY_MAIL_PORT }} 133 | username: ${{ secrets.BUILD_NOTIFY_MAIL_FROM }} 134 | password: ${{ secrets.BUILD_NOTIFY_MAIL_PASSWORD }} 135 | from: build-bot 136 | to: ${{ secrets.BUILD_NOTIFY_MAIL_RCPT }} 137 | subject: ${{ needs.release.outputs.package_name }}.${{ needs.release.outputs.package_version}} build failure 138 | convert_markdown: true 139 | html_body: | 140 | ## Change Details 141 | ${{ github.event.head_commit.message }} 142 | 143 | ## Status: ${{ steps.check.outputs.status }} 144 | 145 | 146 | ## View Log 147 | https://github.com/${{ needs.release.outputs.repo_owner }}/${{ needs.release.outputs.repo_name }}/actions 148 | 149 | 150 | # - name: Dingtalk Robot Notify 151 | # if: always() 152 | # uses: leafney/dingtalk-action@v1.0.0 153 | # env: 154 | # DINGTALK_ACCESS_TOKEN: ${{ secrets.DINGTALK_ACCESS_TOKEN }} 155 | # DINGTALK_SECRET: ${{ secrets.DINGTALK_SECRET }} 156 | # with: 157 | # msgtype: markdown 158 | # title: CI Notification | Success 159 | # text: | 160 | # ### ${{ needs.release.outputs.package_name }} Build Success 161 | # ${{ needs.release.outputs.package_version }} has been published to PYPI 162 | # ### Change History 163 | # Please check change history at https://${{ needs.release.outputs.repo_owner }}.github.io/${{ needs.release.outputs.repo_name }}/latest/history 164 | # ### Package Download 165 | # Please download the pacakge at: https://pypi.org/project/${{ needs.release.outputs.repo_name }}/ 166 | -------------------------------------------------------------------------------- /workflows/requirements.txt: -------------------------------------------------------------------------------- 1 | colorama==0.4.6 2 | frida==16.1.11 3 | psutil==5.9.7 4 | pyfiglet==1.0.2 5 | --------------------------------------------------------------------------------