CreateProcess из буфера памяти
Я могу использовать CreateProcess для запуска EXE. Я хочу иметь содержимое EXE в буфере памяти и сделать CreateProcess (или эквивалент) на нем без необходимости записывать его в файл. Есть ли способ сделать это?
Предыстория: мы делаем игры. Мы отправляем простой дистрибутив EXE нашим дистрибьюторам, которые затем оборачивают его, используя свои любимые DRM, и продают его своим пользователям. Были случаи, когда пользователи находили сбои. Для устранения большинства сбоев требуется 5 минут, но патч должен пройти через дистрибьютора, и это может занять несколько дней, даже недель. Я не могу просто отправить исправленный EXE-файл игрокам, потому что у него не будет DRM дистрибьютора. Я думаю о том, чтобы распространять настоящий EXE-файл игры в зашифрованном файле данных, чтобы то, что было упаковано (внешний EXE-файл), просто расшифровывало и запускало настоящий EXE-файл. Таким образом, я мог бы безопасно распространить исправление, не отключая DRM.
6 ответов
Это на самом деле довольно легко. Подобная техника была описана в статье, которую я прочитал 3 года назад.
Windows позволяет вам вызывать функцию CreateProcess с флагом CREATE_SUSPENDED, который говорит API о необходимости приостановить процесс до вызова функции ResumeThread.
Это дает нам время для захвата контекста приостановленного потока с помощью функции GetThreadContext, а затем в регистре EBX будет храниться указатель на структуру PBE(блок обработки процесса), которая нам необходима для определения базового адреса.
Из макета структуры PBE мы можем видеть, что ImageBaseAddress хранится в 8-м байте, поэтому [EBX+8] даст нам фактический базовый адрес приостановленного процесса.
Теперь нам нужен EXE-файл в памяти и выполняется соответствующее выравнивание, если выравнивание EXE-файла и памяти отличается.
Если базовый адрес приостановленного процесса и исполняемого файла в памяти совпадает, плюс если imageSize исполняемого файла в памяти меньше или равен приостановленному процессу, мы можем просто использовать WriteProcessMemory для записи исполняемого файла в памяти в пространство памяти приостановленный процесс.
Но если вышеупомянутые условия не были выполнены, нам нужно немного больше магии. Сначала нам нужно отменить отображение исходного изображения с помощью ZwUnmapViewOfSection, а затем выделить достаточно памяти, используя VirtualAllocEx, в пространстве памяти приостановленного процесса. Теперь нам нужно записать исполняемый файл в памяти в пространство приостановленного процесса, используя функцию WriteProcessMemory.
Затем вставьте BaseAddress исполняемого файла в памяти в PEB->ImageBaseAddress приостановленного процесса.
Регистр EAX контекста потока содержит адрес EntryPoint, который нам нужно переписать с адресом EntryPoint исполняемого файла в памяти. Теперь нам нужно сохранить измененный контекст потока, используя функцию SetThreadContext.
Вуаля! Мы готовы вызвать функцию ResumeThread в приостановленном процессе, чтобы выполнить ее!
Вы можете скомпилировать игру как DLL и поместить DLL в зашифрованный файл данных. DLL может быть загружена из памяти без записи на диск. Пожалуйста, смотрите этот учебник (с примером кода в конце): Загрузка DLL из памяти
Для того, что вы хотите сделать, требуется NtCreateProcess, но он недокументирован и поэтому хрупок. Эта книга, по- видимому, охватывает его использование.
Возможно, вы могли бы создать систему исправлений? Например, при запуске программа проверяет наличие исправления DLL в том же каталоге и загружает его, если он существует.
Зачем вам нужно создавать новый процесс? Я бы подумал, что вы можете запустить в контексте процесса, который выполняет распаковку / дешифрование.
То, что вы хотите, может быть достигнуто с помощью так называемого "упаковщика". На самом деле запуск exe из памяти может быть возможен, но это намного сложнее, чем упаковщик;)
Одним из самых известных упаковщиков является UPX (Google it). Существуют инструменты для его расшифровки, но он должен по крайней мере дать вам отправную точку для работы с ним. Я также уверен, что UPX с открытым исходным кодом.