Ранг: 253.9 (наставник) Активность: 0.13↘0 Статус: Участник
|
Создано: 26 декабря 2005 00:13 · Личное сообщение · #1
Доброго времени суток, уважаемая аудитория!
Понадобилось мне как-то сделать лоадер, да не простой, а такой, чтобы пропатчить память определенной DLL запускаемого процесса. Везде обыскался, ничего не нашел. Поэтому написал свой, довольно универсальный лоадер. Можно патчить хоть сам EXE'шник, хоть любую его DLL.
Лоадер написан на Borland C++ 5.0 с использованием VCL. На выхлопе получается ~100 кб., сжимается до ~45 кб.
Держите и пользуйтесь, кому надо.
/*
MemPatcher
A process memory patcher
Written by Tim
E-mail: timqwerty@yandex.ru
12/26/2005 1.00 Первая версия
*/
#include <vcl.h>
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
long filesize(FILE *stream);
long MyGetFileSize(AnsiString FileName);
int MyMessageBox(AnsiString Text);
WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Создаваемый процесс. Внимание! Это не тот процесс, который будем патчить!
AnsiString RunApplication = "FL.exe";
// Модуль создаваемого процесса, который будем патчить. Это может быть как
// загружаемая DLL, так и сам EXE файл (читай, создаваемый процесс).
AnsiString VictimModule = "FLEngine.dll";
// Размер модуля на жестком диске.
long VictimSize = 1178112;
// Ждем пока протектор/упаковщик распакует данные. Если вы собираетесь
// патчить сам EXE файл, то можете поставить здесь даже 0, а вот если
// будете патчить DLL, то это зависит от ее типа загрузки. Т.е., если она
// находится в таблице импорта создаваемого процесса, то функция CreateProcess
// не вернет управление лоадеру, пока не загрузит все DLL. Значит можно
// поставить даже 0. А вот если тип загрузки DLL - динамический, то возникает
// проблема. Вам нужно будет подобрать такое значение, чтобы создаваемый
// процесс успел загрузить эту DLL (т.е., чтобы она появилась при перечислении
// модулей процесса). Обычно хватает 200-300 мс.
// Еще раз оговорюсь. Это значение имеет очень важную роль, если вы хотите
// патчить DLL, которая подгружается динамически.
unsigned int Delay = 555;
// Количество попыток пропатчить данные. Если вы хотите, чтобы лоадер
// пропатчил процесс до того, как он начнет выполняться с OEP, вам нужно
// проконтролировать количество сделанных попыток. Если лоадер пропатчил все
// с первого раза (0) - значит он не успел сделать это до OEP. Если же попыток
// было несколько (5 и больше) - то есть гарантия, что процесс был пропатчен
// до OEP.
// Внизу по коду есть закоментированный MessageBox. Используйте его для
// контроля попыток.
// Важное замечание. Если вы делаете лоадер на ASProtect, то количество
// попыток может быть равно 0, иначе он выдаст "Error: 45" (ошибка CRC).
unsigned int Retries = 1000;
// Задержка между попытками. Retries * RetryDelay = максимальное время работы
// лоадера. Например, если количество попыток равно 1000, а задержка равна
// 5 мс, то лоадер будет 5 секунд пытаться пропатчить данные.
unsigned int RetryDelay = 0;
// Количество байт в патче (смотрите ниже).
unsigned long DataSize = 24;
// Адрес по которому патчить (смотреть в дампе, без Image Base).
DWORD Address = 0x1C27B4;
// Оригинальные байты.
static const unsigned char OriginalData[] = {
0x33, 0xD2, 0x83, 0x78, 0x18, 0x02, 0x75, 0x0D,
0x8B, 0x40, 0x14, 0x8B, 0x40, 0x08, 0xF6, 0x40,
0x0D, 0x80, 0x0F, 0x95, 0xC2, 0x8B, 0xC2, 0xC3 };
// Измененные байты.
static const unsigned char ModifiedData[] = {
0x33, 0xD2, 0x83, 0x78, 0x18, 0x02, 0x75, 0x0D,
0x8B, 0x40, 0x14, 0x8B, 0x40, 0x08, 0xF6, 0x40,
0x0D, 0x80, 0x0F, 0x95, 0xC2, 0x33, 0xC0, 0xC3 };
// -----
if(!FileExists(RunApplication))
{
MyMessageBox("File doesn't exist:\n" + RunApplication);
exit(1);
}
if(!FileExists(VictimModule))
{
MyMessageBox("File doesn't exist:\n" + VictimModule);
exit(1);
}
if(MyGetFileSize(VictimModule) != VictimSize)
{
MyMessageBox("File is wrong size:\n" + VictimModule);
exit(1);
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
if(CreateProcess(NULL,
AnsiString(RunApplication + " " + lpCmdLine).c_str(),
NULL, NULL,
false,
0,
NULL, NULL,
&si, &pi))
{
Sleep(Delay);
MODULEENTRY32 me;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pi.dwProcessId);
memset(&me, 0, sizeof(MODULEENTRY32));
me.dwSize = sizeof(MODULEENTRY32);
if(!hSnapshot)
{
MyMessageBox("Can't take a snapshot of the module:\n" + RunApplication);
exit(1);
}
bool Status = false;
if(Module32First(hSnapshot, &me))
do
{
if(AnsiString(me.szModule).LowerCase() == VictimModule.LowerCase())
{
// -----
bool DataDiffers;
unsigned long BytesRead;
unsigned long BytesWrote;
unsigned char *Data = new unsigned char[DataSize];
unsigned int RetriesCount = 0;
while(RetriesCount < Retries)
{
if(!ReadProcessMemory(pi.hProcess,
(LPVOID)(Address + (DWORD)me.modBaseAddr),
(LPVOID)Data,
DataSize,
&BytesRead))
{
MyMessageBox("Can't read process memory:\n" + VictimModule);
exit(1);
}
if(BytesRead != DataSize)
{
MyMessageBox("Read the wrong number of bytes:\n" + VictimModule);
exit(1);
}
DataDiffers = false;
for(unsigned long i = 0; i < DataSize; i++)
if(Data[i] != OriginalData[i])
{
DataDiffers = true;
break;
}
if(!DataDiffers)
break;
Sleep(RetryDelay);
RetriesCount++;
}
if(DataDiffers)
{
MyMessageBox("File is wrong version:\n" + VictimModule);
exit(1);
}
SuspendThread(pi.hThread);
if(!WriteProcessMemory(pi.hProcess,
(LPVOID)(Address + (DWORD)me.modBaseAddr),
(LPVOID)ModifiedData,
DataSize,
&BytesWrote))
{
MyMessageBox("Can't write process memory:\n" + VictimModule);
exit(1);
}
ResumeThread(pi.hThread);
CloseHandle (pi.hThread);
if(BytesWrote != DataSize)
MyMessageBox("Wrote the wrong number of bytes:\n" + VictimModule);
Status = true;
// Контроль попыток.
/*
MessageBox(NULL,
AnsiString("Number of retries: " + IntToStr(RetriesCount)).c_str(),
"Information",
MB_ICONINFORMATION);
*/
// -----
break;
}
}
while(Module32Next(hSnapshot, &me));
if(!Status)
MyMessageBox("Module not found in the snapshot:\n" + VictimModule);
CloseHandle(hSnapshot);
}
else
{
MyMessageBox("Can't execute:\n" + RunApplication);
exit(1);
}
return 0;
}
long filesize(FILE *stream)
{
long curpos;
long length;
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
fseek(stream, curpos, SEEK_SET);
return length;
}
long MyGetFileSize(AnsiString FileName)
{
long length;
FILE *in = fopen(FileName.c_str(), "rb");
if(in)
{
length = filesize(in);
fclose(in);
return length;
}
return -1;
}
int MyMessageBox(AnsiString Text)
{
return MessageBox(NULL, Text.c_str(), "Error", MB_ICONERROR);
}
----- MicroSoft? Is it some kind of a toilet paper? | Сообщение посчитали полезным: |