Я пытаюсь отредактировать указатель инструкций потока, чтобы он вызывал какую-то собранную сборку x64, прежде чем вернуться к старому указателю инструкций и продолжить в обычном режиме.Программа, с которой я делаю это, вылетает после возобновления потока, который, как я полагаю, указывает, что он не возвращается к старому указателю инструкции.
В настоящее время я пытаюсь выполнить следующее
Получить дескриптор потока
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenThread(ThreadPrivileges dwDesiredAccess, bool bInheritHandle, IntPtr dwThreadId);
public enum ThreadPrivileges
{
SuspendResume = 0x02,
GetContext = 0x08,
SetContext = 0x010,
AllAccess = SuspendResume | GetContext | SetContext
}
var threadId = Process.GetProcessesByName(processName)[0].Threads[0].Id;
var threadHandle = OpenThread(ThreadPrivileges.AllAccess, false, (IntPtr)threadId);
Приостановить поток
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void SuspendThread(IntPtr hThread);
SuspendThread(threadHandle);
Получить контекст потока
Структуру Context64 и ContextFlags можно найти по этой ссылке
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetThreadContext(IntPtr hThread, ref Context64 lpContext);
var context = new Context64() { ContextFlags = ContextFlags.ContextFull };
GetThreadContext(threadHandle, ref context);
Попытка записать указатель старой инструкции в стек
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, int lpNumberOfBytesWritten);
context.Rsp -= sizeof(ulong); // Allocate 8 bytes on the stack
WriteProcessMemory(processHandle, (IntPtr)context.Rsp, BitConverter.GetBytes(context.Rip), sizeof(ulong), 0);
Перезаписать указатель инструкции
context.Rip = (ulong)myAssemblyPointer;
Установить контекст потока в отредактированный контекст
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetThreadContext(IntPtr hThread, ref Context64 lpContext);
SetThreadContext(threadHandle, ref context);
Наконец возобновите поток
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void ResumeThread(IntPtr hThread);
ResumeThread(threadHandle);
Я не уверен, имеет ли это какое-либо значение, но я использую следующую сборку
PUSHFQ
PUSH rax
PUSH rbx
PUSH rcx
PUSH rdx
PUSH r8
PUSH r9
PUSH r10
PUSH r11
sub RSP, 0x28
movabs RCX, 0x0000000000000000 ; Pointer 1
movabs RAX, 0x0000000000000000 ; Pointer 2
call RAX
add RSP, 0x28
POP r11
POP r10
POP r9
POP r8
POP rdx
POP rcx
POP rbx
POP rax
POPFQ
ret
IЯ пытался исключить столько кода (проверка ошибок и очистка после), сколько смогу, чтобы этот пост был коротким, но все мои ошибкиПроверка, кажется, указывает на то, что методы pinvoke работают так, как задумано.Моя главная проблема - когда я пытаюсь записать указатель старой инструкции в стек.Хотя WriteProcessMemory
не терпит неудачу, у меня такое ощущение, что я делаю это неправильно.Буду признателен, если кто-нибудь сможет объяснить мне, правильно ли я записываю указатель старой инструкции в стек, а если нет, то как я могу это сделать.
Пожалуйста, дайте мне знать, если вы хотите, чтобы я предоставил какие-либо дополнительныеинформация, например, processHandle
или myAssemblyPointer
переменных.