I made this loader/debugger long ago for a simple target, but never finished it. It worked for native x64 targets. I don't know if setting 0x01 (bp il opcode) will fire up the ExceptionCode.STATUS_BREAKPOINT. I tried to follow here https://github.com/dotnet/coreclr/blob/master/src/vm/excep.cpp but I am a very bad coder...
Code:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Microsoft.Samples.Debugging.Native;
namespace Test2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region WinNT Definitions
private const uint CONTEXT_FULL = 0x10007;
private const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ
private const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00
private static short SW_SHOWNORMAL = 1;
private const uint STARTF_USESTDHANDLES = 0x00000100;
private const uint STARTF_USESHOWWINDOW = 0x00000001;
private CreateProcessFlags flags;
#endregion
private void button1_Click(object sender, EventArgs e)
{
// PART 1 !!!!!
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
flags = CreateProcessFlags.DEBUG_ONLY_THIS_PROCESS | CreateProcessFlags.CREATE_SUSPENDED;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(@"test.exe", null, IntPtr.Zero, IntPtr.Zero, false, flags, IntPtr.Zero, null, si, pi);
// Taken from Kao's solution in part 1 :)
PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
int d;
NtQueryInformationProcess(pi.hProcess, 0, ref pbi, Marshal.SizeOf(pbi), out d);
byte[] dummy2 = new byte[8];
int dummy;
// in 64bit OS, main module imagebase is at PEB+0x10
ReadProcessMemory(pi.hProcess, new IntPtr((Int64)pbi.PebBaseAddress + 0x10), dummy2, (UIntPtr)8, out dummy);
Int64 realImageBase = BitConverter.ToInt64(dummy2, 0);
textBox1.Text = realImageBase.ToString("X2");
// STARTUPINFO
STARTUPINFO StartupInfo = new STARTUPINFO();
StartupInfo.dwFlags = (int)(STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
StartupInfo.wShowWindow = SW_SHOWNORMAL;
/*var IMAGE_SECTION_HEADER = new byte[0x28]; // pish
var IMAGE_NT_HEADERS = new byte[0xf8]; // pinh
var IMAGE_DOS_HEADER = new byte[0x40]; // pidh
var PROCESS_INFO = new int[0x4]; // pi
byte* pish;
fixed (byte* p = &IMAGE_SECTION_HEADER[0]) pish = p;
byte* pinh;
fixed (byte* p = &IMAGE_NT_HEADERS[0]) pinh = p;
byte* pidh;
fixed (byte* p = &IMAGE_DOS_HEADER[0]) pidh = p;
// Get the DOS header of the EXE.
ReadProcessMemory(pi.hProcess, new IntPtr(realImageBase), IMAGE_DOS_HEADER, (UIntPtr)IMAGE_DOS_HEADER.Length, out dummy);
// Sanity check: See if we have MZ header.
if (*(ushort*)(pidh + 0x0) != IMAGE_DOS_SIGNATURE)
MessageBox.Show("Bad MZ header");
var e_lfanew = *(int*)(pidh + 0x3c);
textBox2.Text = e_lfanew.ToString("X2");
// Get the NT header of the EXE.
ReadProcessMemory(pi.hProcess, new IntPtr(realImageBase + e_lfanew), IMAGE_NT_HEADERS, (UIntPtr)IMAGE_NT_HEADERS.Length, out dummy);
// Sanity check: See if we have PE00 header.
if (*(uint*)(pinh + 0x0) != IMAGE_NT_SIGNATURE)
MessageBox.Show("Bad PE00 header");
var AddressOfEntryPoint = *(int*)(pinh + 0x28);
textBox3.Text = AddressOfEntryPoint.ToString("X2");
byte[] OEPData = new byte[9];
ReadProcessMemory(pi.hProcess, new IntPtr(realImageBase + AddressOfEntryPoint), OEPData, (UIntPtr)9, out dummy);
textBox4.Text = BitConverter.ToString(OEPData).Replace("-", "");*/
// PART 2 !!!!!
var buffer = new byte[1] { 0xCC };
var origIN_OUT = new byte[1] { 0x48 };
var dummy4 = new UIntPtr();
byte[] buffer2 = new byte[5];
WriteProcessMemory(pi.hProcess, new IntPtr(realImageBase + 0x1B1AA4), buffer, (UIntPtr)1, out dummy4);
WriteProcessMemory(pi.hProcess, new IntPtr(realImageBase + 0x1B1AA9), buffer, (UIntPtr)1, out dummy4);
ContinueStatus dwContinueStatus = ContinueStatus.DBG_CONTINUE;
DebugEvent64 event64 = new DebugEvent64();
ResumeThread(pi.hThread);
bool continuar = true;
while (continuar)
{
if (!WaitForDebugEvent64(ref event64, -1))
{
MessageBox.Show("Debug loop aborted");
return;
}
switch (event64.header.dwDebugEventCode)
{
case NativeDebugEventCode.EXIT_PROCESS_DEBUG_EVENT:
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return;
case NativeDebugEventCode.EXCEPTION_DEBUG_EVENT:
{
EXCEPTION_DEBUG_INFO exception = event64.union.Exception;
switch (exception.ExceptionRecord.ExceptionCode)
{
case ExceptionCode.STATUS_BREAKPOINT:
{
SuspendThread(pi.hThread); // Always suspend target before getting context or you will get bad data
CONTEXT64 context = new CONTEXT64(); // Create a new Context64 struct.
context.ContextFlags = ContextFlags.AMD64ContextAll;
if (!GetThreadContext(pi.hThread, ref context)) // Read thread context
MessageBox.Show("There was a problem getting context");
if (context.Rip == (ulong)(realImageBase + 0x1B1AA4 + 1)) // Compare in BP
{
context.Rip -= 1; // Change EIP to -1
if (!SetThreadContext(pi.hThread, ref context)) // Update changed context
MessageBox.Show("There was a problem setting context");
// Do the stuff
MessageBox.Show("Message box open");
WriteProcessMemory(pi.hProcess, new IntPtr(realImageBase + 0x1B1AA4), origIN_OUT, (UIntPtr)1, out dummy4); // Set original bytes to resume process
}
if (context.Rip == (ulong)(realImageBase + 0x1B1AA9 + 1)) // Compare out BP
{
context.Rip -= 1; // Change EIP to -1
if (!SetThreadContext(pi.hThread, ref context)) // Update changed context
MessageBox.Show("There was a problem setting context");
// Do the stuff
MessageBox.Show("Message box closed");
WriteProcessMemory(pi.hProcess, new IntPtr(realImageBase + 0x1B1AA9), origIN_OUT, (UIntPtr)1, out dummy4); // Set original bytes to resume process
}
ResumeThread(pi.hThread); // Resume target
await Task.Delay(200); // Small delay before putting BPs back or they might get hit more than once
break;
}
default:
{
dwContinueStatus = ContinueStatus.DBG_EXCEPTION_NOT_HANDLED;
break;
}
}
break;
}
}
if (!ContinueDebugEvent(event64.header.dwProcessId, event64.header.dwThreadId, dwContinueStatus))
MessageBox.Show("Error continuing debug event");
// Reset
dwContinueStatus = ContinueStatus.DBG_CONTINUE;
// Set BPs again
WriteProcessMemory(pi.hProcess, new IntPtr(realImageBase + 0x1B1AA4), buffer, (UIntPtr)1, out dummy4);
WriteProcessMemory(pi.hProcess, new IntPtr(realImageBase + 0x1B1AA9), buffer, (UIntPtr)1, out dummy4);
}
}
}
}
|