看了老外的白皮书兴高采烈去挖洞了,然后发现人家挖洞是黑名单,我挖洞是白名单。需要自己找gadget,可是一个一个找构造函数、getter、setter是真的慢,干脆学一下 https://github.com/0xd4d/dnlib 看能不能整个.net的tabby出来算求。
接下来我将以下面这个类作为测试的程序集,讲解dnlib的使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using System ;
using System.Collections.Generic ;
namespace TestApp
{
internal class Program
{
static void Main ( string [] args )
{
Console . WriteLine ( "asd" );
}
}
abstract class A
{
public int AProp { get ; set ; }
public abstract void M ();
}
interface ITest
{
void IMethod ();
void IMethod ( string s );
int IProp { get ; set ; }
}
class Test
{
public int MyProperty { get ; set ; }
private int MyValue { get ; set ; }
private int Count ;
public delegate void Handler ();
public event Handler Change ;
public static string Hello ( string s )
{
Console . WriteLine ( s );
return "hello" ;
}
public Test () { Console . WriteLine ( "ctor" ); }
public Test ( string s ) { Console . WriteLine ( "ctor string " + s ); }
}
class Container
{
public class Nested
{
private Container parent ;
public Nested ()
{
}
public Nested ( Container parent )
{
this . parent = parent ;
}
}
}
enum E
{
None = 0 ,
}
class G : Comparer < string >
{
public override int Compare ( string x , string y )
{
return x . CompareTo ( y );
}
}
}
AssemblyDef assembly程序集类 ModuleDef 模块类 TypeDef 类型定义 包含了事件、属性、字段等 EventDef 事件类 FieldDef 字段类 PropertyDef 属性类 会发现,都是以XXDef命名,还有一些是以XXRef命名的类,表示引用类,这里暂不讨论。
XXDef为抽象类,真正实现类在XXDefMD,如ModuleDef
其实现类为ModuleDefMD,我们用也是用它。
首先要先引入命名空间
1
2
using dnlib.DotNet ;
using dnlib.DotNet.Emit ;
dnlib中提供了多种读取dotnet程序集的方式
1
2
ModuleContext modCtx = ModuleDef . CreateModuleContext ();
ModuleDefMD module = ModuleDefMD . Load ( @"C:\path\to\file.exe" , modCtx );
Load有多个重载,提供从文件中、byte中、内存中或者是System.Reflection.Module示例读取程序集
比如以下代码就将从type void拿到System.Reflection.Module实例,从而加载mscorlib.dll
1
2
3
System . Reflection . Module reflectionModule = typeof ( void ). Module ; // Get mscorlib.dll's module
ModuleContext modCtx = ModuleDef . CreateModuleContext ();
ModuleDefMD module = ModuleDefMD . Load ( reflectionModule , modCtx );
在dnlib的Example1 https://github.com/0xd4d/dnlib/blob/master/Examples/Example1.cs 中给了例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System ;
using dnlib.DotNet ;
namespace dnlib.Examples {
// This example will open mscorlib.dll and then print out all types
// in the assembly, including the number of methods, fields, properties
// and events each type has.
public class Example1 {
public static void Run () {
// Load mscorlib.dll
var filename = typeof ( void ). Module . FullyQualifiedName ;
var mod = ModuleDefMD . Load ( filename );
int totalNumTypes = 0 ;
// mod.Types only returns non-nested types.
// mod.GetTypes() returns all types, including nested types.
foreach ( var type in mod . GetTypes ()) {
totalNumTypes ++;
Console . WriteLine ();
Console . WriteLine ( "Type: {0}" , type . FullName );
if ( type . BaseType is not null )
Console . WriteLine ( " Base type: {0}" , type . BaseType . FullName );
Console . WriteLine ( " Methods: {0}" , type . Methods . Count );
Console . WriteLine ( " Fields: {0}" , type . Fields . Count );
Console . WriteLine ( " Properties: {0}" , type . Properties . Count );
Console . WriteLine ( " Events: {0}" , type . Events . Count );
Console . WriteLine ( " Nested types: {0}" , type . NestedTypes . Count );
if ( type . Interfaces . Count > 0 ) {
Console . WriteLine ( " Interfaces:" );
foreach ( var iface in type . Interfaces )
Console . WriteLine ( " {0}" , iface . Interface . FullName );
}
}
Console . WriteLine ();
Console . WriteLine ( "Total number of types: {0}" , totalNumTypes );
}
}
}
通过mod.GetTypes()拿到type定义后,我们可以获取type的method、field、prop、event等等属性,我们写一下代码解析下我们的TestApp.exe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ModuleContext modCtx = ModuleDef . CreateModuleContext ();
ModuleDefMD module = ModuleDefMD . Load ( @"E:\code\ConsoleApp2\TestApp\bin\Debug\TestApp.exe" , modCtx );
AssemblyDef assembly = module . Assembly ;
foreach ( ModuleDef m in assembly . Modules )
{
Console . WriteLine ( "Module: " + m . FullName );
//遍历类
foreach ( TypeDef type in m . Types )
{
Console . WriteLine ( "Class: " + type . Name );
//遍历方法
foreach ( MethodDef method in type . Methods )
{
Console . WriteLine ( "Method: " + method . Name );
}
//遍历字段
foreach ( FieldDef field in type . Fields )
{
Console . WriteLine ( "Field: " + field . Name );
}
}
}
Console . ReadKey ();
输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Module: TestApp.exe
Class: <Module>
Class: Program
Method: Main
Method: .ctor
Class: A
Method: get_AProp
Method: set_AProp
Method: M
Method: .ctor
Field: <AProp>k__BackingField
Class: ITest
Method: IMethod
Method: IMethod
Method: get_IProp
Method: set_IProp
Class: Test
Method: get_MyProperty
Method: set_MyProperty
Method: get_MyValue
Method: set_MyValue
Method: add_Change
Method: remove_Change
Method: Hello
Method: .ctor
Method: .ctor
Field: <MyProperty>k__BackingField
Field: <MyValue>k__BackingField
Field: Count
Field: Change
Class: Container
Method: .ctor
Class: E
Field: value__
Field: None
Class: G
Method: Compare
Method: .ctor
解析call关系其实是解析method body的opcode,比如静态方法调用的OpCodes.Call https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.calli?view=net-7.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System ;
using dnlib.DotNet ;
using dnlib.DotNet.Emit ;
namespace tabby
{
internal class Program
{
static void Main ( string [] args )
{
ModuleContext modCtx = ModuleDef . CreateModuleContext ();
ModuleDefMD module = ModuleDefMD . Load ( @"E:\code\ConsoleApp2\TestApp\bin\Debug\TestApp.exe" , modCtx );
AssemblyDef assembly = module . Assembly ;
foreach ( ModuleDef m in assembly . Modules )
{
Console . WriteLine ( "Module: " + m . FullName );
//遍历类
foreach ( TypeDef type in m . Types )
{
Console . WriteLine ( "Class: " + type . Name );
//遍历方法
foreach ( MethodDef method in type . Methods )
{
Console . WriteLine ( "Method: " + method . Name );
if ( method . HasBody && method . Body . HasInstructions )
{
var instructions = method . Body . Instructions ;
foreach ( var ins in instructions )
{
if ( ins . OpCode == OpCodes . Call || ins . OpCode == OpCodes . Callvirt )
{
// 获取调用的方法
IMethod calledMethod = ( IMethod ) ins . Operand ;
// 输出调用关系
Console . WriteLine ( "{0} {1} {2}" , method . FullName , ins . OpCode , calledMethod . FullName );
}
}
}
}
//遍历字段
foreach ( FieldDef field in type . Fields )
{
Console . WriteLine ( "Field: " + field . Name );
}
}
}
Console . ReadKey ();
}
}
}
输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Module: TestApp.exe
Class: <Module>
Class: Program
Method: Main
System.Void TestApp.Program::Main(System.String[]) call System.Void System.Console::WriteLine(System.String)
Method: .ctor
System.Void TestApp.Program::.ctor() call System.Void System.Object::.ctor()
Class: A
Method: get_AProp
Method: set_AProp
Method: M
Method: .ctor
System.Void TestApp.A::.ctor() call System.Void System.Object::.ctor()
Field: <AProp>k__BackingField
Class: ITest
Method: IMethod
Method: IMethod
Method: get_IProp
Method: set_IProp
Class: Test
Method: get_MyProperty
Method: set_MyProperty
Method: get_MyValue
Method: set_MyValue
Method: add_Change
System.Void TestApp.Test::add_Change(TestApp.Test/Handler) call System.Delegate System.Delegate::Combine(System.Delegate,System.Delegate)
System.Void TestApp.Test::add_Change(TestApp.Test/Handler) call TestApp.Test/Handler System.Threading.Interlocked::CompareExchange<TestApp.Test/Handler>(TestApp.Test/Handler&,TestApp.Test/Handler,TestApp.Test/Handler)
Method: remove_Change
System.Void TestApp.Test::remove_Change(TestApp.Test/Handler) call System.Delegate System.Delegate::Remove(System.Delegate,System.Delegate)
System.Void TestApp.Test::remove_Change(TestApp.Test/Handler) call TestApp.Test/Handler System.Threading.Interlocked::CompareExchange<TestApp.Test/Handler>(TestApp.Test/Handler&,TestApp.Test/Handler,TestApp.Test/Handler)
Method: Hello
System.String TestApp.Test::Hello(System.String) call System.Void System.Console::WriteLine(System.String)
Method: .ctor
System.Void TestApp.Test::.ctor() call System.Void System.Object::.ctor()
System.Void TestApp.Test::.ctor() call System.Void System.Console::WriteLine(System.String)
Method: .ctor
System.Void TestApp.Test::.ctor(System.String) call System.Void System.Object::.ctor()
System.Void TestApp.Test::.ctor(System.String) call System.String System.String::Concat(System.String,System.String)
System.Void TestApp.Test::.ctor(System.String) call System.Void System.Console::WriteLine(System.String)
Field: <MyProperty>k__BackingField
Field: <MyValue>k__BackingField
Field: Count
Field: Change
Class: Container
Method: .ctor
System.Void TestApp.Container::.ctor() call System.Void System.Object::.ctor()
Class: E
Field: value__
Field: None
Class: G
Method: Compare
System.Int32 TestApp.G::Compare(System.String,System.String) callvirt System.Int32 System.String::CompareTo(System.String)
Method: .ctor
System.Void TestApp.G::.ctor() call System.Void System.Collections.Generic.Comparer`1<System.String>::.ctor()
# 修改method body 这个案例我们直接看Example2.cs就行了 https://github.com/0xd4d/dnlib/blob/master/Examples/Example2.cs
用dnspy看看
确实多了这个类
简单写了写怎么用,和javassist差的还是比较远,需要实现IL的翻译。
不过只是为了找到call关系的话,足够了,优化下加个多线程,加个neo4j就是下一个tabby for dotnet。
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。