deepspider 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/.claude/agents/check.md +122 -0
  2. package/.claude/agents/debug.md +106 -0
  3. package/.claude/agents/dispatch.md +214 -0
  4. package/.claude/agents/implement.md +96 -0
  5. package/.claude/agents/plan.md +396 -0
  6. package/.claude/agents/research.md +120 -0
  7. package/.claude/commands/evolve/merge.md +80 -0
  8. package/.claude/commands/trellis/before-backend-dev.md +13 -0
  9. package/.claude/commands/trellis/before-frontend-dev.md +13 -0
  10. package/.claude/commands/trellis/break-loop.md +107 -0
  11. package/.claude/commands/trellis/check-backend.md +13 -0
  12. package/.claude/commands/trellis/check-cross-layer.md +153 -0
  13. package/.claude/commands/trellis/check-frontend.md +13 -0
  14. package/.claude/commands/trellis/create-command.md +154 -0
  15. package/.claude/commands/trellis/finish-work.md +129 -0
  16. package/.claude/commands/trellis/integrate-skill.md +219 -0
  17. package/.claude/commands/trellis/onboard.md +358 -0
  18. package/.claude/commands/trellis/parallel.md +193 -0
  19. package/.claude/commands/trellis/record-session.md +62 -0
  20. package/.claude/commands/trellis/start.md +280 -0
  21. package/.claude/commands/trellis/update-spec.md +213 -0
  22. package/.claude/hooks/inject-subagent-context.py +758 -0
  23. package/.claude/hooks/ralph-loop.py +374 -0
  24. package/.claude/hooks/session-start.py +126 -0
  25. package/.claude/settings.json +41 -0
  26. package/.claude/skills/deepagents-guide/SKILL.md +428 -0
  27. package/.cursor/commands/trellis-before-backend-dev.md +13 -0
  28. package/.cursor/commands/trellis-before-frontend-dev.md +13 -0
  29. package/.cursor/commands/trellis-break-loop.md +107 -0
  30. package/.cursor/commands/trellis-check-backend.md +13 -0
  31. package/.cursor/commands/trellis-check-cross-layer.md +153 -0
  32. package/.cursor/commands/trellis-check-frontend.md +13 -0
  33. package/.cursor/commands/trellis-create-command.md +154 -0
  34. package/.cursor/commands/trellis-finish-work.md +129 -0
  35. package/.cursor/commands/trellis-integrate-skill.md +219 -0
  36. package/.cursor/commands/trellis-onboard.md +358 -0
  37. package/.cursor/commands/trellis-record-session.md +62 -0
  38. package/.cursor/commands/trellis-start.md +156 -0
  39. package/.cursor/commands/trellis-update-spec.md +213 -0
  40. package/.env.example +11 -0
  41. package/.husky/pre-commit +1 -0
  42. package/.mcp.json +8 -0
  43. package/.trellis/.template-hashes.json +65 -0
  44. package/.trellis/.version +1 -0
  45. package/.trellis/scripts/add-session.sh +384 -0
  46. package/.trellis/scripts/common/developer.sh +129 -0
  47. package/.trellis/scripts/common/git-context.sh +263 -0
  48. package/.trellis/scripts/common/paths.sh +208 -0
  49. package/.trellis/scripts/common/phase.sh +150 -0
  50. package/.trellis/scripts/common/registry.sh +247 -0
  51. package/.trellis/scripts/common/task-queue.sh +142 -0
  52. package/.trellis/scripts/common/task-utils.sh +151 -0
  53. package/.trellis/scripts/common/worktree.sh +128 -0
  54. package/.trellis/scripts/create-bootstrap.sh +299 -0
  55. package/.trellis/scripts/get-context.sh +7 -0
  56. package/.trellis/scripts/get-developer.sh +15 -0
  57. package/.trellis/scripts/init-developer.sh +34 -0
  58. package/.trellis/scripts/multi-agent/cleanup.sh +396 -0
  59. package/.trellis/scripts/multi-agent/create-pr.sh +241 -0
  60. package/.trellis/scripts/multi-agent/plan.sh +207 -0
  61. package/.trellis/scripts/multi-agent/start.sh +310 -0
  62. package/.trellis/scripts/multi-agent/status.sh +828 -0
  63. package/.trellis/scripts/task.sh +1118 -0
  64. package/.trellis/spec/backend/deepagents-guide.md +337 -0
  65. package/.trellis/spec/backend/directory-structure.md +126 -0
  66. package/.trellis/spec/backend/examples/skills/deepagents-guide/README.md +11 -0
  67. package/.trellis/spec/backend/examples/skills/deepagents-guide/agent.js.template +20 -0
  68. package/.trellis/spec/backend/examples/skills/deepagents-guide/skills-config.js.template +13 -0
  69. package/.trellis/spec/backend/examples/skills/deepagents-guide/subagent.js.template +19 -0
  70. package/.trellis/spec/backend/hook-guidelines.md +178 -0
  71. package/.trellis/spec/backend/index.md +36 -0
  72. package/.trellis/spec/backend/quality-guidelines.md +201 -0
  73. package/.trellis/spec/backend/state-management.md +76 -0
  74. package/.trellis/spec/backend/tool-guidelines.md +144 -0
  75. package/.trellis/spec/backend/type-safety.md +71 -0
  76. package/.trellis/spec/guides/code-reuse-thinking-guide.md +92 -0
  77. package/.trellis/spec/guides/cross-layer-thinking-guide.md +94 -0
  78. package/.trellis/spec/guides/index.md +79 -0
  79. package/.trellis/tasks/archive/02-02-evolving-skills/prd.md +61 -0
  80. package/.trellis/tasks/archive/02-02-evolving-skills/task.json +29 -0
  81. package/.trellis/tasks/archive/2026-02/00-bootstrap-guidelines/prd.md +86 -0
  82. package/.trellis/tasks/archive/2026-02/00-bootstrap-guidelines/task.json +27 -0
  83. package/.trellis/tasks/archive/2026-02/02-02-skills-system/check.jsonl +3 -0
  84. package/.trellis/tasks/archive/2026-02/02-02-skills-system/debug.jsonl +2 -0
  85. package/.trellis/tasks/archive/2026-02/02-02-skills-system/implement.jsonl +5 -0
  86. package/.trellis/tasks/archive/2026-02/02-02-skills-system/prd.md +33 -0
  87. package/.trellis/tasks/archive/2026-02/02-02-skills-system/task.json +41 -0
  88. package/.trellis/workflow.md +407 -0
  89. package/.trellis/workspace/index.md +123 -0
  90. package/.trellis/workspace/pony/index.md +40 -0
  91. package/.trellis/workspace/pony/journal-1.md +7 -0
  92. package/.trellis/worktree.yaml +47 -0
  93. package/AGENTS.md +18 -0
  94. package/CLAUDE.md +292 -0
  95. package/README.md +134 -0
  96. package/agents/deepspider.md +142 -0
  97. package/docs/DEBUG.md +42 -0
  98. package/docs/GUIDE.md +334 -0
  99. package/docs/PROMPT.md +60 -0
  100. package/docs/USAGE.md +226 -0
  101. package/eslint.config.js +51 -0
  102. package/package.json +78 -0
  103. package/requirements-crypto.txt +14 -0
  104. package/src/agent/index.js +97 -0
  105. package/src/agent/logger.js +164 -0
  106. package/src/agent/middleware/filterTools.js +64 -0
  107. package/src/agent/middleware/report.js +79 -0
  108. package/src/agent/prompts/system.js +315 -0
  109. package/src/agent/run.js +575 -0
  110. package/src/agent/skills/anti-detect/SKILL.md +28 -0
  111. package/src/agent/skills/anti-detect/evolved.md +12 -0
  112. package/src/agent/skills/captcha/SKILL.md +37 -0
  113. package/src/agent/skills/captcha/evolved.md +12 -0
  114. package/src/agent/skills/config.js +30 -0
  115. package/src/agent/skills/crawler/SKILL.md +9 -0
  116. package/src/agent/skills/crawler/evolved.md +16 -0
  117. package/src/agent/skills/dynamic-analysis/SKILL.md +91 -0
  118. package/src/agent/skills/dynamic-analysis/evolved.md +12 -0
  119. package/src/agent/skills/env/SKILL.md +72 -0
  120. package/src/agent/skills/env/evolved.md +12 -0
  121. package/src/agent/skills/evolve.js +79 -0
  122. package/src/agent/skills/general/SKILL.md +12 -0
  123. package/src/agent/skills/general/evolved.md +12 -0
  124. package/src/agent/skills/js2python/SKILL.md +30 -0
  125. package/src/agent/skills/js2python/evolved.md +13 -0
  126. package/src/agent/skills/report/SKILL.md +21 -0
  127. package/src/agent/skills/report/evolved.md +12 -0
  128. package/src/agent/skills/sandbox/SKILL.md +22 -0
  129. package/src/agent/skills/sandbox/evolved.md +16 -0
  130. package/src/agent/skills/static-analysis/SKILL.md +93 -0
  131. package/src/agent/skills/static-analysis/evolved.md +12 -0
  132. package/src/agent/skills/xpath/SKILL.md +119 -0
  133. package/src/agent/subagents/anti-detect.js +45 -0
  134. package/src/agent/subagents/captcha.js +51 -0
  135. package/src/agent/subagents/crawler.js +138 -0
  136. package/src/agent/subagents/dynamic.js +64 -0
  137. package/src/agent/subagents/env-agent.js +82 -0
  138. package/src/agent/subagents/index.js +37 -0
  139. package/src/agent/subagents/js2python.js +72 -0
  140. package/src/agent/subagents/sandbox.js +55 -0
  141. package/src/agent/subagents/static.js +66 -0
  142. package/src/agent/tools/analysis.js +135 -0
  143. package/src/agent/tools/analyzer.js +85 -0
  144. package/src/agent/tools/anti-detect.js +89 -0
  145. package/src/agent/tools/antidebug.js +64 -0
  146. package/src/agent/tools/async.js +43 -0
  147. package/src/agent/tools/browser.js +324 -0
  148. package/src/agent/tools/captcha.js +223 -0
  149. package/src/agent/tools/capture.js +179 -0
  150. package/src/agent/tools/correlate.js +303 -0
  151. package/src/agent/tools/crawler.js +116 -0
  152. package/src/agent/tools/cryptohook.js +80 -0
  153. package/src/agent/tools/debug.js +246 -0
  154. package/src/agent/tools/deobfuscator.js +90 -0
  155. package/src/agent/tools/env.js +83 -0
  156. package/src/agent/tools/envdump.js +92 -0
  157. package/src/agent/tools/evolve.js +164 -0
  158. package/src/agent/tools/extract.js +114 -0
  159. package/src/agent/tools/extractor.js +54 -0
  160. package/src/agent/tools/file.js +224 -0
  161. package/src/agent/tools/hook.js +84 -0
  162. package/src/agent/tools/hookManager.js +178 -0
  163. package/src/agent/tools/index.js +137 -0
  164. package/src/agent/tools/nodejs.js +101 -0
  165. package/src/agent/tools/patch.js +46 -0
  166. package/src/agent/tools/preprocess.js +71 -0
  167. package/src/agent/tools/profile.js +122 -0
  168. package/src/agent/tools/python.js +627 -0
  169. package/src/agent/tools/report.js +124 -0
  170. package/src/agent/tools/runtime.js +132 -0
  171. package/src/agent/tools/sandbox.js +79 -0
  172. package/src/agent/tools/store.js +73 -0
  173. package/src/agent/tools/trace.js +74 -0
  174. package/src/agent/tools/tracing.js +201 -0
  175. package/src/agent/tools/utils.js +51 -0
  176. package/src/agent/tools/verify.js +184 -0
  177. package/src/agent/tools/webcrack.js +109 -0
  178. package/src/analyzer/ASTAnalyzer.js +387 -0
  179. package/src/analyzer/CallStackAnalyzer.js +379 -0
  180. package/src/analyzer/Deobfuscator.js +289 -0
  181. package/src/analyzer/EncryptionAnalyzer.js +99 -0
  182. package/src/analyzer/index.js +22 -0
  183. package/src/browser/EnvBridge.js +186 -0
  184. package/src/browser/cdp.js +168 -0
  185. package/src/browser/client.js +197 -0
  186. package/src/browser/collector.js +444 -0
  187. package/src/browser/collectors/RequestCryptoLinker.js +109 -0
  188. package/src/browser/collectors/ResponseSearcher.js +107 -0
  189. package/src/browser/collectors/ScriptCollector.js +158 -0
  190. package/src/browser/collectors/index.js +26 -0
  191. package/src/browser/defaultHooks.js +932 -0
  192. package/src/browser/hooks/crypto.js +55 -0
  193. package/src/browser/hooks/index.js +64 -0
  194. package/src/browser/hooks/native.js +9 -0
  195. package/src/browser/hooks/network.js +33 -0
  196. package/src/browser/index.js +42 -0
  197. package/src/browser/interceptors/NetworkInterceptor.js +116 -0
  198. package/src/browser/interceptors/ScriptInterceptor.js +76 -0
  199. package/src/browser/interceptors/index.js +6 -0
  200. package/src/browser/ui/analysisPanel.js +1782 -0
  201. package/src/browser/ui/confirmDialog.js +158 -0
  202. package/src/browser/ui/panel.html +152 -0
  203. package/src/browser/ui/selector.js +170 -0
  204. package/src/config/index.js +5 -0
  205. package/src/config/paths.js +71 -0
  206. package/src/config/patterns/crypto.js +36 -0
  207. package/src/config/profiles/chrome.json +71 -0
  208. package/src/config/profiles/firefox.json +44 -0
  209. package/src/config/profiles/safari.json +38 -0
  210. package/src/core/EnvMonitor.js +200 -0
  211. package/src/core/PatchGenerator.js +278 -0
  212. package/src/core/Sandbox.js +181 -0
  213. package/src/env/AntiAntiDebug.js +111 -0
  214. package/src/env/AsyncHook.js +68 -0
  215. package/src/env/BrowserAPIList.js +265 -0
  216. package/src/env/CookieHook.js +48 -0
  217. package/src/env/CryptoHook.js +205 -0
  218. package/src/env/EnvCodeGenerator.js +157 -0
  219. package/src/env/EnvDumper.js +356 -0
  220. package/src/env/EnvExtractor.js +220 -0
  221. package/src/env/HookBase.js +618 -0
  222. package/src/env/NetworkHook.js +159 -0
  223. package/src/env/modules/bom/history.js +29 -0
  224. package/src/env/modules/bom/location.js +26 -0
  225. package/src/env/modules/bom/navigator.js +70 -0
  226. package/src/env/modules/bom/screen.js +26 -0
  227. package/src/env/modules/bom/storage.js +23 -0
  228. package/src/env/modules/dom/document.js +110 -0
  229. package/src/env/modules/dom/event.js +51 -0
  230. package/src/env/modules/index.js +34 -0
  231. package/src/env/modules/webapi/fetch.js +46 -0
  232. package/src/env/modules/webapi/url.js +47 -0
  233. package/src/env/modules/webapi/xhr.js +48 -0
  234. package/src/index.js +27 -0
  235. package/src/mcp/server.js +89 -0
  236. package/src/store/DataStore.js +708 -0
  237. package/src/store/Store.js +158 -0
  238. package/src/store/Validator.js +24 -0
  239. package/test/analyze.test.js +90 -0
  240. package/test/envdump.test.js +74 -0
  241. package/test/flow.test.js +90 -0
  242. package/test/hooks.test.js +138 -0
  243. package/test/plugin.test.js +35 -0
  244. package/test/refactor-full.test.js +30 -0
  245. package/test/refactor.test.js +21 -0
  246. package/test/samples/obfuscated.js +61 -0
  247. package/test/samples/original.js +66 -0
  248. package/test/samples/v10_eval_chain.js +52 -0
  249. package/test/samples/v11_bytecode_vm.js +81 -0
  250. package/test/samples/v12_polymorphic.js +69 -0
  251. package/test/samples/v1_ob_basic.js +98 -0
  252. package/test/samples/v2_ob_advanced.js +99 -0
  253. package/test/samples/v3_jjencode.js +77 -0
  254. package/test/samples/v4_aaencode.js +73 -0
  255. package/test/samples/v5_control_flow.js +86 -0
  256. package/test/samples/v6_string_encryption.js +71 -0
  257. package/test/samples/v7_jsvmp.js +83 -0
  258. package/test/samples/v8_anti_debug.js +79 -0
  259. package/test/samples/v9_proxy_trap.js +49 -0
  260. package/test/samples.test.js +96 -0
  261. package/test/webcrack.test.js +55 -0
@@ -0,0 +1,379 @@
1
+ /**
2
+ * DeepSpider - 调用栈分析器
3
+ * 入口点识别、函数调用图、数据流分析、参数追踪
4
+ */
5
+
6
+ import { parse } from '@babel/parser';
7
+ import traverse from '@babel/traverse';
8
+
9
+ export class CallStackAnalyzer {
10
+ constructor() {
11
+ this.ast = null;
12
+ this.code = '';
13
+ this.callGraph = new Map();
14
+ this.funcMap = new Map();
15
+ }
16
+
17
+ parse(code) {
18
+ this.code = code;
19
+ this.ast = parse(code, {
20
+ sourceType: 'unambiguous',
21
+ plugins: ['jsx', 'typescript', 'decorators-legacy'],
22
+ errorRecovery: true,
23
+ });
24
+ return this.ast;
25
+ }
26
+
27
+ // 识别入口点
28
+ findEntryPoints(code) {
29
+ const ast = this.parse(code);
30
+ const entries = [];
31
+
32
+ traverse.default(ast, {
33
+ CallExpression: (path) => {
34
+ const node = path.node;
35
+ // IIFE
36
+ if (node.callee.type === 'FunctionExpression' ||
37
+ node.callee.type === 'ArrowFunctionExpression') {
38
+ entries.push({
39
+ type: 'iife',
40
+ start: node.start,
41
+ loc: node.loc,
42
+ code: this.code.slice(node.start, Math.min(node.start + 50, node.end)) + '...'
43
+ });
44
+ }
45
+ // 常见入口调用
46
+ if (node.callee.type === 'Identifier') {
47
+ const name = node.callee.name;
48
+ if (['main', 'init', 'start', 'run', 'bootstrap', 'setup'].includes(name)) {
49
+ entries.push({ type: 'call', name, start: node.start, loc: node.loc });
50
+ }
51
+ }
52
+ // DOMContentLoaded / onload
53
+ if (node.callee.type === 'MemberExpression') {
54
+ const memberPath = this._getMemberPath(node.callee);
55
+ if (memberPath.includes('addEventListener') || memberPath.includes('onload')) {
56
+ entries.push({ type: 'event', path: memberPath, start: node.start, loc: node.loc });
57
+ }
58
+ }
59
+ },
60
+ ExpressionStatement: (path) => {
61
+ const node = path.node;
62
+ if (node.expression.type === 'CallExpression') {
63
+ const callee = node.expression.callee;
64
+ if (callee.type === 'Identifier') {
65
+ entries.push({
66
+ type: 'toplevel-call',
67
+ name: callee.name,
68
+ start: node.start,
69
+ loc: node.loc
70
+ });
71
+ }
72
+ }
73
+ }
74
+ });
75
+
76
+ return entries;
77
+ }
78
+
79
+ // 构建完整调用图(带调用者追踪)
80
+ buildCallGraph(code) {
81
+ const ast = this.parse(code);
82
+ this.callGraph.clear();
83
+ this.funcMap.clear();
84
+ const self = this;
85
+
86
+ // 单次遍历:收集函数定义并分析内部调用
87
+ traverse.default(ast, {
88
+ FunctionDeclaration(path) {
89
+ const node = path.node;
90
+ if (node.id) {
91
+ const funcName = node.id.name;
92
+ self.funcMap.set(funcName, {
93
+ node,
94
+ type: 'declaration',
95
+ params: node.params.map(p => self._getParamName(p))
96
+ });
97
+
98
+ // 收集函数内的调用
99
+ const calls = [];
100
+ path.traverse({
101
+ CallExpression(innerPath) {
102
+ const callNode = innerPath.node;
103
+ const callee = self._getCalleeName(callNode.callee);
104
+ if (callee) {
105
+ calls.push({
106
+ callee,
107
+ args: callNode.arguments.length,
108
+ argValues: callNode.arguments.map(a => self.code.slice(a.start, a.end)),
109
+ start: callNode.start,
110
+ loc: callNode.loc
111
+ });
112
+ }
113
+ }
114
+ });
115
+ self.callGraph.set(funcName, calls);
116
+ }
117
+ },
118
+ VariableDeclarator(path) {
119
+ const node = path.node;
120
+ if (node.id.type === 'Identifier' &&
121
+ (node.init?.type === 'FunctionExpression' ||
122
+ node.init?.type === 'ArrowFunctionExpression')) {
123
+ const funcName = node.id.name;
124
+ self.funcMap.set(funcName, {
125
+ node: node.init,
126
+ type: node.init.type === 'ArrowFunctionExpression' ? 'arrow' : 'expression',
127
+ params: node.init.params.map(p => self._getParamName(p))
128
+ });
129
+
130
+ // 收集函数内的调用
131
+ const calls = [];
132
+ path.traverse({
133
+ CallExpression(innerPath) {
134
+ const callNode = innerPath.node;
135
+ const callee = self._getCalleeName(callNode.callee);
136
+ if (callee) {
137
+ calls.push({
138
+ callee,
139
+ args: callNode.arguments.length,
140
+ argValues: callNode.arguments.map(a => self.code.slice(a.start, a.end)),
141
+ start: callNode.start,
142
+ loc: callNode.loc
143
+ });
144
+ }
145
+ }
146
+ });
147
+ self.callGraph.set(funcName, calls);
148
+ }
149
+ },
150
+ AssignmentExpression(path) {
151
+ const node = path.node;
152
+ if (node.left.type === 'Identifier' &&
153
+ (node.right.type === 'FunctionExpression' ||
154
+ node.right.type === 'ArrowFunctionExpression')) {
155
+ const funcName = node.left.name;
156
+ self.funcMap.set(funcName, {
157
+ node: node.right,
158
+ type: 'assigned',
159
+ params: node.right.params.map(p => self._getParamName(p))
160
+ });
161
+
162
+ // 收集函数内的调用
163
+ const calls = [];
164
+ path.traverse({
165
+ CallExpression(innerPath) {
166
+ const callNode = innerPath.node;
167
+ const callee = self._getCalleeName(callNode.callee);
168
+ if (callee) {
169
+ calls.push({
170
+ callee,
171
+ args: callNode.arguments.length,
172
+ argValues: callNode.arguments.map(a => self.code.slice(a.start, a.end)),
173
+ start: callNode.start,
174
+ loc: callNode.loc
175
+ });
176
+ }
177
+ }
178
+ });
179
+ self.callGraph.set(funcName, calls);
180
+ }
181
+ }
182
+ });
183
+
184
+ // 分析全局作用域的调用
185
+ const globalCalls = [];
186
+ traverse.default(ast, {
187
+ CallExpression: (path) => {
188
+ const node = path.node;
189
+ // 检查是否在函数内
190
+ let inFunction = false;
191
+ for (const [, funcInfo] of this.funcMap) {
192
+ if (node.start >= funcInfo.node.start && node.end <= funcInfo.node.end) {
193
+ inFunction = true;
194
+ break;
195
+ }
196
+ }
197
+ if (!inFunction) {
198
+ const callee = this._getCalleeName(node.callee);
199
+ if (callee) {
200
+ globalCalls.push({
201
+ callee,
202
+ args: node.arguments.length,
203
+ start: node.start,
204
+ loc: node.loc
205
+ });
206
+ }
207
+ }
208
+ }
209
+ });
210
+
211
+ if (globalCalls.length > 0) {
212
+ this.callGraph.set('__global__', globalCalls);
213
+ }
214
+
215
+ return this.callGraph;
216
+ }
217
+
218
+ _getCalleeName(callee) {
219
+ if (callee.type === 'Identifier') return callee.name;
220
+ if (callee.type === 'MemberExpression') return this._getMemberPath(callee);
221
+ return null;
222
+ }
223
+
224
+ _getMemberPath(node) {
225
+ if (!node) return '';
226
+ if (node.type === 'Identifier') return node.name;
227
+ if (node.type === 'ThisExpression') return 'this';
228
+ if (node.type === 'MemberExpression') {
229
+ const obj = this._getMemberPath(node.object);
230
+ const prop = node.computed
231
+ ? `[${node.property.name || node.property.value || '?'}]`
232
+ : (node.property.name || node.property.value);
233
+ return obj ? `${obj}.${prop}` : String(prop);
234
+ }
235
+ return '';
236
+ }
237
+
238
+ _getParamName(param) {
239
+ if (param.type === 'Identifier') return param.name;
240
+ if (param.type === 'RestElement') return `...${param.argument?.name || 'rest'}`;
241
+ if (param.type === 'AssignmentPattern') return param.left?.name || 'default';
242
+ return 'param';
243
+ }
244
+
245
+ // 追踪参数传递(向上追溯)
246
+ traceParameter(code, funcName, paramIndex) {
247
+ this.buildCallGraph(code);
248
+ const traces = [];
249
+
250
+ // 找到所有调用该函数的地方
251
+ for (const [caller, calls] of this.callGraph) {
252
+ for (const call of calls) {
253
+ if (call.callee === funcName && call.argValues[paramIndex]) {
254
+ traces.push({
255
+ caller,
256
+ argValue: call.argValues[paramIndex],
257
+ start: call.start,
258
+ loc: call.loc
259
+ });
260
+ }
261
+ }
262
+ }
263
+
264
+ return traces;
265
+ }
266
+
267
+ // 反向追踪:找到谁调用了指定函数
268
+ findCallers(code, targetFunc) {
269
+ this.buildCallGraph(code);
270
+ const callers = [];
271
+
272
+ for (const [caller, calls] of this.callGraph) {
273
+ for (const call of calls) {
274
+ if (call.callee === targetFunc) {
275
+ callers.push({
276
+ caller,
277
+ args: call.argValues,
278
+ start: call.start,
279
+ loc: call.loc
280
+ });
281
+ }
282
+ }
283
+ }
284
+
285
+ return callers;
286
+ }
287
+
288
+ // 正向追踪:找到指定函数调用了谁
289
+ findCallees(code, sourceFunc) {
290
+ this.buildCallGraph(code);
291
+ return this.callGraph.get(sourceFunc) || [];
292
+ }
293
+
294
+ // 构建完整调用链(从入口到目标)
295
+ buildCallChain(code, targetFunc) {
296
+ this.buildCallGraph(code);
297
+ const chains = [];
298
+
299
+ const dfs = (current, path, visited) => {
300
+ if (visited.has(current)) return;
301
+ visited.add(current);
302
+
303
+ const calls = this.callGraph.get(current) || [];
304
+ for (const call of calls) {
305
+ const newPath = [...path, { from: current, to: call.callee, args: call.argValues }];
306
+
307
+ if (call.callee === targetFunc) {
308
+ chains.push(newPath);
309
+ } else if (this.funcMap.has(call.callee)) {
310
+ dfs(call.callee, newPath, new Set(visited));
311
+ }
312
+ }
313
+ };
314
+
315
+ // 从全局和所有入口开始
316
+ dfs('__global__', [], new Set());
317
+ for (const [funcName] of this.funcMap) {
318
+ dfs(funcName, [], new Set());
319
+ }
320
+
321
+ return chains;
322
+ }
323
+
324
+ // 数据流分析:追踪变量在函数间的传递
325
+ traceDataFlow(code, varName) {
326
+ const ast = this.parse(code);
327
+ const flow = [];
328
+
329
+ traverse.default(ast, {
330
+ VariableDeclarator: (path) => {
331
+ const node = path.node;
332
+ if (node.id.type === 'Identifier' && node.id.name === varName && node.init) {
333
+ flow.push({
334
+ type: 'declaration',
335
+ value: this.code.slice(node.init.start, node.init.end),
336
+ start: node.start,
337
+ loc: node.loc
338
+ });
339
+ }
340
+ },
341
+ AssignmentExpression: (path) => {
342
+ const node = path.node;
343
+ const left = node.left.type === 'Identifier'
344
+ ? node.left.name
345
+ : this._getMemberPath(node.left);
346
+
347
+ if (left === varName || left.startsWith(varName + '.')) {
348
+ flow.push({
349
+ type: 'assignment',
350
+ target: left,
351
+ value: this.code.slice(node.right.start, node.right.end),
352
+ start: node.start,
353
+ loc: node.loc
354
+ });
355
+ }
356
+ },
357
+ CallExpression: (path) => {
358
+ const node = path.node;
359
+ // 检查变量是否作为参数传递
360
+ node.arguments.forEach((arg, idx) => {
361
+ if (arg.type === 'Identifier' && arg.name === varName) {
362
+ const callee = this._getCalleeName(node.callee);
363
+ flow.push({
364
+ type: 'passed-to',
365
+ callee,
366
+ argIndex: idx,
367
+ start: node.start,
368
+ loc: node.loc
369
+ });
370
+ }
371
+ });
372
+ }
373
+ });
374
+
375
+ return flow;
376
+ }
377
+ }
378
+
379
+ export default CallStackAnalyzer;
@@ -0,0 +1,289 @@
1
+ /**
2
+ * DeepSpider - 反混淆器
3
+ * 支持:obfuscator.io、sojson、JShaman 等常见混淆器
4
+ * 流程:字符串解码 → 控制流还原 → 死代码删除 → 变量重命名
5
+ */
6
+
7
+ export class Deobfuscator {
8
+ constructor() {
9
+ this.pipeline = [
10
+ 'unicode',
11
+ 'hex-string',
12
+ 'base64',
13
+ 'string-array',
14
+ 'control-flow',
15
+ 'deadcode',
16
+ 'simplify',
17
+ 'rename'
18
+ ];
19
+
20
+ // 常见混淆器特征
21
+ this.obfuscatorSignatures = {
22
+ 'obfuscator.io': [
23
+ /var _0x[a-f0-9]+\s*=\s*\[/,
24
+ /function _0x[a-f0-9]+\(_0x[a-f0-9]+,\s*_0x[a-f0-9]+\)/
25
+ ],
26
+ 'sojson': [
27
+ /sojson\.v\d/i,
28
+ /jsjiami\.com/i
29
+ ],
30
+ 'jshaman': [
31
+ /_\$_[a-zA-Z0-9]+/,
32
+ /\['\\x/
33
+ ],
34
+ 'jsfuck': [
35
+ /^\s*\[\]\[/,
36
+ /\(!?\[\]\+\[\]\)/
37
+ ]
38
+ };
39
+ }
40
+
41
+ // 标准化流程执行
42
+ runPipeline(code, steps = this.pipeline) {
43
+ let result = code;
44
+ const applied = [];
45
+
46
+ for (const step of steps) {
47
+ const before = result;
48
+ result = this._applyStep(result, step);
49
+ if (result !== before) {
50
+ applied.push(step);
51
+ }
52
+ }
53
+
54
+ return { code: result, applied };
55
+ }
56
+
57
+ _applyStep(code, step) {
58
+ switch (step) {
59
+ case 'unicode':
60
+ return this._deobfuscateUnicode(code).code;
61
+ case 'hex-string':
62
+ return this._deobfuscateHexStrings(code).code;
63
+ case 'base64':
64
+ return this._deobfuscateBase64(code).code;
65
+ case 'string-array':
66
+ return this._deobfuscateStringArray(code).code;
67
+ case 'control-flow':
68
+ return this._deobfuscateControlFlow(code).code;
69
+ case 'deadcode':
70
+ return this._removeDeadCode(code);
71
+ case 'simplify':
72
+ return this._simplifyCode(code);
73
+ case 'rename':
74
+ return this._renameVariables(code).code;
75
+ default:
76
+ return code;
77
+ }
78
+ }
79
+
80
+ // 识别混淆器类型
81
+ detectObfuscator(code) {
82
+ for (const [name, patterns] of Object.entries(this.obfuscatorSignatures)) {
83
+ if (patterns.some(p => p.test(code))) {
84
+ return name;
85
+ }
86
+ }
87
+ return 'unknown';
88
+ }
89
+
90
+ deobfuscate(code, type = 'auto') {
91
+ if (type === 'auto') {
92
+ type = this._detectType(code);
93
+ }
94
+
95
+ switch (type) {
96
+ case 'eval':
97
+ return this._deobfuscateEval(code);
98
+ case 'string-array':
99
+ return this._deobfuscateStringArray(code);
100
+ case 'hex-string':
101
+ return this._deobfuscateHexStrings(code);
102
+ case 'unicode':
103
+ return this._deobfuscateUnicode(code);
104
+ default:
105
+ return { code, type: 'unknown' };
106
+ }
107
+ }
108
+
109
+ _detectType(code) {
110
+ if (/eval\s*\(/.test(code)) return 'eval';
111
+ if (/\\x[0-9a-f]{2}/i.test(code)) return 'hex-string';
112
+ if (/\\u[0-9a-f]{4}/i.test(code)) return 'unicode';
113
+ if (/\[['"][^'"]+['"]\]/.test(code) && /0x[0-9a-f]+/i.test(code)) {
114
+ return 'string-array';
115
+ }
116
+ return 'unknown';
117
+ }
118
+
119
+ _deobfuscateEval(code) {
120
+ // 替换 eval 为返回内容
121
+ const replaced = code.replace(
122
+ /eval\s*\(([^)]+)\)/g,
123
+ '(function(){return $1})()'
124
+ );
125
+ return { code: replaced, type: 'eval' };
126
+ }
127
+
128
+ // Base64 解码
129
+ _deobfuscateBase64(code) {
130
+ let result = code;
131
+ // atob('xxx') 形式
132
+ result = result.replace(/atob\s*\(\s*['"]([A-Za-z0-9+/=]+)['"]\s*\)/g, (m, b64) => {
133
+ try {
134
+ return `"${Buffer.from(b64, 'base64').toString()}"`;
135
+ } catch { return m; }
136
+ });
137
+ return { code: result, type: 'base64' };
138
+ }
139
+
140
+ // 字符串数组还原(obfuscator.io 风格)
141
+ _deobfuscateStringArray(code) {
142
+ // 提取字符串数组
143
+ const arrayMatch = code.match(/var\s+(_0x[a-f0-9]+)\s*=\s*\[([\s\S]*?)\];/);
144
+ if (!arrayMatch) {
145
+ return { code, type: 'string-array', note: '未找到字符串数组' };
146
+ }
147
+
148
+ const arrayName = arrayMatch[1];
149
+ const arrayContent = arrayMatch[2];
150
+
151
+ // 解析数组内容
152
+ const strings = [];
153
+ const strRegex = /['"]([^'"]*)['"]/g;
154
+ let match;
155
+ while ((match = strRegex.exec(arrayContent)) !== null) {
156
+ strings.push(match[1]);
157
+ }
158
+
159
+ if (strings.length === 0) {
160
+ return { code, type: 'string-array', note: '数组为空' };
161
+ }
162
+
163
+ // 替换数组访问
164
+ let result = code;
165
+ const accessPattern = new RegExp(`${arrayName}\\[(0x[a-f0-9]+|\\d+)\\]`, 'gi');
166
+ result = result.replace(accessPattern, (m, idx) => {
167
+ const index = parseInt(idx, idx.startsWith('0x') ? 16 : 10);
168
+ if (index < strings.length) {
169
+ return `"${strings[index]}"`;
170
+ }
171
+ return m;
172
+ });
173
+
174
+ return { code: result, type: 'string-array', stringsFound: strings.length };
175
+ }
176
+
177
+ _deobfuscateHexStrings(code) {
178
+ const result = code.replace(/\\x([0-9a-f]{2})/gi, (m, hex) => {
179
+ return String.fromCharCode(parseInt(hex, 16));
180
+ });
181
+ return { code: result, type: 'hex-string' };
182
+ }
183
+
184
+ _deobfuscateUnicode(code) {
185
+ const result = code.replace(/\\u([0-9a-f]{4})/gi, (m, uni) => {
186
+ return String.fromCharCode(parseInt(uni, 16));
187
+ });
188
+ return { code: result, type: 'unicode' };
189
+ }
190
+
191
+ decodeStrings(code) {
192
+ const decoded = [];
193
+
194
+ // 解码 hex 字符串
195
+ code.replace(/\\x([0-9a-f]{2})/gi, (m, hex) => {
196
+ decoded.push({ type: 'hex', value: String.fromCharCode(parseInt(hex, 16)) });
197
+ return m;
198
+ });
199
+
200
+ // 解码 unicode
201
+ code.replace(/\\u([0-9a-f]{4})/gi, (m, uni) => {
202
+ decoded.push({ type: 'unicode', value: String.fromCharCode(parseInt(uni, 16)) });
203
+ return m;
204
+ });
205
+
206
+ return decoded;
207
+ }
208
+
209
+ // 删除死代码(冗余的 switch-case 结构)
210
+ _removeDeadCode(code) {
211
+ // 移除空的 switch 语句
212
+ let result = code.replace(
213
+ /switch\s*\([^)]+\)\s*\{\s*\}/g,
214
+ ''
215
+ );
216
+ // 移除连续空行
217
+ result = result.replace(/\n{3,}/g, '\n\n');
218
+ return result;
219
+ }
220
+
221
+ // 简化代码
222
+ _simplifyCode(code) {
223
+ let result = code;
224
+ // 简化 void 0 为 undefined
225
+ result = result.replace(/void\s+0/g, 'undefined');
226
+ // 简化 !0 为 true, !1 为 false
227
+ result = result.replace(/!0\b/g, 'true');
228
+ result = result.replace(/!1\b/g, 'false');
229
+ // 简化 1 == 1 为 true
230
+ result = result.replace(/1\s*===?\s*1/g, 'true');
231
+ result = result.replace(/0\s*===?\s*0/g, 'true');
232
+ // 简化字符串拼接
233
+ result = result.replace(/['"]\s*\+\s*['"]/g, '');
234
+ return result;
235
+ }
236
+
237
+ // 控制流平坦化还原
238
+ _deobfuscateControlFlow(code) {
239
+ // 检测 switch-case 控制流
240
+ const switchMatch = code.match(
241
+ /while\s*\(\s*!!\[\]\s*\)\s*\{\s*switch\s*\(\s*(\w+)\[(\w+)\+\+\]\s*\)/
242
+ );
243
+ if (!switchMatch) {
244
+ return { code, type: 'control-flow', note: '未检测到控制流平坦化' };
245
+ }
246
+ return { code, type: 'control-flow', note: '检测到控制流平坦化,需要动态分析' };
247
+ }
248
+
249
+ // 变量重命名(将 _0x 开头的变量重命名为可读名称)
250
+ _renameVariables(code) {
251
+ const varMap = new Map();
252
+ let counter = { var: 0, func: 0, param: 0 };
253
+
254
+ // 收集所有 _0x 开头的标识符
255
+ const pattern = /_0x[a-f0-9]+/gi;
256
+ const matches = code.match(pattern) || [];
257
+ const unique = [...new Set(matches)];
258
+
259
+ for (const name of unique) {
260
+ if (!varMap.has(name)) {
261
+ // 根据上下文推断类型
262
+ if (new RegExp(`function\\s+${name}`).test(code)) {
263
+ varMap.set(name, `func_${counter.func++}`);
264
+ } else {
265
+ varMap.set(name, `var_${counter.var++}`);
266
+ }
267
+ }
268
+ }
269
+
270
+ let result = code;
271
+ for (const [old, newName] of varMap) {
272
+ result = result.replace(new RegExp(old, 'g'), newName);
273
+ }
274
+
275
+ return { code: result, type: 'rename', renamed: varMap.size };
276
+ }
277
+
278
+ // 提取函数(按名称)
279
+ extractFunction(code, funcName) {
280
+ const pattern = new RegExp(
281
+ `function\\s+${funcName}\\s*\\([^)]*\\)\\s*\\{[^}]*\\}`,
282
+ 'g'
283
+ );
284
+ const matches = code.match(pattern);
285
+ return matches || [];
286
+ }
287
+ }
288
+
289
+ export default Deobfuscator;