-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.js
More file actions
114 lines (91 loc) · 3.55 KB
/
index.js
File metadata and controls
114 lines (91 loc) · 3.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
* ⚠️ PRIVACY RESEARCH USE ONLY
* For authorized testing environments that comply with all applicable laws.
* See: https://github.com/botswin/FunCaptcha-Privacy-Research/blob/main/DISCLAIMER.md
*/
// @ts-check
import { generate } from '@babel/generator';
import parser from '@babel/parser';
import axios from 'axios';
import fs from 'fs/promises';
import puppeteer from 'puppeteer';
import {
bindSingleArgCalls,
convertComputedToProperty,
evaluateAndInlineCalls,
inlineImmutableBindings,
mergeStringConcat,
removeArrayFunctions,
removeShuffleIIFE,
} from './utils.js';
const LANDING_URL = 'https://blizzard-api.arkoselabs.com/v2/2.16.0/enforcement.f845a08949c076f42e09da2c4b7496a6.html';
(async () => {
// Launch headless browser
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
// Enable request interception
await page.setRequestInterception(true);
/** @type {string} */
let originalScript;
page.on('request', async (request) => {
const url = request.url();
if (url === LANDING_URL) {
const { data: html } = await axios.get(url);
// remove Content-Security-Policy meta
let modifiedHtml = html.replace(/<meta http-equiv="Content-Security-Policy"[^>]*>/, '');
// remove attribute "integrity" from script tags
modifiedHtml = modifiedHtml.replace(/<script[^>]*integrity="[^"]*"[^>]*>/g, (match) => {
return match.replace(/ integrity="[^"]*"/, '');
});
// Respond with modified HTML
await request.respond({
status: 200,
contentType: 'text/html; charset=utf-8',
body: modifiedHtml,
});
return;
}
// Intercept any request matching "/enforcement.*.js"
if (/\/enforcement\..*\.js$/.test(url)) {
// Fetch the script via Axios
({ data: originalScript } = await axios.get(url));
// Perform AST transformation
let ast = parser.parse(originalScript);
inlineImmutableBindings(ast);
ast = bindSingleArgCalls(ast);
const modifiedScript = generate(ast, { retainLines: true }).code;
// Respond with modified script
await request.respond({
status: 200,
contentType: 'application/javascript; charset=utf-8',
body: modifiedScript,
});
return;
}
await request.continue();
});
await page.goto(LANDING_URL, { waitUntil: 'networkidle0' });
// Perform additional transformations
const ast = parser.parse(originalScript);
inlineImmutableBindings(ast);
bindSingleArgCalls(ast);
// Evaluate and inline function calls
await evaluateAndInlineCalls(page, ast);
mergeStringConcat(ast);
convertComputedToProperty(ast);
removeArrayFunctions(ast);
removeShuffleIIFE(ast);
const modifiedScript = generate(ast, { retainLines: false }).code;
// Save the modified script to a file
const outputPath = './funcaptcha.transformed.js';
const prettier = await import('prettier');
const prettierConfig = await prettier.resolveConfig(outputPath);
const formatted = await prettier.format(modifiedScript, {
...prettierConfig,
filepath: outputPath,
});
await fs.writeFile(outputPath, formatted, 'utf-8');
// Close the browser
await browser.close();
console.log(`Transformed script saved to ${outputPath}`);
})();