
03 · 符号混淆名称就是第一道防线目录为什么名称本身就能构成防线VTable跨继承链的名称一致性NameServiceConditionalWeakTable 驱动的重命名引擎六种命名模式跨模块协同ProtectionSession.RunRename引用追踪INameReference 体系可见性过滤与不可重命名标记结语1. 为什么名称本身就能构成防线混淆前MyApp.LicenseValidator.Validate(string key) MyApp.PaymentProcessor.ProcessTransaction(decimal amount) MyApp.CryptoHelper.Encrypt(byte[] data)混淆后\u200b.\u200c\u200d(int a) \u200b.\u200b\u200c(decimal a)消除名称中的语义信息 攻击者无法通过名称判断该分析哪个类。2. VTable跨继承链的名称一致性基类和子类的 override 方法必须使用同一个新名称。我们的VTableAnalyzer追踪完整的继承链// 构建 VTable 关系链publicstaticvoidAnalyze(IEnumerableTypeDeftypes){foreach(vartypeintypes){foreach(varmethodintype.Methods){if(!method.IsVirtual||method.IsRuntime)continue;// 追溯基类中的原始方法声明varbaseMethodmethod.GetBaseMethod();if(baseMethodnull)continue;// 收集整个 override 链上的所有方法varoverridesFindAllOverrides(baseMethod);// 所有同链方法分配同一个 VTableSlot// 确保重命名后名称一致varslotnewVTableSlot(baseMethod,overrides);_vtableSlots.Add(slot);}}}接口方法通过MethodImpl映射与隐式接口实现自动关联。3. NameServiceConditionalWeakTable 驱动的重命名引擎使用ConditionalWeakTable替代传统 Dictionary实现零侵入的元数据注解publicclassNameService{// ConditionalWeakTable 不阻止 GC 回收比 Dictionary 更安全readonlyConditionalWeakTableIDnlibDef,NameAnnotation_annotationsnew();// 6 种命名模式staticreadonlychar[]unicodeCharset{\u200b,\u200c,\u200d,\u200e,\u200f,\u202a,\u202b,\u202c,\u202d,\u202e,...};staticreadonlychar[]letterCharset...;// 字母表staticreadonlychar[]asciiCharset...;// ASCIIstaticreadonlychar[]alphaNumCharset...;// 字母数字// 核心方法根据哈希值和模式生成新名称stringObfuscateNameInternal(byte[]hash,RenameModemode){returnmodeswitch{RenameMode.Empty,RenameMode.UnicodeNameUtils.EncodeString(hash,unicodeCharset),RenameMode.LettersNameUtils.EncodeString(hash,letterCharset),RenameMode.ASCIINameUtils.EncodeString(hash,asciiCharset),RenameMode.Decodable_NameUtils.EncodeString(hash,alphaNumCharset),RenameMode.Sequential_Interlocked.Increment(ref_seqCounter),};}// AnalyzeAll 三阶段收集 → 构建VTable → 分析引用publicvoidAnalyzeAll(){...}// RenameAll延迟重命名 迭代收敛 死锁检测publicvoidRenameAll(){...}}4. 六种命名模式模式字符集示例名称适用Empty“”空字符串极简UnicodeU200B-U206F\u200b\u200c\u200d不可见最大隐蔽性ASCIIa-zabc,xyz,aab轻型混淆Letters拉丁字符cnffjbe(ROT13 风格)可读但无意义Decodable字母数字_A1B2C3D4调试友好Sequential递增数字_1,_2,_3调试友好通过--rename-mode mode选择。5. 跨模块协同ProtectionSession.RunRenamepublicclassProtectionSession{publicIListProtectionContextContexts{get;}// 所有模块上下文publicNameService?NameService{get;}// 共享名称服务publicRandomServiceRandom{get;}// 共享随机数publicvoidRunRename(){if(NameServicenull)return;// 阶段1收集所有模块的可重命名成员// 阶段2构建跨模块 VTable 关系图NameService.AnalyzeAll();// 阶段3统一分配新名称 更新所有跨模块引用NameService.RenameAll();}}关键EXE 中引用的 DLL 类型在 DLL 重命名后同步更新引用。6. 引用追踪INameReference 体系// 每种引用类型实现 INameReferencepublicinterfaceINameReference{stringName{get;set;}boolShouldUpdate{get;}voidUpdateName(stringnewName);}// TypeRef 引用A.dll 的 TypeRef MyClass 在 B.exe 中classTypeRefReference:INameReference{...}// MemberRef 引用如调用 A.dll 的方法classMemberRefReference:INameReference{...}// Override 指令.override IL 指令classOverrideDirectiveReference:INameReference{...}// 兄弟方法同 class 中隐藏/重写的方法classMemberSiblingReference:INameReference{...}7. 可见性过滤与不可重命名标记// 默认不重命名 public 成员if(member.IsPublic!options.RenamePublic)continue;// 标记为不可重命名运行时注入类型MarkAsNotRenameable(injectedType);MarkAsNotRenameable(injectedMethod);// 在 ObfuscationStep.IsEnabled 中检查boolCanRename(IDnlibDefdef)!HasAttributeNotRenameableAttribute(def);8. 结语符号混淆看似简单实际上要处理 VTable 继承链、接口映射、跨模块引用、ConditionalWeakTable 注解等大量细节。好的混淆器不是全改就完事而是精准地只改该改的部分。下一篇将深入控制流混淆——如何打乱方法的执行逻辑。本文由 TWSoft.AssemblyProtector 驱动。完整源码和工具请访问项目主页。