
एक radare2 स्क्रिप्ट जो gopclntab को पार्स करके Go बाइनरी के रिवर्स इंजीनियरिंग को सुविधाजनक बनाती है।
नोट: यह सुविधा सीधे radare2 के कोर में gopc analysis plugin के रूप में लागू की गई है।
Go बाइनरीज़ से फंक्शन सिंबल पुनर्प्राप्त करने के लिए एक radare2-आधारित Go gopclntab पार्सर, जिसमें पूरी तरह से स्ट्रिप किए गए बाइनरी भी शामिल हैं। ELF, Mach-O, और PE बाइनरी को Go संस्करण 1.2, 1.16, 1.18, और 1.20+ में सपोर्ट करता है।
प्रत्येक Go 1.2+ बाइनरी में gopclntab (Program Counter Line Table) नामक एक डेटा क्षेत्र एम्बेड होता है जिसका उपयोग Go रनटाइम स्टैक ट्रेस, पैनिक संदेश, गार्बेज कलेक्शन और डीबगर सपोर्ट के लिए करता है। यह Go बाइनरी में सिंबल जानकारी के सबसे मूल्यवान स्रोतों में से एक है।
r2gopclntabParser radare2 के माध्यम से इस क्षेत्र को पढ़ता है, संस्करण-विशिष्ट संरचनाओं को पार्स करता है, और या तो पुनर्प्राप्त फंक्शन सूची (पतों, स्रोत फ़ाइलों और लाइन नंबरों के साथ) प्रिंट करता है या पुनर्प्राप्त नामों को फंक्शन परिभाषाओं, फ्लैग्स और टिप्पणियों के रूप में खुले radare2 सत्र में वापस लागू करता है।
| निर्भरता | न्यूनतम संस्करण |
|---|---|
| Python 3 | 3.8+ |
| radare2 | 5.0+ (6.0.9 पर परीक्षित) |
| r2pipe | कोई भी |
किसी अन्य Python पैकेज की आवश्यकता नहीं है। स्क्रिप्ट केवल मानक लाइब्रेरी (struct, json, argparse, os, sys) और r2pipe का उपयोग करती है।
python3 r2_gopclntab.py -f ./mybinary -l
python3 r2_gopclntab.py -f ./mybinary -n main.main
python3 r2_gopclntab.py -f ./mybinary -v -l
python3 r2_gopclntab.py -f ./mybinary --apply
python3 r2_gopclntab.py -f ./mybinary --json
#!pipe python3 r2_gopclntab.py --r2pipe --apply -v
## CLI संदर्भ```
usage: r2_gopclntab.py [-h] [-f FILE] [-n FUNCNAME] [-v] [-l]
[--apply] [--json] [--files] [--r2pipe]
| Flag | Description |
|---|---|
-f FILE, --file FILE | विश्लेषण करने के लिए Go बाइनरी का पथ। स्क्रिप्ट अपना स्वयं का r2 उदाहरण शुरू करती है। |
--r2pipe | पहले से चल रहे r2 सत्र से जुड़ें (r2 कंसोल के अंदर उपयोग के लिए)। |
| Flag | Description |
|---|---|
-l, --list | प्रत्येक पुनर्प्राप्त फ़ंक्शन को उसके पते के साथ प्रिंट करें। |
-n NAME, --funcname NAME | केवल उन फ़ंक्शनों को प्रिंट करें जिनके नाम में NAME है (सबस्ट्रिंग मिलान)। यदि कोई सटीक मिलान मौजूद है, तो उसका पता अलग से प्रिंट किया जाता है। |
-v, --verbose | प्रगति संदेश, पार्स किए गए हेडर फ़ील्ड और आंतरिक ऑफ़सेट प्रिंट करें। |
--apply | पुनर्प्राप्त फ़ंक्शन नामों को radare2 सत्र में फ़ंक्शन परिभाषाओं (af+), go. फ़्लैगस्पेस में फ़्लैग, और मूल Go नाम और स्रोत स्थान के साथ टिप्पणियों के रूप में लिखें। |
--json | हेडर और पूर्ण फ़ंक्शन सूची को JSON के रूप में stdout पर आउटपुट करें। |
--files | फ़ाइल तालिका से निकाले गए स्रोत फ़ाइल पथों की सूची प्रिंट करें। |
-h, --help | सहायता संदेश दिखाएँ। |
फ़्लैग को स्वतंत्र रूप से जोड़ा जा सकता है। जब कोई आउटपुट फ़्लैग नहीं दिया जाता है, तो डिफ़ॉल्ट व्यवहार हेडर और पूर्ण फ़ंक्शन सूची को प्रिंट करना है।
नीचे दिए गए सभी उदाहरण एक स्ट्रिप की गई Go 1.26 Mach-O arm64 बाइनरी (जो -ldflags="-s -w" के साथ बनाई गई है) पर चलाए गए थे। परीक्षण प्रोग्राम main.main, main.fibonacci, main.helloWorld, और main.addNumbers को परिभाषित करता है। कंपाइलर ने helloWorld और addNumbers को इनलाइन कर दिया, इसलिए वे gopclntab में दिखाई नहीं देते।
बिना किसी फ़्लैग (या केवल -f) के चलाने पर पार्स किया गया हेडर और उसके बाद पूर्ण फ़ंक्शन तालिका प्रिंट होती है:```
$ python3 r2_gopclntab.py -f ./gotest_stripped
[No content provided in the INPUT section.]```
============================================================
Go pclntab Header
============================================================
Magic: 0xFFFFFFF1
Go version: 1.20+
Pointer size: 8
Min LC (quantum):4
Num functions: 2030
Num files: 261
funcnameOffset: 0x48
cuOffset: 0x14D20
filetabOffset: 0x158D8
pctabOffset: 0x19A98
pclnOffset: 0x55E40
============================================================
ADDRESS FUNCTION NAME
----------------------------------------------------------------------
0x100001000 go:buildid
0x100001070 internal/abi.BoundsDecode (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/bounds.go:86)
0x100001150 internal/abi.NoEscape (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/escape.go:19)
0x100001160 internal/abi.Kind.String (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:143)
0x1000011E0 internal/abi.TypeOf (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:181)
0x1000011F0 internal/abi.(*Type).ExportedMethods (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:453)
...
0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13)
0x1000A0C20 main.main (/tmp/gotest/main.go:20)
0x1000A0D20 go:textfipsstart
0x1000A0D30 go:textfipsend
[+] 2030 function(s) shown
सेक्शन स्कैनिंग प्रगति, textStart रिज़ॉल्यूशन विवरण, और आंतरिक ऑफ़सेट जानकारी जोड़ता है:``` $ python3 r2_gopclntab.py -f ./gotest_stripped -v
## स्थापना
Regexploit को pip के साथ स्थापित करें
```bash
pip install regexploit
और इसे चलाएँ
python -m regexploit
या इसे regexploit.derf.net पर ऑनलाइन आज़माएँ
Regexploit ने कई कमज़ोरियाँ खोजी हैं। सबसे खराब उदाहरण हैं:
\s+ और बहुत सारे रिक्त स्थानों वाले UUID के उपयोग के कारण हुआ।कई और वैध ReDoS कमज़ोरियाँ लोकप्रिय Python लाइब्रेरीज़ में पाई गई हैं, जिनके लिए CVE प्राप्त हुए हैं जैसे Pillow में CVE-2021-25292, httplib2 में CVE-2021-21240, और pygments में CVE-2021-27291। Node.js में भी कई ReDoS कमज़ोरियाँ हैं, जैसे hosted-git-info में CVE-2021-23362। Regexploit ने इन्हें खोजा है, और और भी खोज सकता है।
npm/pypi से किसी पैकेज पर Regexploit चलाने के लिए:
regexploit npm vueregexploit pip djangoregexploit pip flaskअधिक जानकारी --help के साथ।```
[] Running radare2 analysis...
[] Binary format: mach0, endian: little, arch: arm, bits: 64
[] Scanning binary for gopclntab magic bytes...
[] Scanning section '0.__TEXT.__text' (0x100001000, 0x9FD44)...
[] Scanning section '1.__TEXT.__symbol_stub1' (0x1000A0D60, 0x2B8)...
[] Scanning section '2.__TEXT.__rodata' (0x1000A1020, 0xACC2)...
[] Scanning section '3.__TEXT.__gopclntab' (0x1000ABCE8, 0xA48AE)...
[] Found magic at vaddr=0x1000ABCE8
[] Parsed header: PcHeader(magic=0xFFFFFFF1, version=1.20+, ptrSize=8, minLC=4,
nfunc=2030, nfiles=261, textStart=0x0)
[] textStart is 0, using .text section vaddr: 0x100001000
[*] Parsed 2030 functions
Magic: 0xFFFFFFF1 Go version: 1.20+ ...
### खोज मोड (-n)
फ़ंक्शन सूची को सबस्ट्रिंग मिलान द्वारा फ़िल्टर करता है। यदि कोई सटीक मिलान मौजूद है, तो उसका
पता अलग से मुद्रित किया जाता है।
`main.` वाले सभी फ़ंक्शन के लिए सबस्ट्रिंग खोज:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "main."
0x100041920 runtime.main.func2 (/opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go:207) 0x10006CE30 runtime.main.func1 (/opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go:174) 0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13) 0x1000A0C20 main.main (/tmp/gotest/main.go:20)
[+] 4 function(s) shown (filtered from 2030 total)
सटीक मिलान खोज:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "main.fibonacci"
0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13)
[+] 1 function(s) shown (filtered from 2030 total)
[+] Exact match: main.fibonacci @ 0x1000A0BB0
GC-संबंधित रनटाइम आंतरिकताओं की खोज करना:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "runtime.gc"
0x10001F310 runtime.gcinit (/opt/homebrew/.../src/runtime/mgc.go:179) 0x10001F3C0 runtime.gcenable (/opt/homebrew/.../src/runtime/mgc.go:211) 0x10001F730 runtime.gcStart (/opt/homebrew/.../src/runtime/mgc.go:733) 0x10001FFE0 runtime.gcMarkDone (/opt/homebrew/.../src/runtime/mgc.go:1015) 0x100020A50 runtime.gcMarkTermination (/opt/homebrew/.../src/runtime/mgc.go:1344) 0x100021C10 runtime.gcBgMarkWorker (/opt/homebrew/.../src/runtime/mgc.go:1750) 0x1000223D0 runtime.gcMark (/opt/homebrew/.../src/runtime/mgc.go:1956) 0x1000227A0 runtime.gcSweep (/opt/homebrew/.../src/runtime/mgc.go:2049) ... 0x100076C60 runtime.gcWriteBarrier1 (/opt/homebrew/.../src/runtime/asm_arm64.s:1533)
[+] 73 function(s) shown (filtered from 2030 total)
`fmt.` (मानक लाइब्रेरी प्रिंटिंग) खोज रहा है:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "fmt."
--nmap <file> एक कस्टम पूर्व-कॉन्फ़िगर Nmap स्कैन सेट करें। (डिफ़ॉल्ट: nmap -sV -O -A -T4 $target -Pn)```
ADDRESS FUNCTION NAME0x100098AA0 fmt.(*fmt).writePadding (/opt/homebrew/.../src/fmt/format.go:66) 0x100098BF0 fmt.(*fmt).pad (/opt/homebrew/.../src/fmt/format.go:93) 0x100099590 fmt.(*fmt).fmtInteger (/opt/homebrew/.../src/fmt/format.go:197) 0x10009ADF0 fmt.Fprintf (/opt/homebrew/.../src/fmt/print.go:222) 0x10009AED0 fmt.Fprintln (/opt/homebrew/.../src/fmt/print.go:303) 0x10009D3F0 fmt.(*pp).printArg (/opt/homebrew/.../src/fmt/print.go:721) 0x10009D950 fmt.(*pp).printValue (/opt/homebrew/.../src/fmt/print.go:797) 0x10009FA60 fmt.(*pp).doPrintf (/opt/homebrew/.../src/fmt/print.go:1018) ...
`sync.` (समवर्ती प्रिमिटिव) की खोज कर रहे हैं:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "sync."
0x10006FFE0 sync.runtime_registerPoolCleanup (/opt/homebrew/.../src/runtime/mgc.go:2150) 0x100070BA0 sync.fatal (/opt/homebrew/.../src/runtime/panic.go:1160) 0x1000714E0 sync.runtime_procPin (/opt/homebrew/.../src/runtime/proc.go:7912) 0x10007B290 internal/sync.(*Mutex).lockSlow (/opt/homebrew/.../src/internal/sync/mutex.go:95) 0x10007B570 internal/sync.(*Mutex).Unlock (/opt/homebrew/.../src/internal/sync/mutex.go:187) ...
### JSON आउटपुट (--json)
स्क्रिप्टिंग और पाइपलाइन एकीकरण के लिए मशीन-पठनीय आउटपुट:```
$ python3 r2_gopclntab.py -f ./gotest_stripped --json
🖥️ नेटवर्क उपकरण```json { "header": { "magic": "0xFFFFFFF1", "version": "1.20+", "ptrSize": 8, "minLC": 4, "nfunc": 2030, "nfiles": 261, "textStart": "0x0" }, "functions": [ { "name": "go:buildid", "addr": "0x100001000", "args": 0, "source_file": "", "start_line": 0 }, { "name": "internal/abi.BoundsDecode", "addr": "0x100001070", "args": 8, "source_file": "/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/bounds.go", "start_line": 86 }, { "name": "main.fibonacci", "addr": "0x1000A0BB0", "args": 0, "source_file": "/tmp/gotest/main.go", "start_line": 13 }, { "name": "main.main", "addr": "0x1000A0C20", "args": 0, "source_file": "/tmp/gotest/main.go", "start_line": 20 } ], "num_source_files": 261 }
### स्रोत फ़ाइल सूची (--files)
बाइनरी में एम्बेडेड सभी स्रोत फ़ाइल पथों को निकालता है:```
$ python3 r2_gopclntab.py -f ./gotest_stripped --files
/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/bounds.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/escape.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/cpu/cpu.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/cpu/cpu_arm64.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/mgc.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/malloc.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/panic.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/fmt/print.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/fmt/format.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/reflect/value.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/reflect/type.go /tmp/gotest/main.go ... ... and 61 more
### एप्लाई मोड (--apply)
सभी पुनर्प्राप्त फ़ंक्शन नामों को radare2 सत्र में लिखता है। निम्नलिखित स्ट्रिप्ड बाइनरी पर पहले/बाद की तुलना दिखाता है।
**BEFORE** (r2 का मूल विश्लेषण स्ट्रिप्ड बाइनरी पर, कोई gopclntab पार्सिंग नहीं):```
Functions found by r2 natively: 1913
Disassembly at 0x1000a0c20 (main.main, unnamed):
; CODE XREF from fcn.1000a0c20 @ 0x1000a0d14(r)
24: fcn.1000a0c20 (int64_t arg1);
0x1000a0c20 900b40f9 ldr x16, [x28, 0x10]
0x1000a0c24 ff6330eb cmp sp, x16
0x1000a0c28 29070054 b.ls 0x1000a0d0c
Disassembly at 0x1000a0bb0 (main.fibonacci, unnamed):
112: fcn.1000a0bb0 (signed int64_t arg1, int64_t arg_8h);
0x1000a0bb0 900b40f9 ldr x16, [x28, 0x10]
0x1000a0bb4 ff6330eb cmp sp, x16
0x1000a0bb8 a9020054 b.ls 0x1000a0c0c
r2 ने 1913 फ़ंक्शन पाए लेकिन उनमें से किसी का नाम नहीं रखा (केवल अनाम fcn.XXXXXXXX लेबल)। main.main या main.fibonacci खोजने पर कुछ नहीं मिलता।
gopclntab प्रतीक लागू करना:``` [] Binary format: mach0, endian: little, arch: arm, bits: 64 [] Found magic at vaddr=0x1000ABCE8 [] Parsed header: PcHeader(magic=0xFFFFFFF1, version=1.20+, ...) [] textStart is 0, using .text section vaddr: 0x100001000 [*] Parsed 2030 functions [+] Applied 2030 function names to radare2 (0 skipped)
**बाद** (r2 session with gopclntab symbols applied):```
r2 function list matching "main" (after --apply):
0x100041510 0 0 runtime.main
0x100041920 0 0 runtime.main.func2
0x10006ce30 0 0 runtime.main.func1
Flags in go.* flagspace (last 20):
0x10009fa60 1 go.fmt._ptr_pp_.doPrintf
0x1000a0930 1 go.fmt._ptr_pp_.doPrintln
0x1000a0bb0 1 go.main.fibonacci
0x1000a0c20 1 go.main.main
0x1000a0d20 1 go.go:textfipsstart
0x1000a0d30 1 go.go:textfipsend
डिसेम्बली main.main पर अब पुनर्प्राप्त नाम और स्रोत स्थान दिखाती है:```
;-- go.main.main:
24: fcn.1000a0c20 (int64_t arg1);
0x1000a0c20 900b40f9 ldr x16, [x28, 0x10] ; " src: /tmp/gotest/main.go:20"
0x1000a0c24 ff6330eb cmp sp, x16
0x1000a0c28 29070054 b.ls 0x1000a0d0c
`main.fibonacci` पर डिसअसेंबली अब पुनर्प्राप्त नाम और स्रोत स्थान दिखाती है:```
;-- go.main.fibonacci:
112: fcn.1000a0bb0 (signed int64_t arg1, int64_t arg_8h);
0x1000a0bb0 900b40f9 ldr x16, [x28, 0x10] ; " src: /tmp/gotest/main.go:13"
0x1000a0bb4 ff6330eb cmp sp, x16
0x1000a0bb8 a9020054 b.ls 0x1000a0c0c
r2 सत्र में नाम से खोजना अब काम करता है:``` go.main.main resolves to: 0x1000a0c20 go.main.fibonacci resolves to: 0x1000a0bb0
---
## परिणाम सारांश: Mach-O (स्ट्रिप्ड टेस्ट बाइनरी)
| मीट्रिक | r2 Native (स्ट्रिप्ड) | r2_gopclntab.py के बाद |
|---|---|---|
| प्राप्त फंक्शन्स | 1913 (अनाम `fcn.XXXX` लेबल) | 2030 (पूर्ण Go पैकेज-योग्य नाम) |
| पहचाने गए उपयोगकर्ता फंक्शन्स | 0 | `main.main`, `main.fibonacci` स्रोत + लाइन के साथ |
| पुनर्प्राप्त स्रोत फ़ाइलें | 0 | 261 (पूर्ण निरपेक्ष पथ) |
| नामित प्रतीक | केवल C आयात स्टब्स (`sym.imp.mmap`, आदि) | प्रत्येक Go फंक्शन लेबल किया गया (`go.main.main`, `go.runtime.gcStart`, आदि) |
| स्रोत टिप्पणियाँ | कोई नहीं | डिसअसेंबली में इनलाइन `src: /tmp/gotest/main.go:20` |
| नाम से नेविगेट करने योग्य | नहीं | हाँ (`s go.main.main`, `afl~runtime.gc`) |
---
## PE परीक्षण: Greenblood, एक Go रैनसमवेयर बाइनरी
पार्सर को एक वास्तविक PE बाइनरी, Greenblood (`greenblood_1`) के विरुद्ध परीक्षण किया गया, जो एक Go
रैनसमवेयर नमूना है जिसे PE32+ x86-64 Windows एक्ज़ीक्यूटेबल के रूप में संकलित किया गया है। PE बाइनरीज़
में समर्पित `.gopclntab` अनुभाग नहीं होता है, इसलिए यह मैजिक-बाइट स्कैनिंग फ़ॉलबैक पथ का अभ्यास करता है।
### पता लगाना और हैडर```
$ python3 r2_gopclntab.py -f ./greenblood_1 -v
इनपुट:``` [] Binary format: pe, endian: little, arch: x86, bits: 64 [] Scanning binary for gopclntab magic bytes... [] Scanning section '.text' (0x401000, 0xF4000)... [] Scanning section '.rdata' (0x4F5000, 0x127000)... [] Found magic at vaddr=0x568C00 [] Parsed header: PcHeader(magic=0xFFFFFFF1, version=1.20+, ptrSize=8, minLC=1, nfunc=2596, nfiles=345, textStart=0x401000) [] textStart from header: 0x401000 [] Parsed 2596 functions
स्कैनर ने `.rdata` सेक्शन के अंदर `0x568C00` पर gopclntab पाया।
चूंकि यह एक मानक PE (PIE नहीं) है, `textStart` `0x401000` (गैर-शून्य) है,
इसलिए पता गणना के लिए हैडर मान का सीधे उपयोग किया जाता है।
| फ़ील्ड | मान |
|---|---|
| फ़ॉर्मैट | PE32+ x86-64 |
| gopclntab स्थान | `.rdata` at `0x568C00` (मैजिक स्कैन द्वारा पाया गया) |
| मैजिक | `0xFFFFFFF1` (Go 1.20+) |
| पॉइंटर आकार | 8 |
| क्वांटम (minLC) | 1 (x86) |
| textStart | `0x401000` (हैडर से) |
| पुनर्प्राप्त फ़ंक्शन | 2596 |
| स्रोत फ़ाइलें | 345 |
### पुनर्प्राप्त मैलवेयर फ़ंक्शन
मैलवेयर के अपने कोड (`main.`) की खोज:```
$ python3 r2_gopclntab.py -f ./greenblood_1 -n "main."
Session टैब पर जाएं।Session टैब के अंतर्गत, आपको वर्तमान सत्र को सहेजने या पहले से सहेजे गए सत्र को लोड करने के विकल्प दिखाई देंगे।Save बटन पर क्लिक करें। अपने सत्र के लिए एक वर्णनात्मक नाम दर्ज करें और Save पर क्लिक करें।Load पर क्लिक करें।0x4D91E0 main.init (:1) 0x4D9200 main.map.init.0 (/root/victims/ransom/daf/enc.go:59) 0x4D92C0 main.map.init.1 (/root/victims/ransom/daf/enc.go:126) 0x4D95C0 main.NewKeyManager (/root/victims/ransom/daf/enc.go:146) 0x4D97E0 main.getMachineFingerprint (/root/victims/ransom/daf/enc.go:173) 0x4DA2C0 main.getBIOSUUID (/root/victims/ransom/daf/enc.go:249) 0x4DA3C0 main.NewEncryptionEngine (/root/victims/ransom/daf/enc.go:287) 0x4DA560 main.(*EncryptionEngine).fileWorker (/root/victims/ransom/daf/enc.go:303) 0x4DA660 main.(*EncryptionEngine).processFile (/root/victims/ransom/daf/enc.go:319) 0x4DA740 main.(*EncryptionEngine).encryptFile (/root/victims/ransom/daf/enc.go:334) 0x4DB2A0 main.(*EncryptionEngine).EncryptPath (/root/victims/ransom/daf/enc.go:446) 0x4DB620 main.(*EncryptionEngine).shouldSkipDirectory (/root/victims/ransom/daf/enc.go:495) 0x4DB7C0 main.(*EncryptionEngine).shouldEncryptFile (/root/victims/ransom/daf/enc.go:522) 0x4DB9A0 main.(*EncryptionEngine).placeRansomNote (/root/victims/ransom/daf/enc.go:560) 0x4DBB60 main.(*EncryptionEngine).recordSuccess (/root/victims/ransom/daf/enc.go:636) 0x4DBFA0 main.(*EncryptionEngine).Wait (/root/victims/ransom/daf/enc.go:664) 0x4DC3C0 main.formatBytes (/root/victims/ransom/daf/enc.go:689) 0x4DC500 main.disableRecovery (/root/victims/ransom/daf/enc.go:706) 0x4DC720 main.isAdmin (/root/victims/ransom/daf/enc.go:732) 0x4DC8C0 main.main (/root/victims/ransom/daf/enc.go:760) 0x4DD260 main.getLogicalDrives (/root/victims/ransom/daf/enc.go:863) 0x4DD4A0 main.isAlreadyRunning (/root/victims/ransom/daf/enc.go:892) 0x4DD660 main.getDesktopPath (/root/victims/ransom/daf/enc.go:911) 0x4DD780 main.removeExecutable (/root/victims/ransom/daf/enc.go:932) ...
[+] 43 function(s) shown (filtered from 2596 total)
सभी 43 उपयोगकर्ता फ़ंक्शन एक एकल स्रोत फ़ाइल `/root/victims/ransom/daf/enc.go` से पुनर्प्राप्त किए गए थे। फ़ंक्शन नाम तुरंत रैनसमवेयर की क्षमताओं को प्रकट करते हैं: कुंजी प्रबंधन, मशीन फ़िंगरप्रिंटिंग, पथ ट्रैवर्सल के साथ फ़ाइल एन्क्रिप्शन, फिरौती नोट प्लेसमेंट, रिकवरी अक्षम करना, विशेषाधिकार जाँच, म्यूटेक्स-आधारित एकल-उदाहरण प्रवर्तन, ड्राइव गणना, और स्व-विलोपन।
### गैर-मानक-पुस्तकालय निर्भरताएँ
उन स्रोत फ़ाइलों को निकालना जो Go मानक पुस्तकालय का हिस्सा नहीं हैं:```
/root/go/pkg/mod/golang.org/x/[email protected]/windows/dll_windows.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/registry/key.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/registry/value.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/security_windows.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/str.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/syscall.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/syscall_windows.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/zsyscall_windows.go
/root/victims/ransom/daf/enc.go
एकमात्र बाहरी निर्भरता golang.org/x/[email protected] है जो विंडोज-विशिष्ट syscalls (रजिस्ट्री एक्सेस, सुरक्षा टोकन, DLL लोडिंग) के लिए है।
crypto के लिए खोज करने पर 137 क्रिप्टो-संबंधित फंक्शन्स दिखाई देते हैं, जिनमें शामिल हैं:```
$ python3 r2_gopclntab.py -f ./greenblood_1 -n "crypto"
docker run -v tool_config:/.config/tool```
ADDRESS FUNCTION NAME
----------------------------------------------------------------------
0x4AEC00 crypto/cipher.NewCTR (/usr/local/go/src/crypto/cipher/ctr.go:41)
0x4AF520 crypto/cipher.StreamWriter.Write (/usr/local/go/src/crypto/cipher/io.go:36)
0x4AF840 crypto/aes.NewCipher (/usr/local/go/src/crypto/aes/aes.go:36)
0x4C3760 crypto/rand.(*reader).Read (/usr/local/go/src/crypto/rand/rand.go:45)
0x4DE6C0 crypto/internal/fips140/sha256.New (.../sha256/sha256.go:138)
0x4E3EC0 crypto/internal/fips140/sha3.NewCShake128 (.../sha3/shake.go:134)
0x4EED60 crypto/internal/fips140/hmac.New (.../hmac/hmac.go:131)
0x4EF800 crypto/internal/fips140/aes.newBlock (.../aes/aes_asm.go:59)
0x4F0800 crypto/internal/fips140/aes.(*CBCEncrypter).CryptBlocks (.../aes/cbc.go:26)
0x4F0FE0 crypto/internal/fips140/aes.(*CTR).XORKeyStream (.../aes/ctr.go:41)
...
[+] 137 function(s) shown (filtered from 2596 total)
क्रिप्टो उपयोग प्रोफ़ाइल: AES (CBC और CTR मोड), SHA-256, SHA-512, HMAC, CSHAKE128, और DRBG (नियतात्मक यादृच्छिक बिट जनरेटर)। यह रैनसमवेयर के अनुरूप है जो मशीन फिंगरप्रिंट से प्राप्त प्रति-मशीन एन्क्रिप्शन कुंजी उत्पन्न करता है, AES-CTR के साथ फ़ाइलों को एन्क्रिप्ट करता है, और अखंडता के लिए HMAC का उपयोग करता है।
$ python3 r2_gopclntab.py -f ./greenblood_1 --apply [+] Applied 2596 function names to radare2 (0 skipped) [+] Function names applied. Use 'afl' in r2 to see them.
All 2596 functions applied successfully with zero skipped.
---
## रिवर्स इंजीनियरिंग के लिए उपयोग के मामले
### 1. ट्रायेज और पहचान
तुरंत निर्धारित करें कि कोई बाइनरी Go है या नहीं, यह किस संस्करण के साथ बनाई गई है, और यह किन पैकेजों का उपयोग करती है। `--files` आउटपुट Go टूलचेन संस्करण (फ़ाइल पथों जैसे `/usr/local/go/1.26.1/...` से) और प्रत्येक स्रोत फ़ाइल पथ (थर्ड-पार्टी लाइब्रेरी सहित) प्रकट करता है। मैलवेयर के लिए, यह तुरंत बताता है कि नमूना `crypto/tls`, `net/http`, `os/exec`, या अन्य रुचि के पैकेजों का उपयोग करता है या नहीं।
### 2. स्ट्रिप्ड बाइनरी पर प्रतीक पुनर्प्राप्ति
मुख्य उपयोग का मामला। `-ldflags="-s -w"` के साथ स्ट्रिप की गई Go बाइनरी अपनी प्रतीक तालिका खो देती हैं, लेकिन gopclntab बच जाता है। यह उपकरण प्रत्येक फ़ंक्शन नाम को पुनर्स्थापित करता है, अनाम `fcn.1000a0c20` को वापस `main.main` में बदल देता है। यह मैलवेयर नमूनों, CTF चुनौतियों, प्रोडक्शन बाइनरी, और किसी भी स्ट्रिप्ड Go निष्पादन योग्य पर लागू होता है।
### 3. Go रनटाइम को नेविगेट करना
Go बाइनरी में संपूर्ण रनटाइम एम्बेडेड होता है (आमतौर पर 1500 से 2000+ फ़ंक्शन)। नामों के बिना, रनटाइम अनाम फ़ंक्शनों की एक अभेद्य दीवार है। नामों के साथ, आप तुरंत `runtime.mallocgc`, `runtime.gopanic`, `runtime.newproc`, `runtime.gcStart` का पता लगा सकते हैं और समझ सकते हैं कि बाइनरी प्रत्येक कॉल साइट पर क्या कर रही है।
### 4. उपयोगकर्ता कोड को रनटाइम से अलग करना
`main.` या एप्लिकेशन के पैकेज पथ को खोजकर, आप कुल 2030 फ़ंक्शनों में से केवल उपयोगकर्ता के कोड को रनटाइम से अलग कर सकते हैं। उपरोक्त उदाहरणों में, `main.` के लिए फ़िल्टर करने पर तुरंत `main.main` और `main.fibonacci` 2030 कुल फ़ंक्शनों में से सामने आ जाते हैं। आप थर्ड-पार्टी पैकेज नामों (जैसे `-n "github.com/user/repo"`) से भी खोज सकते हैं ताकि बाहरी निर्भरताओं की पहचान हो सके।
### 5. स्रोत-स्तरीय संदर्भ
प्रत्येक फ़ंक्शन अपने स्रोत फ़ाइल पथ और प्रारंभिक लाइन संख्या के साथ आता है। इसका मतलब है कि आप डिसअसेंबली को Go मानक पुस्तकालय स्रोत कोड (जो खुला है) के साथ क्रॉस-रेफरेंस कर सकते हैं, भले ही आप एक स्ट्रिप्ड बाइनरी का विश्लेषण कर रहे हों। यह जानना कि कोई फ़ंक्शन `runtime/mgc.go` की लाइन 733 पर शुरू होता है, आपको डिसअसेंबली के साथ-साथ मूल स्रोत पढ़ने की अनुमति देता है।
### 6. पाइपलाइन और ऑटोमेशन
`--json` मोड स्क्रिप्टिंग सक्षम करता है। आउटपुट को IDA/Ghidra इम्पोर्टर, डिफिंग टूल, YARA नियम जनरेटर, या किसी भी विश्लेषण पाइपलाइन में फीड करें। उदाहरण के लिए, सभी क्रिप्टो-संबंधित फ़ंक्शन निकालने के लिए:```bash
python3 r2_gopclntab.py -f sample.exe --json \
| jq '.functions[] | select(.name | contains("crypto"))'
--apply के बाद, पूरा r2 सत्र Go नाम से नेविगेबल हो जाता है। आप फ़ंक्शन पर जा सकते हैं (s go.main.main), फ़ंक्शन सूची खोज सकते हैं (afl~runtime.gc), क्रॉस-रेफरेंस का निरीक्षण कर सकते हैं (axf go.main.fibonacci), और डिसअसेंबली आउटपुट (pd) में स्रोत स्थान टिप्पणियों को इनलाइन देख सकते हैं। यह r2 को एक सामान्य डिसअसेंबलर से Go-जागरूक विश्लेषण वातावरण में बदल देता है।
| फ़ॉर्मेट | अनुभाग खोज विधि | परीक्षण किया गया |
|---|---|---|
| ELF (Linux) | अनुभाग नाम .gopclntab या .data.rel.ro.gopclntab | हाँ |
| Mach-O (macOS) | अनुभाग नाम __gopclntab (__TEXT सेगमेंट के अंदर) | हाँ |
| PE (Windows) | मैजिक बाइट स्कैन (कोई समर्पित अनुभाग नहीं) | हाँ (Greenblood पर परीक्षण किया गया, एक Go रैनसमवेयर PE64) |
PE बाइनरी और आक्रामक रूप से स्ट्रिप किए गए ELF/Mach-O बाइनरी जिनमें अनुभाग हेडर नहीं होता, के लिए उपकरण सभी अनुभागों को 4-बाइट मैजिक और उसके बाद मान्यता बाइट (pad=0, ptrSize {4,8} में, minLC {1,2,4} में) के लिए स्कैन करता है।
| मैजिक | Go संस्करण | हेडर में textStart | functab.entry प्रकार | startLine फ़ील्ड | स्थिति |
|---|---|---|---|---|---|
0xFFFFFFFB | 1.2 | नहीं | uintptr (निरपेक्ष) | नहीं | समर्थित |
0xFFFFFFFA | 1.16 | नहीं | uintptr (निरपेक्ष) | नहीं | समर्थित |
0xFFFFFFF0 | 1.18 - 1.19 | हाँ | uint32 (सापेक्ष) | नहीं | समर्थित |
0xFFFFFFF1 | 1.20+ | हाँ (शून्य हो सकता है) | uint32 (सापेक्ष) | हाँ | समर्थित |
0xFFFFFFF1 मैजिक का उपयोग Go 1.20 से कम से कम Go 1.26 तक किया जाता है।
पार्सर gopclntab डेटा खोजने के लिए दो-चरणीय दृष्टिकोण का उपयोग करता है:
चरण 1 (ELF/Mach-O): radare2 के अनुभाग सूची (iSj) से पूछताछ करें और .gopclntab, .data.rel.ro.gopclntab, या __gopclntab नामक अनुभागों की तलाश करें।
चरण 2 (PE/वैकल्पिक): यदि कोई नामित अनुभाग नहीं मिलता है, तो सभी अनुभागों को 4-बाइट मैजिक बाइट के लिए स्कैन करें। प्रत्येक उम्मीदवार को यह जाँच कर मान्य किया जाता है कि बाइट 4-7 अपेक्षित पैटर्न से मेल खाते हैं: दो शून्य पैड बाइट, एक मान्य पॉइंटर आकार (4 या 8), और एक मान्य निर्देश क्वांटम (1, 2, या 4)। यह आकस्मिक बाइट पैटर्न से गलत सकारात्मक को समाप्त करता है।
Go >= 1.18 में, functab में फ़ंक्शन प्रवेश बिंदु सापेक्ष ऑफ़सेट के रूप में संग्रहीत होते हैं। निरपेक्ष वर्चुअल पता की गणना करने के लिए एक आधार की आवश्यकता होती है:``` absolute_addr = base + entryoff
आधार निम्नलिखित तर्क के आधार पर हल किया जाता है:```
Is magic 0xFFFFFFFB (Go 1.2)?
YES -> base = 0 (entries are absolute addresses)
NO -> Is magic 0xFFFFFFFA (Go 1.16)?
YES -> base = .text section vaddr (entries are absolute)
NO -> (Go 1.18 / 1.20+)
Is header.textStart != 0?
YES -> base = header.textStart
NO -> base = .text section vaddr
textStart == 0 का मामला Go >= 1.22 में Mach-O और PIE बाइनरीज़ के लिए होता है।
जब ऐसा होता है, तो entryoff मान .text सेक्शन की शुरुआत के सापेक्ष होते हैं, इसलिए पार्सर r2 से .text वर्चुअल एड्रेस प्राप्त करता है और उसे आधार के रूप में उपयोग करता है।
इसे Go 1.26 Mach-O arm64 बाइनरी के विरुद्ध सत्यापित किया गया:
textStart: 0x0.text सेक्शन vaddr: 0x100001000functab[1].entryoff: 0x700x100001000 + 0x70 = 0x100001070internal/abi.BoundsDecode को 0x100001070 पर पुष्टि की।_func स्ट्रक्ट का लेआउट Go 1.18 और Go 1.20+ के बीच भिन्न होता है। एकमात्र परिवर्तन Go 1.20+ में ऑफसेट 36 पर 4-बाइट startLine फ़ील्ड का सम्मिलन है, जो funcID, flag, और nfuncdata को 4 बाइट्स से स्थानांतरित करता है:
| फ़ील्ड | Go 1.18 ऑफसेट | Go 1.20+ ऑफसेट |
|---|---|---|
entryOff | 0 | 0 |
nameOff | 4 | 4 |
args | 8 | 8 |
cuOffset | 32 | 32 |
startLine | (अनुपस्थित) | 36 |
funcID | 36 | 40 |
flag | 37 | 41 |
nfuncdata | 39 | 43 |
पार्सर यह निर्धारित करने के लिए मैजिक नंबर की जाँच करता है कि कौन सा लेआउट उपयोग करना है।
स्रोत फ़ाइल सूचकांक और लाइन नंबर pctab क्षेत्र में कॉम्पैक्ट "PC डेटा प्रोग्राम" के रूप में संग्रहीत होते हैं। प्रत्येक प्रोग्राम हस्ताक्षरित मानों के लिए zig-zag एन्कोडिंग के साथ परिवर्तनीय-लंबाई पूर्णांकों का उपयोग करके (value_delta, pc_delta) जोड़ों के अनुक्रम को एनकोड करता है। पार्सर इन्हें हल करने के लिए डिकोड करता है:
_func.pcfile -> pctab प्रोग्राम -> फ़ाइल सूचकांक -> cutab -> filetab -> फ़ाइल पथ स्ट्रिंग_func.pcln -> pctab प्रोग्राम -> लाइन नंबर (Go 1.20+ के लिए startLine ऑफसेट के साथ)इनलाइन किए गए फ़ंक्शन शीर्ष-स्तरीय फ़ंक्शन तालिका में दिखाई नहीं देते हैं। वे FUNCDATA_InlTree / PCDATA_InlTreeIndex संरचनाओं में एनकोड होते हैं, जिन्हें यह उपकरण वर्तमान में डिकोड नहीं करता है। परीक्षण बाइनरी में, main.helloWorld और main.addNumbers को संकलक द्वारा इनलाइन किया गया था और इसलिए वे आउटपुट में दिखाई नहीं देते हैं।
Go 1.2 समर्थन सर्वोत्तम प्रयास है। Go 1.2 प्रारूप काफी भिन्न है (कोई अलग funcnametab नहीं, कोई cutab नहीं, functab में निरपेक्ष पॉइंटर्स) और व्यवहार में शायद ही कभी सामना होता है।
बिग-एंडियन आर्किटेक्चर सिद्धांत रूप में संभाले जाते हैं (एंडियन का पता radare2 के बाइनरी जानकारी से लगाया जाता है और सभी स्ट्रक्ट रीड के लिए उपयोग किया जाता है) लेकिन परीक्षण नहीं किया गया है।
--apply मोड af+ के साथ फ़ंक्शन स्टब बनाता है जो r2 के स्वतः विश्लेषण के साथ संघर्ष कर सकता है। इसे एक साफ़ सत्र पर चलाने से ( aaa से पहले या उसके बजाय) कुछ मामलों में बेहतर परिणाम मिल सकते हैं।
विस्तृत तकनीकी दस्तावेज़ीकरण documentation/ निर्देशिका में उपलब्ध है: