-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathCoreClrInjector.cs
More file actions
123 lines (96 loc) · 4.03 KB
/
CoreClrInjector.cs
File metadata and controls
123 lines (96 loc) · 4.03 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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Iced.Intel;
using static Iced.Intel.AssemblerRegisters;
namespace HoLLy.ManagedInjector.Injectors
{
public class CoreClrInjector : IInjector
{
private static readonly Guid iidIclrRuntimeHost = new Guid(0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02);
public EntryPointType EntryPoint => EntryPointType.TakesStringReturnsInt;
public void Inject(InjectableProcess process, string dllPath, string typeName, string methodName)
{
bool x86 = !process.Is64Bit;
var getClrRuntimeHostAddr = FindGetCLRRuntimeHost(process.Pid, process.FullHandle, x86);
var callStub = CreateCallStub(process.FullHandle, dllPath, typeName, methodName, null, getClrRuntimeHostAddr, x86);
var hThread = CodeInjectionUtils.RunRemoteCode(process.FullHandle, callStub, x86);
Console.WriteLine("Thread handle: " + hThread.ToInt32().ToString("X8"));
}
private static IntPtr FindGetCLRRuntimeHost(uint pid, IntPtr hProc, bool x86)
{
var mods = NativeHelper.GetModules(pid);
var mod = mods.SingleOrDefault(x => x.moduleName.Equals("coreclr.dll", StringComparison.InvariantCultureIgnoreCase));
if (mod == default)
throw new Exception("Couldn't find coreclr.dll, arch mismatch?");
int fnAddr = CodeInjectionUtils.GetExportAddress(hProc, mod.baseAddress, "GetCLRRuntimeHost", x86);
return mod.baseAddress + fnAddr;
}
private static IReadOnlyList<Instruction> CreateCallStub(IntPtr hProc, string asmPath, string typeFullName, string methodName, string? args, IntPtr fnAddr, bool x86)
{
var ppv = alloc(IntPtr.Size);
var riid = allocBytes(iidIclrRuntimeHost.ToByteArray());
var pReturnValue = alloc(4);
var pwzArgument = allocString(args);
var pwzMethodName = allocString(methodName);
var pwzTypeName = allocString(typeFullName);
var pwzAssemblyPath = allocString(asmPath);
var c = new Assembler(x86 ? 32 : 64);
void AddCallReg(Register r, params object[] callArgs) => CodeInjectionUtils.AddCallStub(c, r, callArgs, x86);
void AddCallPtr(IntPtr fn, params object[] callArgs) => CodeInjectionUtils.AddCallStub(c, fn, callArgs, x86);
if (x86) {
// call GetCLRRuntimeHost
AddCallPtr(fnAddr, riid, ppv);
// call ICLRRuntimeHost::Start
c.mov(edx, __[ppv.ToInt32()]);
c.mov(eax, __[edx]);
c.mov(eax, __[eax + 0x0C]);
AddCallReg(eax, edx);
// call ICLRRuntimeHost::ExecuteInDefaultAppDomain
c.mov(edx, __[ppv.ToInt32()]);
c.mov(eax, __[edx]);
c.mov(eax, __[eax + 0x2C]);
AddCallReg(eax, edx, pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument, pReturnValue);
c.ret();
} else {
const int maxStackIndex = 3;
const int stackOffset = 0x20;
c.sub(rsp, stackOffset + maxStackIndex * 8);
// call GetCLRRuntimeHost
AddCallPtr(fnAddr, riid, ppv);
// call pClrHost->Start();
c.mov(rcx, ppv.ToInt64());
c.mov(rcx, __[rcx]);
c.mov(rax, __[rcx]);
c.mov(rdx, __[rax + 0x18]);
AddCallReg(rdx, rcx);
// call pClrHost->ExecuteInDefaultAppDomain()
c.mov(rcx, ppv.ToInt64());
c.mov(rcx, __[rcx]);
c.mov(rax, __[rcx]);
c.mov(rax, __[rax + 0x58]);
AddCallReg(rax, rcx, pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument, pReturnValue);
c.add(rsp, stackOffset + maxStackIndex * 8);
c.ret();
}
return c.Instructions;
IntPtr alloc(int size, int protection = 0x04) => Native.VirtualAllocEx(hProc, IntPtr.Zero, (uint)size, 0x1000, protection);
void writeBytes(IntPtr address, byte[] b) => Native.WriteProcessMemory(hProc, address, b, (uint)b.Length, out _);
void writeString(IntPtr address, string str) => writeBytes(address, new UnicodeEncoding().GetBytes(str));
IntPtr allocString(string? str)
{
if (str is null) return IntPtr.Zero;
IntPtr pString = alloc(str.Length * 2 + 2);
writeString(pString, str);
return pString;
}
IntPtr allocBytes(byte[] buffer)
{
IntPtr pBuffer = alloc(buffer.Length);
writeBytes(pBuffer, buffer);
return pBuffer;
}
}
}
}