.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月前
|
C#
.NET Core中灵活使用反射
.NET Core中灵活使用反射
|
11月前
|
C#
.NET Core反射获取带有自定义特性的类,通过依赖注入根据Attribute元数据信息调用对应的方法
.NET Core反射获取带有自定义特性的类,通过依赖注入根据Attribute元数据信息调用对应的方法
125 0
|
存储 Linux API
.NET Core获取程序运行行环境信息与反射的应用
.NET Core获取程序运行行环境信息与反射的应用
359 0
.NET Core获取程序运行行环境信息与反射的应用
|
传感器 开发框架 安全
|
.NET
.Net 中的反射(动态创建类型实例) - Part.4
http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx   动态创建对象 在前面节中,我们先了解了反射,然后利用反射查看了类型信息,并学习了如何创建自定义特性,并利用反射来遍历它。
842 0
.NET Reflection 反射 类属性间的拷贝
This code sample demonstrates how to copy class properties from one class to another even if they are not the same type.
625 0
.Net 中的反射(查看基本类型信息) - Part.2
.Net 中的反射(查看基本类型信息) - Part.2 反射概述 和Type类 1.反射的作用 简单来说,反射提供这样几个能力:1、查看和遍历类型(及其成员)的基本信息和程序集元数据(metadata);2、迟绑定(Late-Binding)方法和属性。
981 0
|
.NET
.Net中的反射(动态创建类型实例) - Part.4
.Net 中的反射(动态创建类型实例) - Part.4 动态创建对象 在前面节中,我们先了解了反射,然后利用反射查看了类型信息,并学习了如何创建自定义特性,并利用反射来遍历它。可以说,前面三节,我们学习的都是反射是什么,在接下来的章节中,我们将学习反射可以做什么。
870 0
|
数据库 C# 存储
.Net 中的反射(序章) - Part.1
.Net 中的反射(序章) - Part.1 引言 反射是.Net提供给我们的一件强力武器,尽管大多数情况下我们不常用到反射,尽管我们可能也不需要精通它,但对反射的使用作以初步了解在日后的开发中或许会有所帮助。
789 0
|
数据库
.Net 中的反射(反射特性) - Part.3
.Net 中的反射(反射特性) - Part.3 反射特性(Attribute) 可能很多人还不了解特性,所以我们先了解一下什么是特性。想想看如果有一个消息系统,它存在这样一个方法,用来将一则短消息发送给某人: // title: 标题;author:作者;content:内容;recei...
811 0

相关课程

更多