Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
zyrox — Zyrox: LLVM based, compile-time obfuscator plugin. | Kitploit
उपकरण/GitHubGitHub/peterhackz/zyrox
Static AnalysisCode AnalysisReverse EngineeringBinary AnalysisPapers & ResearchLearning & EducationLearning Paths & Courses
GitHubpeterhackz/zyrox

zyrox

Zyrox: LLVM based, compile-time obfuscator plugin.

रिपॉजिटरी देखें
94116 महीने पहलेKitploit द्वारा समीक्षित

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें
वेबसाइट

Zyrox LLVM Obfuscator

नेटिव कोड को अस्पष्ट करने के लिए llvm कंपाइल और लिंक-टाइम प्लगइन

क्यों

क्यों नहीं ¯\_(ツ)_/¯

मेरी सबसे बड़ी परियोजनाओं में से एक, जहाँ मैंने LLVM के आंतरिक, बाइनरी फ़ॉर्मेट, असेंबली और अस्पष्टीकरण तकनीकों के बारे में बहुत कुछ सीखा।

मेरा मानना है कि निर्माण करते हुए सीखना सबसे अच्छा तरीका है, इसलिए मैंने इन विषयों के बारे में और अधिक जानने के लिए यह परियोजना बनाई।

शोध

मैंने Zyrox के पीछे की अवधारणाओं को समझाते हुए 4 ब्लॉग लिखे हैं:

  • भाग I: Zyrox का निर्माण: एक कस्टम LLVM Obfuscator
  • भाग II: कंट्रोल फ्लो फ़्लैटनिंग
  • भाग III: एन्क्रिप्टेड जंप टेबल्स
  • भाग IV: समापन

ये भाग इस रीडमे से अधिक गहराई में जाते हैं, और यदि आप इस विषय में रुचि रखते हैं तो निश्चित रूप से पढ़ने लायक हैं।

बिल्डिंग

टेम्पलेट से (त्वरित प्रारंभ, अनुशंसित)

यह उन लोगों के लिए है जो Zyrox का त्वरित परीक्षण करना चाहते हैं, या सीखना चाहते हैं कि इसे cmake प्रोजेक्ट में कैसे एकीकृत किया जाए।

Zyrox Template रेपो में दिए गए चरणों का पालन करें।

स्रोत से

llvm इंस्टॉल करें:

root@kitploit:~
sudo apt update
sudo apt install llvm-18 llvm-18-dev clang-18

zyrox को क्लोन और कंपाइल करें:

root@kitploit:~
git clone --recurse-submodules https://github.com/PeterHackz/zyrox.git
cd zyrox
cmake -S . -B build -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++
cmake --build build --parallel 4

पायथन (पोस्ट-कंपाइल) प्लगइन सेटअप

सुनिश्चित करें कि आपके पास python3 और pip इंस्टॉल है।

एक वातावरण सेटअप करें (अनुशंसित)

root@kitploit:~
# एक वर्चुअल एनवायरनमेंट बनाएं
python3 -m venv .venv

# एनवायरनमेंट को सक्रिय करें
source .venv/bin/activate

pip install -r requirements.txt

वैश्विक रूप से इंस्टॉल करें

root@kitploit:~
pip install -r requirements.txt

उपयोग

त्वरित उपयोग

root@kitploit:~
clang -O0 -flto=full -c main.c -o out/main.o
clang -flto=full -fuse-ld=lld -Wl,--load-pass-plugin=./build/libzyrox.so out/main.o -o out/main

अस्पष्टीकरण के बाद, जंप टेबल को एन्क्रिप्ट करने के लिए PyPlugin.py चलाएँ:

root@kitploit:~
# यदि आपने एक वर्चुअल एनवायरनमेंट में डिपेंडेंसी इंस्टॉल की है, तो पहले इसे सक्रिय करें:
source .venv/bin/activate
#  फिर इसके साथ चलाएँ:
python PyPlugin.py --in=<input_file> [--out=<output_file>] [--tables=<zyrox_tables_file>] [--android]

CMake के साथ

CMake एकीकरण के उदाहरण के लिए Zyrox Template रेपो देखें।

संपर्क

मुझे पता है कि यह एक जटिल विषय है, और यह परियोजना अधिकतर शैक्षिक उद्देश्यों के साथ-साथ BSD Brawl की सेवा के लिए थी। यदि आपका कोई प्रश्न है, या बस बातचीत करना चाहते हैं, तो बेझिझक मुझसे संपर्क करें:

  • डिस्कॉर्ड: @s.b
  • ईमेल: [email protected] या [email protected]
  • डिस्कॉर्ड सर्वर

पुल रिक्वेस्ट या इश्यू के माध्यम से कोई भी मदद सराहनीय है!

यह कैसे काम करता है

ZyroxPlugin.cpp पास को रजिस्टर करता है, फिर siphash (इस पर बाद में अधिक) को लिंक करता है और स्ट्रिंग्स को एन्क्रिप्ट करने के लिए StringEncryption को कॉल करता है। हम स्ट्रिंग्स को जल्दी एन्क्रिप्ट करने का कारण यह है कि बाद में डिक्रिप्शन लॉजिक भी अस्पष्ट हो जाए।

फिर यह ModuleUtils::ExpandCustomAnnotations और QuickConfig::RegisterPasses को कॉल करता है ताकि सभी __attribute__((annotate("..."))) एक्सप्रेशन को पार्स किया जा सके और QuickJs कॉन्फ़िग (जो ZyroxConfig.js में स्थित है) चलाया जा सके।

प्रत्येक फ़ंक्शन को ZyroxCore.cpp में स्थित Zyrox::RunOnFunction को कॉल करके अस्पष्ट किया जाता है, भविष्य में इसके बारे में अधिक दस्तावेज़ उपलब्ध कराए जाएंगे।

अतिरिक्त उपयोगिता

स्विच जंप टेबल और PHI नोड्स बनाते हैं, इनसे निपटना कष्टप्रद है, इसलिए हम इन्हें क्रमशः समतल करने (if स्टेटमेंट में) और अवनत करने के लिए FunctionUtils और BasicBlockUtils का उपयोग करते हैं।

पासेस

अरे यार, मैं कहाँ से शुरू करूँ

  • बेसिक ब्लॉक स्प्लिटर
  • कंट्रोल फ्लो फ़्लैटनिंग
  • अप्रत्यक्ष ब्रांचिंग
  • सरल अप्रत्यक्ष ब्रांचिंग
  • मिश्रित बूलियन अंकगणित

सभी js-प्लगइन तर्क index.d.ts में हैं, इसलिए इस दस्तावेज़ में उनके बारे में बात नहीं की जाएगी।

एनोटेशन दस्तावेज़ के लिए, यहाँ क्लिक करें

बेसिक ब्लॉक स्प्लिटर

यह पास एक बेसिक ब्लॉक को छोटे ब्लॉकों में विभाजित और फेरबदल करता है। मान लीजिए हमारे पास यह है:

root@kitploit:~
int __test_fn(int x)
{
    if (x == 2) {
        printf("x is 2\n");
    } else {
        printf("x is not 2!, x is: %d\n", x);
    }
    return x + 4 * x - 2 / 4;
}

जो इस प्रकार कंपाइल होता है:

root@kitploit:~
define internal i32 @__test_fn(i32 noundef %0) #0 !zyrox !8 !obfuscated !11 {
  %2 = alloca i32, align 4
  store i32 %0, ptr %2, align 4
  %3 = load i32, ptr %2, align 4
  %4 = icmp eq i32 %3, 2
  br i1 %4, label %5, label %7

5:                                                ; preds = %1
  %6 = call i32 (ptr, ...) @printf(ptr noundef @.str.1)
  br label %10

7:                                                ; preds = %1
  %8 = load i32, ptr %2, align 4
  %9 = call i32 (ptr, ...) @printf(ptr noundef @.str.2, i32 noundef %8)
  br label %10

10:                                               ; preds = %7, %5
  %11 = load i32, ptr %2, align 4
  %12 = load i32, ptr %2, align 4
  %13 = mul nsw i32 4, %12
  %14 = add nsw i32 %11, %13
  %15 = sub nsw i32 %14, 0
  ret i32 %15
}

जब इस कॉन्फ़िग के साथ बेसिक ब्लॉक स्प्लिटर का उपयोग किया जाता है:

root@kitploit:~
z.RegisterPass(ObfuscationType.BasicBlockSplitter, {
    PassIterations: 1,
    "BasicBlockSplitter.SplitBlockChance": 100,
    "BasicBlockSplitter.SplitBlockMinSize": 2,
    "BasicBlockSplitter.SplitBlockMaxSize": 5,
});

यह बन जाता है:

root@kitploit:~
define internal i32 @__test_fn(i32 noundef %0) #0 !zyrox !8 !obfuscated !11 {
  %2 = alloca i32, align 4
  store i32 %0, ptr %2, align 4
  %3 = load i32, ptr %2, align 4
  %4 = icmp eq i32 %3, 2
  br i1 %4, label %5, label %14

5:                                                ; preds = %1
  %6 = call i32 (ptr, ...) @printf(ptr noundef @.str.1)
  br label %7

7:                                                ; preds = %14, %5
  %8 = load i32, ptr %2, align 4
  %9 = load i32, ptr %2, align 4
  %10 = mul nsw i32 4, %9
  %11 = add nsw i32 %8, %10
  br label %12

12:                                               ; preds = %7
  %13 = sub nsw i32 %11, 0
  ret i32 %13

14:                                               ; preds = %1
  %15 = load i32, ptr %2, align 4
  %16 = call i32 (ptr, ...) @printf(ptr noundef @.str.2, i32 noundef %15)
  br label %7
}

अब यह इतने छोटे फ़ंक्शन के लिए बहुत अलग नहीं होगा, लेकिन ध्यान दें कि इसने एक बेसिक ब्लॉक को कैसे विभाजित किया? यह अन्य पासों जैसे कंट्रोल फ्लो फ़्लैटनिंग के साथ संयुक्त होने पर सहायक है।

कंट्रोल फ्लो फ़्लैटनिंग

अरे, इस पास में सभी की तुलना में सबसे अधिक सुविधाएँ हैं! मैं यह समझाकर शुरू करूँगा कि यह कैसे काम करता है, फिर इसका कॉन्फ़िग। मान लीजिए हमारे पास यह कोड है:

root@kitploit:~
LABEL_A: bool b = x == 2;
         IF EQ: goto LABEL_B
         goto LABEL_C
LABEL_B  do_stuff()
LABEL_C  do_other_stuff()
         goto LABEL_A

प्रत्येक बेसिक ब्लॉक (A, B और C) को एक अद्वितीय डिस्पैचर स्थिति (state) दी जाती है, उदाहरण: (सरलीकृत)

root@kitploit:~
states = {
    1: LABEL_A,
    2: LABEL_B,
    3: LABEL_C,
};

फिर हम एक डिस्पैचर ब्लॉक इंजेक्ट करते हैं जो सब कुछ नियंत्रित करता है और कोड बन जाता है:

root@kitploit:~
         int state = 0;
LABEL_D  goto LABEL_CA // डिस्पैचर लेबल पहली शर्त ब्लॉक, लेबल कंडीशन A पर जाता है
LABEL_CA if state == 1: goto LABEL_A
         // यदि 1 नहीं है, तो जाँचें कि क्या यह लेबल B है (फ़ॉलबैक)
LABEL_CB if state == 2: goto LABEL_B
LABEL_CC if state == 3: goto LABEL_CC
         // अप्राप्य (unreachable)
         goto LABEL_D
LABEL_A: bool b = x == 2;
         // IF EQ: goto LABEL_B
         // goto LABEL_C
         state = 2 if b else 3 // जिस ब्लॉक पर जाना है उसके लिए स्थिति अपडेट करें और वापस डिस्पैचर पर जाएँ
         goto LABEL_D
LABEL_B  do_stuff()
LABEL_C  do_other_stuff()
         state = 1
         goto LABEL_D

अब इसमें कुछ कमियाँ हैं जिन्हें अस्पष्टकर्ता ठीक करता है। जैसा कि आप देखते हैं, चूँकि हमारे पास एक ही डिस्पैचर वेरिएबल है, इसलिए इसे डी-अस्पष्ट करना आसान है क्योंकि हम जानते हैं कि स्थिति सेट करने के बाद एक ब्लॉक कहाँ जा रहा है। ठीक करना आसान है!

root@kitploit:~
z.RegisterPass(ObfuscationType.ControlFlowFlattening, {
    PassIterations: 1,
    "ControlFlowFlattening.UseFunctionResolverChance": 60,
    "ControlFlowFlattening.UseGlobalStateVariablesChance": 60,
    "ControlFlowFlattening.UseOpaqueTransformationChance": 40,
    "ControlFlowFlattening.UseGlobalVariableOpaquesChance": 80,
    "ControlFlowFlattening.UseSipHashedStateChance": 40,
    "ControlFlowFlattening.CloneSipHashChance": 80,
});

आइए विकल्पों पर एक-एक करके चर्चा करें:

  • UseFunctionResolverChance: स्थिति की जाँच करने के लिए एक फ़ंक्शन इंजेक्ट करता है, इसलिए if (state == expected_state) करने के बजाय, यह if (injected_resolver(state)) करता है। उदाहरण:
    root@kitploit:~
    bool __fastcall cff_resolve_state_check_3585(__int64 a1)
    {
        return a1 == 0x288A6154F8A5E3E2LL;
    }
    
  • UseGlobalStateVariablesChance: तुलना किए जाने वाले स्थिति मान को एक वैश्विक चर में सहेजें:
    root@kitploit:~
    bool __fastcall cff_resolve_state_check_506(__int64 a1)
    {
        return a1 == qword_1B20D8;
    }
    
  • UseOpaqueTransformationChance: जाँच को किसी ऐसे रूपांतरण में अस्पष्ट करें जो केवल एक विशिष्ट स्थिति के लिए सत्य देगा:
    root@kitploit:~
    bool __fastcall cff_resolve_state_check_7901(__int64 a1)
    {
        return ((((a1 ^ 0xEA9E45BB6099BC6ELL) + qword_1C64D8) << qword_1A63F0)
                   | (((a1 ^ 0xEA9E45BB6099BC6ELL)
                       + qword_1C64D8) >> qword_1ACE98)) == qword_1B0B80;
    }
    
  • UseGlobalVariableOpaquesChance: करते समय संख्या के बजाय एक वैश्विक चर का उपयोग करें, जैसा कि आपने ऊपर दिए गए उदाहरण में देखा। (, , )

अप्रत्यक्ष ब्रांचिंग

मान लीजिए हमारे पास यह कोड है:

root@kitploit:~
if (x == 2) goto LABEL_A
            goto LABEL_B
LABEL_A:    do_stuff()
LABEL_B:    // ...

यह इसमें रूपांतरित होगा:

root@kitploit:~
@global jump_table = {0, &LABEL_A, &LABEL_B};
if (x == 2) goto jump_table[0] + @inline(decrypt(jump_table[1]));
            goto jump_table[0] + @inline(decrypt(jump_table[2]));
// ...

जब इस पास का उपयोग किया जाता है, तो प्लगइन एक zyrox_tables.txt फ़ाइल आउटपुट करेगा जिसका उपयोग PyPlugin.py द्वारा किया जाएगा।

PyPlugin.py जंप टेबल को एन्क्रिप्ट करेगा और रिलोकेशन एंट्री को पैच करेगा, फिर रिलोकेटर को प्रत्येक तालिका के jump_table[0] की ओर इंगित करेगा। एक रिलोकेटर मूल रूप से यह करता है: target.writePointer(base.add(value)), इसलिए value को 0 पर सेट करके, हम रिलोकेटर को हमें बेस एड्रेस देने और रनटाइम पर इसे जंप टेबल में डालने देते हैं, और हम goto के साथ इसका उपयोग करके रनटाइम एड्रेस उत्पन्न करते हैं। arm32 थंब मोड पर पास डिक्रिप्शन के बाद स्वचालित रूप से | 1 जोड़ता है।

PyPlugin.py का उपयोग करने के लिए बस निम्नलिखित करें:

(यदि venv का उपयोग कर रहे हैं, तो पहले इसे सक्रिय करें)

root@kitploit:~
python3 PyPlugin.py --in <out_obfuscated_file> --android

यदि आप arm64 संस्करण को लक्षित कर रहे हैं तो --android पास करना महत्वपूर्ण है क्योंकि x86_64 संस्करण में एक अलग रिलोकेटर सिग्नेचर है।

आप --out भी पास कर सकते हैं (डिफ़ॉल्ट रूप से यह --in में दी गई फ़ाइल का ही उपयोग करेगा) और आप --tables पास कर सकते हैं (डिफ़ॉल्ट रूप से यह zyrox_tables.txt है)।

सरल अप्रत्यक्ष ब्रांचिंग

जबकि अप्रत्यक्ष ब्रांचिंग अच्छी लगती है, यह रनटाइम पर पॉइंटर्स को डिक्रिप्ट करने के कारण प्रदर्शन हिट के साथ आती है, यह एक सरल संस्करण है जो प्रदर्शन को प्रभावित नहीं करता, जहाँ यह:

root@kitploit:~
if (x == 2) goto LABEL_A
            goto LABEL_B
LABEL_A:    do_stuff()
LABEL_B:    // ...

बन जाता है:

root@kitploit:~
            @stack jump_table = {&LABEL_B, &LABEL_A}
            goto jump_table[!(x == 2)]
LABEL_A:    do_stuff()
LABEL_B:    // ...

हालाँकि यह सरल और आसानी से तोड़ने योग्य लगता है (मैं सहमत हूँ), यह IDA और Ghidra को तोड़ने के लिए पर्याप्त है, बिना प्रदर्शन को प्रभावित किए।

मिश्रित बूलियन अंकगणित

जिसे MBA Sub (मिश्रित बूलियन अंकगणित प्रतिस्थापन) के रूप में भी जाना जाता है, सरल ऑपरेशनों को जटिल ऑपरेशनों में बदलता है जो समान आउटपुट देते हैं। यह पूर्व-परिभाषित सेट का उपयोग करता है। उदाहरण:

root@kitploit:~
a ^ b = (~a & b) | (a & ~b)
b * c = (((b | c) * (b & c)) + ((b & ~c) * (c &  ~b)))
r = rand(); c = b + r; a = a + c; a = a - r

यदि आप रुचि रखते हैं तो आप Passes/MBASub.cpp में पूरी सूची देख सकते हैं।

Zyrox एनोटेशन

बस index.d.ts देखें। एनोटेशन पार्सर उसी क्रम का उपयोग करता है। किसी फ़ंक्शन को चिह्नित करने के लिए बस निम्नलिखित करें:

root@kitploit:~
__attribute__((annotate("ibr:1,100"))) void hello_world () {
    some_hello ();
}

एनोटेशन कोड:

  • बेसिक ब्लॉक स्प्लिटर: bbs
  • कंट्रोल फ्लो फ़्लैटनिंग: cff
  • अप्रत्यक्ष ब्रांचिंग: ibr
  • सरल अप्रत्यक्ष ब्रांचिंग: sibr
  • मिश्रित बूलियन अंकगणित: mba

उदाहरण: index.d.ts में हम देखते हैं:

root@kitploit:~
{
    "BasicBlockSplitter.SplitBlockMinSize"?: number;
    "BasicBlockSplitter.SplitBlockMaxSize"?: number;
    "BasicBlockSplitter.SplitBlockChance"?: number;
};

अब बात यह है, पहला तर्क और सभी पासों के लिए साझा तर्क PassIterations है, इसलिए यह एनोटेशन में पहला तर्क होगा। bbs के साथ किसी चीज़ को एनोटेट करने के लिए हम करते हैं:

root@kitploit:~
__attribute__((annotate("bbs:1,15,30,100"))) void hello_world () {
    some_hello ();
}

इसका मतलब है: hello_world पर बेसिक ब्लॉक स्प्लिटर 1 बार चलाएँ जिसमें न्यूनतम आकार = 15, अधिकतम आकार = 30 और संभावना = 100।

आप पासों को भी जोड़ सकते हैं:

root@kitploit:~
__attribute__((annotate("bbs:1,15,30,100 ibr:1,100 sibr:1,100"))) void hello_world () {
    some_hello ();
}

इसका मतलब है hello_world पर पहले बेसिक ब्लॉक स्प्लिटर फिर अप्रत्यक्ष ब्रांचिंग और फिर सरल अप्रत्यक्ष ब्रांचिंग चलाएँ। वे परिभाषा के क्रम में बाएँ से दाएँ चलेंगे।

टूल डाउनलोड करें
UseOpaqueTransformationChance
qword_1C64D8
qword_1A63F0
qword_1ACE98
  • UseSipHashedStateChance: स्थिति की जाँच करने के लिए एक छोटे अनुकूलित siphash फ़ंक्शन का उपयोग करता है। तो if (state == 23872) कुछ इस तरह बन जाता है if (siphash(state) == 3874872081) जिससे यह पता लगाना मुश्किल हो जाता है कि कोई ब्लॉक कहाँ जा रहा है। ब्लॉक state = 23872 करेगा जब यह जहाँ जाता है उसकी स्थिति हैश की गई होती है। प्रत्येक siphash कॉल का उपयोग करके इसे अनुकरण करना कठिन बनाने के लिए यादृच्छिक मानों का उपयोग किया जाता है।
  • CloneSipHashChance: siphash फ़ंक्शन को क्लोन करें और यदि संभव हो तो इनलाइन करने का प्रयास करें, जिससे इसके लिए एक से अधिक सिब्लिंग बनते हैं, जिससे एक ही फ़ंक्शन को हुक करना पर्याप्त नहीं होता। इसका उपयोग करना अत्यधिक पसंद किया जाता है क्योंकि यह केवल बाइनरी आकार बढ़ाता है और प्रदर्शन को प्रभावित नहीं करता।