Почему внедрение пещер кода с внедрением потока приводит к сбою моего целевого win32 EXE?

В настоящее время я пытаюсь внедрить пещеру кода с внедрением потоков в удаленный EXE-файл win32, работающий в моей системе win7 (x64). Для этого я использую Microsoft VB6, через который делаю следующее:

  • OpenProcess, чтобы получить дескриптор удаленного процесса [OK]
  • VirtualAllocEx, чтобы выделить некоторое пространство внутри процесса (с защитой PAGE_EXECUTE и MEM_COMMIT в качестве параметра. lpAddress установлен в NULL, чтобы функция определяла, где выделить область) [ОК, возвращает допустимое смещение]
  • WriteProcessMemory, чтобы написать мой шеллкод [ОК, на самом деле правильно записывает байты, я проверил с помощью CheatEngine/MemoryView]
  • CreateRemoteThread, внедрение потока для выполнения моей пещеры кода [ОК, возвращает дескриптор, который не равен NULL, мой удаленный поток был - предположительно - успешно создан]
  • Мой целевой EXE-файл (хост для только что созданного удаленного потока) дает сбой в этот момент ("exename" перестало работать)
  • WaitForSingleObject / CloseHandle / VirtualFreeEx

Ради проверки успешной инъекции кода я пытаюсь внедрить шелл-код, который ничего не делает. Я не очень разбираюсь в шеллкодинге и ассемблере, но только начал учиться.

Я пробовал вводить разные коды, например: - только NOP (сбой, но я предполагаю, что это нормально): \x90\x90\x90.. - только NULL (то же, что и выше): \x00\x00\x00.. Однако чего я не понимаю, так это того, что NOP, за которым следует RETN, приводит к сбою моего целевого EXE, а также \x90\x90\x90\xCB. За каждой последовательностью байтов, которую я пытался внедрить, следовал нулевой байт.

Почему мой целевой процесс дает сбой? Какую последовательность байтов мне нужно ввести, чтобы выполнить успешную инъекцию, которая не приведет к сбою моего целевого EXE-файла (но ничего не делает, просто ради проверки схемы инъекции)?

В итоге я хочу внедрить целевую функцию PUSH x, CALL в игру. Но если мой фиктивный шеллкод приведет к сбою моего целевого процесса, я предполагаю, что последняя последовательность байтов тоже. Спасибо за ваше время.

РЕДАКТИРОВАТЬ: исключение, которое я получаю, это 0xC0000005 [Нарушение прав доступа при записи]

Код VB6: просто вызовите подпрограмму с целевым идентификатором Exe в качестве аргумента.

Private Const PAGE_READWRITE As Long = &H4
Private Const PAGE_EXECUTE As Long = &H10

Private Const MEM_RELEASE As Long = &H8000
Private Const MEM_COMMIT As Long = &H1000
Private Const INFINITE As Long = &HFFFFFF

Public Const PROCESS_ALL_ACCESS As Long = &H1F0FFF

Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Public Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function CreateRemoteThread Lib "kernel32" (ByVal hProcess As Long, lpThreadAttributes As Long, ByVal dwStackSize As Long, lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long

'Function that performs the shellcode injection to a remote process. Takes the target's PID as argument
Public Sub injectCode(ByVal lngPid As Long)
    Dim RemThread As Long, LngModule As Long, LngProcess As Long
    Dim i As Long

    'The byte sequence we'll inject in the remote process (
    Dim shellcode(4) As Byte
    shellcode(0) = &H90 'NOP : just to pretend that it's actual code
    shellcode(1) = &H90 'NOP : same
    shellcode(2) = &HC2 'Near return to calling procedure and pop 4 bytes from stack.
    shellcode(3) = &H4
    shellcode(4) = 0    'NULL terminator

    'OpenProcess, to get a handle to the remote process
    LngProcess = OpenProcess(PROCESS_ALL_ACCESS, False, lngPid)
    'to allocate some space inside of process (with PAGE_EXECUTE protection and MEM_COMMIT as parameter.
    'lpAddress set to NULL so that the function determines where to allocate the region)
    LngModule = VirtualAllocEx(LngProcess, 0, UBound(shellcode), MEM_COMMIT, PAGE_EXECUTE)

    Debug.Print "VirtualAllocEx: " & Hex(LngModule) 'debug info

    'writing our shellcode to the target's memory
    For i = 0 To UBound(shellcode)
        Call WriteProcessMemory(LngProcess, LngModule + i, shellcode(i), 1, 0&)
    Next i
    'thread injection to execute my code cave
    RemThread = CreateRemoteThread(LngProcess, 0&, 0&, ByVal LngModule, 0&, 0&, ByVal 0&)

    Debug.Print "CreateRemoteThread: " & Hex(RemThread) 'debug info

    'wait for the thread to run
    Call WaitForSingleObject(RemThread, INFINITE)
    CloseHandle (RemThread)
    Call VirtualFreeEx(LngProcess, LngModule, UBound(shellcode), MEM_RELEASE)

    Debug.Print "DONE" 'debug info
End Sub

Хотя происходит что-то странное. Когда я помещаю MsgBox (который приостанавливает выполнение) в целях отладки ПЕРЕД вызовом CreateRemoteThread, функция возвращает ненулевой дескриптор (но целевой EXE-файл аварийно завершает работу). И если я не помещаю Msgbox перед вызовом CreateRemoteThread, возвращается дескриптор NULL.


person Mike    schedule 03.03.2019    source источник
comment
lpParameter As Any по-прежнему неправильно   -  person Alex Guteniev    schedule 04.03.2019
comment
Привет, Александр, даже при объявлении lpParameter как Long (в объявлении API) вызов CreateRemoteThread возвращает 0. Я действительно не знаю, как это исправить. Я прочитал ваш комментарий, в котором упоминается API, отличный от COM, но мне не удалось исправить вызов: Private Declare Function CreateRemoteThread Lib kernel32 (ByVal hProcess As Long, lpThreadAttributes As Long, ByVal dwStackSize As Long, lpStartAddress As Long, lpParameter As Long , ByVal dwCreationFlags As Long, lpThreadId As Long) As Long   -  person Mike    schedule 06.03.2019


Ответы (1)


Обратный вызов ThreadProc, переданный CreateRemoteThread, принимает один параметр LPVOID, а ThreadProc равен __stdcall.

Параметр LPVOID для ThreadProc передается от LPVOID lpParameter пользователя CreateRemoteThread.

На x86 это означает, что вам нужно поставить инструкцию RET, которая освобождает четыре байта из стека.

(Кроме того, ThreadProc возвращает DWORD, это означает, что вы должны вернуть значение EAX перед возвратом, но если вас не волнует возвращаемое значение, вы можете пропустить его)

Кроме того, CB - дальний возврат, вам нужно использовать ближний возврат.

Найдите код операции RETN imm, похоже, вам нужен C2 04 00

person Alex Guteniev    schedule 03.03.2019
comment
Спасибо за ваш вклад! Я попытался внедрить следующую последовательность байтов: \x90\x90\xC2\x04\x00 (бесполезные NOP, просто чтобы притвориться, что это настоящий код), но это тоже дает сбой. Из вашего ответа я думаю, что понимаю, что все, что я буду вводить, должно заканчиваться таким образом (почти вернуться к вызывающей процедуре и извлечь 4 байта из стека, которые соответствуют адресу возврата). Однако в моем вызове VB6 CreateRemoteThread я действительно не знаю, что передать в качестве аргументов. Я видел много LPTHREAD_START_ROUTINE в Интернете, но не могу найти ничего подобного в VB6. - person Mike; 03.03.2019
comment
я выполняю вызов таким образом в MS VB6: CreateRemoteThread (processHandle, 0, 0, remoteCodeOffset, 0, 0, 0). Я думал, что ThreadProc был вызываемым (удаленное смещение) - person Mike; 03.03.2019
comment
Я отредактировал свой ответ, чтобы уточнить, что передается в качестве аргументов. Тем не менее, не думаю, что это поможет, похоже, у вас есть проблема с чем-то еще. - person Alex Guteniev; 03.03.2019
comment
Вам нужно определить исключение, почему именно целевой exe перестает работать, используя отладчик, или из сообщения о сбое, или путем проверки аварийного дампа, или из журнала событий. - person Alex Guteniev; 03.03.2019
comment
Вот что я получаю: код исключения c0000005 [якобы нарушение прав доступа, поэтому мой код пытается получить доступ к адресу, на который у него нет прав]. Как код узнает, куда возвращаться? Извлекая 4 байта из стека и переходя к предыдущему eIP? Что ведет к моему приложению для вызова VB? Извините за эти вопросы, я пытаюсь понять, но есть вещи, которые я пока не понимаю. - person Mike; 03.03.2019
comment
Нарушение доступа имеет параметры, такие как чтение/запись/выполнение и местоположение, может быть некоторая подсказка. - person Alex Guteniev; 03.03.2019
comment
Такие функции, как CreateThread или CreateRemoteThread, вызывают пользовательскую функцию из оболочки, поэтому есть место, куда можно вернуться. В случае CreateRemoteThread это место находится в удаленном процессе. (В конечном итоге поток вызовет NtTerminateThread, но это делается внутри системной части, которая обертывает ваш ThreadProc) - person Alex Guteniev; 03.03.2019
comment
Пожалуйста, опубликуйте свой код VB6. Я следовал шагам, и у меня все работает. - person Alex Guteniev; 03.03.2019
comment
Вы должны быть в состоянии сказать, по какому адресу произошло нарушение прав доступа. Это адрес вашего внедренного кода? - person prl; 03.03.2019
comment
Вы правы, должно быть что-то не так с моим кодом VB6. Я попробовал инжектор кода Python gist.github.com/andreafortuna/20d19ac02393264930b3d331fe66a6f6, и он работает с последовательность байтов \xc2\x04\x00, поэтому ошибка может исходить из моей реализации vb. Однако я не могу понять, что я вызываю CreateRemoteThread так же, как это делается в приведенном выше скрипте Python. То же количество аргументов, те же типы. Я не знаю, что сделать, чтобы это работало в VB. Большое спасибо за предоставленную информацию! - person Mike; 03.03.2019
comment
Может быть, у оболочки VB для CreateRemoteThread по какой-то причине есть дополнительный параметр или другой порядок? - person prl; 03.03.2019
comment
Я думаю, что разница все же в коде. \xc2\x04\x00 — это строка из 3 байтов: C2 04 00 как в C, так и в Python. Но я не уверен в Visual Basic. Если это буквально \xc2\x04\x00, то есть байт для \ , байт для x, байт для c и т. д., это точно не сработает. - person Alex Guteniev; 03.03.2019
comment
Вот мой код VB6: pastebin.com/4LcTSA10 Напоминание: я использую то же количество аргументов, что и версия python с GitHub (предыдущий комментарий). Спасибо за помощь. Почти готово. - person Mike; 03.03.2019
comment
Соответствующие объявления: pastebin.com/VZCztMC9 (извините, я забыл включить их в свой предыдущий комментарий) - person Mike; 03.03.2019
comment
Тип параметра As Any не следует использовать для не-COM API, таких как CreateRemoteThread. Также передайте остальные параметры ByVal As Long. - person Alex Guteniev; 03.03.2019