Привет, ребята.
Представляю Вашему вниманию BritishLoader v2.0 - загрузчик DLL-библиотек, маскирующийся под стандартную библиотеку DirectX. Основной особенностью является универсальность: поддерживаются приложения, использующие технологию DirectX версий 7, 8 и 9.
Да-да, загрузчик будет работать не только в Perfect World.
Как этим можно воспользоваться? Можно делать любые плагины или читы для игр в виде DLL-библиотек.
Плюсы и удобства:
* поддерживается большинство современных (и не очень) игр;
* крайне полезно, если нужно поставить какие-то патчи, но клиент игры запакован; обычно так делают на пвп-серверах, чтобы защитить клиент;
* отдельная папка для хранения плагинов (во избежание замусоривания директории с игрой);
* все плагины будут внедрены в игру ещё до создания её окна;
* снимается защита с секций кода и данных, что позволяет патчить исполняемый код и константы приложения, не заботясь о VirtualProtect.
Недостатки ограничиваются одним пунктом:
* плагины вполне могут быть вредоносными (в том числе могут установить хук на клаву или поля для ввода логина и пароля), поэтому рекомендуется использовать лишь те плагины, к авторам которых у Вас есть доверие.
Более подробный ридми с описанием по установке и использованию - в архиве.
Идея и основная разработка - BritishColonist.
Спасибо соавторам, без которых было бы сложно реализовать всё именно в таком виде, как есть:
listener, Freeman.
[Ссылки могут видеть только зарегистрированные пользователи. ]
Сам загрузчик - во вложении к посту.
В комплекте с загрузчиком идут два плагина для Perfect World (для официального сервера; сегодня 01.01.2012, и всё прекрасно работает):
*TAGS_HACK - максимальная дальность прорисовки ников игроков и названий ресурсов/предметов (для включения и выключения этих опций нажимайте в игре F12 и F11 соответственно). Может помочь в сборе ресурсов или при пвп.
*MiscPatches - набор мелких, но полезных патчей:
1. Перерисовка неактивного окна игры (unfreeze).
2. Поддержка нескольких окон игры (мультиклиент).
3. Увеличенный лимит смайлов в чате (до 7-8 смайлов вместо стандартно допустимых 3).
4. Пропуск анимационной заставки перед окном логина (теперь после начальной загрузки не нужно будет вручную пропускать эту ерунду, а можно будет сразу зайти в аккаунт).
5. Изменение стандартных графических характеристик игры (дальность прорисовки, затуманенность): измените стандартную дальность прорисовки в настройках игры, чтобы увидеть результат; для более слабых компьютеров первые два положения ползунка, для более сильных - последние два. Может существенно сказаться на FPS.
Чтобы устанавливать плагины для Perfect World, загрузчик должен лежать рядом с "elementclient.exe" (в папке element).
Скриншот, демонстрирующий работу данных плагинов (можно заметить огромную дистанцию видимости и ник какого-то игрока. Названия ресурсов/предметов включать не стал, ибо валялось очень много всякого мусора):
[Ссылки могут видеть только зарегистрированные пользователи. ]
В данной теме можно как обсуждать загрузчик, так и делиться своими плагинами. Особенно интересные я буду размещать в этом сообщении. По всем вопросам можно также обращаться ко мне в ICQ: 5385047, исходный код не предоставляю (во всяком случае бесплатно ).
________________
Принимаю реквесты на статьи, программы. Всё будет запилено в лучшем виде :3
Последний раз редактировалось BritishColonist; 26.02.2012 в 16:40.
Дорогой товарищ, а теперь позвольте узнать, как писать плагины для вашего чуда? В мануале информация отсутствует полностью.... Какие функции, какой формат вызова и набор параметров... без этих данных данный плагин лишь демонстрирует что можно делать и все. так что от + / - пока воздержусь, не смотря на то что идея хороша.
О каких функциях речь?
Это не платформа типа PW Development Framework, нет.
Это реально просто загрузчик для DLL-библиотек. Поэтому создание плагинов лежит полностью на знаниях и фантазии кодера.
Я обычно оформляю плагины так (код типичной DLL-библиотеки):
//---------------------------------------------------------------------------
#include <windows.h>
//---------------------------------------------------------------------------
#define BA 0xB27A04
#define GA 0xB280C4
//---------------------------------------------------------------------------
#define HACKS_COUNT 2 // дефайны для удобства при возможных дальнейших обновах
#define HACK_NAME_TAGS 0
#define HACK_RESOURCE_NAMES 1
//---------------------------------------------------------------------------
bool KeyPressed(BYTE key) // проверка на нажатость клавиши
{
return ((GetAsyncKeyState(key)&(1<<16))!=0);
}
//---------------------------------------------------------------------------
bool IsGameWindowActive() // развёрнуто ли окно игры?
{
HWND hWnd = GetForegroundWindow();
if(!hWnd)
return false;
DWORD pId = 0;
GetWindowThreadProcessId(hWnd,&pId);
return (pId==GetCurrentProcessId());
}
bool IsClientVersionValid() // туда ли нас заинжектили?
{
return (*(DWORD*)(BA) +0x1C == GA);
}
//---------------------------------------------------------------------------
void Hack()
{
if(!IsClientVersionValid) {
MessageBox(NULL,"Sorry.\nInvalid Game Version..\nOnly 1.4.4 \"Genesis\" is supported","Players and Resources Tags FAIL",MB_OK);
return;
}
bool state[HACKS_COUNT] = {false, false};
DWORD ExeBase = (DWORD)GetModuleHandle(NULL);
while(1) // обработчик нажатий клавиш. также можно запилить хук на клаву, но будет больше геморроя
{
Sleep(50); // чтобы не грузить проц
if(IsGameWindowActive())
{
if(KeyPressed(VK_F11))
{
state[HACK_RESOURCE_NAMES]=!state[HACK_RESOURCE_NAMES]; // переключаем состояние чита
*(BYTE*)(ExeBase+0x24A9C2) = state[HACK_RESOURCE_NAMES] ? 0xEB : 0x74; // патчим
do{
Sleep(50); // ждём отпускания клавиши, чтобы состояние
}while(KeyPressed(VK_F11)); // чита не менялось при удерживании клавиши
}
if(KeyPressed(VK_F12)) // аналогично
{
state[HACK_NAME_TAGS]=!state[HACK_NAME_TAGS];
*(BYTE*)(ExeBase+0x25519E) = state[HACK_NAME_TAGS] ? 0x01 : 0x00;
do{
Sleep(50);
}while(KeyPressed(VK_F12));
}
}
}
}
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
if(reason==DLL_PROCESS_ATTACH)
{
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)Hack,NULL,NULL,NULL);
// создаём поток, в котором будет выполняться код;
// если же бесконечный цикл юзать здесь, то игра зависнет при запуске.
}
return 1;
}
//---------------------------------------------------------------------------
Собственно, это и есть демонстрация всех необходимых функций/техник при создании плагинов к любым играм.
Естественно, при написании подобных библиотек может использоваться любой язык программирования.
Поскольку в С/С++/С# не разбираюсь. то почти ничего не понял в приведенном коде....
т.е. как я понял, я пишу любую либу и что хочу то ворочу...
Для лучшего понимания нельзя ли рабочий пример на делфи ?
library delphi_dll;
uses
Windows;
//---------------------------------------------------------------------------
const
BA = $B27A04;
GA = $B280C4;
HACKS_COUNT = 2;
HACK_NAME_TAGS = 0;
HACK_RESOURCE_NAMES = 1;
//---------------------------------------------------------------------------
function KeyPressed(Key: Byte): Boolean;
begin
KeyPressed := (GetAsyncKeyState(Key) and (1 shl 16)<>0)
end;
//---------------------------------------------------------------------------
function IsGameWindowActive: Boolean;
var
Wnd: HWND;
pId: DWORD;
begin
IsGameWindowActive := False;
Wnd := GetForegroundWindow;
if(Wnd=0)then Exit;
GetWindowThreadProcessId(Wnd,pId);
IsGameWindowActive := (pId = GetCurrentProcessId)
end;
//---------------------------------------------------------------------------
function IsClientVersionValid: Boolean;
begin
Sleep(200); // !!!
IsClientVersionValid := ( PDWORD(BA)^ +$1C = GA)
end;
//---------------------------------------------------------------------------
procedure Hack;
var
state: array [0..HACKS_COUNT-1] of Boolean;
ExeBase: DWORD;
i: Integer;
begin
if(not IsClientVersionValid)then
begin
MessageBox(0,'Sorry.'#13#10'Invalid Game Version..'#13#10'Only 1.4.4 "Genesis" is supported','Players and Resources Tags FAIL',MB_OK);
Exit
end;
for i:=0 to HACKS_COUNT-1 do
state[i] := False;
ExeBase := DWORD(GetModuleHandle(nil));
repeat
Sleep(50);
if(IsGameWindowActive)then
begin
if(KeyPressed(VK_F11))then
begin
state[HACK_NAME_TAGS] := not state[HACK_NAME_TAGS];
if(state[HACK_NAME_TAGS])then
PBYTE(ExeBase+$24A9C2)^ := $EB
else
PBYTE(ExeBase+$24A9C2)^ := $74;
repeat
Sleep(50)
until not KeyPressed(VK_F11)
end;
if(KeyPressed(VK_F12))then
begin
state[HACK_RESOURCE_NAMES] := not state[HACK_RESOURCE_NAMES];
if(state[HACK_RESOURCE_NAMES])then
PBYTE(ExeBase+$25519E)^ := $01
else
PBYTE(ExeBase+$25519E)^ := $00;
repeat
Sleep(50)
until not KeyPressed(VK_F12)
end;
end
until false
end;
//---------------------------------------------------------------------------
procedure DLLMain(Reason: DWORD);
var
UselessShit: DWORD;
begin
if(Reason=DLL_PROCESS_ATTACH)then
begin
CreateThread(nil,0,@Hack,nil,0,UselessShit)
end
end;
//---------------------------------------------------------------------------
begin
DLLProc := @DLLMain;
DLLProc(DLL_PROCESS_ATTACH)
end.
//---------------------------------------------------------------------------
Различия в реализации я постарался свести на минимум. Но их получилось как минимум два:
* DLLMain в Delphi нужно указывать самому (в C++ функция DLLMain создаётся по умолчанию. хотя вроде можно обойтись без имитации DLLMain, я просто в Delphi впервые делал библиотеку и вычитал такое из гугла);
* в функцию IsClientVersionValid пришлось добавить Sleep на 200 мс, т.к. функция всегда возвращала False (возможно, причина в том, что дельфийская DLL шустрее внедряется в память клиента и читает адрес BA, в котором на тот момент лежат некорректные данные).
Последний раз редактировалось BritishColonist; 12.02.2012 в 18:55.
В отдельное окно - слишком много WinAPI-шного кода, я юзаю следующий вариант.
Запись в файл. Банально и просто. Плюсы - можно мутить крутые логи работы программы, возвращать результат, который действительно полезно хранить, а не просматривать (например, структуры в двоичном виде для дальнейшего исследования в шестнадцатеричных редакторах).
Если нужно просто что-то быстро проверить, то подойдёт первый способ. Если хочется управлять работой библиотеки, то могу предложить такой вариант:
Существует конфиг, который определяет поведение программы (ini-файл). DLL либо по нажатию клавиши, либо просто через определённые интервалы времени грузит из этого файла настройки. INI-файл редактируешь через программу-конфигуратор. Вот такая хитрая получится связь.
Есть более хардкорный способ, который я пока не пробовал. Нагуглить можно по фразам "File Mapping" и "WM_COPYDATA". Так можно будет обмениваться данными напрямую, но, опять же, грамотно всё реализовать, насколько я понял, довольно сложно.