struct REMOTE_THREAD_INFO
{
int data1;
int data2;
int data3;
};
static DWORD CALLBACK RemoteThreadProc(REMOTE_THREAD_INFO* info)
{
try {
... use the info to do something ...
} catch (...) {
... ignore all exceptions ...
}
return 0;
}
static void EndOfRemoteThreadProc()
{
}
// Error checking elided for expository purposes
void DoSomethingCrazy()
{
// Calculate the number of code bytes.
SIZE_T functionSize = (BYTE*)EndOfRemoteThreadProc - (BYTE*)RemoteThreadProc;
// Allocate memory in the remote process
SIZE_T allocSize = sizeof(REMOTE_THREAD_INFO) + functionSize;
REMOTE_THREAD_INFO* buffer = (REMOTE_THREAD_INFO*)
VirtualAllocEx(targetProcess, NULL, allocSize, MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
// Write data to the remote process
REMOTE_THREAD_INFO localInfo = { ... };
WriteProcessMemory(targetProcess, buffer,
&localInfo, sizeof(localInfo));
// Write code to the remote process
WriteProcessMemory(targetProcess, buffer + 1,
(void*)RemoteThreadProc, functionSize);
// Execute it!
CreateRemoteThread(targetProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)(buffer + 1),
buffer);
}
VirtualAlloc
для выделения памяти под этот процесс. Первая часть блока данных содержала какие-то данные, которые нужно было передать. Вторая часть блока данных содержала байты кода, которые нужно было исполнить, и клиент запускал эти байты кода при помощи CreateRemoteThread
.RemoteThreadProc
не зависит от позиции. Требование независимости сгенерированного кода от позиции отсутствует. Например, один из вариантов генерации кода для операторов switch
заключается в использовании таблицы переходов, и эта таблица состоит из абсолютных адресов x86.catch
, чтобы было понятно, какой оператор catch
использовать. И если бы использовался catch
с фильтрацией, то существовали бы дополнительные таблицы для определения того, применяется ли фильтр catch
к выданному исключению.EndOfRemoteThreadProc
и RemoteThreadProc
.EndOfRemoteThreadProc
будет размещена в памяти непосредственно после RemoteThreadProc
. На самом деле, нет даже гарантий того, что EndOfRemoteThreadProc
будет иметь отдельную сущность. Компоновщик может выполнить свёртывание COMDAT, при котором несколько идентичных функций соединяются в одну. Даже если отключить свёртывание COMDAT, то Profile-Guided Optimization переместит функции по отдельности и маловероятно, что они окажутся в одном месте.RemoteThreadProc
вообще были смежными! Profile-Guided Optimization изменяет порядок базовых блоков и код одной функции может оказаться разбросанным по разным частям программы (это зависит от паттернов использования).структуру дескриптора, содержащую пару указателей: один на gp
функции, второй на первый байт кода. (Тот же паттерн используется в PowerPC.)LoadLibrary
. Она бы вызвала загрузчик, который бы проделал всю работу по реализации необходимых исправлений, правильно бы распределил память с корректным выравниванием, регистрацией защиты потока управления и таблиц раскрутки исключений, загрузил бы зависимые библиотеки и в целом правильно подготовил среду выполнения для запуска нужного кода.К сожалению, не доступен сервер mySQL