-
Notifications
You must be signed in to change notification settings - Fork 1
/
PEInjector.cs
98 lines (87 loc) · 4.11 KB
/
PEInjector.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
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using Microsoft.Win32.SafeHandles;
using System.IO;
using Squared.Task;
namespace Squared.PE {
public static class PEInjector {
public static unsafe RemoteMemoryRegion Inject (
Process process, PortableExecutable executable, IntPtr payloadArgument,
Future<Int32> threadResultFuture, Future<UInt32> threadIdFuture
) {
RemoteMemoryRegion region = null;
using (var handle = Win32.OpenProcessHandle(
ProcessAccessFlags.VMRead | ProcessAccessFlags.VMWrite |
ProcessAccessFlags.VMOperation | ProcessAccessFlags.CreateThread |
ProcessAccessFlags.QueryInformation,
false, process.Id
))
try {
region = RemoteMemoryRegion.Allocate(
process, handle, executable.OptionalHeader.SizeOfImage
);
region.Protect(handle, 0, region.Size, MemoryProtection.ReadWrite);
var baseAddress = (UInt32)region.Address.ToInt64();
executable.Rebase(baseAddress);
executable.ResolveImports();
foreach (var section in executable.Sections.Values) {
// 0-byte remote memory read/write/protect operations will fail with an error.
if (section.Size <= 0)
continue;
fixed (byte* data = section.RawData) {
region.Write(
handle, section.VirtualAddress, section.Size, data
);
// Why the fuck isn't this a flags-style enumeration? Sigh, classic windows.
MemoryProtection protection = MemoryProtection.ReadOnly;
if ((section.Characteristics & PortableExecutable.SectionCharacteristics.MemExecute) == PortableExecutable.SectionCharacteristics.MemExecute)
protection = MemoryProtection.ExecuteRead;
else if ((section.Characteristics & PortableExecutable.SectionCharacteristics.MemWrite) == PortableExecutable.SectionCharacteristics.MemWrite)
protection = MemoryProtection.ReadWrite;
region.Protect(
handle, section.VirtualAddress, section.Size, protection
);
}
}
UInt32 threadId = 0;
UInt32 creationFlags = 0x0;
IntPtr remoteThreadHandle = Win32.CreateRemoteThread(
handle.DangerousGetHandle(), IntPtr.Zero, 0,
baseAddress + executable.OptionalHeader.AddressOfEntryPoint,
payloadArgument,
creationFlags, out threadId
);
if (remoteThreadHandle == IntPtr.Zero) {
var error = Win32.GetLastError();
throw new Exception(String.Format("Thread start failed: Error {0:x8}", error));
}
threadIdFuture.Complete(threadId);
var threadHandle = new ThreadWaitHandle(new SafeWaitHandle(remoteThreadHandle, true));
ThreadPool.RegisterWaitForSingleObject(threadHandle, (s, e) => {
Int32 exitCode;
Win32.GetExitCodeThread(handle.DangerousGetHandle(), out exitCode);
threadResultFuture.Complete(exitCode);
threadHandle.Close();
}, null, -1, true);
var theResult = region;
region = null;
return theResult;
} finally {
if (region != null) {
bool exited = true;
try {
exited = process.HasExited;
} catch {
}
if (!exited)
region.Dispose();
}
}
}
}
}