diff --git a/gui.py b/gui.py index 99576d3..3f175d3 100644 --- a/gui.py +++ b/gui.py @@ -22,6 +22,7 @@ from PySide6.QtWidgets import ( QTreeWidget, QTreeWidgetItem, QProgressBar, QStackedWidget, QMenu, QHeaderView, QAbstractItemView, QFileDialog, QInputDialog, QTabWidget, QTableWidget, QTableWidgetItem, QDialog, QSizePolicy, + QCheckBox, ) from src.cli import CliOptions, CDP_PORT @@ -29,7 +30,6 @@ from src.logger import Logger from src.engine import DebugEngine from src.navigator import MiniProgramNavigator from src.cloud_audit import CloudAuditor -from src.userscript import load_userscripts_by_files # ══════════════════════════════════════════ # 配色 @@ -71,7 +71,6 @@ if getattr(sys, 'frozen', False): _BASE_DIR = os.path.dirname(sys.executable) _CFG_FILE = os.path.join(_BASE_DIR, "gui_config.json") -os.makedirs(os.path.join(_BASE_DIR, "userscripts"), exist_ok=True) os.makedirs(os.path.join(_BASE_DIR, "hook_scripts"), exist_ok=True) @@ -411,6 +410,28 @@ def build_qss(tn): margin: 4px 8px; }} + /* ── QCheckBox ── */ + QCheckBox {{ + color: {c['text1']}; + background: transparent; + spacing: 5px; + }} + QCheckBox::indicator {{ + width: 14px; + height: 14px; + border-radius: 3px; + border: 1px solid {c['border2']}; + background: {c['input']}; + }} + QCheckBox::indicator:checked {{ + background: {c['accent']}; + border-color: {c['accent']}; + image: none; + }} + QCheckBox::indicator:hover {{ + border-color: {c['accent']}; + }} + /* ── Hook 行 ── */ QFrame.hook_row {{ background: {row_bg}; @@ -638,10 +659,13 @@ class App(QMainWindow): self._cancel_ev = None self._route_poll_id = None self._all_routes = [] + self._flat_routes = [] # tree visual order for prev/next self._cloud_scan_active = False self._cloud_scan_poll_timer = None self._redirect_guard_on = False self._hook_injected = set() + self._global_hook_scripts = set(self._cfg.get("global_hook_scripts", [])) + self._global_inject_gen = 0 self._blocked_seen = 0 self._miniapp_connected = False self._sb_fetch_gen = 0 @@ -650,8 +674,6 @@ class App(QMainWindow): self._sts_q = queue.Queue() self._rte_q = queue.Queue() self._cld_q = queue.Queue() - - self._selected_preload = list(self._cfg.get("selected_preload_scripts", [])) self._nav_route_idx = -1 self._sb_items = {} @@ -866,30 +888,6 @@ class App(QMainWindow): lay.addWidget(c1) - # Card 2: 前加载脚本 - c2 = _make_card() - c2_lay = QVBoxLayout(c2) - c2_lay.setContentsMargins(16, 10, 16, 10) - c2_lay.setSpacing(4) - hdr_row = QHBoxLayout() - hdr_row.addWidget(_make_label("前加载脚本", bold=True)) - hdr_row.addWidget(_make_label("(启动调试前可用)", muted=True)) - hdr_row.addStretch() - self._btn_preload_refresh = _make_btn("刷新", self._preload_refresh) - hdr_row.addWidget(self._btn_preload_refresh) - c2_lay.addLayout(hdr_row) - preload_scroll = QScrollArea() - preload_scroll.setWidgetResizable(True) - preload_scroll.setMaximumHeight(160) - preload_inner = QWidget() - self._preload_container = QVBoxLayout(preload_inner) - self._preload_container.setSpacing(2) - self._preload_container.setContentsMargins(0, 0, 0, 0) - preload_scroll.setWidget(preload_inner) - c2_lay.addWidget(preload_scroll) - lay.addWidget(c2) - self._preload_refresh() - # Action row ar = QHBoxLayout() self._btn_start = _make_btn("▶ 启动调试", self._do_start) @@ -1143,13 +1141,27 @@ class App(QMainWindow): name_lbl.setFont(QFont(_FN, 10)) row_lay.addWidget(name_lbl, 1) + is_global = fn in self._global_hook_scripts injected = fn in self._hook_injected - status_lbl = QLabel("● 已注入" if injected else "○ 未注入") + if is_global and injected: + status_text = "全局 ● 已注入" + elif is_global: + status_text = "全局 ○ 待注入" + elif injected: + status_text = "● 已注入" + else: + status_text = "○ 未注入" + status_lbl = QLabel(status_text) c = _TH[self._tn] status_lbl.setStyleSheet(f"color: {c['success'] if injected else c['text3']};") row_lay.addWidget(status_lbl) self._hook_status_lbls[fn] = status_lbl + global_cb = QCheckBox("全局") + global_cb.setChecked(is_global) + global_cb.toggled.connect(lambda checked, f=fn: self._hook_global_toggle(f, checked)) + row_lay.addWidget(global_cb) + inject_btn = _make_btn("注入", lambda checked=False, f=fn: self._hook_inject(f)) row_lay.addWidget(inject_btn) clear_btn = _make_btn("清除", lambda checked=False, f=fn: self._hook_clear(f)) @@ -1190,8 +1202,57 @@ class App(QMainWindow): c = _TH[self._tn] lbl = self._hook_status_lbls.get(filename) if lbl: - lbl.setText("● 已注入" if injected else "○ 未注入") - lbl.setStyleSheet(f"color: {c['success'] if injected else c['text3']};") + is_global = filename in self._global_hook_scripts + if is_global and injected: + lbl.setText("全局 ● 已注入") + lbl.setStyleSheet(f"color: {c['success']};") + elif is_global: + lbl.setText("全局 ○ 待注入") + lbl.setStyleSheet(f"color: {c['text3']};") + elif injected: + lbl.setText("● 已注入") + lbl.setStyleSheet(f"color: {c['success']};") + else: + lbl.setText("○ 未注入") + lbl.setStyleSheet(f"color: {c['text3']};") + + def _hook_global_toggle(self, filename, checked): + if checked: + self._global_hook_scripts.add(filename) + else: + self._global_hook_scripts.discard(filename) + injected = filename in self._hook_injected + self._hook_update_status(filename, injected) + self._auto_save() + + def _hook_auto_inject_globals(self): + """Auto-inject all global hook scripts (called when miniapp stabilizes).""" + if not self._engine or not self._loop or not self._loop.is_running(): + return + hook_dir = os.path.join(_BASE_DIR, "hook_scripts") + for fn in list(self._global_hook_scripts): + if fn in self._hook_injected: + continue + filepath = os.path.join(hook_dir, fn) + if not os.path.isfile(filepath): + continue + try: + with open(filepath, "r", encoding="utf-8") as f: + source = f.read() + except Exception: + continue + asyncio.run_coroutine_threadsafe( + self._ahook_inject(fn, source), self._loop) + + def _do_global_inject(self, gen): + """独立的全局注入定时回调,只在小程序连接变化时触发,不受 CDP 等影响。""" + if gen != self._global_inject_gen: + return + if not self._miniapp_connected: + return + if self._global_hook_scripts: + self._hook_auto_inject_globals() + self._log_add("info", "[Hook] 自动注入全局脚本") # ── 云扫描 ── @@ -1342,11 +1403,11 @@ class App(QMainWindow): # 自动反编译 & 自动提取 开关 func_row.addWidget(_make_label("自动反编译")) self._tog_auto_dec = ToggleSwitch(self._cfg.get("auto_decompile", False)) - self._tog_auto_dec.toggled.connect(lambda v: (self._auto_save(), self._ext_auto_process_pending() if v else None)) + self._tog_auto_dec.toggled.connect(lambda v: self._auto_save()) func_row.addWidget(self._tog_auto_dec) func_row.addWidget(_make_label("自动提取")) self._tog_auto_scan = ToggleSwitch(self._cfg.get("auto_scan", False)) - self._tog_auto_scan.toggled.connect(lambda v: (self._auto_save(), self._ext_auto_process_pending() if v else None)) + self._tog_auto_scan.toggled.connect(lambda v: self._auto_save()) func_row.addWidget(self._tog_auto_scan) main_lay.addLayout(func_row) @@ -1688,7 +1749,12 @@ class App(QMainWindow): c = _TH[self._tn] output_base = os.path.join(_BASE_DIR, "output") - for appid, pkgs in sorted(appid_groups.items()): + # 按最新包文件的修改时间排序,最旧的先插入,最新的最后插入到位置0因此显示在最上面 + def _appid_mtime(item): + _, pkgs = item + return max((os.path.getmtime(p["path"]) for p in pkgs if os.path.exists(p["path"])), default=0) + + for appid, pkgs in sorted(appid_groups.items(), key=_appid_mtime): row = QFrame() row.setStyleSheet( f"QFrame {{ background: {c['input']}; border-radius: 8px; }}" @@ -1763,8 +1829,8 @@ class App(QMainWindow): "btn_view": btn_view, "btn_del": btn_del, "lbl_name": lbl_name, } - # 插入在 stretch 之前 - self._ext_list_layout.insertWidget(self._ext_list_layout.count() - 1, row) + # 插入在最前面(最新的在上面) + self._ext_list_layout.insertWidget(0, row) self._ext_status_lbl.setText(f"发现 {len(appid_groups)} 个小程序") # 记录当前已知 appid 集合 (供目录监控用) @@ -2732,47 +2798,6 @@ class App(QMainWindow): self._stack.addWidget(page) self._page_map["logs"] = self._stack.count() - 1 - # ────────────────────────────────── - # 前加载脚本 - # ────────────────────────────────── - - def _preload_refresh(self): - while self._preload_container.count(): - item = self._preload_container.takeAt(0) - w = item.widget() - if w: - w.deleteLater() - - scripts_dir = os.path.join(_BASE_DIR, "userscripts") - js_files = sorted(f for f in os.listdir(scripts_dir) if f.endswith(".js")) if os.path.isdir(scripts_dir) else [] - - if not js_files: - lbl = QLabel("userscripts/ 目录下无 .js 文件") - lbl.setProperty("class", "muted") - self._preload_container.addWidget(lbl) - return - - for fn in js_files: - row = QHBoxLayout() - tog = ToggleSwitch(fn in self._selected_preload) - tog.setFixedSize(36, 18) - tog.toggled.connect(lambda v, f=fn: self._preload_toggle(f, v)) - row.addWidget(tog) - row.addWidget(QLabel(fn)) - row.addStretch() - w = QWidget() - w.setLayout(row) - self._preload_container.addWidget(w) - - def _preload_toggle(self, filename, val): - if val: - if filename not in self._selected_preload: - self._selected_preload.append(filename) - else: - if filename in self._selected_preload: - self._selected_preload.remove(filename) - self._auto_save() - # ────────────────────────────────── # 页面切换 # ────────────────────────────────── @@ -2836,11 +2861,11 @@ class App(QMainWindow): "cdp_port": self._cp_ent.text(), "debug_main": self._tog_dm.isChecked(), "debug_frida": self._tog_df.isChecked(), - "selected_preload_scripts": list(self._selected_preload), "extract_packages_dir": self._ext_path_ent.text(), "extract_custom_patterns": dict(self._ext_custom_patterns), "auto_decompile": self._tog_auto_dec.isChecked(), "auto_scan": self._tog_auto_scan.isChecked(), + "global_hook_scripts": list(self._global_hook_scripts), } _save_cfg(data) @@ -2898,22 +2923,15 @@ class App(QMainWindow): except ValueError: self._log_add("error", "[gui] 端口号无效") return - scripts_dir = os.path.join(_BASE_DIR, "userscripts") - selected_files = [os.path.join(scripts_dir, fn) for fn in self._selected_preload] opts = CliOptions( cdp_port=cp, debug_main=self._tog_dm.isChecked(), debug_frida=self._tog_df.isChecked(), - scripts_dir=scripts_dir, - script_files=selected_files) + scripts_dir="", + script_files=[]) logger = Logger(opts) logger.set_output_callback(lambda lv, tx: self._log_q.put((lv, tx))) - us = load_userscripts_by_files(selected_files) if selected_files else [] - if us: - logger.info(f"[脚本] 已加载 {len(us)} 个") - else: - logger.info("[脚本] 无脚本") - self._engine = DebugEngine(opts, logger, us) + self._engine = DebugEngine(opts, logger) self._navigator = MiniProgramNavigator(self._engine) self._auditor = CloudAuditor(self._engine) self._engine.on_status_change(lambda s: self._sts_q.put(s)) @@ -3115,6 +3133,8 @@ class App(QMainWindow): def _do_go(self): r = self._sel_route() if r and self._engine and self._loop: + if r in self._flat_routes: + self._nav_route_idx = self._flat_routes.index(r) asyncio.run_coroutine_threadsafe( self._anav("navigate_to", r, "跳转"), self._loop) @@ -3193,31 +3213,33 @@ class App(QMainWindow): self._btn_auto.setEnabled(True) def _do_prev(self): - if not self._all_routes: + routes = self._flat_routes or self._all_routes + if not routes: self._log_add("error", "[导航] 请先获取路由") return if self._nav_route_idx <= 0: - self._nav_route_idx = len(self._all_routes) - 1 + self._nav_route_idx = len(routes) - 1 else: self._nav_route_idx -= 1 - route = self._all_routes[self._nav_route_idx] + route = routes[self._nav_route_idx] self._select_tree_route(route) - self._log_add("info", f"[导航] 上一个: {route} ({self._nav_route_idx + 1}/{len(self._all_routes)})") + self._log_add("info", f"[导航] 上一个: {route} ({self._nav_route_idx + 1}/{len(routes)})") if self._engine and self._loop: asyncio.run_coroutine_threadsafe( self._anav("navigate_to", route, "跳转"), self._loop) def _do_next(self): - if not self._all_routes: + routes = self._flat_routes or self._all_routes + if not routes: self._log_add("error", "[导航] 请先获取路由") return - if self._nav_route_idx >= len(self._all_routes) - 1: + if self._nav_route_idx >= len(routes) - 1: self._nav_route_idx = 0 else: self._nav_route_idx += 1 - route = self._all_routes[self._nav_route_idx] + route = routes[self._nav_route_idx] self._select_tree_route(route) - self._log_add("info", f"[导航] 下一个: {route} ({self._nav_route_idx + 1}/{len(self._all_routes)})") + self._log_add("info", f"[导航] 下一个: {route} ({self._nav_route_idx + 1}/{len(routes)})") if self._engine and self._loop: asyncio.run_coroutine_threadsafe( self._anav("navigate_to", route, "跳转"), self._loop) @@ -3320,6 +3342,9 @@ class App(QMainWindow): parts = p.split("/") g = parts[0] if len(parts) > 1 else "(root)" groups.setdefault(g, []).append(p) + + flat = [] # tree visual order for prev/next + tl = [p for p in pages if p in tabs] if tl: nd = QTreeWidgetItem(["TabBar"]) @@ -3330,6 +3355,7 @@ class App(QMainWindow): child = QTreeWidgetItem([d]) child.setData(0, Qt.UserRole, p) nd.addChild(child) + flat.append(p) for g in sorted(groups): nd = QTreeWidgetItem([g]) self._tree.addTopLevelItem(nd) @@ -3340,8 +3366,16 @@ class App(QMainWindow): child = QTreeWidgetItem([d]) child.setData(0, Qt.UserRole, p) nd.addChild(child) + flat.append(p) + + self._flat_routes = flat self._tree.setUpdatesEnabled(True) + # 默认选中并定位到第一个页面 + if flat and self._nav_route_idx < 0: + self._nav_route_idx = 0 + self._select_tree_route(flat[0]) + def _select_tree_route(self, route): """Select the tree item matching the given route path.""" for i in range(self._tree.topLevelItemCount()): @@ -3606,17 +3640,25 @@ class App(QMainWindow): lb.setText(f"{name}: {'已连接' if on else '未连接'}") lb.setStyleSheet(f"color: {c['success'] if on else c['text2']};") # 断开时立即禁用(除了已有路由时保留导航按钮) - if not is_connected: + if not is_connected and self._miniapp_connected: if not self._all_routes: self._nav_btns(False) self._btn_vc_enable.setEnabled(False) self._btn_vc_disable.setEnabled(False) self._vc_status_lbl.setText("状态: 未连接小程序") + # 清除注入标记,切换小程序时全局脚本会重新注入 + self._hook_injected.clear() + self._hook_refresh() # 已有路由数据时不清除侧栏信息(短暂断连不影响) if not self._all_routes: self._sb_fetch_gen += 1 gen = self._sb_fetch_gen QTimer.singleShot(5000, lambda: self._delayed_clear_app_info(gen)) + # 小程序连接时,独立定时器触发全局 Hook 注入(不受 CDP 等状态变化影响) + if is_connected and not self._miniapp_connected and self._global_hook_scripts: + self._global_inject_gen += 1 + _gi_gen = self._global_inject_gen + QTimer.singleShot(1500, lambda: self._do_global_inject(_gi_gen)) # 连接时延迟启用,等连接稳定(防止重启时反复抖动) self._vc_stable_gen += 1 gen_stable = self._vc_stable_gen @@ -3661,6 +3703,11 @@ class App(QMainWindow): elif kind == "current": r = item[1] self._route_lbl.setText(f"当前路由: /{r}" if r else "当前路由: --") + if r: + routes = self._flat_routes or self._all_routes + if r in routes: + self._nav_route_idx = routes.index(r) + self._select_tree_route(r) elif kind == "progress": _, i, total, route = item if total > 0: diff --git a/gui_config.json b/gui_config.json index 1fd8366..394131c 100644 --- a/gui_config.json +++ b/gui_config.json @@ -1,8 +1,11 @@ { "theme": "dark", - "debug_port": "9421", "cdp_port": "62000", "debug_main": false, "debug_frida": false, - "selected_preload_scripts": [] + "extract_packages_dir": "", + "extract_custom_patterns": {}, + "auto_decompile": false, + "auto_scan": false, + "global_hook_scripts": [] } \ No newline at end of file diff --git a/src/__pycache__/__init__.cpython-310.pyc b/src/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index c5c66f8..0000000 Binary files a/src/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/__init__.cpython-314.pyc b/src/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 40ece51..0000000 Binary files a/src/__pycache__/__init__.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/cli.cpython-310.pyc b/src/__pycache__/cli.cpython-310.pyc deleted file mode 100644 index 63fcb06..0000000 Binary files a/src/__pycache__/cli.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/cli.cpython-314.pyc b/src/__pycache__/cli.cpython-314.pyc deleted file mode 100644 index 3bedcb3..0000000 Binary files a/src/__pycache__/cli.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/cloud_audit.cpython-310.pyc b/src/__pycache__/cloud_audit.cpython-310.pyc deleted file mode 100644 index 2e23723..0000000 Binary files a/src/__pycache__/cloud_audit.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/cloud_audit.cpython-314.pyc b/src/__pycache__/cloud_audit.cpython-314.pyc deleted file mode 100644 index 84ef039..0000000 Binary files a/src/__pycache__/cloud_audit.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/codex.cpython-310.pyc b/src/__pycache__/codex.cpython-310.pyc deleted file mode 100644 index 0067ce1..0000000 Binary files a/src/__pycache__/codex.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/codex.cpython-314.pyc b/src/__pycache__/codex.cpython-314.pyc deleted file mode 100644 index 818c4e4..0000000 Binary files a/src/__pycache__/codex.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/constants.cpython-310.pyc b/src/__pycache__/constants.cpython-310.pyc deleted file mode 100644 index 1608042..0000000 Binary files a/src/__pycache__/constants.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/constants.cpython-314.pyc b/src/__pycache__/constants.cpython-314.pyc deleted file mode 100644 index a16882e..0000000 Binary files a/src/__pycache__/constants.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/engine.cpython-310.pyc b/src/__pycache__/engine.cpython-310.pyc deleted file mode 100644 index 8f3c4bb..0000000 Binary files a/src/__pycache__/engine.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/engine.cpython-313.pyc b/src/__pycache__/engine.cpython-313.pyc deleted file mode 100644 index 9954a9d..0000000 Binary files a/src/__pycache__/engine.cpython-313.pyc and /dev/null differ diff --git a/src/__pycache__/engine.cpython-314.pyc b/src/__pycache__/engine.cpython-314.pyc deleted file mode 100644 index cf21032..0000000 Binary files a/src/__pycache__/engine.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/extract_worker.cpython-310.pyc b/src/__pycache__/extract_worker.cpython-310.pyc deleted file mode 100644 index 8e660e3..0000000 Binary files a/src/__pycache__/extract_worker.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/extractor.cpython-310.pyc b/src/__pycache__/extractor.cpython-310.pyc deleted file mode 100644 index 9216d5b..0000000 Binary files a/src/__pycache__/extractor.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/js_analyzer.cpython-310.pyc b/src/__pycache__/js_analyzer.cpython-310.pyc deleted file mode 100644 index bed304f..0000000 Binary files a/src/__pycache__/js_analyzer.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/js_analyzer.cpython-314.pyc b/src/__pycache__/js_analyzer.cpython-314.pyc deleted file mode 100644 index ed5cc08..0000000 Binary files a/src/__pycache__/js_analyzer.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/logger.cpython-310.pyc b/src/__pycache__/logger.cpython-310.pyc deleted file mode 100644 index 11b6248..0000000 Binary files a/src/__pycache__/logger.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/logger.cpython-314.pyc b/src/__pycache__/logger.cpython-314.pyc deleted file mode 100644 index 32f71ee..0000000 Binary files a/src/__pycache__/logger.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/navigator.cpython-310.pyc b/src/__pycache__/navigator.cpython-310.pyc deleted file mode 100644 index 51b51ed..0000000 Binary files a/src/__pycache__/navigator.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/navigator.cpython-314.pyc b/src/__pycache__/navigator.cpython-314.pyc deleted file mode 100644 index 6b5b3f6..0000000 Binary files a/src/__pycache__/navigator.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/userscript.cpython-310.pyc b/src/__pycache__/userscript.cpython-310.pyc deleted file mode 100644 index 902e14f..0000000 Binary files a/src/__pycache__/userscript.cpython-310.pyc and /dev/null differ diff --git a/src/__pycache__/userscript.cpython-314.pyc b/src/__pycache__/userscript.cpython-314.pyc deleted file mode 100644 index 146dba2..0000000 Binary files a/src/__pycache__/userscript.cpython-314.pyc and /dev/null differ diff --git a/src/__pycache__/wxapkg.cpython-310.pyc b/src/__pycache__/wxapkg.cpython-310.pyc deleted file mode 100644 index 0507ee9..0000000 Binary files a/src/__pycache__/wxapkg.cpython-310.pyc and /dev/null differ diff --git a/src/third_party/__pycache__/__init__.cpython-310.pyc b/src/third_party/__pycache__/__init__.cpython-310.pyc index ef19bfc..88f07c7 100644 Binary files a/src/third_party/__pycache__/__init__.cpython-310.pyc and b/src/third_party/__pycache__/__init__.cpython-310.pyc differ diff --git a/src/third_party/__pycache__/wmpf_debug_pb2.cpython-310.pyc b/src/third_party/__pycache__/wmpf_debug_pb2.cpython-310.pyc index 0a96f27..050636c 100644 Binary files a/src/third_party/__pycache__/wmpf_debug_pb2.cpython-310.pyc and b/src/third_party/__pycache__/wmpf_debug_pb2.cpython-310.pyc differ diff --git a/userscripts/bypass_debugger.js b/userscripts/bypass_debugger.js deleted file mode 100644 index c822e8f..0000000 --- a/userscripts/bypass_debugger.js +++ /dev/null @@ -1,87 +0,0 @@ -// ==UserScript== -// @name Bypass_Debugger -// @namespace https://github.com/0xsdeo/Bypass_Debugger -// @version 2024-12-06 -// @description Bypass new Function --> debugger && constructor --> debugger && eval --> debugger -// @author 0xsdeo -// @match http://*/* -// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== -// @grant none -// @run-at document-start -// ==/UserScript== - -(function() { - 'use strict'; - - globalThis.__INJECTED__ = true; - - // eval may not exist in WeChat miniapp context - if (typeof eval !== 'undefined') { - try { - let temp_eval = eval; - window.eval = function () { - if (typeof arguments[0] == "string") { - arguments[0] = arguments[0].replaceAll(/debugger/g, ''); - } - return temp_eval(...arguments); - } - } catch(e) {} - } - - try { - let OrigFunction = Function; - - let NewFunction = function () { - for (let i = 0; i < arguments.length; i++) { - if (typeof arguments[i] == "string") { - arguments[i] = arguments[i].replaceAll(/debugger/g, ''); - } - } - return OrigFunction(...arguments); - } - - // Try to set prototype, skip if read-only (WeChat freezes Function) - try { NewFunction.prototype = OrigFunction.prototype; } catch(e) {} - try { - NewFunction.prototype.constructor = function () { - for (let i = 0; i < arguments.length; i++) { - if (typeof arguments[i] == "string") { - arguments[i] = arguments[i].replaceAll(/debugger/g, ''); - } - } - return OrigFunction(...arguments); - } - NewFunction.prototype.constructor.prototype = NewFunction.prototype; - } catch(e) {} - - // Replace global Function - try { window.Function = NewFunction; } catch(e) {} - try { globalThis.Function = NewFunction; } catch(e) {} - try { Object.freeze(NewFunction); } catch(e) {} - } catch(e) {} - - // Also patch setTimeout/setInterval which can take string arguments with debugger - try { - let origSetTimeout = setTimeout; - window.setTimeout = function(fn, delay) { - if (typeof fn === 'string') { - fn = fn.replaceAll(/debugger/g, ''); - } - return origSetTimeout.apply(this, arguments); - }; - } catch(e) {} - - try { - let origSetInterval = setInterval; - window.setInterval = function(fn, delay) { - if (typeof fn === 'string') { - fn = fn.replaceAll(/debugger/g, ''); - } - return origSetInterval.apply(this, arguments); - }; - } catch(e) {} - - console.log('[Bypass_Debugger] hooks installed'); - window.__BYPASS_DEBUGGER__ = true; - Object.freeze(Function); -})();