Внедрение своего кода в адресное пространство процессов
Время на прочтение
5 мин
Количество просмотров 39K
Intro
Внедрение своего кода( динамически ) в чужие процессы — штука достаточно интересная. Это может служить как во благо, так и во зло. Хотя, понятие «зло», местами, весьма абстрактно в информационном мире, я не могу провести точную границу между тем, что «плохо», а что «хорошо», тем более, если это касается внедрения кода…
В данной статье мы займемся созданием своего DLL инжектора. Что это такое, думаю, знают все. Такой способ внедрения стороннего кода достаточно популярен и удобен.
Писать DLL Injector мы будем на C++ в среде Microsoft Visual Studio 2010. Для создания динамически подключаемой библиотеки можно использовать любой инструмент, который вам по душе. Я же для создания библиотеки выбрал CodeGear RAD Studio 2009, язык Delphi( Object Pascal ).
Как же работает DLL Injection ?
Схема работы данного метода проста:
1) поиск и получение дескриптора нужного процесса
2) выделение памяти в процессе и последующая запись пути в DLL`ке по адресу, где произошло выделение памяти
3) создание нового потока в виртуальном пространстве процесса, дескриптор которого был получен.
Начнем с создания DLL.
Как я уже говорил, для этой цели будет использоваться язык Delphi:
Теперь добавим в DLL некоторые ресурсы, а именно — форму и кнопки для управления:
Сама DLL состоит лишь из нескольких строчек кода, которые будут отображать созданную форму. Также можно удалить все комментарии для более удобного визуального восприятия кода:
Теперь программируем интерфейс формы DLL. На форме есть две кнопки. Первая будет «убивать» родительский процесс( т.е процесс, в виртуальном пространстве которого был создан поток, в котором, в свою очередь, выполняется код DLL ). Вторая — рисовать 10 квадратов размером 25x25px в контексте всех окон приложения, принадлежащих процессу:
procedure TForm1.Button1Click(Sender: TObject);
var _curr_process:DWORD;
p_handle: THANDLE;
begin
// Убиваем родительский процесс
_curr_process:=GetCurrentProcessId();
p_handle:=OpenProcess(PROCESS_ALL_ACCESS,false,_curr_process);
TerminateProcess(p_handle,4);
end;
var dw:DWORD; // PID текущего процесса
procedure drawGroup(h:HWND);
var canvas:TBitMap;
rect:TRect;
x,y:integer;
i: Integer;
begin
// рисуем 10 квадратов
for i := 1 to 10 do
begin
canvas:=TBitMap.Create();
canvas.Canvas.Handle:=GetDC(h); // устанавливаем дескриптор контекста
randomize;
canvas.Canvas.Brush.Color:=rgb(random(255),random(255),random(255));
GetWindowRect(h,rect);
x:=random(rect.Right-rect.Left-25);
y:=random(rect.Bottom-rect.Top-25);
canvas.Canvas.Rectangle(x,y,x+25,y+25);
end;
end;
function func(h:HWND):BOOL; stdcall;
var pid:DWORD;
begin
GetWindowThreadProcessId(h,pid);
// запускаем функцию рисования в окне, если оно принадлежит нужному процессу:
if(pid=dw) then drawGroup(h);
result:=true;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// Запускаем функцию рисования квадратов
// ( в перечислителе окон системы )
dw:=GetCurrentProcessId();
EnumWindows(@func,0); // перечисляем окна
end;
Исходный код интерфейсной части можно посмотреть здесь .
Тут все достаточно просто.
Итак, динамическая библиотека написана. Теперь компилируем ее и на выходе получаем скомпилированный файл с расширением «.dll», который можно переименовать для удобства.
Я переименую библиотеку в «inj.dll».
Создание DLL завершено.
Осталось лишь скопировать нашу DLL`ку в системную директорию Windows, чтобы любое приложение могло отыскать её лишь по одному имени.
Переходим к разработке инжектора. Идем в Visual Studio и создаем Пустой проект( File->New->Project->Visual C++->General->Empty Project). Вся разработка будет производиться на «чистом» WinApi.
Первым делом создадим простейший визуальный интерфейс: форма, кнопка и текстовое поле. Выглядеть это будет примерно так:
Как видно, это приложение, обладающее минимальным дизайном и простейшим интерфейсом. В нем присутствуют два текстовых поля, предназначенных для ввода имени процесса( или его определенной части ), в который требуется произвести инжектирование DLL и для ввода имени самой DLL. Кнопка, соответственно, запускает процесс инжекта.
Для инжекта DLL в адресное пространство процессов понадобятся следующие WinApi функции:
Для поиска нужного процесса:
CreateToolHelp32SnapShot
Process32First
Process32Next
Для инжекта:
OpenProcess
GetProcAddress
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread
Итак, обдумаем, как же, собственно организовать «умную» архитектуру приложения, которая была бы понятной и простой.
Я предлагаю начать с обработки щелка по кнопке
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
// Button Click
if(msg.hwnd==button && msg.message==WM_LBUTTONUP)
{
// Getting Process Name
GetWindowText(edit_proc,buff,sizeof(buff));
strncpy(_p_name,buff,BUFF);
// Getting DLL Name
ZeroMemory(buff,sizeof(buff));
GetWindowText(edit_dll,buff,BUFF);
strncpy(_dll_name,buff,BUFF);
// Start Injection
StartInjection();
}
Ок, далее, переходим к реализации функции
StartInjection();
, которая служит для поиска процесса по его имени:
int StartInjection()
{
// Searching of Process
PROCESSENTRY32 pe;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(snapshot==INVALID_HANDLE_VALUE)
{
ShowMessage("SnapShot Failed.");
return 0;
}
pe.dwSize = sizeof(PROCESSENTRY32);
int curr = Process32First(snapshot,&pe);
while(curr)
{
CharLowerBuff(pe.szExeFile,lstrlen(pe.szExeFile));
if(strstr(pe.szExeFile,_p_name)) {pid = pe.th32ProcessID; break;}
curr = Process32Next(snapshot,&pe);
}
if(pid==NULL)
{
ShowMessage("Searching of process failed.");
return 0;
}
bool result = Inject();
if(result==false)
{
ShowMessage("Injection failed.");
return 0;
}
}
И, наконец, завершающая процесс инжектирования функция
Inject()
:
// Injection
bool Inject()
{
if(pid==NULL) return false;
// Получение дескриптора процесса
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
if(process==NULL) return false;
// "Вытягивание" функции из системной библиотеки для динамической
// подгрузки DLL в адресное пространство открытого процесса
LPVOID fp = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"),"LoadLibraryA");
if(fp==NULL) return false;
// Выделение участка памяти размером strlen(_dll_name) для последующей
// записи имени библеотеки в память процесса.
LPVOID alloc = (LPVOID)VirtualAllocEx(process,0,strlen(_dll_name), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if(alloc==NULL) return false;
// Запись имени инжектируемой DLL в память
BOOL w = WriteProcessMemory(process,(LPVOID)alloc,_dll_name,strlen(_dll_name),0);
if(w==NULL) return false;
// Создание "удаленного" потока в адресном пространстве
// открытого процесса и последующая подгрузка нашей DLL.
HANDLE thread = CreateRemoteThread(process,0,0,(LPTHREAD_START_ROUTINE)fp,(LPVOID)alloc,0,0);
if(thread==NULL) return false;
CloseHandle(process);
return true;
}
Полный код инжектора можно посмотреть здесь.
Тестируем работоспособность инжектора:
Сначала инжектимся «сами в себя». При клике на кнопку «Draw» происходит рисование 10 квадратов. При клике на «Crash it!» происходит немедленное завершение «родительского» процесса. Теперь попробуем инжектиться во что-нибудь посерьезнее, например, в браузер Mozilla Firefox. Для этого необходимо поменять лишь имя процесса в первом текстовом поле и нажать на кнопку:
Как видно, инжект успешно удался. Квадраты рисуются во всех окнах, принадлежащих родительскому процессу браузера. При нажатии на кнопку «Crash it!» Mozilla FireFox немедленно закрывается.
Outro
Для чего нам это вообще нужно? Ведь наша основная цель — это взлом( игр, софта ). Так вот в дальнейшем мы, наверняка, будем использовать этот инжектор для внедрения своего кода в чужое адресное пространство. Благодаря этому можно сэкономить немало времени, сил и нервов
Удачи!
Загрузка…
Simple C++/C DLL injector
Простенький инъектор .dll, созданный как альтернатива для GameOwner. Использует метод LoadLibrary.
Как использовать?
- Скачать injector.exe
- Распаковать в любую папку (желательно на флешку)
- Перенести вашу .dll в папку с инъектором
- Запустить инъектор и ввести название .dll
- Profit
Компиляция кода
Для компиляции кода нужен любой компилятор C++/C (например, GNU GCC Compiler).
Копируете injector.cpp и компилируете, полная копи-паста компатибилити чо.
В случае если Вы будете компилировать на чистом Си, нужно будет добавить в самое начало:
или же
typedef int bool; #define true 1 #define false 0
Модификация кода
В сурс коде я прописал все как можно подробнее, все должно быть понятно.
Например, чтобы код инъекции работал не только в hl2.exe, а в любом, то можно написать следующий код:
char process_name[64]; scanf("%s",&process_name); DWORD pID = GetTargetThreadIDFromProcName(process_name);
в данном случае пользователь должен будет вводить еще и имя процесса, чтобы код нормально работал.
-
#1
Как написать Инжектор с нуля на C++
Как написать Инжектор с нуля на C++
В данной статье я вам расскажу и покажу как работает инжектор dll и как написать инжектор с нуля с методом LoadLibrary, я вам расскажу о каждом методе и последовательно как и что происходит, для новичков будет особенно полезная статья потому-что в интернете мало где можно найти написание инжектора с нуля на языке C++ давайте начнем
Что такое Инжектор? — это метод используемый для запуска кода в адресном пространстве другого процесса, заставляя его загружать библиотеку динамической компоновки
Соответственно для инжектора нам нужна динамическая библиотека которая будет выполнять код в адресном пространстве который мы освободим и создадим поток!
Давайте начнем писать сам инжектор, а с динамической библиотекой вы уже сами разберетесь или можете найти на форуме
Для начало нам нужно подключить несколько инклудов
#include <Windows.h>
#include <TlHelp32.h>
Нам нужна будет функция с помощью которой мы будем получать PID процесса, при открытий программ он генерируется всегда рандомно
Поэтому нам нужно получить его что бы на основе его открыть ручку процесса и предоставить нам полный доступ к процессу в User Mode
C++:
DWORD GetProcessID(const char* processName)
{
if (!processName)
return 0;
DWORD id = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap)
{
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
if (Process32First(hSnap, &pe32))
{
while (Process32Next(hSnap, &pe32))
{
if (strcmp(processName, pe32.szExeFile) == 0)
{
id = pe32.th32ProcessID;
break;
}
}
}
}CloseHandle(hSnap);
return id;
}
Теперь давайте в нашем main() найдем процесс нужной нам игры куда будем внедрять, откроем дескриптор процесса (получаем полный доступ) и освободим память и создадим наш поток адресного пространства
C++:
int main() {
DWORD gameProcess = 0; // Создаем переменную под наш GetProcessID метод
const char* DllPath = "anonymcheats.dll"; // Наша DLL которую инжектим, в данном случае он найдет рядом с инжектором (только)
gameProcess = GetProcessID("csgo.exe");
if (!gameProcess) { // Если наш процесс не был найден
printf("Process csgo was not found");
}
// Если процесс найден открываем ручку
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, gameProcess);
if (hProcess == INVALID_HANDLE_VALUE) {
// Если нашу ручку не удалось открыть
printf("Handle Error");
}
void* allocated = VirtualAllocEx(hProcess, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // Освобождаем память под нашу DLL
if (!WriteProcessMemory(hProcess, allocated, DllPath, strlen(DllPath) + '', 0)) // Записываем нашу DLL и проверяем что если неудалось записать
{
CloseHandle(hProcess);
return false;
}
void* hThread = CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)LoadLibraryA, allocated, 0, 0); // Создаем поток адресса которого мы освободили это наша DLL
if (hThread != 0) // закрываем Handle
CloseHandle(hThread);
CloseHandle(hProcess); // Закрываем Handle Process
printf("Inject Successfulled"); // Инжект произошел успешно
return 0; // Возвращаем 0
}
-
#3
Как написать Инжектор с нуля на C++
В данной статье я вам расскажу и покажу как работает инжектор dll и как написать инжектор с нуля с методом LoadLibrary, я вам расскажу о каждом методе и последовательно как и что происходит, для новичков будет особенно полезная статья потому-что в интернете мало где можно найти написание инжектора с нуля на языке C++ давайте начнем
Что такое Инжектор? — это метод используемый для запуска кода в адресном пространстве другого процесса, заставляя его загружать библиотеку динамической компоновки
Соответственно для инжектора нам нужна динамическая библиотека которая будет выполнять код в адресном пространстве который мы освободим и создадим поток!Давайте начнем писать сам инжектор, а с динамической библиотекой вы уже сами разберетесь или можете найти на форуме
Для начало нам нужно подключить несколько инклудов
#include <Windows.h>
#include <TlHelp32.h>Нам нужна будет функция с помощью которой мы будем получать PID процесса, при открытий программ он генерируется всегда рандомно
Поэтому нам нужно получить его что бы на основе его открыть ручку процесса и предоставить нам полный доступ к процессу в User ModeC++:
DWORD GetProcessID(const char* processName) { if (!processName) return 0; DWORD id = 0; HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnap) { PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; if (Process32First(hSnap, &pe32)) { while (Process32Next(hSnap, &pe32)) { if (strcmp(processName, pe32.szExeFile) == 0) { id = pe32.th32ProcessID; break; } } } }CloseHandle(hSnap); return id; }
Теперь давайте в нашем main() найдем процесс нужной нам игры куда будем внедрять, откроем дескриптор процесса (получаем полный доступ) и освободим память и создадим наш поток адресного пространства
C++:
int main() { DWORD gameProcess = 0; // Создаем переменную под наш GetProcessID метод const char* DllPath = "anonymcheats.dll"; // Наша DLL которую инжектим, в данном случае он найдет рядом с инжектором (только) gameProcess = GetProcessID("csgo.exe"); if (!gameProcess) { // Если наш процесс не был найден printf("Process csgo was not found"); } // Если процесс найден открываем ручку HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, gameProcess); if (hProcess == INVALID_HANDLE_VALUE) { // Если нашу ручку не удалось открыть printf("Handle Error"); } void* allocated = VirtualAllocEx(hProcess, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // Освобождаем память под нашу DLL if (!WriteProcessMemory(hProcess, allocated, DllPath, strlen(DllPath) + '', 0)) // Записываем нашу DLL и проверяем что если неудалось записать { CloseHandle(hProcess); return false; } void* hThread = CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)LoadLibraryA, allocated, 0, 0); // Создаем поток адресса которого мы освободили это наша DLL if (hThread != 0) // закрываем Handle CloseHandle(hThread); CloseHandle(hProcess); // Закрываем Handle Process printf("Inject Successfulled"); // Инжект произошел успешно return 0; // Возвращаем 0 }
А теперь как обойти античит
-
#5
А как сделать что-бы с сайта дллка скачивалась
-
#6
А как сделать что-бы с сайта дллка скачивалась
C++:
URLDownloadToFile(0, L"ссылка на прямое скачивание", L"Путь, куда она скачается", 0, 0);
-
#7
Как написать Инжектор с нуля на C++
В данной статье я вам расскажу и покажу как работает инжектор dll и как написать инжектор с нуля с методом LoadLibrary, я вам расскажу о каждом методе и последовательно как и что происходит, для новичков будет особенно полезная статья потому-что в интернете мало где можно найти написание инжектора с нуля на языке C++ давайте начнем
Что такое Инжектор? — это метод используемый для запуска кода в адресном пространстве другого процесса, заставляя его загружать библиотеку динамической компоновки
Соответственно для инжектора нам нужна динамическая библиотека которая будет выполнять код в адресном пространстве который мы освободим и создадим поток!Давайте начнем писать сам инжектор, а с динамической библиотекой вы уже сами разберетесь или можете найти на форуме
Для начало нам нужно подключить несколько инклудов
#include <Windows.h>
#include <TlHelp32.h>Нам нужна будет функция с помощью которой мы будем получать PID процесса, при открытий программ он генерируется всегда рандомно
Поэтому нам нужно получить его что бы на основе его открыть ручку процесса и предоставить нам полный доступ к процессу в User ModeC++:
DWORD GetProcessID(const char* processName) { if (!processName) return 0; DWORD id = 0; HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnap) { PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; if (Process32First(hSnap, &pe32)) { while (Process32Next(hSnap, &pe32)) { if (strcmp(processName, pe32.szExeFile) == 0) { id = pe32.th32ProcessID; break; } } } }CloseHandle(hSnap); return id; }
Теперь давайте в нашем main() найдем процесс нужной нам игры куда будем внедрять, откроем дескриптор процесса (получаем полный доступ) и освободим память и создадим наш поток адресного пространства
C++:
int main() { DWORD gameProcess = 0; // Создаем переменную под наш GetProcessID метод const char* DllPath = "anonymcheats.dll"; // Наша DLL которую инжектим, в данном случае он найдет рядом с инжектором (только) gameProcess = GetProcessID("csgo.exe"); if (!gameProcess) { // Если наш процесс не был найден printf("Process csgo was not found"); } // Если процесс найден открываем ручку HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, gameProcess); if (hProcess == INVALID_HANDLE_VALUE) { // Если нашу ручку не удалось открыть printf("Handle Error"); } void* allocated = VirtualAllocEx(hProcess, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // Освобождаем память под нашу DLL if (!WriteProcessMemory(hProcess, allocated, DllPath, strlen(DllPath) + '', 0)) // Записываем нашу DLL и проверяем что если неудалось записать { CloseHandle(hProcess); return false; } void* hThread = CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)LoadLibraryA, allocated, 0, 0); // Создаем поток адресса которого мы освободили это наша DLL if (hThread != 0) // закрываем Handle CloseHandle(hThread); CloseHandle(hProcess); // Закрываем Handle Process printf("Inject Successfulled"); // Инжект произошел успешно return 0; // Возвращаем 0 }
ты забыл про
#include <stdio.h>
?)
-
#8
Как написать Инжектор с нуля на C++
В данной статье я вам расскажу и покажу как работает инжектор dll и как написать инжектор с нуля с методом LoadLibrary, я вам расскажу о каждом методе и последовательно как и что происходит, для новичков будет особенно полезная статья потому-что в интернете мало где можно найти написание инжектора с нуля на языке C++ давайте начнем
Что такое Инжектор? — это метод используемый для запуска кода в адресном пространстве другого процесса, заставляя его загружать библиотеку динамической компоновки
Соответственно для инжектора нам нужна динамическая библиотека которая будет выполнять код в адресном пространстве который мы освободим и создадим поток!Давайте начнем писать сам инжектор, а с динамической библиотекой вы уже сами разберетесь или можете найти на форуме
Для начало нам нужно подключить несколько инклудов
#include <Windows.h>
#include <TlHelp32.h>Нам нужна будет функция с помощью которой мы будем получать PID процесса, при открытий программ он генерируется всегда рандомно
Поэтому нам нужно получить его что бы на основе его открыть ручку процесса и предоставить нам полный доступ к процессу в User ModeC++:
DWORD GetProcessID(const char* processName) { if (!processName) return 0; DWORD id = 0; HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnap) { PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; if (Process32First(hSnap, &pe32)) { while (Process32Next(hSnap, &pe32)) { if (strcmp(processName, pe32.szExeFile) == 0) { id = pe32.th32ProcessID; break; } } } }CloseHandle(hSnap); return id; }
Теперь давайте в нашем main() найдем процесс нужной нам игры куда будем внедрять, откроем дескриптор процесса (получаем полный доступ) и освободим память и создадим наш поток адресного пространства
C++:
int main() { DWORD gameProcess = 0; // Создаем переменную под наш GetProcessID метод const char* DllPath = "anonymcheats.dll"; // Наша DLL которую инжектим, в данном случае он найдет рядом с инжектором (только) gameProcess = GetProcessID("csgo.exe"); if (!gameProcess) { // Если наш процесс не был найден printf("Process csgo was not found"); } // Если процесс найден открываем ручку HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, gameProcess); if (hProcess == INVALID_HANDLE_VALUE) { // Если нашу ручку не удалось открыть printf("Handle Error"); } void* allocated = VirtualAllocEx(hProcess, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // Освобождаем память под нашу DLL if (!WriteProcessMemory(hProcess, allocated, DllPath, strlen(DllPath) + '', 0)) // Записываем нашу DLL и проверяем что если неудалось записать { CloseHandle(hProcess); return false; } void* hThread = CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)LoadLibraryA, allocated, 0, 0); // Создаем поток адресса которого мы освободили это наша DLL if (hThread != 0) // закрываем Handle CloseHandle(hThread); CloseHandle(hProcess); // Закрываем Handle Process printf("Inject Successfulled"); // Инжект произошел успешно return 0; // Возвращаем 0 }
-
#9
C++:
URLDownloadToFile(0, L"ссылка на прямое скачивание", L"Путь, куда она скачается", 0, 0);
Спасибо
-
#12
Будет информация по поиску base для engine.dll и client.dll
И поиску паттернов, таких который hazedumper выкладывает?
-
#16
Когда нибудь может и пригодится, но я уверен, что очень годно)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
.486 ; create 32 bit code .model flat, stdcall ; 32 bit memory model option casemap :none ; case sensitive ;подключаем макросы и библиотеки include masm32includewindows.inc include masm32macrosmacros.asm include masm32macroswindows.asm uselib kernel32, user32, masm32 ;структурка, в которую мы запишем свой jump ;на код нашего перехватчика функции JUMPNEAR STRUCT opcd BYTE ? reladdr DWORD ? JUMPNEAR ENDS global_hook_cnt = 0 ;Макрос для вызова оригинальной функции ;с оригинальными параметрами из тела перехватчика ;(пример — далее) ;func — имя перехваченной функции ;args — число аргументов ;have_prologue — имеет ли функция пролог ;(то есть, есть ли в ее начале команды mov edi,edi, push ebp; mov ebp, esp) ;(не задавайте для функций с числом аргументов больше 0, они всегда имеют пролог) HOOK_ORIGINAL_CALL MACRO func:REQ, args:=< 0 >, have_prologue:=< 1 > cnt = 0 REPEAT args push [ebp+(&args — cnt + 1)*4] cnt = cnt + 1 ENDM push offset @CatStr(next_inst_, %global_hook_cnt) IF have_prologue EQ 1 push ebp mov ebp,esp ENDIF mov eax,@CatStr(&func, _hook) add eax,5 jmp eax @CatStr(next_inst_, %global_hook_cnt): global_hook_cnt = global_hook_cnt + 1 ENDM ;Макрос для вызова оригинальной функции ;с произвольными параметрами из любого места программы ;(если перехват установлен) ;(пример — далее) ;func — имя перехваченной функции ;have_prologue — имеет ли функция пролог ;(не задавайте для функций с числом аргументов больше 0, они всегда имеют пролог) ;params — список аргументов функции HOOK_ORIGINAL_CALL_PARAM MACRO func:REQ, have_prologue:=< 1 >, params:VARARG count = 0 FOR xparam, <params> count = count + 1 @CatStr(var,%count) TEXTEQU @CatStr(&xparam) ENDM REPEAT count push @CatStr(var,%count) count = count — 1 ENDM push offset @CatStr(next_inst_, %global_hook_cnt) IF have_prologue EQ 1 push ebp mov ebp,esp ENDIF mov eax,@CatStr(&func, _hook) add eax,5 jmp eax @CatStr(next_inst_, %global_hook_cnt): global_hook_cnt = global_hook_cnt + 1 ENDM ;Макрос для установки перехвата ;(пример — далее) ;lib — имя библиотеки, в которой содержится функция ;func — имя функции ;hook_label — название метки, по которой лежит наше тело перехватчика ;ifload — загрузить ли предварительно библиотеку (0 по умолчанию) ;have_prologue — имеет ли функция пролог ;(не задавайте для функций с числом аргументов больше 0, они всегда имеют пролог) SET_HOOK MACRO lib:REQ, func:REQ, hook_label:REQ, ifload:=< 0 >, have_prologue:=< 1 > %ECHO [The hook on &func is SET on @CatStr(%@Line) Line] .data? @CatStr(libn, %global_hook_cnt) dd ? IFNDEF &func&_hook_ @CatStr(&func, _hook) dd ? @CatStr(&func, _hook_) EQU <1> ENDIF IF have_prologue EQ 0 IFNDEF &func&_prologue_ @CatStr(&func, _prologue1) dw ? @CatStr(&func, _prologue2) db ? @CatStr(&func, _prologue3) dw ? @CatStr(&func, _prologue_) EQU <1> ENDIF ENDIF @CatStr(protect_, %global_hook_cnt) dd ? .code IF ifload EQ 1 mov @CatStr(libn, %global_hook_cnt), FUNC(LoadLibrary,chr$(«&lib»)) ELSE mov @CatStr(libn, %global_hook_cnt), FUNC(GetModuleHandle,chr$(«&lib»)) ENDIF mov @CatStr(&func, _hook), FUNC(GetProcAddress, @CatStr(libn, %global_hook_cnt), chr$(«&func»)) invoke VirtualProtect, @CatStr(&func, _hook), sizeof JUMPNEAR, PAGE_READWRITE, offset @CatStr(protect_, %global_hook_cnt) mov eax, @CatStr(&func, _hook) IF have_prologue EQ 0 mov cx, word ptr [eax] mov @CatStr(&func, _prologue1), cx mov cl, byte ptr [eax+2] mov @CatStr(&func, _prologue2), cl mov cx, word ptr [eax+3] mov @CatStr(&func, _prologue3), cx ENDIF assume eax: ptr JUMPNEAR mov [eax].opcd, 0e9h mov ecx, offset &hook_label sub ecx,@CatStr(&func, _hook) sub ecx,5 mov [eax].reladdr,ecx assume eax:nothing invoke VirtualProtect, @CatStr(&func, _hook), sizeof JUMPNEAR, @CatStr(protect_, %global_hook_cnt), offset @CatStr(protect_, %global_hook_cnt) global_hook_cnt = global_hook_cnt + 1 ENDM ;Макрос для снятия перехвата ;(пример — далее) ;func — имя функции ;have_prologue — имеет ли функция пролог ;(не задавайте для функций с числом аргументов больше 0, они всегда имеют пролог) REMOVE_HOOK MACRO func:REQ, have_prologue:=< 1 > %ECHO [The hook on &func is REMOVED on @CatStr(%@Line) Line] .data? @CatStr(protect_, %global_hook_cnt) dd ? .code invoke VirtualProtect, @CatStr(&func, _hook), sizeof JUMPNEAR, PAGE_READWRITE, offset @CatStr(protect_, %global_hook_cnt) mov eax, @CatStr(&func, _hook) IF have_prologue EQ 0 mov cx, @CatStr(&func, _prologue1) mov word ptr [eax], cx mov cl, @CatStr(&func, _prologue2) mov byte ptr [eax+2], cl mov cx, @CatStr(&func, _prologue3) mov word ptr [eax+3], cx ELSE mov word ptr [eax], 0ff8bh mov byte ptr [eax+2], 55h mov word ptr [eax+3], 0e589h ENDIF invoke VirtualProtect, @CatStr(&func, _hook), sizeof JUMPNEAR, @CatStr(protect_, %global_hook_cnt), offset @CatStr(protect_, %global_hook_cnt) global_hook_cnt = global_hook_cnt + 1 ENDM ;начало примера .code ;Тело нашего перехватчика для функции MessageBoxA MyFunc: push ebp mov ebp,esp ;сюда можно поместить любой код ;[ebp+8] будет содержать первый аргумент функции ;[ebp+12] — второй аргумент и т.д. ;[ebp+4] будет содержать адрес возврата из функции ;вызываем оригинальную функцию с переданными параметрами HOOK_ORIGINAL_CALL MessageBoxA, 4 ;это эквивалентно записи ;HOOK_ORIGINAL_CALL_PARAM MessageBoxA,1, [ebp+8], [ebp+12], [ebp+16], [ebp+20] ;а теперь подменим параметры (текст месадж бокса и иконку): HOOK_ORIGINAL_CALL_PARAM MessageBoxA,1, [ebp+8], chr$(«ахаха, перехват быдлозащиты!»), [ebp+16], MB_SYSTEMMODAL or MB_ICONERROR ;сюда тоже можно поместить любой код ;[ebp+8] будет содержать первый аргумент функции ;[ebp+12] — второй аргумент и т.д. ;[ebp+4] будет содержать адрес возврата из функции ;регистр eax будет содержать возвращенное функцией значение ;его можно заменить здесь pop ebp retn 4*4; (число аргументов функции MessageBoxA) * 4 ;Тело перехватчика GetTickCount (помните, не факт, что это заработает на вашей системе, как я уже говорил!) MyFunc2: push ebp mov ebp,esp ;сюда можно поместить любой код ;[ebp+4] будет содержать адрес возврата из функции ;вызываем оригинальную функцию HOOK_ORIGINAL_CALL GetTickCount, 0, 0 ;это эквивалентно записи ;HOOK_ORIGINAL_CALL_PARAM GetTickCount,0 ;сюда тоже можно поместить любой код ;[ebp+4] будет содержать адрес возврата из функции ;регистр eax будет содержать возвращенное функцией значение, его можно заменить здесь mov eax,1337 ;вот мы и подменили ответ функции pop ebp ret ;(0 аргументов у GetTickCount, поэтому просто ret) ;Точка входа в DLL LibMain proc instance:DWORD,reason:DWORD,reserved:DWORD LOCAL buf [20] :byte ;локальная переменная для хранения значения, возвращенного GetTickCount .if reason == DLL_PROCESS_ATTACH ;если наша DLL свежезагружена ;устанавливаем перехват MessageBoxA SET_HOOK user32.dll, MessageBoxA, MyFunc ;этот вызов будет перехвачен invoke MessageBox,0,chr$(«Hooked message box»),chr$(«Test»),MB_SYSTEMMODAL or MB_ICONINFORMATION ;этот вызов не будет перехвачен — он выполняется в обход тела перехватчика HOOK_ORIGINAL_CALL_PARAM MessageBoxA,1, 0,chr$(«Message box call without hook»),chr$(«Test»),MB_SYSTEMMODAL or MB_ICONINFORMATION ;снимаем перехват REMOVE_HOOK MessageBoxA ;этот вызов уже не перехватывается invoke MessageBox,0,chr$(«Original message box call»),chr$(«Test»),MB_SYSTEMMODAL or MB_ICONINFORMATION ;теперь установим перехват GetTickCount (эта функция не имеет пролога) SET_HOOK kernel32.dll, GetTickCount, MyFunc2, 0, 0 ;этот вызов перехвачен, и значение тут подменено — 1337 invoke GetTickCount ;преобразуем ответ функции в текстовый вид invoke wsprintf,addr buf,chr$(«%u»),eax ;выведем ответ, который вернула GetTickCount (он тут подменен) invoke MessageBox,0,addr buf,chr$(«Test»),MB_SYSTEMMODAL or MB_ICONINFORMATION ;убираем перехват REMOVE_HOOK GetTickCount, 0 ;этот вызов уже не перехвачен invoke GetTickCount ;преобразуем ответ функции в текстовый вид invoke wsprintf,addr buf,chr$(«%u»),eax ;выведем ответ, который вернула GetTickCount invoke MessageBox,0,addr buf,chr$(«Test»),MB_SYSTEMMODAL or MB_ICONINFORMATION mov eax,1 ;сообщаем об успешной загрузке нашей DLL .endif ret LibMain ENDP end LibMain |
// получаем хэндл процесса
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcId("gta_sa.exe"));
// Указываем путь до нашей dll
const char* DllPath = "C:\test.dll";
// получаем размер строки нашего пути
size_t SizePatch = strlen(DllPath) + 1;
// выделяем память в gta_sa с размером нашей строки
LPVOID pDllPath = VirtualAllocEx(hProcess, NULL, SizePatch, MEM_COMMIT, PAGE_READWRITE);
// записываем наш путь в выделенную память
WriteProcessMemory(hProcess, pDllPath, (LPVOID)DllPath, SizePatch, NULL);
HMODULE kernel = GetModuleHandleA("Kernel32.dll"); // Получаем адрес kernel32
DWORD Adr = (DWORD)GetProcAddress(kernel, "LoadLibraryA"); // получаем адрес функции LoadLibraryA
// Вызываем LoadLibraryA в gta_sa.exe с аргументом "C:\test.dll" и возвращаем адрес нашего потока
HANDLE hThread = CreateRemoteThread(hProcess, 0, 0,(LPTHREAD_START_ROUTINE)Adr, pDllPath, 0, 0);
// Ожидаем завершение нашего потока(ждем завершения DllMain с аргументом DLL_PROCESS_ATTACH)
WaitForSingleObject(hThread, INFINITE);
// Закрываем дескриптор потока
CloseHandle(hThread);
// Освобождаем выделенную память
VirtualFreeEx(hProcess, pDllPath, SizePatch, MEM_RELEASE);
// Закрываем дескриптор процесса
CloseHandle(hProcess);