PDA

Просмотр полной версии : Перехват из Engine.dll


goodvin1709
19.09.2013, 01:40
Вот уже много времени мучаюсь над тем что пытаюсь написать что то подобие перехватчика,уже и пробовал перейти на С++ но в основном сижу на делфи.
Вот проблема состоит в том что бы каким то образом перехватить любую вызывающуюся функцию из Engine.dll.
Я получил их названия под свой клиент:
Расшифрована:
int UGameEngine::OnDie(struct User *,class L2ParamStack &)
Зашифрована:
?OnDie@UGameEngine@@UAEHPAUUser@@AAVL2ParamStack@@ @Z
Но как прехватить, я вобще не понимаю, посмотрел кучу исходником.
Может найдется тот человек который разжует все, и покажет исходник как именно это осуществить.
P.S Да в принципе пофиг какая функция и какая библиотека,хоть Core.dll хоть Engine.dll
Помогите добрые люди пожалуйста.

Yegor
19.09.2013, 10:06
Под Delphi есть готовая библиотека advApiHook.pas вроде есть в исходниках пакетхака.

Там есть функция

function HookProc(lpModuleName, lpProcName: PChar; NewProc: pointer; var OldProc: pointer): boolean;



var
OnDieOriginal: function (lpLibFileName: PAnsiChar): integer;


function NewFunc: integer;
begin

//код



Result:= OnDieOriginal;//вызов оригинальной функции
end;



HookProc('Engine.dll', 'OnDie', @NewFunc, @OnDieOriginal);

Но в таком виде прокатит только если перехватываемая функция идет без параметров, так как в Delphi в функции параметры передаются как stdCall, а в клиенте l2 fastcall. Нужно лепить специальный переходник. Xсor где то выкладывал на форуме.

goodvin1709
19.09.2013, 14:36
Да это уже сам перехват,а до этого что вобще нужно сделатЬ?
Каким фигом оно будет HookProc('Engine.dll', ... искать именно эту библиотеку? lpProcName: PChar; это параметр закодированого или открытого
названия функции?*
?OnDie@UGameEngine@@UAEHPAUUser@@AAVL2ParamStack@@ @Z
Вот этот параметр?

Добавлено через 7 минут
Можешь дать свой скайп что бы чуть чуть обьяснить?

Добавлено через 7 минут
Нашел сам файл advApiHook.pas
http://l2ph.coderx.ru/svn/l2phx3/3.6.x/units/advApiHook.pas
он вот тут.
Когда именно делать этот хук?

Добавлено через 24 минуты
OnDieOriginal: function (lpLibFileName: PAnsiChar): integer; Откуда ее взять?

Добавлено через 2 минуты

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,advApiHook, StdCtrls;

type
TForm1 = class(TForm)
btn1: TButton;
lbl1: TLabel;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
OnDieOriginal: function (lpLibFileName: PAnsiChar): integer;
implementation

{$R *.dfm}
function NewFunc: integer;
begin
form1.lbl1.Caption:='Перехвачена была вызвана функция.';
end;

procedure TForm1.btn1Click(Sender: TObject);
begin
HookProc('Engine.dll', '?Say2@UNetworkHandler@@UAEXAAVL2ParamStack@@@Z', @NewFunc, @OnDieOriginal);
end;

end.

Будет ли работать так?

Yegor
20.09.2013, 01:39
Да, все правильно надо передавать закодированное название функции.

Перед тем как хукать нужно подгрузить в процесс l2 свою dll, а уже в ней осуществлять перехват.
В advApiHook есть функции внедрения своей dll в чужой процесс.

goodvin1709
20.09.2013, 18:23
А так это не юнит,а library писать нужно?

St1mul
20.09.2013, 21:26
Самое главное если стоит LameGuard подгружать dll нужно вручную, не добавляй ее в список автоматом загружаемых dll или у тебя дальше выбора сервера не дойдет.
Если поищешь на этом форуме есть исходники l2cc вот их могу объяснить, но там не используется хукпроцедура, там другой метод.

goodvin1709
21.09.2013, 02:46
Хотел бы с тобой пообщаться,может даш скайп или как с тобой связаться для быстрой переписки,видел l2cc

Добавлено через 4 часа 35 минут
Поковырялся,и подумал посидел, в итоге у меня что то получилось.
Взял тотал командер, через F3 вытянул названия из Engine.dll, т.е названия функций.Так как у меня Interlude клиент был под рукой,взял самую мне необходимую.
?RequestBypassToServer@UNetworkHandler@@UAEHAAVL2P aramStack@@@Z
И начал ковырять.
Написал код библиотеки:

library Project2;

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,advApiHook, StdCtrls;

{$R *.res}
var
RequestBypassToServer_Old: function (lpLibFileName: PAnsiChar): integer;

function RequestBypassToServer_New: Integer;
begin
MessageDlg('Функция RequesBypassToServer была вызвана.',mtError, [mbOk],0);
//result:=RequestBypassToServer_Old('Engine.dll');
end;

begin
HookProc('Engine.dll','?RequestBypassToServer@UNet workHandler@@UAEHAAVL2ParamStack@@@Z', @RequestBypassToServer_New, @RequestBypassToServer_Old);
end.


Взял WinInject 1.7b и прииньектил к L2.exe мою скомпилированую dll.
Все заработало.
Подхожу к NPC и нажимаю любой диалог, сразу ще выскакивает сообщение "Функция RequesBypassToServer была вызвана."
Вроде все не так уж и плохо.Но в игре действия не происходит,так как не возвращается результат.
Дальше я изменил функцию свою на :
function RequestBypassToServer_New: Integer;
begin
MessageDlg('Функция RequesBypassToServer была вызвана.',mtError, [mbOk],0);
result:=RequestBypassToServer_Old('Engine.dll');
end;
И сразу же выскакивает критом,я понял что результат не возвращается.
Теперь у меня задача,получать параметры от функций а так же их грамотно отправлять.
Помогите с этим.

Yegor
21.09.2013, 03:07
Вот тут Xcor привел пример как сделать переходник для перехвата из Delphi

http://coderx.ru/showpost.php?p=50250&postcount=36

goodvin1709
21.09.2013, 03:23
Можешь сделать пример полегче,что то у меня нечего не получилось, я не понял с переходами,и откуда взять этот чертов параметр.
или даже пример как с моим перехватом Bypass,
еще очень запутался че к чему,если поподробней обьяснить.

Yegor
21.09.2013, 12:36
Мне самому надо в это вникать. Вникну напишу :)

goodvin1709
24.09.2013, 09:56
Вот тут снизу мой быдлокод.


library hook;

uses
Windows, //Для GetProcAddress
Variants, //Для перевода VarToStr(Когда выводим MessageDlg)
Dialogs, //Ну собствено для MessageDlg
advApiHook, //Для HookProc
SysUtils; //Для IntToStr и обратно.

type
TL2ParamStack = array[0..16] of byte; //Тип L2ParamStack это массив из 16 байт.
PL2ParamStack = ^TL2ParamStack;

TL2Param = class //Делаем с Tl2param сразу классом.Для простого управления.
l2p: PL2ParamStack; //Парамет имеет тип с 16 байт.
public
constructor Create; //Конструктор.
destructor Destroy; //Деструктор.
procedure l2PushBack(cmd: string); // L2patamStack [00 00 00 00 00 00 00 00 xx xx xx xx xx xx xx xx] в xx- помещаем String Значение.
procedure l2PushBackInt(i: integer); // L2patamStack [00 00 00 00 00 00 00 00 00 00 00 00 xx xx xx xx] в xx- помещаем Int Значение.
procedure l2Clear; //Очищаем тип.
procedure l2Free; //Освобождаем.
end;

var
//Указатель на UNetworkHandler]
NH:Pointer;
//-------------------Указатели на оригинальные процедуры------------------//
L2ParamStackCreate_Original: procedure(i: integer); stdcall; //Создать стек.
L2ParamStackClear_Original: procedure; stdcall; //Очистить стек.
L2ParamStackPushBack_Original: function(i: pointer): integer; stdcall; //Вставляем значение в стек.
L2ParamStackTop_Original: Procedure (i:Pointer); stdcall; //Достает значение с вершины стека.
L2ParamStackFree_Original: procedure; stdcall; //Очистить стек.
Init_UNetworkHandler_Original:Procedure(I:Integer; UGameEngine:Pointer);stdcall;
//----------------------Тут наши процедуры которые хукаем.------------------------//
UseItem_Original: Procedure (l2p:Pl2ParamStack); stdcall;
//--------------------------------------------------------------------------------//
procedure l2stackCreate(l2p: PL2ParamStack); stdcall; //Создали стек.
asm
push ecx;
mov ecx,l2p;
push 0Ah;
call [L2ParamStackCreate_Original];
pop ecx;
end;

procedure L2StackPushBack(l2p: PL2ParamStack; cmd: string); stdcall;//Заполняем стек(последнее значение) строкой.
asm
mov ecx,cmd;
push ecx;
mov ecx,l2p;
call [L2ParamStackPushBack_Original];
end;

procedure L2StackPushBackInt(l2p: PL2ParamStack; cmd: Integer); stdcall; //Заполняем стек(последнее значение) Int числом (8 байт).
asm
mov ecx,cmd;
push ecx;
mov ecx,l2p;
call [L2ParamStackPushBack_Original];
end;

procedure L2StackClear(l2p: PL2ParamStack); stdcall; //Очищаем стек.
asm
mov ecx,l2p;
call [L2ParamStackClear_Original];
end;

procedure L2StackFree(l2p: PL2ParamStack); stdcall; //Убиваем стек.
asm
mov ecx,l2p;
call [L2ParamStackFree_Original];
end;

constructor TL2Param.create;//Создание L2ParamStack.
begin
New(l2p);//Создали новый динамический класс L2ParamStack.
L2StackCreate(l2p);
end;

destructor TL2Param.Destroy;//Разрушение L2ParamStack.
begin
Dispose(l2p);
end;

procedure TL2Param.l2Clear;//Очищение L2ParamStack.
begin
L2StackClear(l2p);
end;

procedure TL2Param.l2Free;//Освобождение L2ParamStack.
begin
L2StackFree(l2p);
end;

procedure TL2Param.l2PushBack(cmd: string);//Наш переходник вставки cтроки в L2ParamStack
begin
L2StackPushBack(l2p,cmd);
end;

procedure TL2Param.l2PushBackInt(i: integer);//Наш переходник вставки числа в L2ParamStack
begin
L2StackPushBackInt(l2p,i);
end;

procedure UseItem_Call(l2p: PL2ParamStack); stdcall;
asm
push l2p;
mov ecx, NH;// nh - указатель на UNetworkHandler
call [UseItem_Original];
end;
Procedure UseItem(Oid:Integer); //Тут уже формируем ParamStack
var
param: TL2Param;
begin
param:= TL2Param.Create; //Создали Класс.
param.l2Clear; //Очистили Класс.
param.l2PushBackInt(Oid); //В конец Стака вставили значение.
UseItem_call(param.l2p); //Вызвали процедуру уже с переходом на оригинальну.
param.l2Free; //Освободили Класс.
param.Destroy; //Разрушили класс,так как он у нас динамический.
end;

Procedure UseItem_Hook(l2p:PL2ParamStack); //Хукнутая процедура(тут получить параметры и извлекать)
var
ObjOid:Integer;
begin
asm
mov esi,[L2p] //Премещаю в esi L2ParamStack
mov ecx,esi //В ecx премещаю L2ParamStack
Call [L2ParamStackTop_Original] //Посылаю в оригинальную функцию L2ParamStackTop_Original параметр ecx т.е наш L2ParamStack
mov [ObjOid],eax //Получаю резултат от функции в eax и записываю его в ObjOid
end;
MessageDlg('Функция UseItem Была перехвачена.OidПредмета:'+IntToStr(ObjOid),mtInfor mation, [mbOk],0);
//UseItem(Oid);//Вызываем нормальную процедуру.
end;
Procedure Init_UNetworkHandler_Hook(I:Integer;UGameEngine:Po inter);
begin
asm
mov esi,[UGameEngine];
mov [NH],esi;
//call Init_UNetworkHandler_Original;
end;
MessageDlg('UNetworkHandler:'+VarToStr(DWORD(NH)), mtInformation, [mbOk],0);
if UnhookCode(@Init_UNetworkHandler_Original) then MessageDlg('Хук на UNetworkHandler успешно снят.',mtInformation, [mbOk],0)
else
MessageDlg('Не смогли снять хук на UNetworkHandler',mtInformation, [mbOk],0);
end;
begin
//Сначала деаем хук на стаковские процедуры.//
//Interlude ??0L2ParamStack@@QAE@AAV0@@Z
L2ParamStackCreate_Original:= GetProcAddress(GetModuleHandle('Core.dll'),'??0L2P aramStack@@QAE@AAV0@@Z');
//Interlude ?Clear@L2ParamStack@@QAEXXZ
L2ParamStackClear_Original:= GetProcAddress(GetModuleHandle('Core.dll'),'?Clear @L2ParamStack@@QAEXXZ');
//Interlude ?PushBack@L2ParamStack@@QAEHPAX@Z
L2ParamStackPushBack_Original:= GetProcAddress(GetModuleHandle('Core.dll'),'?PushB ack@L2ParamStack@@QAEHPAX@Z');
//Interlude ??1L2ParamStack@@QAE@XZ
L2ParamStackFree_Original:= GetProcAddress(GetModuleHandle('Core.dll'),'??1L2P aramStack@@QAE@XZ');
//Interlude ??1L2ParamStack@@QAE@XZ
L2ParamStackTop_Original:=GetProcAddress(GetModule Handle('Core.dll'),'?Top@L2ParamStack@@QAEPAXXZ');
//Ставим хук на Init_UNetworkHandler.
HookProc('Engine.dll','?Init@UNetworkHandler@@UAEX HPAVUGameEngine@@@Z', @Init_UNetworkHandler_Hook, @Init_UNetworkHandler_Original);
//Ставим хуки на свои процедуры.
HookProc('Engine.dll','?RequestUseItem@UNetworkHan dler@@UAEHAAVL2ParamStack@@@Z', @UseItem_Hook, @UseItem_Original);
end.


Procedure Init_UNetworkHandler_Hook(I:Integer;UGameEngine:Po inter);
begin
asm
mov esi,[UGameEngine];
mov [NH],esi;
//call Init_UNetworkHandler_Original;
end;
MessageDlg('UNetworkHandler:'+VarToStr(DWORD(NH)), mtInformation, [mbOk],0);
if UnhookCode(@Init_UNetworkHandler_Original) then MessageDlg('Хук на UNetworkHandler успешно снят.',mtInformation, [mbOk],0)
else
MessageDlg('Не смогли снять хук на UNetworkHandler',mtInformation, [mbOk],0);
end;

Как сделать возврат в оригинальную?
Получать то получаю UnetworkHandler а вот назад его запихнуть не могу(
Или как получить этот указатель другим путем.:?

Добавлено через 3 часа 4 минуты
Сылка на библиотеку для хука и иньектора. (http://rghost.ru/48932514)

Добавлено через 11 часов 37 минут
UP

goodvin1709
24.09.2013, 10:19
library hook;

uses
Windows, //Для GetProcAddress
Variants, //Для перевода VarToStr(Когда выводим MessageDlg)
Dialogs, //Ну собствено для MessageDlg
advApiHook, //Для HookProc
SysUtils; //Для IntToStr и обратно.

type
TL2ParamStack = array[0..16] of byte; //Тип L2ParamStack это массив из 16 байт.
PL2ParamStack = ^TL2ParamStack;

TL2Param = class //Делаем с Tl2param сразу классом.Для простого управления.
l2p: PL2ParamStack; //Парамет имеет тип с 16 байт.
public
constructor Create; //Конструктор.
destructor Destroy; //Деструктор.
procedure l2PushBack(cmd: string); // L2patamStack [00 00 00 00 00 00 00 00 xx xx xx xx xx xx xx xx] в xx- помещаем String Значение.
procedure l2PushBackInt(i: integer); // L2patamStack [00 00 00 00 00 00 00 00 00 00 00 00 xx xx xx xx] в xx- помещаем Int Значение.
procedure l2Clear; //Очищаем тип.
procedure l2Free; //Освобождаем.
end;

var
//Указатель на UNetworkHandler
UNetworkHundler:Pointer;
//-------------------Указатели на оригинальные процедуры------------------//
L2ParamStackCreate_Original: procedure(i: integer); stdcall; //Создать стек.
L2ParamStackClear_Original: procedure; stdcall; //Очистить стек.
L2ParamStackPushBack_Original: function(i: pointer): integer; stdcall; //Вставляем значение в стек.
L2ParamStackTop_Original: Procedure (i:Pointer); stdcall; //Достает значение с вершины стека.
L2ParamStackFree_Original: procedure; stdcall; //Очистить стек.
Init_UNetworkHandler_Original:Procedure(I:Integer; UGameEngine:Pointer);stdcall;
//----------------------Тут наши процедуры которые хукаем.------------------------//
UseItem_Original: Procedure (l2p:Pl2ParamStack); stdcall;
//--------------------------------------------------------------------------------//
Function L2ParamStackToString(l2p:Pl2ParamStack):String;
var
i:Integer;
S:String;
begin
S:='';
for i:=1 to 16 do
begin
if (l2p[i] in [0..9]) then S:=S+'0'+IntToStr(l2p[i])+' '
else
S:=S+IntToStr(l2p[i])+' ';
end;
result:=S;
end;

procedure l2stackCreate(l2p: PL2ParamStack); stdcall; //Создали стек.
asm
push ecx;
mov ecx,l2p;
push 0Ah;
call [L2ParamStackCreate_Original];
pop ecx;
end;

procedure L2StackPushBack(l2p: PL2ParamStack; cmd: string); stdcall;//Заполняем стек(последнее значение) строкой.
asm
mov ecx,cmd;
push ecx;
mov ecx,l2p;
call [L2ParamStackPushBack_Original];
end;

procedure L2StackPushBackInt(l2p: PL2ParamStack; cmd: Integer); stdcall; //Заполняем стек(последнее значение) Int числом (8 байт).
asm
mov ecx,cmd;
push ecx;
mov ecx,l2p;
call [L2ParamStackPushBack_Original];
end;

procedure L2StackClear(l2p: PL2ParamStack); stdcall; //Очищаем стек.
asm
mov ecx,l2p;
call [L2ParamStackClear_Original];
end;

procedure L2StackFree(l2p: PL2ParamStack); stdcall; //Убиваем стек.
asm
mov ecx,l2p;
call [L2ParamStackFree_Original];
end;

constructor TL2Param.create;//Создание L2ParamStack.
begin
New(l2p);//Создали новый динамический класс L2ParamStack.
L2StackCreate(l2p);
end;

destructor TL2Param.Destroy;//Разрушение L2ParamStack.
begin
Dispose(l2p);
end;

procedure TL2Param.l2Clear;//Очищение L2ParamStack.
begin
L2StackClear(l2p);
end;

procedure TL2Param.l2Free;//Освобождение L2ParamStack.
begin
L2StackFree(l2p);
end;

procedure TL2Param.l2PushBack(cmd: string);//Наш переходник вставки cтроки в L2ParamStack
begin
L2StackPushBack(l2p,cmd);
end;

procedure TL2Param.l2PushBackInt(i: integer);//Наш переходник вставки числа в L2ParamStack
begin
L2StackPushBackInt(l2p,i);
end;

procedure UseItem_Call(l2p: PL2ParamStack); stdcall;
asm
push l2p;
mov ecx, UNetworkHundler;// nh - указатель на UNetworkHandler
call [UseItem_Original];
end;
Procedure UseItem(Oid:Integer); //Тут уже формируем ParamStack
var
param: TL2Param;
begin
param:= TL2Param.Create; //Создали Класс.
param.l2Clear; //Очистили Класс.
param.l2PushBackInt(Oid); //В конец Стака вставили значение.
UseItem_call(param.l2p); //Вызвали процедуру уже с переходом на оригинальну.
param.l2Free; //Освободили Класс.
param.Destroy; //Разрушили класс,так как он у нас динамический.
end;

Procedure UseItem_Hook(l2p:PL2ParamStack); //Хукнутая процедура(тут получить параметры и извлекать)
var
ObjOid:Integer;
begin
asm
mov esi,[L2p]; //Премещаю в esi L2ParamStack
mov [UNetworkHundler],esi;
mov ecx,esi; //В ecx премещаю L2ParamStack
Call [L2ParamStackTop_Original]; //Посылаю в оригинальную функцию L2ParamStackTop_Original параметр ecx т.е наш L2ParamStack
mov [ObjOid],eax; //Получаю резултат от функции в eax и записываю его в ObjOid
end;
MessageDlg('Функция UseItem Была перехвачена.OidПредмета:'+IntToStr(ObjOid)+' L2ParamStack:'+L2ParamStackToString(l2p),mtInforma tion, [mbOk],0);
//UseItem(ObjOid);//Вызываем нормальную процедуру.
end;
{Procedure Init_UNetworkHandler_Hook(I:Integer;UGameEngine:Po inter);
begin
asm
mov esi,[UGameEngine];
mov [NH],esi;
call Init_UNetworkHandler_Original;
end;
MessageDlg('UNetworkHandler:'+VarToStr(DWORD(NH)), mtInformation, [mbOk],0);
if UnhookCode(@Init_UNetworkHandler_Original) then MessageDlg('Хук на UNetworkHandler успешно снят.',mtInformation, [mbOk],0)
else
MessageDlg('Не смогли снять хук на UNetworkHandler',mtInformation, [mbOk],0);
end; }
begin
//Сначала деаем хук на стаковские процедуры.//
//Interlude ??0L2ParamStack@@QAE@AAV0@@Z
L2ParamStackCreate_Original:= GetProcAddress(GetModuleHandle('Core.dll'),'??0L2P aramStack@@QAE@AAV0@@Z');
//Interlude ?Clear@L2ParamStack@@QAEXXZ
L2ParamStackClear_Original:= GetProcAddress(GetModuleHandle('Core.dll'),'?Clear @L2ParamStack@@QAEXXZ');
//Interlude ?PushBack@L2ParamStack@@QAEHPAX@Z
L2ParamStackPushBack_Original:= GetProcAddress(GetModuleHandle('Core.dll'),'?PushB ack@L2ParamStack@@QAEHPAX@Z');
//Interlude ??1L2ParamStack@@QAE@XZ
L2ParamStackFree_Original:= GetProcAddress(GetModuleHandle('Core.dll'),'??1L2P aramStack@@QAE@XZ');
//Interlude ??1L2ParamStack@@QAE@XZ
L2ParamStackTop_Original:=GetProcAddress(GetModule Handle('Core.dll'),'?Top@L2ParamStack@@QAEPAXXZ');
//Ставим хук на Init_UNetworkHandler.
//HookProc('Engine.dll','?Init@UNetworkHandler@@UAEX HPAVUGameEngine@@@Z', @Init_UNetworkHandler_Hook, @Init_UNetworkHandler_Original);
//Ставим хуки на свои процедуры.
HookProc('Engine.dll','?RequestUseItem@UNetworkHan dler@@UAEHAAVL2ParamStack@@@Z', @UseItem_Hook, @UseItem_Original);
end.

Что я не так делаю?
P.S Добавил функцию для отображения уже L2ParamStack.
Вот еще пока без возвратки так как еще не отловил UNetworkHandler.
Ух этот клиет,а я думаю что же будет дальше то Там же нужно будет нарыть структуру User))) и все такое
Может кто то делал это все с функциями полегче? например что то в чат ебануть?
а то да действительно гемора немного есть с L2ParamStack.)
Я прикреплю ниже свою библиотеку,протестите и скажите какие результаты пожалуйста.
http://rghost.ru/48942586Вот сама библиотека хука.
http://rghost.ru/48942628Вот иньектор.
ОШИБКА ТУТ
procedure L2StackPushBackInt(l2p: PL2ParamStack; cmd: Integer); stdcall; //Заполняем стек(последнее значение) Int числом (8 байт).
asm
mov ecx,cmd;
push ecx;
mov ecx,l2p;
call [L2ParamStackPushBack_Original];
end;
Как ее блин исправить то?

goodvin1709
26.09.2013, 10:11
UP

Добавлено через 11 часов 7 минут
UP

goodvin1709
27.09.2013, 10:29
UP

SeregaZ
27.09.2013, 13:02
во! попробуй на cracklab.ru на форуме тему создать. там думаю подскажут :) правда регистрация галимая...

Elecktron
29.09.2013, 02:01
а какой тайный смысл перехватывать L2ParamStack?

goodvin1709
29.09.2013, 03:34
В каком это смысле?В параметре приходит L2ParamStack
Я от туда извлекаю то что мне нужно т.е данные.
потом создаю чистый L2ParamStack
Засовываю туда данные,и отправляю на сервер вызовом оригинальной функции.
Вот только данные вставить нормально не могу(
1.Создаю
procedure l2stackCreate(l2p: PL2ParamStack); stdcall;
asm
mov ecx,l2p;
push ecx;
push 0Ah;
call [L2ParamStackCreate_Original];
end;

Вот тут создали стек.Все работает хорошо.
Потом очищаю стек.

procedure L2StackClear(l2p: PL2ParamStack); stdcall;
asm
mov ecx,l2p;
call [L2ParamStackClear_Original];
end;

Тут все хорошо работает,вроде очистили.
Потом я в него вставляю что мне нужно:
procedure L2StackPushBackInt(l2p: PL2ParamStack; cmd: Integer); stdcall;
asm
mov ecx,cmd;
push ecx;
mov ecx,l2p;
call [L2ParamStackPushBack_Original];
end;
Правда тут почему то ошибка,но по плану следующий шаг отправка.
procedure UseItem_Call(l2p: PL2ParamStack); stdcall;
begin
asm
push l2p;
mov ecx, UNetworkHundler;
call [UseItem_Original];
end;
Но блин откуда взять
1.UnetworkHandler,нужен он вобще или нет?
2.Как правильно запихнуть данные и отправить?

goodvin1709
02.10.2013, 03:56
UP

Yegor
02.10.2013, 10:31
goodvin1709, я тебе дал аську, авторизовал твой контакт. Почему не пишешь? Тут как то скомкано ты нагородил всего нужно разбираться постепенно.

SeregaZ
02.10.2013, 12:33
кстати! а гугл хром таким же макаром можно будет ковырнуть? мне при вызове одной функции надо один параметр подменить.

Yegor
02.10.2013, 23:13
SeregaZ, я вообще на calc.exe эксперементировал :)

SeregaZ
03.10.2013, 13:22
а как это выглядит? небольшой патчик, типа применил к ехе целевой программы и она всегда после этого работает как надо, или эта программа висит все время в запущенном состоянии и как только целевой процесс полез за нужной функцией - делает свое черное дело.
(я к тому, что версий хрома миллион и выходят каждый раз новые - как можно предусмотреть кросплатформенность, или точнее кроссверсионность :))

Elecktron
03.10.2013, 16:06
В каком это смысле?В параметре приходит L2ParamStack
Я от туда извлекаю то что мне нужно т.е данные.
потом создаю чистый L2ParamStack
Засовываю туда данные,и отправляю на сервер вызовом оригинальной функции.
Вот только данные вставить нормально не могу(
...
Но блин откуда взять
1.UnetworkHandler,нужен он вобще или нет?
2.Как правильно запихнуть данные и отправить?

зачем пользоваться глючным стеком? оО
можно проще. например(с++):
void __cdecl ReqvMagicSkillUse(int Skill,int Ctrl,int Shift)
{
char *mask = "cddc";
asm
{
mov ECX,[UNetHandler] //UnetworkHandler
mov EDI,ECX
mov ECX,DWORD PTR DS:[EDI+0x48]
mov EDX,DWORD PTR DS:[ECX]
push Shift
push Ctrl
push Skill
push 0x39
push mask
push ECX
CALL [EDX+0x6c]
add esp,0x18
}
}

CALL [EDX+0x6c] - по сути вызов сенда в engine.dll - и его можно заменить на хардкод.

UnetworkHandler - нужен!
получить его несложно.
void __cdecl UNetworkHandlerInit_hook()
{
asm
{
mov dword [UNetHandler],ecx //он лежит в ecx, копируем
MOV EAX,DWORD PTR FS:[0] //
jmp DWORD PTR initUH_orig
}
}
HMODULE hEngine = LoadLibraryA("Engine.dll");
(FARPROC&) initUH_addr = GetProcAddress(hEngine, "?Init@UNetworkHandler@@UAEXHPAVUGameEngine@@@Z");

initUH_orig = initUH_addr + 6;
DWORD buf = (DWORD)&UNetworkHandlerInit_hook + 3;

DWORD op;
short comm =0xe9;
VirtualProtect((void*)(initUH_addr),5,PAGE_READWRI TE, &op);
DWORD offset = (DWORD) buf - (DWORD) initUH_addr - 5;
WriteProcessMemory(GetCurrentProcess(), (void*)(initUH_addr),(void*)&comm,1,NULL);
WriteProcessMemory(GetCurrentProcess(), (void*)(initUH_addr+0x01),(void*)&offset,4,NULL);
VirtualProtect((void*)(initUH_addr),5,op, &op);

перехват инита, для получения NetworkHandler - чистая магия, местами подогнанная по месту, так что приведена исключительно для осознания что и куда.

p.s.как-то пробовал сделать на делфи - могу поискать исходники, но они "портированы" с с++, так что по сути тоже самое
p.p.s. есть еще способ (если защита смотрит откуда сенд вызван)

Elecktron
10.10.2013, 00:44
как успехи?

SeregaZ
10.10.2013, 02:33
лично у меня совсем маленький сдвиг есть :) насчет goodvin1709 не знаю :)

мне дали код, где в целевой процесс вшиваться моя дополнительная длл, и уже из нее происходит перехват целевой функции. и я испытывал на своем проекте, где использовалась та моя функция и я точно знаю что она там есть - однако процесс хука работает через раз (сразу вспомнились запуски пиратской 1С бухгалтерии почему-то :)), то нормально запустит и перехват я вижу, то сразу при запуске целевая вылетает с критом. чем в теории может быть вызвано такое нестабильное "хучение" процесса?

хром же и вовсе отказался хукаться... хотя может и не отказался, а просто не использует ту мою предполагаемую функцию, из-за которой сыр бор... нужен продвинутый апи монитор, который бы показывал крипто апи тоже! где взять такое? чтобы выяснить на 100% каким образом хром получает список названий сертификатов.

Elecktron
10.10.2013, 15:08
а я никак не могу победить обработку данных при вызове сенда
с отправкой своего и обработкой приходящего - все ок..

centos
11.10.2013, 17:59
Частично оффтоп, частично по теме:

Задача: защитить клиентские файлы от декрипта стандартными для lineage средствами. Сделать невозможным использовать клиент lineage с серверами, Ip которых отличен от нашего.
Файлы формата: *ukx *.dat

Оплата - договоримся!

ICQ:261-900303 (Михаил)

SeregaZ
11.10.2013, 18:39
centos, а если ты переедишь на другой хостинг и соответственно айпи поменятся - чо делать? :)

centos
11.10.2013, 19:11
centos, а если ты переедишь на другой хостинг и соответственно айпи поменятся - чо делать? :)

В ТЗ, такие моменты описаны в тз.

goodvin1709
12.10.2013, 01:44
перехват удачно идет а вот вызов оригинальной неа(

SeregaZ
12.10.2013, 05:32
Procedure NewMessageBeep(Type.l)
MessageRequester("APIHOOK", "Beep!")
!jmp dword[p_oldMessageBeep]
EndProcedure

***

*oldMessageBeep = sethook("crypt32.dll", "CertGetCertificateContextProperty", @NewMessageBeep())

а вот такого у тебя подобного нет?

Elecktron
16.10.2013, 15:19
Файлы формата: *ukx *.dat

Михаил, в этих файлах невозможно сделать привязку, по причине того, что в них нет исполняемого кода - это файлы текстур и текстовых данных клиента.

cvillian
27.03.2015, 13:46
зачем пользоваться глючным стеком? оО
можно проще. например(с++):

перехват инита, для получения NetworkHandler - чистая магия, местами подогнанная по месту, так что приведена исключительно для осознания что и куда.

p.s.как-то пробовал сделать на делфи - могу поискать исходники, но они "портированы" с с++, так что по сути тоже самое
p.p.s. есть еще способ (если защита смотрит откуда сенд вызван)

Тема наверное уже мертва но всё равно попробую :)
Может кто-то напишет пример как на дельфях получить этот долбаный NetworkHandler :)

Elecktron
08.04.2015, 00:55
как я уже упоминал - "портировано 1 к 1 с с++":

получение указателя на экземпляр UNetworkHandler'а


UNetworkHandler: Pointer

//UNetworkHandler_Init
procedure UNetworkHandlerInit_hook();
asm
mov UNetworkHandler, ecx //сохраняем указатель на экземпляр
MOV EAX,DWORD PTR FS:[0] //
jmp DWORD PTR initUH_orig //прыгаем в оригинальную
end;

внедрение кода (ставим свои адреса и радуемся)

function InitThread(lpParameter: pointer):dword;// stdcall;
begin
//подождать engine.dll, и начать внедрение своего кода
repeat
Sleep(100);
until (GetModuleHandleA('engine.dll')<>0);

buf := DWORD(@UNetworkHandlerInit_hook);
//тут магия, хардкод и шанс попортить регистры.
initUH_orig:=Engine+$003B2D96;
comm :=$e9;
// Обычно страницы в этой области недоступны для записи
// поэтому принудительно разрешаем запись
VirtualProtect(ptr(Engine+$003B2D90),5,PAGE_READWR ITE, @op);
//вычисляем смещение которое запишем в джамп
offset := buf - (Engine+$003B2D90 + 5);
// Пишем новый адрес
// нужно писать СМЕЩЕНИЕ!
WriteProcessMemory(GetCurrentProcess(), ptr(Engine+$003B2D90),@comm,1,written);
WriteProcessMemory(GetCurrentProcess(), ptr(Engine+$003B2D90+$01),@offset,4,written);
end;

"DLL Main"

procedure DLLEntryPoint(dwReason: DWORD); export;
var
ThreadId:dword;
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
CreateThread(nil,0,@ InitThread,nil,0,ThreadId);
end;
DLL_PROCESS_DETACH:
begin

end;
end
end;

все это "хардкод", "дурной тон" и "так нельзя" :D
и не забываем все действия десять раз перепроверить в отладчике.

user713
09.04.2015, 11:44
Люди добрые, выручайте! Пытаюсь из engine.dll вызвать UGameEngine::OnNpcHtmlMessage.

void * html_this = NULL; // <<< где взять изначально???

typedef int (__thiscall *_OnNpcHtmlMessage) (void * This, void * user, wchar_t * html, int unk);
_OnNpcHtmlMessage true_OnNpcHtmlMessage;

int __fastcall new_OnNpcHtmlMessage(void * This, unsigned int EDX, void * user, wchar_t * html, int unk)
{
if(html_this == NULL) html_this = This; //Тут выдёргиваю пойнтер при первом вызове диалога сервером
return true_OnNpcHtmlMessage(This, 0, html, 0);
}

void NpcHtmlMessage()
{
wchar_t html[] = L"<html></html>";
if(html_this != NULL) true_OnNpcHtmlMessage(html_this, 0, html, 0);
}

P.S: Если html_this != NULL, то окно можно открыть хоть на экране ввода логина и пароля.
Хукается вроде успешно, НО где достать пойнтер This, чтобы вызывать эту функцию без предварительного получения This?

Добавлено через 7 минут
Да и вообще очень интересует как вызвать (__thiscall)OnNpcHtmlMessage, да или вообще что угодно из engine.dll !!! Дайте пример или пните в каком направлении капать))

Yegor
09.04.2015, 12:37
This - это указатель в памяти на объект UNetworkHandler, чтобы его получить надо перехватить один из его методов и получить этот адрес.

Например ставим хук на



class UNetworkHandler {};

UNetworkHandler* UNH;

int __fastcall UNetworkHandler_AddNetworkQueue_hook(UNetworkHandl er* This, int /*edx*/, NetworkPacket* packet)
{
if(UNH == 0)
{
UNH = This;
}

....


Но чтобы произошел AddNetworkQueue_hook необходимо отправка хотя бы одного пакета на сервер. Например при вводе пароля.

Botter100
11.01.2016, 12:15
Посоны привет! Я тут это все читаю, чето все всё перехватывают. А я понять не могу - это все делается на клиенте с откусанной темидой и ГГ или прям со всем этим добром? Я просто пытаюсь делать хук и у меня крэшится. Причем крэшится не доходя до моего кода, но и не сразу, а только там где я залез своми грязнуми руками в енжин.длл.

Моя первая цель - вызвать MessageBox при вызове OnNpcHtmlMessage

Вот тут хукаю

bool Entry()
{
HMODULE hEngine = GetModuleHandle(L"Engine.dll");

if (hEngine == INVALID_HANDLE_VALUE)
MessageBox(HWND_DESKTOP, L"Can't get module handle.", L"Error", MB_OK | MB_ICONERROR);

char* addr = (char*)GetProcAddress(hEngine, "?OnNpcHtmlMessage@UGameEngine@@UAEHPAUUser@@PA_WHH @Z");

if (!addr)
MessageBox(HWND_DESKTOP, L"Can't get proc address.", L"Error", MB_OK | MB_ICONERROR);

DWORD protection;
DWORD ff = (DWORD)UGameEngine__OnNpcHtmlMessage;

Log::putstring(L"dump_UGameEngine__OnNpcHtmlMessage.txt", L"UGameEngine__OnNpcHtmlMessage = 0x%0X\n", ff);
Log::putstring(L"dump_UGameEngine__OnNpcHtmlMessage.txt", L"UGameEngine::OnNpcHtmlMessage = 0x%0X\n", (DWORD)addr);

//VirtualProtect(addr, 5, PAGE_EXECUTE_READWRITE, &protection);
*addr = char(0xE9); // op code
memcpy(addr + 1, &ff, 4);
//VirtualProtect(addr, 5, protection, 0);

HANDLE hDumpFile = CreateFile(L"dump.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);

DWORD bytesWritten = 0;
WriteFile(hDumpFile, addr, 200, &bytesWritten, NULL);
CloseHandle(hDumpFile);


MessageBox(HWND_DESKTOP, L"I am in...", L"Yop", MB_OK);

return true;
}

тут я просто инжеклю jmp на мою функцию представленую ниже

__declspec(naked) void UGameEngine__OnNpcHtmlMessage()
{
MessageBox(HWND_DESKTOP, L"Called 'UGameEngine__OnNpcHtmlMessage'", L"Yop", MB_OK);
}

Это все делается под геймгуардом и с темидой, не знаю влияет ли это как то. Просто бот л2тавер показывает что это возможно. Подсобите че не так делаю? Спасибо.

Barsik
11.01.2016, 12:57
__declspec(naked) void UGameEngine__OnNpcHtmlMessage()


Твоя функция подмены должна быть по параметрам и возвращаемому значению идентична оригинальной функции. Вот так этот метод класса выглядит:
int __thiscall UGameEngine::OnNpcHtmlMessage(UGameEngine *this, struct User *, wchar_t *, int)

Botter100
11.01.2016, 13:02
Твоя функция подмены должна быть по параметрам и возвращаемому значению идентична оригинальной функции. Вот так этот метод класса выглядит:
int __thiscall UGameEngine::OnNpcHtmlMessage(UGameEngine *this, struct User *, wchar_t *, int)

Это понятно, если я хочу жить после всего этого. Но щас для меня цель отобразить мессадж бокс и гори оно синим пламенем. Ведь должно же по логике проканать. Мне не надо сохранять стэк и прочее ведь? По сути че происходит - вызывается функция из енжин длл OnNpcHtmlMessage а там вместо ее кода уже мой тупо jmp а по этому жмп тупо call MessageBox.

я не переписываю адрес функции в таблице, я хукаюсь внутрь самой функции и мне в принципе пофигу на параметры.

Barsik
11.01.2016, 14:08
memcpy(addr + 1, &ff, 4); неверно, так как нужно пересчитать относительное смещение т.е.
вместо &ff UGameEngine__OnNpcHtmlMessage - addr - 5;

с GG не пробовал хукать, возможно он палит, попробуй хукнуть не на первом байте а дальше, глянь что в отладчике переписывается ли джамп

Yegor
11.01.2016, 17:53
А какие хроники клиента? Если ИЛ то там не получится хукнуть в лоб заменив первые 4 байта функции.

Barsik
11.01.2016, 22:25
А какие хроники клиента? Если ИЛ то там не получится хукнуть в лоб заменив первые 4 байта функции.

Почему именно первые 4? если в ИЛ то первый байт jmp следующие 4 адрес. В случае ИЛ хукается еще проще просто переписывается адрес 4 байта после джампа т.е. 2-5 байты.

Yegor
12.01.2016, 23:59
Оно то не сложно но я же не вижу как вы хукаете, и там не просто адрес а смешение.

Barsik
13.01.2016, 09:37
memcpy(addr + 1, &ff, 4); неверно, так как нужно пересчитать относительное смещение т.е.
вместо &ff UGameEngine__OnNpcHtmlMessage - addr - 5;

вот расчет относительного смещения
========================
в отладчике после jmp виден адрес готового перехода который на самом деле вычесляется
Предположим, что функция A расположена по адресу 0×401000, а функция B – по адресу 0×401800. Далее мы определим требуемое относительное смещение. Разница между адресами данных функций составляет 0×800 байт, и мы хотим перейти из функции A в функцию B, так что нам пока не нужно беспокоиться об отрицательных смещениях.

Дальше следует хитрый момент. Предположим, что мы уже записали нашу инструкцию перехода по адресу 0×401000 (функции A), и что данная инструкция выполняется. CPU при этом сделает следующее: сначала он добавит длину инструкции к Указателю на Инструкцию [3] (или Программному Счетчику). Длина инструкции перехода равна пяти байтам, как мы установили ранее. После этого к Указателю на Инструкцию добавляется относительное смещение. Другими словами, CPU вычисляет новое значение Указателя на Инструкцию следующим образом:
instruction_pointer = instruction_pointer + 5 + relative_offset;

Поэтому для вычисления относительного смещения нам нужно переписать формулу в следующем виде:
relative_offset = function_B - function_A - 5;

Мы вычитаем 5, поскольку это длина инструкции перехода, которую CPU добавляет при запуске данной инструкции, а function_A is вычитается из function_B, так как это относительный переход. Разница между адресами функций равна, как мы помним, 0×800 байтам. (Например, если мы забудем вычесть function_A, то CPU перейдет по адресу 0×401800 + 0×401000 + 5, что, очевидно, нежелательно).
вот кусок кода правда не мой но как пример подойдет :void* Create_Hook(BYTE *src, const BYTE *dst, const int len)
{
BYTE *jmp; DWORD dwback;
DWORD jumpto, newjump;
VirtualProtect(src,len,PAGE_READWRITE,&dwback);
if(src[0] == 0xE9)
{
jmp = (BYTE*)malloc(10);
jumpto = (*(DWORD*)(src+1))+((DWORD)src)+5;
newjump = (jumpto-(DWORD)(jmp+5));
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = newjump;
jmp += 5;
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src-jmp);
}
else
{
jmp = (BYTE*)malloc(5+len);
memcpy(jmp,src,len);
jmp += len;
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src+len-jmp)-5;
}
src[0] = 0xE9;
*(DWORD*)(src+1) = (DWORD)(dst - src) - 5;
for(int i = 5; i < len; i++)
src[i] = 0x90;
VirtualProtect(src,len,dwback,&dwback);
return (jmp-len);
}

Yegor
14.01.2016, 01:08
Так у тебя на ИЛ клиенте крашится все таки?