Reverse-engineering du fichier GameOps.dll
Modification de la position de sanctuaire par défaut personnage (Serveur 1.25)
Cette modification de la DLL GameOps permet de modifier la position du sanctuaire par défaut d'un personnage en jeu, quand le flag contenant la position du sanctuaire de ce personnage n'a pas encore été créé (autrement dit, quand le joueur n'a encore jamais placé son sanctuaire explicitement quelque part).
ATTENTION: cette valeur ne doit pas être confondue avec la position d'apparition d'un nouveau personnage, qui elle, se modifie directement dans l'exécutable du serveur T4C.
Tout d'abord, nous savons que le sanctuaire par défaut d'un personnage est, jusqu'à ce qu'il place son sanctuaire lui-même dans un temple, identique à sa position d'apparition dans le jeu quand le personnage vient juste d'être créé. Cette position est : 2945,1058,0.
Il suffit donc d'ouvrir la DLL dans le désassembleur de votre choix (comme par exemple IDA Pro) et, une fois le désassemblage de la DLL terminé, de rechercher la valeur 2945 en hexadécimal (0x0B81) dans votre désassembleur.
A un certain moment nous tombons sur :
.text:1001F2B2 loc_1001F2B2: .text:1001F2B2 push edi .text:1001F2B3 push 0 .text:1001F2B5 push 422h .text:1001F2BA push 0B81h .text:1001F2BF call ?TeleportFunc@@YAXHHHPAVUnit@@@Z .text:1001F2C4 jmp short loc_1001F2F8 .text:1001F2C6 ; ---------------------------------------------------------------------------
Examinons de plus près cette fonction.
.text:1001F2B2 push edi .text:1001F2B3 push 0 ; Pos W .text:1001F2B5 push 422h ; Pos Y .text:1001F2BA push 0B81h ; Pos X .text:1001F2BF call ?TeleportFunc@@YAXHHHPAVUnit@@@Z ; TeleportFunc(int,int,int,Unit *)
Nous plaçons trois valeurs arbitraires sur la pile, puis nous appelons la fonction TeleportFunc(). Ces trois valeurs sont :
- 0x0000 (0 décimal)
- 0x0422 (1058 décimal)
- 0x0b81 (2954 décimal)
Il s'agit des coordonnées que nous recherchons, empilées en ordre inverse afin de construire la pile de paramètres de la fonction TeleportFunc. Ce sont donc ces valeurs qu'il faut changer.
L'adresse de ces valeurs est l'adresse virtuelle (Virtual Address ou VA) correspondante à ces lignes dans la section de l'exécutable nommée ".text". Si vous utilisez le désassembleur IDA, l'offset correspondant dans le fichier est indiqué juste à côté en bas à gauche de votre écran. Sinon, il faut le calculer. Corrigez-moi si je me trompe : (--Sorkvild 17 mars 2008 à 17:06 (MSK))
FileOffset = VirtualAddress - VirtualOffset + RawOffset
- VirtualAddress est nos trois addresses VA, respectivement 0x1001F2B3 + 1 octet (pour l'instruction push) soit 0x1001F2B4, 0x1001F2B5 + 1 octet (même remarque) soit 0x1001F2B6, et 0x1001F2BA + 1 octet (idem) soit 0x1001F2BB de la section .text.
- VirtualOffset est l'adresse où démarre notre section .text. Cette valeur se trouve dans les informations de l'en-tête des sections (sections header dans votre désassembleur). Celui-ci nous renseigne : la section .text commence à 0x10001000.
- RawOffset est un décalage arbitraire dans le fichier binaire à partir duquel les sections commencent. Le désassembleur nous renseigne encore : dans notre DLL, il vaut 0x00001000.
Ce qui nous donne :
FileOffsetW = 0x1001F2B4 - 0x10001000 + 0x00001000 = 0x0001F2B4 = 127668 FileOffsetY = 0x1001F2B6 - 0x10001000 + 0x00001000 = 0x0001F2B6 = 127670 FileOffsetX = 0x1001F2BB - 0x10001000 + 0x00001000 = 0x0001F2BB = 127675
On récupère donc les offsets dans le fichier :
- 127668 pour la coordonnée w,
- 127670 pour la coordonnée y,
- 127675 pour la coordonnée x.
Vous trouverez davantage d'informations sur le format PE sur cette page.
Une fois les offsets trouvés, il vous suffira de développer un petit logiciel de patch ou bien de modifier à l'aide d'un éditeur hexadécimal les 3 valeurs des coordonnées du sanctuaire par défaut.
Exemple d'un patcheur pour cette DLL en Delphi
(* -------------------------------------------------------------------------- *)
(* T4C Start Location By Mestoph *)
(* -------------------------------------------------------------------------- *)
unit Patcheur;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, WinSkinData;
type
TForm1 = class(TForm)
SkinData1: TSkinData;
GroupBox1: TGroupBox;
OpenDialog1: TOpenDialog;
Lbl_X: TLabel;
Lbl_Y: TLabel;
Lbl_Z: TLabel;
Edit_Z: TEdit;
Edit_Y: TEdit;
Edit_X: TEdit;
Edit_Fichier: TEdit;
Btn_Ouvrir: TButton;
Btn_Patch: TButton;
Btn_Fermer: TButton;
GroupBox3: TGroupBox;
Lbl_Taille: TLabel;
Bevel1: TBevel;
procedure Btn_OuvrirClick(Sender: TObject);
procedure Btn_FermerClick(Sender: TObject);
procedure Btn_PatchClick(Sender: TObject);
procedure Edit_XKeyPress(Sender: TObject; var Key: Char);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
(* -------------------------------------------------------------------------- *)
(* Ouverture du fichier *)
(* -------------------------------------------------------------------------- *)
procedure TForm1.Btn_OuvrirClick(Sender: TObject);
Var Fichier : File;
Begin
If OpenDialog1.Execute = True Then
Begin
Edit_Fichier.Text := OpenDialog1.FileName;
AssignFile(Fichier, OpenDialog1.filename);
Reset(Fichier,1);
Lbl_Taille.Caption := IntToStr(Filesize(Fichier)) + ' Octets';
CloseFile(Fichier);
End;
end;
(* -------------------------------------------------------------------------- *)
(* Fermeture du programme *)
(* -------------------------------------------------------------------------- *)
procedure TForm1.Btn_FermerClick(Sender: TObject);
begin
Application.Terminate;
end;
(* -------------------------------------------------------------------------- *)
(* Patche du fichier *)
(* -------------------------------------------------------------------------- *)
procedure TForm1.Btn_PatchClick(Sender: TObject);
Var Taille_Fichier : LongInt;
Donnees, Emplacement : Pbyte;
Fichier : File;
begin
If (Edit_Fichier.Text <> '') Then
Begin
If (Edit_Z.Text <> '') And (Edit_Y.Text <> '') And (Edit_X.Text <> '') Then
Begin
If (StrToInt(Copy(Lbl_Taille.Caption,1,Length(Lbl_Taille.Caption)-7)) >= 340030) then
Begin
AssignFile(Fichier,Edit_Fichier.Text);
Reset(Fichier,1);
Taille_Fichier := FileSize(Fichier);
// On alloue une nouvelle zone mémoire
GetMem(Donnees,Taille_Fichier);
// On mets les données du fichier en mémoire
BlockRead(Fichier,Donnees^,Taille_Fichier);
Emplacement := Donnees;
// On se place a l'offset 0001F2B3 (:1001F2B3 6A00 push 00000000 => Z)
Emplacement := Pointer(LongInt(Emplacement) + 127668);
Pbyte(LongInt(Emplacement))^ := StrToInt(Edit_Z.Text);
// On se place a l'offset 0001F2B5 (:1001F2B5 6822040000 push 00000422 => Y)
Emplacement := Pointer(LongInt(Emplacement) + 2);
Pword(LongInt(Emplacement))^ := StrToInt(Edit_Y.Text);
// On se place a l'offset 0001F2BA (:1001F2BA 68810B0000 push 00000B81 => X)
Emplacement := Pointer(LongInt(Emplacement) + 5);
Pword(LongInt(Emplacement))^ := StrToInt(Edit_X.Text);
CloseFile(Fichier);
RenameFile(Edit_Fichier.Text,Edit_Fichier.Text+'.bak');
AssignFile(Fichier,Edit_Fichier.Text);
Rewrite(Fichier,1);
// On mets les données de la mémore dans le fichier
BlockWrite(Fichier,Donnees^,Taille_Fichier);
CloseFile(Fichier);
// On libère la mémoire
FreeMem(Donnees);
ShowMessage('Le fichier : ' + #13 + Edit_Fichier.Text + #13 + 'a été patché avec succès !');
Edit_X.Text := '';
Edit_Y.Text := '';
Edit_Z.Text := '';
Edit_Fichier.Text := '';
Lbl_Taille.Caption := '0 Octets';
End
Else ShowMessage('Le fichier ne correspont pas au fichier GameOps.dll de base !');
End
Else ShowMessage('Vous n''avez pas rempli de façon correct les informations requises !');
End
Else ShowMessage('Vous devez ouvrir le fichier GameOps.dll !');
End;
(* -------------------------------------------------------------------------- *)
(* Detection des touche clavier *)
(* -------------------------------------------------------------------------- *)
procedure TForm1.Edit_XKeyPress(Sender: TObject; var Key: Char);
begin
if Key in ['0'..'9', Chr(VK_BACK), Chr(VK_DELETE)] then
else
begin
showmessage('Uniquement les chiffres de 0 à 9 sont autorisés !');
Key:=#0;
end;
end;
end.
--Mestoph 17 mars 2008 à 05:04 (MSK)