Skip to content

C sharp (.NET)

.NET

简单来说,.NET 是微软开发的一个免费、跨平台、开源的开发者平台。它不仅仅是一门语言,而是一个包含语言、运行时(Runtime)和类库的完整生态系统。

  • 原材料:C#、F#、VB.NET 代码。

  • 产品:可以在 Windows、Linux、macOS、iOS、Android 上运行的程序。

1. 核心架构:CLR 和 FCL

  • CLR (Common Language Runtime,公共语言运行时):

    • 这是 .NET 的“虚拟机”或“引擎”。

    • 作用: 它负责管理内存(Garbage Collection)、线程执行、代码安全验证、异常处理等。

    • 回顾你的题目: DIE 检测出的 CLR v4.0.30319 就是指这个引擎的版本。你的 Matrix.exe 不是直接跑在 CPU 上,而是跑在 CLR 上,由 CLR 指挥 CPU 干活。

  • FCL (Framework Class Library,框架类库):

    • 这是一堆写好的标准代码库。

    • 作用: 提供像“文件读写”、“网络通信”、“加密算法”、“数据库连接”等现成功能。

    • 回顾你的题目: 你在代码里看到的 System.Console.WriteLine、System.Security.Cryptography、System.Text.StringBuilder,全是 FCL 提供的现成工具。

2. 运行机制:从源代码到机器码(重点)

这是逆向 .NET 程序(如 Matrix.exe)之所以容易反编译的根本原因。

传统的 C/C++ 编译是直接变成机器码(0和1),很难还原。而 .NET 的流程是:

  1. 源代码 (Source Code):你写的 if/else、for 循环。

  2. 编译 (Compile):C# 编译器(Roslyn)把代码编译成 MSIL (Microsoft Intermediate Language),即微软中间语言。

    • 关键点: 这就是 DIE 告诉你的 MSIL。它是半成品,包含大量元数据(Metadata),保留了类名、变量名、函数名。

    • 这就是为什么你可以用 dnSpy 看到几乎完美的源码,而不用看汇编。

  3. 运行时 (Runtime):当用户双击 EXE 时,CLR 启动。

  4. JIT (Just-In-Time) 编译:CLR 里的 JIT 编译器把 MSIL 实时翻译成当前电脑能听懂的本机机器码 (Native Code)。

3. .NET 的版本家族

  • **.NET Framework:

    • 老牌经典,仅支持 Windows。

    • 版本号通常是 v2.0, v3.5, v4.x(你的题目是 v4.5.2)。

    • 系统自带,兼容性好,目前主要处于维护模式。

  • .NET Core / .NET 5+ / .NET 6+:

    • 跨平台(Windows, Linux, Mac)。

    • 高性能,模块化。

    • 这是微软现在的重心。

  • Xamarin / Mono:

    • 主要用于移动端(Android/iOS)开发(比如 Unity 游戏引擎就大量使用 Mono)。

    • 如果做手游逆向,遇到的大多是基于 Mono 的 .NET 环境。

C# 结构(dnSpy)

图示:Pasted image 20260209143438

1. 根节点:程序集 (Assembly)

  • 位置: 树状图的最顶级节点 Matrix-Int (1.0.0.0)。

  • 含义: 这是一个编译后的二进制文件(.exe 或 .dll)。它是部署和版本控制的最小单元。

  • 逻辑: 你要分析哪个文件,就先找到这个文件的根节点。如果有多个 DLL 依赖,这里会列出一排。

2. 第一层子节点:模块 (Module)

  • 位置: Matrix-Int.exe (紫色图标)。

  • 含义: 程序集通常包含一个主模块(偶尔有多模块,但很少见)。

  • 逻辑: 这一层主要包含底层的 PE 头信息 (PE)、引用的其他库 (引用) 以及所有的代码定义。绝大多数时候,你只需要关注这一层下面的内容。

3. 第二层子节点:命名空间 (Namespace)

  • 位置: {} (花括号图标) 和 Matrix_Int (金色花括号)。

  • 含义: 命名空间是用来组织代码的“文件夹”。

    • {} (空命名空间): 这里的代码没有定义命名空间,通常包含一些编译器生成的底层代码,或者简单的“Hello World”级代码。

    • Matrix_Int: 这是开发者自定义的命名空间。通常,核心业务逻辑都藏在名字看起来像项目名(如 Matrix_Int)的命名空间里。

  • 逻辑: 寻找 Main 方法时,优先展开那个名字最像程序本身名字的命名空间。

4. 第三层子节点:类 (Class)

  • 位置: Matrix, Program, Square (带有三色方块图标)。

  • 含义: 类是代码的容器。

    • Program 类: 在 C# 控制台程序(Console App)中,按照约定俗成的惯例,程序的入口点通常放在名为 Program 的类中。

    • Matrix / Square 类: 这些通常是辅助类,定义了数据结构(如矩阵)和特定算法。

  • 逻辑:

    • 找入口?找 Program。

    • 找算法?找 Matrix 或 Util。

    • 找界面逻辑?找 Form1 或 MainWindow。

5. 第四层子节点:成员 (Member)

  • 位置: Program 类下方的 Main, GetSquare (紫色立方体图标)。

  • 含义: 这是具体的代码块。

    • Main(string[]) : void: 这是标准的 C# 入口方法。当你双击 EXE 时,系统首先执行这里的代码。注意它的图标上有一把小锁,表示它是 private (私有) 的;如果是星星,表示是 protected;如果是手掌,表示是 public。但在 dnSpy 中,这种权限限制对你无效,你可以随意查看。

    • GetSquare(): 这是 Program 类里的另一个辅助方法。

  • 逻辑: 逆向的第一步,永远是双击 Main,从这里开始顺藤摸瓜。


总结:你的寻找逻辑

当你拿到一个新的 .NET 题目时,在 dnSpy 左侧的点击顺序应该是:

  1. 展开程序集 (Matrix-Int) -> 确认加载成功。

  2. 展开模块 (Matrix-Int.exe) -> 进入代码区。

  3. 寻找核心命名空间 (Matrix_Int) -> 避开 Microsoft 或 System 开头的系统库。

  4. 定位入口类 (Program) -> 绝大多数控制台程序的入口都在这。

  5. 锁定入口方法 (Main) -> 双击它,右侧就会显示代码。

  6. 如果不确定入口在哪里,直接选中最顶层的 程序集节点 (Matrix-Int (1.0.0.0) ),在右侧代码区找 [assembly: ...] 下方,通常会有 Entry Point: ... 的链接,点击它就能一键跳转到 Main 方法,省去一层层翻找的麻烦。