.Net 反射脱壳机代码核心代码详解

简介: 本文主要对 《.Net 反射脱壳机核心源代码 》一文代码的原理和使用进行详细介绍。 首先介绍一下代码主要流程: 入口函数 void DumpAssembly(Assembly ass,string path) 枚举所有type,调用 void DumpType(Type tp, BinaryWri...

本文主要对 《.Net 反射脱壳机核心源代码 》一文代码的原理和使用进行详细介绍。


首先介绍一下代码主要流程:
入口函数
void DumpAssembly(Assembly ass,string path)
枚举所有type,调用
void DumpType(Type tp, BinaryWriter sw)
枚举所有方法,调用
void DumpMethod(MethodBase mb, BinaryWriter sw)
{
MethodBody mbd = mb.GetMethodBody();
if (mbd == null)
return;
SetOffset(sw, mb.MetadataToken);

WriteHeader(sw, mbd);

WriteILCode(sw, mbd);

WriteSEH(sw, mbd);

}

对于 DumpAssembly, DumpType 在很久以前的文章里面就已经介绍过了,这里就不再重复。本次主要介绍 DumpMethod 以及被 DumpMethod直接或间接调用的函数。

在我之前的一篇文章《Net内存程序集通用脱壳机实现原理(二、反射以及重建方法头) 》 中介绍过,方法体是由三部分组成的, 方法头+IL字节码+SEH Table。

再来看 DumpMethod 的代码,首先获取 MethodBody ,这里要注意不是所有方法都存在 MethodBody,像PInvoke 调用 api的方法就没有MethodBody。在元数据中 rva 等于 0 的方法,就是没有MethodBody的方法。在C#中我们可以直接判断返回值是否 null 来确定这一点。
获取方法体后调用SetOffset , 这个函数用来设置当前方法体在文件中的偏移量。设置好偏移量后,我就可以直接把方法体的三部分写入文件了。

SetOffset函数,通过元数据查找方法体的rva,然后
int offsetra = (int)(offsetrva - 0x1000);
计算出文件中的偏移量,注意这里的 0x1000 是硬编码,你可能需要调整这个值,或者根据pe的section自动计算这个值。

WriteHeader 函数 中,首先调用 IsTiny 判断当前方法体是否 Tiny方法体,然后进行相应的方法头重构并写入文件。

WriteILCode 这个函数很简单,就是直接把IL字节码写入文件,在这个函数的最后处理了4字节对齐问题,SEH TABLE起始位置需要要4 byte对齐的。

最后调用 WriteSEH(sw, mbd) 重构SEH TABLE并写入文件,完成一个方体的dump工作。

WriteSEH 函数中,首先判断当前是否包含异常处理结构,如果没有就直接返回了。
然后 判断 SEH TABLE 是 Tiny的还是 Fat的。
再分别重构相应格式的SEH TABLE。

SEH TABLE 也是由两部分组成的,sehHeader + sehRows。
其中 不管是tiny还是fat的seh,其sehHeader都占用 4 字节空间。
按照cli标准重构seh比较简单,其中有一个麻烦事,就是 catch子句中,被catch的异常类在当前程序集中的token值。
我们能够在C#中直接得到这个 异常类的 type 对象,但是通过 type的metatoken得的值是它在其被定义程序集中的token值,也就是它是一个 typedef值,如果它就是在当前程序集中定义的,那么可以直接使用。如果不是,就需要解析它的 typeref token值了。这个由函数 int GetTypeToken(Type tp) 来实现。

注意 GetTypeToken 使用了 if (tp.Assembly == Assembly.GetEntryAssembly())
来判断 是否同一程序集,因为这里假定了 当前dump的就是 EntryAssembly。你可能需要根据实际情况修改。

查找 typeref值的原理,首先通过type对象获取 异常类的完整名称,然后通过元数据枚举所有引用的 类型,通过 名称比较。名字一样的就是了。


使用:
如何使用这个类来自己实现反射脱壳机?
首先你需要修改 DumpAssembly 为 public的函数。
然后实例化这个类,调用 DumpAssembly 函数即可。
第一个参数你你要dump的 Assembly 对象,第二个参数是这个 Assembly dump后的存储路径。注意第二参数,这里没有实现pe dumper 的功能,你需要先用pe dumper把程序集dump到 磁盘,然后把这个路径 作为参数传入。

尝试过直接用pe dump的人应该都清楚,直接从内存里面整个dump出来的程序集,方法体也是空的,然后这个类实现的功能,就是补充方法体的内容。

另外前面提到的这个类需要改造的地方
1,SetOffset函数。
2,GetTypeToken函数。

还有就是这个类中使用的 WrapperClass 实际上是 。net 元数据API的包装类,元数据api可以参考 msdn。

 

 


 

目录
相关文章
|
4月前
|
API
【Azure 媒体服务】Media Service的编码示例 -- 创建缩略图子画面的.NET代码调试问题
【Azure 媒体服务】Media Service的编码示例 -- 创建缩略图子画面的.NET代码调试问题
|
19天前
|
开发框架 .NET PHP
ASP.NET Web Pages - 添加 Razor 代码
ASP.NET Web Pages 使用 Razor 标记添加服务器端代码,支持 C# 和 Visual Basic。Razor 语法简洁易学,类似于 ASP 和 PHP。例如,在网页中加入 `@DateTime.Now` 可以实时显示当前时间。
|
1月前
|
敏捷开发 缓存 中间件
.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素
本文深入探讨了.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素,并通过企业级应用和Web应用开发的实践案例,展示了如何在实际项目中应用这些模式,旨在为开发者提供有益的参考和指导。
24 3
|
4月前
|
C# 开发者 Windows
在VB.NET项目中使用C#编写的代码
在VB.NET项目中使用C#编写的代码
62 0
|
2月前
|
前端开发 JavaScript C#
CodeMaid:一款基于.NET开发的Visual Studio代码简化和整理实用插件
CodeMaid:一款基于.NET开发的Visual Studio代码简化和整理实用插件
|
3月前
|
C#
在.NET Core中灵活使用反射
在.NET Core中灵活使用反射
|
4月前
|
Kubernetes 监控 Devops
【独家揭秘】.NET项目中的DevOps实践:从代码提交到生产部署,你不知道的那些事!
【8月更文挑战第28天】.NET 项目中的 DevOps 实践贯穿代码提交到生产部署全流程,涵盖健壮的源代码管理、GitFlow 工作流、持续集成与部署、容器化及监控日志记录。通过 Git、CI/CD 工具、Kubernetes 及日志框架的最佳实践应用,显著提升软件开发效率与质量。本文通过具体示例,助力开发者构建高效可靠的 DevOps 流程,确保项目成功交付。
91 0
|
4月前
|
XML 开发框架 .NET
.NET框架:软件开发领域的瑞士军刀,如何让初学者变身代码艺术家——从基础架构到独特优势,一篇不可错过的深度解读。
【8月更文挑战第28天】.NET框架是由微软推出的统一开发平台,支持多种编程语言,简化应用程序的开发与部署。其核心组件包括公共语言运行库(CLR)和类库(FCL)。CLR负责内存管理、线程管理和异常处理等任务,确保代码稳定运行;FCL则提供了丰富的类和接口,涵盖网络、数据访问、安全性等多个领域,提高开发效率。此外,.NET框架还支持跨语言互操作,允许开发者使用C#、VB.NET等语言编写代码并无缝集成。这一框架凭借其强大的功能和广泛的社区支持,已成为软件开发领域的重要工具,适合初学者深入学习以奠定职业生涯基础。
112 1
|
4月前
|
API
【Azure Key Vault】.NET 代码如何访问中国区的Key Vault中的机密信息(Get/Set Secret)
【Azure Key Vault】.NET 代码如何访问中国区的Key Vault中的机密信息(Get/Set Secret)
|
4月前
|
存储 Linux 网络安全
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Linux/Linux Container)
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Linux/Linux Container)
下一篇
DataWorks