Как мне вернуться к (старому) указателю инструкций, если я отредактирую указатель инструкций потока? - PullRequest
0 голосов
/ 21 сентября 2018

Я пытаюсь отредактировать указатель инструкций потока, чтобы он вызывал какую-то собранную сборку 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 переменных.

...