Skip to content

Instantly share code, notes, and snippets.

@LRNAB
Created July 5, 2014 09:56
Show Gist options
  • Save LRNAB/1275ba38d3ef0a66cf09 to your computer and use it in GitHub Desktop.
Save LRNAB/1275ba38d3ef0a66cf09 to your computer and use it in GitHub Desktop.
Edit Image Path, Dll Path and Directory of a Process
unsafe class PEBEditor
{
[DllImport("ntdll.dll")]
static extern UInt32 NtQueryInformationProcess(IntPtr ProcessHandle, Int32 ProcessInformationClass, out Process_Basic_Information ProcessInformation, UInt32 ProcessInformationLength, out UInt32 ReturnLength);
[DllImport("kernel32.dll")]
static extern Boolean VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, UInt32 dwSize, UInt32 flNewProtect, out UInt32 lpflOldProtect);
[DllImport("kernel32.dll")]
static extern Boolean WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, UInt32 nSize, out UInt32 lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern Boolean ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, UInt32 nSize, out UInt32 lpNumberOfBytesRead);
[StructLayout(LayoutKind.Sequential)]
struct Process_Basic_Information
{
public IntPtr Reserved1;
public IntPtr PebBaseAddress;
public IntPtr Reserved2a;
public IntPtr Reserved2b;
public UInt32 UniqueProcessId;
public IntPtr Reserved3;
}
[StructLayout(LayoutKind.Sequential)]
struct Process_Environment_Block
{
public fixed Byte Reserved1[2];
public Byte BeingDebugged;
public fixed Byte Reserved2[1];
public IntPtr Mutant;
public IntPtr ImageBaseAddress;
public IntPtr LoaderData;
public IntPtr ProcessParameters;
public fixed Byte Reserved4[104];
public fixed UInt32 Reserved5[52];
public IntPtr PostProcessInitRoutine;
public fixed Byte Reserved6[128];
public fixed UInt32 Reserved7[1];
public UInt32 SessionId;
}
[StructLayout(LayoutKind.Sequential)]
struct Rtl_User_Process_Parameters
{
public UInt32 MaximumLength;
public UInt32 Length;
public UInt32 Flags;
public UInt32 DebugFlags;
public IntPtr ConsoleHandle;
public UInt32 ConsoleFlags;
public IntPtr StdInputHandle;
public IntPtr StdOutputHandle;
public IntPtr StdErrorHandle;
public UNICODE_STRING CurrentDirectoryPath;
public IntPtr CurrentDirectoryHandle;
public UNICODE_STRING DllPath;
public UNICODE_STRING ImagePathName;
public UNICODE_STRING CommandLine;
public IntPtr Environment;
public UInt32 StartingPositionLeft;
public UInt32 StartingPositionTop;
public UInt32 Width;
public UInt32 Height;
public UInt32 CharWidth;
public UInt32 CharHeight;
public UInt32 ConsoleTextAttributes;
public UInt32 WindowFlags;
public UInt32 ShowWindowFlags;
public UNICODE_STRING WindowTitle;
public UNICODE_STRING DesktopName;
public UNICODE_STRING ShellInfo;
public UNICODE_STRING RuntimeData;
public fixed Byte DLCurrentDirectory[0x20 * 0xc];
}
public struct UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
public static void EditPaths(IntPtr hProcess, String imagepathname, String dllpath, String currentdirectorypath)
{
if (hProcess == IntPtr.Zero)
return;
var ProcessBasicInfo = new Process_Basic_Information();
var PEB = new Process_Environment_Block();
var UserProcessParam = new Rtl_User_Process_Parameters();
var ProcessBasicInfoSize = (UInt32)Marshal.SizeOf(typeof(Process_Basic_Information));
var PEBSize = (UInt32)Marshal.SizeOf(typeof(Process_Environment_Block));
var UserProcessParamSize = (UInt32)Marshal.SizeOf(typeof(Rtl_User_Process_Parameters));
UInt32 BytesRead = 0;
UInt32 BytesWritten = 0;
// Fill ProcessBasicInfo to get PEBBaseAddress. 0x00000000 is NtStatus.Success
if (NtQueryInformationProcess(hProcess, 0, out ProcessBasicInfo, ProcessBasicInfoSize, out BytesRead) != 0x00000000)
return;
// Output
Console.WriteLine(String.Concat("PEBBaseAddress: ", ProcessBasicInfo.PebBaseAddress));
Console.WriteLine("Continue? y/n");
if (Console.ReadKey(false).Key != ConsoleKey.Y)
return;
Console.WriteLine(" ");
// Read from the PEBBaseAddress to fill PEB and get ProcessParameters(Pointer to RTL_USER_PROCESS_PARAMETERS structure).
if (!Convert.ToBoolean(ReadProcessMemory(hProcess, ProcessBasicInfo.PebBaseAddress, (IntPtr)(&PEB), PEBSize, out BytesRead)))
return;
// Output
Console.WriteLine(String.Concat("ProcessParameters: ", PEB.ProcessParameters));
Console.WriteLine(String.Concat("ImageBaseAddress: ", PEB.ImageBaseAddress));
Console.WriteLine("Continue? y/n");
if (Console.ReadKey(false).Key != ConsoleKey.Y)
return;
Console.WriteLine(" ");
// Get RTL_USER_PROCESS_PARAMETERS from ProcessParameters
if (!ReadProcessMemory(hProcess, PEB.ProcessParameters, (IntPtr)(&UserProcessParam), UserProcessParamSize, out BytesRead))
return;
// Write new locations
WriteString(hProcess, ref UserProcessParam.ImagePathName, imagepathname);
WriteString(hProcess, ref UserProcessParam.CommandLine, dllpath);
WriteString(hProcess, ref UserProcessParam.CurrentDirectoryPath, currentdirectorypath);
// Update the memory to reflect the changes.
if (!WriteProcessMemory(hProcess, PEB.ProcessParameters, (IntPtr)(&UserProcessParam), UserProcessParamSize, out BytesWritten))
return;
// Output
Console.WriteLine("Finished!");
}
private static void WriteString(IntPtr hProcess, ref UNICODE_STRING unicode, String ascii)
{
if (String.IsNullOrEmpty(ascii))
return;
UInt32 oldaccess;
// Encode the String
Byte[] stringbuffer = Encoding.Unicode.GetBytes(ascii);
// Allocate unmanaged memory in this process
IntPtr ptr = Marshal.AllocHGlobal(stringbuffer.Length);
// Copy encoded string to the unmanaged memory allocated
Marshal.Copy(stringbuffer, 0, ptr, stringbuffer.Length);
// Grant me PAGE_EXECUTE_READWRITE access to memory of process
VirtualProtectEx(hProcess, unicode.Buffer, (UInt32)stringbuffer.Length, 0x40, out oldaccess);
// Decode Unicode String to ASCII
Console.WriteLine(String.Concat("Over-writing ", unicode.ToString(), " with ", ascii));
Console.WriteLine("Continue? y/n");
if (Console.ReadKey(false).Key != ConsoleKey.Y)
return;
Console.WriteLine(" ");
// Overwrite the memory
WriteProcessMemory(hProcess, unicode.Buffer, ptr, (UInt32)stringbuffer.Length, out oldaccess);
// Convert ASCII length to Unicode Length
unicode.Length = (UInt16)(ascii.Length * 2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment