Reverse-engineering du fichier GameOps.dll

De T4C Tech
Aller à la navigation Aller à la recherche

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)