
PerimeterX के बाइटकोड VM के लिए रिवर्स इंजीनियरिंग टूलकिट, जिसमें CFG-आधारित डिस्सेम्बलर, 5-लेयर डिक्रिप्शन पाइपलाइन, ओपकोड टेबल पुनर्निर्माण, और बॉट डिटेक्शन फिंगरप्रिंटिंग पर सुरक्षा अनुसंधान के लिए स्टैक एमुलेशन क्लीनर शामिल है।
यह रिपॉजिटरी PerimeterX के auditor.js के रिवर्स इंजीनियरिंग का दस्तावेजीकरण करती है, जो एक बाइटकोड वर्चुअल मशीन है जो PX की बॉट डिटेक्शन पाइपलाइन में द्वितीयक फिंगरप्रिंटिंग परत के रूप में उपयोग होती है। यह विश्लेषण निम्नलिखित को कवर करता है:
नोट: यह रिपॉजिटरी केवल एक (स्थिर) VM संस्करण को कवर करती है और सुरक्षा अनुसंधान और विश्लेषण उद्देश्यों के लिए है। इसमें डायनामिक सॉल्वर या प्रोडक्शन सॉल्वर इम्प्लीमेंटेशन शामिल नहीं हैं।
गुरुवार, 2 अप्रैल 2026 को, PerimeterX ने अपनी बॉट डिटेक्शन पाइपलाइन के भाग के रूप में एक नया बाइटकोड VM तैनात किया।
auditor.js एक सामान्य PX सेंसर स्क्रिप्ट जैसा नहीं दिखता। सामान्य अस्पष्ट प्रॉपर्टी लुकअप और कलेक्टर फ़ंक्शन के बजाय:
_fg0 से _fg7 तक), एन्क्रिप्टेड VM प्रोग्राम चरों में विभाजित_dp) जिसमें प्रति-साइट कुंजी (_pk) प्रोग्राम JSON को अनपैक करती है_0x8df7) जो डिक्रिप्शन कुंजी प्राप्त करने के लिए VM के अपने स्रोत को हैश करता है, ताकि कोई भी संशोधन बाइटकोड डिक्रिप्शन को चुपचाप तोड़ देVM प्रोग्राम 8 चरों में विभाजित है, फिर _dp() के माध्यम से प्रति-साइट XOR सिफर का उपयोग करके डिक्रिप्ट किया जाता है, जो _pk द्वारा कुंजीबद्ध है:
var _pk = 893686289;
function _dp(_b) {
var _r = atob(_b), _o = new Array(_r.length);
for (var _i = 0; _i < _r.length; _i++) {
_o[_i] = String.fromCharCode(
_r.charCodeAt(_i) ^ (((_pk >>> (8 * (_i % 4))) ^ Math.imul(_i + 1, 0x6B8B4567)) & 0xFF)
);
}
return _o.join("");
}
परिणाम अस्पष्ट दो-अक्षर की-नामों वाला एक JSON ऑब्जेक्ट है (जैसे, बीज के लिए "uo", नॉन्स के लिए "dk")। एक मैपिंग तालिका उन्हें मानक नामों में परिवर्तित करती है।
node extractor.js
# -> program.json
सभी 1095 स्ट्रिंग कॉन्स्टेंट्स दो परतों के साथ एन्क्रिप्टेड हैं:
परत 1: 4008000571 द्वारा कुंजीबद्ध स्थिर मरमर XOR, स्थिति-निर्भर।
परत 2: PRNG स्ट्रीम XOR एक glibc LCG का उपयोग करके, प्रोग्राम बीज को नथ के गुणक हैश के माध्यम से प्रत्येक कॉन्स्टेंट के इंडेक्स के साथ मिलाकर बीजित किया जाता है।
डिक्रिप्शन से पहले, बीज को पर्यावरण फिंगरप्रिंट (_0xaf48) के साथ XOR किया जाता है, एक 8-बिट बिटमास्क जो ब्राउज़र API की जांच करके गणना की जाती है:
Chrome के लिए: _0xaf48 = 0b01111111 = 127, जो प्रभावी बीज = 12755 ^ 127 = 12716 देता है।
इसका अर्थ है कि एक ही प्रोग्राम विभिन्न वातावरणों में अलग-अलग डिक्रिप्शन परिणाम उत्पन्न करता है। इसे Node.js बनाम Chrome बनाम Firefox में चलाने पर अलग-अलग बीज प्राप्त होते हैं।
node decrypt_constants.js
# -> program_decrypted.json, constants_table.txt
डिक्रिप्ट की गई स्ट्रिंग्स हमें बताती हैं कि VM वास्तव में क्या फिंगरप्रिंट करता है:
ब्राउज़र फिंगरप्रिंटिंग: screenWidth, screenHeight, innerWidth, innerHeight, devicePixelRatio, colorDepth, platform, userAgent, language, timezone, timezoneOffset, forcedColors, highContrast
प्रदर्शन समय: navigationStart, domComplete, domLoading, fetchStart, requestStart, responseEnd, secureConnectionStart, serverTiming
RSA क्रिप्टोग्राफी: BigInt, modPow, AQAB (65537 बेस64 में), modulusLength, shiftLeft, shiftRight, getRandomValues
DOM/SVG जांच: http://www.w3.org/2000/svg, createElementNS, getBoundingClientRect, getTotalLength, getBBox
PX फील्ड नाम: mtr, tst, mst, enc, sbx, fstec, pdc, prb, wvi, wva, pti, dis, los, cv, sc, jd, , ,
एंडपॉइंट संदर्भ: https://fst-ec.perimeterx.net/?id=
एंटी-डीबगर: _CMP_RCX_07;_JNZ_0x0A_EB_CC, CC|CD-04|BREAKPOINT-005
पूर्ण JavaScript भाषा को कवर करने वाले 107 आधार ऑपकोड, साथ ही गतिशील रूप से उत्पन्न शोर:
40 हनी ऑपकोड गणितीय रूप से समकक्ष लेकिन वाक्य रचनात्मक रूप से भिन्न अभिव्यक्तियों का उपयोग करके अंकगणित/तुलना संचालन के वैकल्पिक कार्यान्वयन हैं। ADD (a^b) + 2*(a&b) या -((-a)-b) या a-(-b) के रूप में प्रकट हो सकता है। प्रत्येक आधार ऑपकोड में बीज से नियतात्मक रूप से उत्पन्न 3 प्रकार तक हो सकते हैं। एक साधारण ADD निर्देश एक ही प्रोग्राम के भीतर 4 अलग-अलग बाइटकोड मानों के रूप में प्रकट हो सकता है, जो पैटर्न-मिलान दृष्टिकोण को तोड़ता है।
24 पैडिंग ऑपकोड क्रमचय में आवंटित होते हैं लेकिन उनके कोई हैंडलर नहीं होते और कभी उत्सर्जित नहीं होते। वे ऑपकोड स्थान का विस्तार करने और शफल को उलटना कठिन बनाने के लिए मौजूद हैं।
16 सुपरइंस्ट्रक्शन समूह सबसे महत्वपूर्ण एंटी-एनालिसिस विशेषता हैं। जब डिस्पैच लूप एक ऑपकोड को सुपरइंस्ट्रक्शन लीडर के रूप में हल करता है, तो हैंडलर बाइटकोड स्ट्रीम से एक अतिरिक्त बाइट पढ़ता है और एक उप-हैंडलर को डिस्पैच करता है। उप-हैंडलर पूरी तरह से अलग ऑपरेशन हो सकता है:
ऑपकोड तालिका प्रभावी बीज द्वारा बीजित फिशर-येट्स के माध्यम से शफल की जाती है, इसलिए बाइटकोड मान प्रति बिल्ड भिन्न होते हैं।
node build_opcodes.js
# -> opcode_table.json, opcode_table.txt
टूलकिट का मूल। cfg.js PC=0 से सभी निष्पादन पथों का अनुसरण करके, सही एन्क्रिप्शन संदर्भ के साथ प्रत्येक निर्देश को डिकोड करके एक नियंत्रण प्रवाह ग्राफ बनाता है।
PX ब्लॉक सीमाओं पर ओवरलैपिंग निर्देशों का उपयोग करता है। एक ही बाइट एक निष्पादन पथ पर ऑपरेंड के रूप में और दूसरे पर ऑपकोड के रूप में डीकोड होते हैं, जो ब्लॉक एन्क्रिप्शन संदर्भ पर निर्भर करता है। एक रैखिक स्कैन प्रत्येक बाइट स्थिति को एक बार डीकोड करता है और वैकल्पिक पथ को छोड़ देता है। CFG फॉल-थ्रू और जंप दोनों किनारों का अनुसरण करता है, प्रत्येक पथ को स्वतंत्र रूप से डीकोड करता है।
_0x3ca8): कच्चे बेस64 बाइट्स पर स्थिर मरमर XOR, 4008000571 द्वारा कुंजीबद्ध_0xece1): दो उप-परतों के साथ प्रति-फ़ंक्शन XOR: स्थिति-निर्भर स्थिर कुंजी + कोड इंटीग्रिटी हैश कुंजी_0x427d): प्रति-ब्लॉक रोलिंग XOR। प्रत्येक एन्क्रिप्शन ब्लॉक (fn.bl सीमाओं द्वारा परिभाषित) को फ़ंक्शन कुंजी और ब्लॉक इंडेक्स से प्राप्त एक अतिरिक्त XOR मिलता है। ब्लॉक 0 पहले एक्सेस पर अनएन्क्रिप्टेड है; ब्लॉक 1+ एन्क्रिप्टेड हैं। यही कारण है कि एक रैखिक डिसअसेंबलर पहले ब्लॉक के लिए काम करता है लेकिन बाद के ब्लॉक के लिए कचरा उत्पन्न करता है।CFG सभी पाँच परतों को गैर-विनाशकारी रूप से लागू करता है (ऑपरेंड XOR ऑन-द-फ्लाई गणना, इन-प्लेस नहीं) ताकि ओवरलैपिंग निर्देश क्षेत्र एक-दूसरे को दूषित न करें।
प्रत्येक सुपरइंस्ट्रक्शन लीडर के लिए, CFG उप-बाइट पढ़ता है, super_groups.json में वास्तविक हैंडलर देखता है, और वास्तविक ऑपकोड के लिए ऑपरेंड डीकोड करता है। फ्यूज्ड जंप ऑपकोड (जैसे, जो ASSIGN_OP_VAR जैसा दिखता है लेकिन वास्तव में JMP है) से जंप लक्ष्य सही ढंग से अनुसरण किए जाते हैं।
node cfg.js # सभी फ़ंक्शन -> cfg_output/
node cfg.js 79 # एकल फ़ंक्शन stdout पर
ब्राउज़र निष्पादन ट्रेस के विरुद्ध सत्यापित: 14 फ़ंक्शनों में 600 निर्देश ट्रेस किए गए, स्टैक डेल्टा में 0 बेमेल। सभी 34 अद्वितीय ऑपकोड मान्य किए गए। सुपरइंस्ट्रक्शन डिस्पैच इनिशियलाइज़ेशन के दौरान निष्पादित सभी 10 लीडर समूहों के लिए सही पुष्टि की गई।
CFG आउटपुट लेता है और अभिव्यक्ति टिप्पणियाँ उत्पन्न करने के लिए स्टैक इम्यूलेशन चलाता है। कच्चे बाइटकोड को पठनीय स्यूडो-कोड में बदलता है।
node cleaner.js 79 # fn79 stdout पर
एक आभासी स्टैक को ट्रैक करते हुए क्रम में निर्देशों पर चलता है। प्रत्येक पुश/पॉप/कॉल एक अभिव्यक्ति स्ट्रिंग बनाता है:
0018 GET_VAR ; 0.0001
001e GET_VAR ; or
0024 PUSH_CONST ; "_0x166"
002b CALL_METHOD_C ; 0.0001._0x88(or, "_0x166")
...
0114 PUSH_CONST ; "fontSize"
011b PUSH_CONST ; "pdc"
0122 CALL_METHOD_C ; _0x18c.getHours("fontSize", "pdc")
केवल खाली स्टैक पर शुद्ध अंकगणित/तुलना शोर को दबाया जाता है। बाकी सब कुछ रखा जाता है क्योंकि CFG ने पहले ही हनी और पैडिंग को फ़िल्टर कर दिया है।
112 फ़ंक्शन, 5435 निर्देश रखे गए, 207 शोर दबाया गया। fn79 (फिंगरप्रिंट कलेक्टर, 1109 निर्देश) में 85% अभिव्यक्ति टिप्पणी कवरेज है।
256-स्लॉट स्टैक, स्कोप चेन, try/catch हैंडलर चेन, और for-in इटरेटर स्टैक के साथ स्टैक-आधारित VM। डिस्पैच लूप 2-बाइट LE ऑपकोड पढ़ता है, क्रमचय + स्थिति XOR + ब्लॉक ऑफ़सेट के माध्यम से हल करता है, ऑपरेंड को इन-प्लेस डिक्रिप्ट करता है, हैंडलर निष्पादित करता है, फिर ऑपरेंड को पुनः एन्क्रिप्ट करता है ताकि बाइटकोड मेमोरी में कभी पूरी तरह से डिक्रिप्ट न हो।
BigInt, modPow, घातांक 65537 का उपयोग करके फिंगरप्रिंट आउटपुट का RSA एन्क्रिप्शनgetTotalLength() और getBBox() के माध्यम से SVG रेंडरिंग फिंगरप्रिंटिंगperformance.timing वॉटरफॉल संग्रहCC|CD-04|BREAKPOINT-005)कोड का दस्तावेजीकरण करने, टूलिंग लिखने और इस readme का मसौदा तैयार करने में AI का उपयोग किया गया है।
पूरी तरह से शैक्षिक/सुरक्षा अनुसंधान के लिए। कोई सॉल्वर या बाईपास नहीं, केवल यह दस्तावेजीकरण किया जा रहा है कि VM कैसे काम करता है क्योंकि यह वास्तव में दिलचस्प है।
यदि PerimeterX/HUMAN Security के किसी भी व्यक्ति को इस रिपॉजिटरी के बारे में कोई चिंता है, तो कृपया संपर्क करें: [email protected]
| फील्ड | विवरण |
|---|
s | बीज (12755), सभी क्रिप्टोग्राफिक संचालन को संचालित करता है |
n | नॉन्स (1603730985), प्रति-प्रोग्राम यादृच्छिकीकरण |
g | जनरेटर फ्लैग, इंटीग्रिटी हैश डिक्रिप्शन परत को सक्षम करता है |
x | एन्क्रिप्टेड फ्लैग, कॉन्स्टेंट्स XOR-एन्क्रिप्टेड हैं |
c | कॉन्स्टेंट्स पूल, 1230 प्रविष्टियाँ |
f | फ़ंक्शन, 112 प्रविष्टियाँ एन्क्रिप्टेड बाइटकोड के साथ |
e | एंट्री पॉइंट, फ़ंक्शन इंडेक्स 0 |
| बिट | परीक्षण | Chrome |
|---|
| 0 | typeof window.matchMedia === "function" | 1 |
| 1 | document.elementFromPoint मौजूद है | 1 |
| 2 | typeof window.requestAnimationFrame === "function" | 1 |
| 3 | typeof window.getComputedStyle === "function" | 1 |
| 4 | CSS.supports मौजूद है | 1 |
| 5 | navigator.sendBeacon मौजूद है | 1 |
| 6 | document.execCommand मौजूद है | 1 |
| 7 | process.versions.node मौजूद है (Node.js) | 0 |
adsenveinit| लीडर के रूप में हल होता है | उप-बाइट | वास्तव में निष्पादित होता है |
|---|
FOR_IN_NEXT | 74 | FOR_IN_NEXT |
FOR_IN_NEXT | 100 | MAKE_CLOSURE |
ASSIGN_OP_VAR | 165 | ASSIGN_OP_VAR |
ASSIGN_OP_VAR | 37 | JMP |
GET_VAR_PROP_C | 143 | SET_VAR_POP |
GET_VAR_PROP_C | 23 | JMP_NULLISH |