Repository navigation
Expand file tree
/
Copy pathUnsafeMemoryExtensions.cs
More file actions
165 lines (153 loc) · 7.04 KB
/
Copy pathUnsafeMemoryExtensions.cs
File metadata and controls
165 lines (153 loc) · 7.04 KB
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using ProcessNET.Marshaling;
using ProcessNET.Native;
namespace ProcessNET.Extensions
{
public static class FastCall
{
public static IntPtr InvokePtr { get; private set; }
private static Byte[] InvokeCode = new Byte[]
{
0x5A, // pop edx
0x36, 0x87, 0x54, 0x24, 0x08, // xchg ss:[esp+08],edx
0x58, // pop eax
0x59, // pop ecx
0xFF, 0xE0 // jmp eax
};
private static Byte[] WrapperCode = new Byte[]
{
0x58, // pop eax
0x52, // push edx
0x51, // push ecx
0x50, // push eax
0x68, 0x00, 0x00, 0x00, 0x00, // push ...
0xC3 // retn
};
/*
static FastCall()
{
FastCall.InvokePtr = Kernel32.VirtualAlloc(IntPtr.Zero, FastCall.InvokeCode.Length,
AllocationType.Commit, MemoryProtection.ExecuteReadWrite);
Marshal.Copy(FastCall.InvokeCode, 0, FastCall.InvokePtr, FastCall.InvokeCode.Length);
}
public static IntPtr WrapStdCallInFastCall(IntPtr stdCallPtr)
{
var result = Kernel32.VirtualAlloc(IntPtr.Zero, FastCall.WrapperCode.Length, AllocationType.Commit, MemoryProtection.ExecuteReadWrite);
Marshal.Copy(FastCall.WrapperCode, 0, result, FastCall.WrapperCode.Length);
Marshal.WriteIntPtr(result, 5, stdCallPtr);
return result;
}
*/
}
public static class UnsafeMemoryExtensions
{
// Gets an address from a vtable index.Since it uses index * IntPtr, it should work for both x64 and x32.
// public static IntPtr GetVtableIntPtr(this IntPtr intPtr, int functionIndex)
// {
// var vftable = intPtr.Read<IntPtr>();
// return (vftable + functionIndex * IntPtr.Size).Read<IntPtr>();
// }
//public static IntPtr GetVtableIntPtr2(this IntPtr intPtr, int functionIndex)
//{
// var vftable = MemoryHelper.InternalRead<IntPtr>(intPtr);
// return MemoryHelper.InternalRead<IntPtr>(vftable + functionIndex * IntPtr.Size);
//}
// Converts an unmanaged delegate to a function pointer.
public static IntPtr ToFunctionPtr(this Delegate d)
{
return Marshal.GetFunctionPointerForDelegate(d);
}
// Converts an unmanaged function pointer to the given delegate type.
public static T ToDelegate<T>(this IntPtr addr) where T : class
{
if (addr == null)
{
return null;
}
if (typeof (T).GetCustomAttributes(typeof (UnmanagedFunctionPointerAttribute), true).Length == 0)
throw new InvalidOperationException(
"This operation can only convert to delegates adorned with the UnmanagedFunctionPointerAttribute");
return Marshal.GetDelegateForFunctionPointer(addr, typeof (T)) as T;
}
public static unsafe T Read<T>(this IntPtr address)
{
try
{
// TODO: Optimize this more. The boxing/unboxing required tends to slow this down.
// It may be worth it to simply use memcpy to avoid it, but I doubt thats going to give any noticeable increase in speed.
if (address == IntPtr.Zero)
throw new InvalidOperationException("Cannot retrieve a value at address 0");
object ptrToStructure;
switch (MarshalCache<T>.TypeCode)
{
case TypeCode.Object:
if (MarshalCache<T>.RealType == typeof(IntPtr))
return (T)(object)*(IntPtr*)address;
// If the type doesn't require an explicit Marshal call, then ignore it and memcpy the thing.
if (!MarshalCache<T>.TypeRequiresMarshal)
{
var o = default(T);
var ptr = MarshalCache<T>.GetUnsafePtr(ref o);
//TODO: movememory allocates on the fly, move memory does not (josh thinks. needs confirmation)
Kernel32.MoveMemory(ptr, (void*)address, MarshalCache<T>.Size);
return o;
}
// All System.Object's require marshaling!
ptrToStructure = Marshal.PtrToStructure(address, typeof(T));
break;
case TypeCode.Boolean:
ptrToStructure = *(byte*)address != 0;
break;
case TypeCode.Char:
ptrToStructure = *(char*)address;
break;
case TypeCode.SByte:
ptrToStructure = *(sbyte*)address;
break;
case TypeCode.Byte:
ptrToStructure = *(byte*)address;
break;
case TypeCode.Int16:
ptrToStructure = *(short*)address;
break;
case TypeCode.UInt16:
ptrToStructure = *(ushort*)address;
break;
case TypeCode.Int32:
ptrToStructure = *(int*)address;
break;
case TypeCode.UInt32:
ptrToStructure = *(uint*)address;
break;
case TypeCode.Int64:
ptrToStructure = *(long*)address;
break;
case TypeCode.UInt64:
ptrToStructure = *(ulong*)address;
break;
case TypeCode.Single:
ptrToStructure = *(float*)address;
break;
case TypeCode.Double:
ptrToStructure = *(double*)address;
break;
case TypeCode.Decimal:
// Probably safe to remove this. I'm unaware of anything that actually uses "decimal" that would require memory reading...
ptrToStructure = *(decimal*)address;
break;
default:
throw new ArgumentOutOfRangeException();
}
return (T)ptrToStructure;
}
catch (AccessViolationException ex)
{
Trace.WriteLine("Access Violation on " + address + " with type " + typeof(T).Name + Environment.NewLine +
ex);
return default(T);
}
}
}
}