اللغات: English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Italiano | Русский | العربية
← فهرس التوثيق · ← مشروع NeverC
يُحوِّل مصدر C مباشرةً إلى dyncode ثنائي مسطح مستقل عن الموضع، بلا إعادة تموضع، بلا قسم بيانات.
- دليل تجميع ARM64 (AArch64) — منظور DynCode
- نظرة عامة على البنية متعددة المنصات لـ NeverC DynCode
- تصميم مرورات IR — المبادئ، المسار، وأمثلة قبل/بعد
- دعم dyncode وضع النواة (Ring-0)
- تصميم مرورات MIR — المبادئ ونقاط الخطاف
- مسار DynCode وMIR واستراتيجية PIC (ملاحظات التصميم)
- دليل توسيع المنصة
- مُجمِّع dyncode — تتبع التقدم
- خارطة الطريق
- اكتب C عاديًا — دون حيل خاصة بـ dyncode.
- مسار تلقائي بالكامل —
static int counter = 0وconst char s[] = "..."والدوال العودية وwrite/exit/read/...والمصفوفات الثابتة الكبيرة تُعالَج داخليًا دون تعديل كود المستخدم. - صفر تبعيات خارجية — المخرج
.binتيار تعليمات خالص بلا dyld أو libSystem أو قسم بيانات. - خيارات CLI عبر TableGen — كل
-fdyncode-*فيneverc/include/neverc/Invoke/Options.td.h(لا مطابقة نصوص صلبة). الأخطاء الإملائية → did-you-mean؛--helpيعرض الكل. - قيود المخرجات قابلة للتحقق —
-fdyncode-bad-bytes=/-fdyncode-bad-byte-profile=يفحصان.binالنهائي بعد post-extract ويرفضان المخرجات عند البايتات المحظورة مع الإزاحة والبايت والسياق. - مسار واحد متعدد المنصات — يقوده جدول
TargetDesc. نفس مصدر C لـ macOS / Linux / Android / Windows. منصة جديدة = صف في الجدول + مُستخرج واحد، لا تكرار خمس مجموعات passes.
| Triple | الصيغة | syscall وضع المستخدم | محلل Ring-0 | الحالة |
|---|---|---|---|---|
arm64-apple-macos* |
Mach-O | svc #0x80 (Darwin BSD) |
DarwinXNUKextShim |
Native loader round-trip + kernel resolver covered |
x86_64-apple-macos* |
Mach-O | syscall (BSD class mask 0x2000000) |
DarwinXNUKextShim |
Compile + extract passing; x86_64 __text has no reloc expectation |
aarch64-linux-gnu |
ELF | svc #0 (x8 = nr) |
LinuxKallsymsShim |
Compile + extract + kernel resolver passing |
x86_64-linux-gnu |
ELF | syscall (rax = nr) |
LinuxKallsymsShim |
Compile + extract + kernel resolver passing |
aarch64-linux-android* |
ELF | Same as Linux arm64 | LinuxKallsymsShim (GKI) |
Compile + extract passing |
x86_64-linux-android* |
ELF | Same as Linux x86_64 | LinuxKallsymsShim (GKI) |
Compile + extract passing |
aarch64-pc-windows-msvc |
PE/COFF | PEB walk (ldr xN, [x18, #0x60]) |
WindowsKernelResolverShim |
User-mode PEB read byte sentinel 32 40 f9 validated; ring-0 uses loader resolver |
x86_64-pc-windows-msvc |
PE/COFF | PEB module walk + PE export-table lookup | WindowsKernelResolverShim |
User-mode resolver is full IR-level PEB walk; ring-0 does not reuse PEB |
الثمانية triples (OS, arch) تُشغَّل جميعها بـ نفس مجموعة الـ passes. الاختلافات معزولة في صفوف TargetDesc.cpp وثلاث فروع للمُستخرجات. منصة جديدة = صف إضافي في الجدول + case في كل مُستخرج. بُعد ExecutionLevel متعامد: User يستخدم مسار syscall / PEB في وضع المستخدم؛ Kernel يعطّل الاثنين ويحقن KernelImportPass لإعادة كتابة استدعاءات extern عبر shims. راجع kernel-mode-dyncode.md.
# Always pass -target — output triple is independent of the compiler host.
# 1) Pure computation dyncode — no system calls
neverc -fdyncode -target arm64-apple-macos add.c -o add.bin
# 2) Darwin hello world — write/exit → svc #0x80
neverc -fdyncode -target arm64-apple-macos -mdyncode-syscall hello.c -o hello.bin
# 3) Linux arm64: svc #0 + x8=nr
neverc -fdyncode -target aarch64-linux-gnu -mdyncode-syscall \
hello.c -o hello_linux_arm64.bin
# 4) Linux x86_64: syscall + rax=nr
neverc -fdyncode -target x86_64-linux-gnu -mdyncode-syscall \
hello.c -o hello_linux_x64.bin
# 5) Windows x86_64 (PEB walk for API calls)
neverc -fdyncode -target x86_64-pc-windows-msvc \
-mdyncode-win-peb-import win.c -o win.bin
# 6) Custom entry symbol
neverc -fdyncode -target arm64-apple-macos -fdyncode-entry=dyncode_main kernel.c -o k.bin
# 7) Keep intermediate object for audit (otool / llvm-objdump / dumpbin)
neverc -fdyncode -target arm64-apple-macos -fdyncode-keep-obj=/tmp/dump.obj x.c -o x.bin
# 8) Reject forbidden bytes in final .bin
neverc -fdyncode -target arm64-apple-macos -fdyncode-bad-bytes=00,0a,0d x.c -o x.bin
# 9) Built-in bad-byte profile (same as forbidding 00/0a/0d)
neverc -fdyncode -target arm64-apple-macos -fdyncode-bad-byte-profile=http-newline x.c -o x.bin
# 10) Run on macOS (platform-specific loader)
./loader_arm64_macos add.bin 3 4 # exit code = 7
# 11) Verbose extractor summary
neverc -v -fdyncode -target arm64-apple-macos fib.c -o fib.bin
# dyncode-extractor: wrote 64 bytes to 'fib.bin'
# dyncode-extractor: target = arm64-apple-macos (Mach-O)
# dyncode-extractor: entry symbol = _main
# dyncode-extractor: patched 1 BRANCH26, 0 PAGE21, 0 PAGEOFF12 intra-section reloc(s)| الخيار | الوصف |
|---|---|
-fdyncode |
تفعيل وضع تجميع dyncode. |
-fno-dyncode |
إلغاء -fdyncode سابق. |
-fdyncode-all-blr |
وضع عدواني: تحويل الاستدعاءات المباشرة داخل الوحدة إلى blr xN / call *rax وإزالة relocs الفروع النسبية. غير مطلوب في الاستخدام العادي. |
-mdyncode-syscall |
تفعيل صريح لـ syscall stubs (افتراضي مع -fdyncode على Darwin/Linux/Android؛ للنية أو توافق السكربتات). |
-mdyncode-libsystem |
اسم Darwin القديم لـ -mdyncode-syscall. |
-mdyncode-win-peb-import |
تفعيل صريح لاستيراد PEB في Windows (افتراضي مع -fdyncode + triple Windows). |
-fdyncode-keep-obj=<path> |
نسخ ملف الكائن الوسيط إلى <path> للتدقيق بمُفكك تجميع أصلي. |
-fdyncode-entry=<name> |
استبدال اسم نقطة الدخول (main, _main, dyncode_entry, _dyncode_entry). |
-fdyncode-bad-bytes=<hex-list> |
قائمة بايتات محظورة مفصولة بفواصل. فحص .bin النهائي بعد post-extract؛ عند التطابق يفشل التجميع دون كتابة ملف. |
-fdyncode-bad-byte-profile=<name> |
ملفات محظورة مدمجة: null, c-string, http-newline, line, whitespace, ascii-control. قابلة للجمع مع -fdyncode-bad-bytes=. |
-fdyncode-obfuscate=<spec> |
يُمرَّر إلى خطافات التشويش مستوى IR عبر واجهة الإضافات. no-op بدون إضافة. راجع ir-pass-design.md §9. |
-fdyncode-mir-obfuscate=<spec> |
يُمرَّر إلى خطافات مستوى MIR. الافتراضي -fdyncode-obfuscate= إن لم يُحدَّد. راجع mir-pass-design.md §3. |
ينقسم المسار إلى مرورات IR مستقلة عن الهدف + مُستخرجات خاصة بالمنصة:
flowchart TD
Driver["neverc -fdyncode · OptTable + Options.td.h"]
Frontend["C23 Frontend · PIC default"]
Driver -->|describeTriple| Frontend
Frontend -->|LLVM IR| ZRP
subgraph IR["Target-Independent IR Passes"]
direction TB
ZRP["① ZeroRelocPass — Prep\ninternal + always_inline\nreject ctors / thread_local / extern_weak"]
IBP["② IndirectBrPass\ncomputed-goto → switch"]
SSP["③ SyscallStubPass\nlibc → svc #0x80 / svc #0 / syscall"]
WPP["④ WinPEBImportPass\nextern Win32 API → PEB-walk thunk"]
MIP["⑤ MemIntrinPass\nmemcpy/memset/str* → byte-loop"]
CRP["⑥ CompilerRtPass\ni128 div/mod → inline long-division"]
D2T1["⑦ Data2TextPass — Phase 1\nconst GV → stack stores"]
ZRP --> IBP --> SSP --> WPP --> MIP --> CRP --> D2T1
end
Backend["AArch64 / X86 Backend\nSROA · InstCombine · AlwaysInliner · SLP"]
D2T1 --> Backend
Backend --> D2T2
subgraph Post["Post-Backend IR"]
direction TB
D2T2["⑧ Data2TextPass — Phase 2\nvector const split"]
ZRS["⑨ ZeroRelocPass — Stackify\nglobals → entry alloca"]
ABP["⑩ AllBlrPass (optional)\ndirect call → indirect call"]
D2T2 --> ZRS --> ABP
end
Codegen["Codegen · IR → MIR → Register Allocation"]
ABP --> Codegen
Codegen --> MH1
subgraph MIR["MIR Layer"]
direction TB
MH1["⑪ RunBeforePreEmit interpose"]
MIRP["⑫ DynCodeMIRPrepPass\nstrip CFI / EH_LABEL / XRay / StackMap"]
MH2["⑬ RunAfterPreEmit interpose\ninstruction-level obfuscation entry"]
MH1 --> MIRP --> MH2
end
MH2 -->|"Mach-O / ELF / COFF .o"| Extractor
subgraph Extract["Extractor Layer"]
Extractor["DynCodeExtractor\nMachO · ELF · COFF\npatch intra-.text relocs\nreject external reloc / data section\nbad-byte audit"]
end
Extractor --> Output(["flat .bin dyncode"])
يُعرّف neverc/include/neverc/DynCode/Pipeline/TargetDesc.h بنية TargetDesc لكل تركيبة (OS, arch):
TextSectionName: Mach-O__text/ ELF.text/ COFF.textSyscallABI: enum value (DarwinSvc80/LinuxSvc0/LinuxSyscall/WindowsPEB/None)AsmTemplate:svc #0x80/svc #0/syscallSyscallNumberReg: x16 / x8 / raxSyscallRetReg: x0 / raxArgRegs: ordered list of platform ABI argument registers + countTCBReadAsm/TCBReadConstraint: inline-asm single-instruction template for reading TEB/PEB pointer (Windows x86_64 =movq %gs:0x60, $0, Windows arm64 =ldr $0, [x18, #0x60]).WinPEBImportPassreads directly from the table.DriverInjectFlags: platform-specific driver flags as a null-terminated static array (x86_64 Unix gets-fpic -mcmodel=small; Windows gets-mno-stack-arg-probe//GS-).perTargetInjectFlagsreads from the table.
يولّد SyscallStubPass وWinPEBImportPass InlineAsm من حقول TargetDesc. الخلفية تستخدم أنماط TableGen. هدف جديد = صف إضافي في describeTriple وcase في كل مُستخرج.
| الصيغة | التنفيذ | relocs داخل القسم القابلة للترقيع |
|---|---|---|
| Mach-O | MachOExtractor.cpp |
arm64: ARM64_RELOC_BRANCH26 / PAGE21 / PAGEOFF12; x86_64: X86_64_RELOC_SIGNED / SIGNED_1/2/4 / BRANCH (intra-__text pcrel32); UNSIGNED / GOT_LOAD / GOT / SUBTRACTOR / TLV rejected |
| ELF | ELFExtractor.cpp |
arm64: R_AARCH64_CALL26 / JUMP26 / ADR_PREL_PG_HI21(_NC) / ADD_ABS_LO12_NC / LDST{8,16,32,64,128}_ABS_LO12_NC / PREL32; x86_64: R_X86_64_PC32 / PLT32 (GOTPCREL rejected) |
| COFF | COFFExtractor.cpp |
arm64: IMAGE_REL_ARM64_BRANCH26 / PAGEBASE_REL21 / PAGEOFFSET_12A / PAGEOFFSET_12L / REL32; x86_64: IMAGE_REL_AMD64_REL32 / REL32_[1-5] |
أي نوع آخر أو reloc بين الأقسام يفشل مع تلميحات (libc → stub syscall / _Complex → struct يدوي / fallback تجمع backend، إلخ).
| السيناريو | كود المستخدم | مدعوم | الآلية |
|---|---|---|---|
| Integer arithmetic / bitwise | int f(int a) { return a*3+1; } |
نعم | Pure instruction stream |
| Recursion / loops | int fib(int n) { ... } |
نعم | static + always_inline |
switch / case |
switch (op) { case 0: ... } |
نعم | Driver injects -fno-jump-tables |
| Struct by-value passing | struct Vec3 v = {...}; dot(v); |
نعم | Stack-ified + always_inline |
| Floating-point | double y = x * 3.14; |
نعم | Data2Text rewrites ConstantFP to volatile-loaded bit pattern |
| Small constant arrays | const int t[4] = {1,2,3,4}; |
نعم | Data2Text stack-ifies |
| Large constant arrays (256B+) | const unsigned char tbl[256] = {...} |
نعم | Data2Text, no size limit |
| String literals | const char s[] = "hi\n"; |
نعم | Data2Text stack-ifies |
memcpy / memset / memmove / memcmp |
memcpy(dst, src, n); |
نعم | MemIntrinPass byte-loop wrappers |
strlen / strcpy / strcmp / etc. |
strlen(buf); |
نعم | MemIntrinPass byte-loop wrappers |
__int128 division / modulo |
u128 q = a / b; |
نعم | CompilerRtPass inline long-division |
_Atomic / __atomic_* / __sync_* |
__atomic_fetch_add(&c, 1, ...) |
نعم | Inline LDXR/STXR (arm64) / LOCK (x86_64) |
__builtin_* family |
__builtin_popcount(x) |
نعم | Backend single-instruction selection |
| VLA / flexible array / compound literal | Normal C99/C11 | نعم | -fno-jump-tables + Data2Text |
| Mutable globals | static int counter = 0; |
نعم | ZeroReloc stack-ifies |
| libc write/exit | write(1, s, 3); |
نعم (مع -mdyncode-syscall) |
Syscall wrapper |
| POSIX includes | #include <unistd.h> |
نعم (وضع dyncode يبدّل تلقائياً إلى shim) | Driver injects __NEVERC_DYNCODE__ |
| Win32 API | WriteFile(h, buf, n, &w, 0); |
نعم (مع -mdyncode-win-peb-import) |
PEB-walk thunk |
| Windows SDK includes | #include <windows.h> |
نعم (وضع dyncode يبدّل تلقائياً إلى shim) | Lightweight shim headers |
| Custom entry name | int dyncode_main(...) |
نعم (مع -fdyncode-entry=...) |
Driver pass-through |
| Global constructors | __attribute__((constructor)) |
لا | لا يوجد runtime لتشغيلها |
| TLS / thread_local | thread_local int x; |
Auto-demoted to static | ZeroRelocPass.Prep silently demotes |
| C++ / ObjC | — | لا | المشروع C فقط |
neverc/
├── include/neverc/Invoke/Options.td.h # -fdyncode-* TableGen definitions
├── include/neverc/DynCode/ # Headers (organized by subsystem)
│ ├── Pipeline/ # Pipeline / driver integration
│ │ ├── Pipeline.h # IR + MIR interpose registration
│ │ ├── DriverIntegration.h
│ │ ├── TargetDesc.h # Platform table / descriptors
│ │ ├── DynCodeOptions.h # Cross-subsystem config
│ │ ├── Diagnostics.h # Cross-subsystem diagnostics
│ │ └── SymbolNames.h # Cross-subsystem symbol utilities
│ ├── Extractor/
│ │ └── DynCodeExtractor.h
│ ├── IR/ # IR-level passes and ABIs
│ │ ├── ZeroRelocPass.h / ZeroRelocABI.h
│ │ ├── Data2TextPass.h / Data2TextABI.h
│ │ ├── AllBlrPass.h / IndirectBrPass.h
│ │ ├── MemIntrinPass.h # memcpy/memset/str* inlining
│ │ ├── StringRuntimePass.h / StringRuntimeABI.h
│ │ ├── HeapArenaPass.h # malloc/free → arena + OS fallback
│ │ ├── MmapABI.h # Shared mmap constants (prot/flags)
│ │ ├── DynCodeIRHelpers.h # Common IR utilities (getSizeType, etc.)
│ │ ├── ExternRewriter.h # Extern function rewrite utilities
│ │ └── CompilerRtPass.h # __int128 division inline
│ ├── MIR/
│ │ └── MIRPrepPass.h # Catch-all MachineFunctionPass
│ ├── Import/ # User-mode + kernel-mode import resolution
│ │ ├── SyscallStub.h / SyscallTables.h
│ │ ├── WinPEBImport.h / WinImportTables.h
│ │ ├── KernelImportPass.h / KernelImportABI.h
│ │ └── PtrCacheHelpers.h # Shared address cache encryption helpers
│ └── Tables/ # User-extensible .def tables
├── lib/DynCode/ # Implementation (mirrors header structure)
│ ├── Pipeline/ Extractor/ IR/ MIR/ Import/
└── lib/Invoke/Core/Driver.cpp
tests/neverc/ # Tests (GTest)
├── DynCodeTests.cpp # Core dyncode round-trip tests
├── DynCodeStressTests.cpp # Stress tests (VLA, __sync_*, __int128, etc.)
├── DynCodeCrossTargetTests.cpp # Cross-target compile-only smoke tests
├── dyncode/
│ ├── loader_arm64_macos.c / loader_linux.c / loader_windows.c
│ └── test_dyncode_*.c
docs/dyncode-compiler/
├── README.md ← English
├── README.ar.md ← العربية
├── arm64-assembly-tutorial/README.md
├── cross-platform-architecture/README.md
├── ir-pass-design/README.md
├── kernel-mode-dyncode/README.md
├── mir-pass-design/README.md
├── pipeline-and-pic/README.md
├── platform-extension-guide/README.md
├── progress/README.md
└── roadmap/README.md
- يجب أن يكون عنوان تحميل dyncode بمحاذاة 4 كيلوبايت — سلوك
mmap/VirtualAllocالطبيعي؛ محمّلات الاختبار تلتزم بذلك. - اتفاقيات الاستدعاء تتبع ABI الأصلية لنظام التشغيل:
- Darwin / Linux / Android: System V AMD64 or AAPCS64
- Windows: Win64 (rcx/rdx/r8/r9)
- المُحمّل مسؤول عن تفريغ ذاكرة التعليمات (arm64) / FlushInstructionCache (Windows).
مسار dyncode نفسه يضمن فقط «أن الكود يعمل بشكل صحيح». التشويش وتعدّد الأشكال والمُشفّرات المرحلية وميزات طبقة الاستراتيجية المشابهة غير مضمّنة عمداً — توفّرها إضافات خارج الشجرة عبر واجهة الإضافات.
يعرض المسار 11 نقطة ربط عبر ثلاث طبقات، جميعها متاحة عبر واجهة C Plugin API (NEVERC_INTERPOSE_SC_*):
مستوى IR (6 خطافات):
NEVERC_INTERPOSE_SC_BEFORE_PREP— Before any dyncode passNEVERC_INTERPOSE_SC_AFTER_PREP— Linkage unified (internal + always_inline)NEVERC_INTERPOSE_SC_BEFORE_INLINING— Last chance before AlwaysInlinerNEVERC_INTERPOSE_SC_AFTER_INLINING— IR fully compressed into one large functionNEVERC_INTERPOSE_SC_AFTER_STACKIFY— Final IR shape, next step is codegenNEVERC_INTERPOSE_SC_AFTER_FINAL_IR— After AllBlrPass, the true last IR interpose
مستوى MIR (3 خطافات):
NEVERC_INTERPOSE_SC_BEFORE_PREEMIT— Registers allocated, CFI/EH pseudos still presentNEVERC_INTERPOSE_SC_AFTER_PREEMIT— Built-in MIRPrepPass has stripped pseudos, closest to the byte form AsmPrinter will see; ideal for instruction-level obfuscation/register renamingNEVERC_INTERPOSE_SC_AFTER_FINAL_MIR— True last MIR interpose, after LLVMaddPreEmitPass2(), just before AsmPrinter
مستوى تيار البايتات (2 خطافات):
NEVERC_INTERPOSE_SC_POST_EXTRACT— After extractor completes intra-text relocation patching and data-section audit; before.binis written. Use for whole-payload encryption, junk byte insertion, or custom headers.NEVERC_INTERPOSE_SC_POST_FINALIZE— After all finalize steps; NeverC performs no further auditing.
راجع وثائق واجهة الإضافات للاطلاع على قائمة نقاط الربط الكاملة وتسجيل المرورات وأمثلة الكود.
- IR-level: ir-pass-design.md §9 — Obfuscation Interposes.
- MIR-level: mir-pass-design.md §3 — User Obfuscation Interposes.
- يدعم 8 تركيبات (OS, arch) (انظر المصفوفة). triples أخرى (RISC-V، PowerPC، x86 32-bit، ARM big-endian، إلخ) تُرفض في
describeTriple()مع قائمة المدعوم. كل صف له سياقاتUser/Kernelمستقلة → 16 متغيراً (OS, arch, مستوى). - اجتياز PEB في Windows مُنفَّذ بالكامل مع توزيع multi-DLL.
__neverc_win_resolveيقبل أزواج(dll_hash, api_hash). القائمة البيضاء الحالية تغطي kernel32.dll (~125 API)، ntdll.dll (~26)، user32.dll (~13)، ws2_32.dll (~23)، advapi32.dll (~16)، shell32.dll (~6). إضافة API = صف فيTables/Win32Apis.def+ إعلان فيlib/Headers/windows.h. - القائمة البيضاء للدوال الخارجية تغطي syscalls شائعة لـ Darwin BSD / Linux / Android (~80+) + Win32 (~190). stdio وواجهات runtime الثقيلة غير مشمولة — dyncode لا يمكنه تضمين آلة حالة stdio كاملة.
- لا يدعم C++ / ObjC / CUDA — NeverC مخصّص لـ C فقط.