Java Récupérer la map à partir du packet

Inscrit
19 Juillet 2016
Messages
14
Reactions
0
#1
Bonjour,

J'ai commencé un petit programme en JAVA afin d'analyser les données de D0fus.
Actuellement j'en suis au stade ou je sniffe les packets de l'IP de D0fus.. :

Console:
packetID: 300 inconnu
packetID: 1472 inconnu
packetID: 1472 inconnu
packetID: 1472 inconnu
packetID: 951 inconnu
packetID: 1472 inconnu
packetID: 950 inconnu
packetID: 6362 inconnu
packetID: 952 inconnu
packetID: 6362 inconnu
221: ChangeMapMessage
packetID: 6362 inconnu
packetID: 225 inconnu
packetID: 6362 inconnu
packetID: 226 inconnu


Bon c'est magnifique, sauf que je ne vais pas aller loin avec sa, j'ai donc bien compris le tutoriels concernant le découpage du packet afin de récupérer l'identifiant du packet à convertir, etc...

Il s'avère que les données de mon packet se trouve dans le payload :

Portion de code dans mon sniffer :

Code:
Payload payload = new Payload();
if (packet.hasHeader(payload)) {
    byte[] payloadContent = payload.getByteArray(0, payload.size()); // payloadContent contient donc les données du packet
    byte b1;
    byte b2;
    try {
        b1 = payloadContent[0];
        b2 = payloadContent[1];
        String b1Str = String.format("%02X", b1);
        String b2Str = String.format("%02X", b2);
        Conversion conv = new Conversion(b1Str + b2Str);
                                 
        PacketManage packetManage = new PacketManage(conv.hexToDec());
        packetManage.manage();
                                 
    } catch (Exception e) {
                                 
    }
}
PacketManage.java :
Code:
public void manage(){
       switch(_packetID){
            case 221:
                System.out.println("221: ChangeMapMessage");
                break;
            default:
                System.out.println("packetID: " + _packetID + " inconnu");
                break;
      }
}
La question : Comment récupérer la map en cours ?

Faut-il que je convertisse obligatoirement changeMapMessage.as (D0fusInvoker.swf) pour traiter les données de mon packets ?
Je précise que je ne veux faire que du sniff de packet, je n'ai pas besoin de renvoyer des packets.

Il existe une solution pour extraire les données plus simplement qu'en convertissant cette classe ?


Merci de votre aide, si vous manquez d'informations pour m'aider, n'hésitez pas !
 
Inscrit
2 Juin 2016
Messages
82
Reactions
3
#2
Tu déserialize ton paquet et tu auras ses infos. où est le soucis?
 
Inscrit
20 Juin 2016
Messages
41
Reactions
2
#3
Tu as un tableau de byte qui contient les donnés, ce que je te conseil de faire c'est de passer par un inputstream c'est beaucoup plus simple pour deserializer un packet.

Pour ça tu peux instancier l'objet ByteArrayInputStream(byte[] buf), et à partir de cet inputstream tu as juste à lire les donnés.
Pour le cas de ton packet 221 il suffit que tu lise un integer.
 

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#4
non t'es pas obligé de convertir mapjesaisplusquoi.as ou de "deserialiser" quoique ce soit mais faut quand meme que tu regardes dedans (dans le .as) ou est l'info que tu cherches , une fois que tu sais ou c'est ... y'a plus qu'a aller directement lire dans ton "packet" a cette position
 
Inscrit
19 Juillet 2016
Messages
14
Reactions
0
#5
D'accord merci de vos réponses, c'est bien ce que je pensais par rapport au fait qu'il faut récupérer la manière dont le packet est récupéré en AS, je vais étudier sa ;-)
 
Inscrit
2 Juin 2016
Messages
82
Reactions
3
#6
non t'es pas obligé de convertir mapjesaisplusquoi.as ou de "deserialiser" quoique ce soit mais faut quand meme que tu regardes dedans (dans le .as) ou est l'info que tu cherches , une fois que tu sais ou c'est ... y'a plus qu'a aller directement lire dans ton "packet" a cette position
C'est le principe de déserializer une information...bravo.
 
Inscrit
19 Juillet 2016
Messages
14
Reactions
0
#7
DrBrook, bien que sa te paraisse logique moi qui commence tout juste à comprendre ce domaine, sa ne fais pas de mal qu'on me confirme ces choses, même si c'est à peu près ce que j'imaginais.

Sinon j'ai pu récupérer l'identifiant de la map via une lecture BigEndian, merci de votre aide.

byte[] packet = hexStringToByteArray("037504092E0505");
int result = new BigInteger(packet).intValue(); // = mapID : ok

Imaginons qu'il y ai plusieurs données dans un packet (par exemple 5658 : UpdateLifePointsMessage) : Comment faire pour récupérer toutes les données ?

Il faut soustraire au packet à chaque fois les données qu'on y retire ?

Merci:)
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#8
Exactement, il existe deux modes de lecture, le BigEndian et le LittleEndian.
Le LittleEndian n'existe quasiment pas sur Dofus (Sauf dans le HumanCheck).

En suivant le schéma des classes network du jeu, tu connaitras l'ordre des données à lire.

PS: @DrBrook Ne soit pas méprisant avec @ToOnS, il apporte des informations sur un vocabulaire que tout le monde ne connait pas. ( @microbique étant tout nouveau sur le forum )
 
Dernière édition:
Inscrit
2 Juin 2016
Messages
82
Reactions
3
#9
Je ne suis pas méprisant, je suis un développeur et je suis pragmatique par définition, c'est tout. :)

Sinon la meilleure chose à faire dans ton cas serait de traduire les classes en AS3 en classe Java pour pouvoir lire ou écrire tout les packets (enfin...la meilleure des choses si tu as beaucoup de paquets à lire, sinon à la main ca reste tout aussi bien)
 
Inscrit
19 Juillet 2016
Messages
14
Reactions
0
#10
D'acc sa marche :)

En gros pour lire des données à la suite dans un packet, l'idée serrait la suivante si j'ai bien compris :

(on imagine que mon packet contient 2 identifiant de map à la suite (impossible je sais, c'est juste pour l'exemple) ) :

Code:
byte[] packet = hexStringToByteArray("05037504092E050505037504092E0504");

ByteArrayInputStream bais = new ByteArrayInputStream(packet,0, 8);
ByteArrayInputStream bais2 = new ByteArrayInputStream(packet,8, 16);

byte[] map1 = read(bais);
byte[] map2 = read(bais2);

int result1 = new BigInteger(map1).intValue(); // = 154010885
System.out.println(result1);
      
int result2 = new BigInteger(map2).intValue(); // = 154010884
System.out.println(result2);
Résultat de console :
154010885
154010884

L'idée plus tard serrait de caser le ByteArrayInputStream dans une boucle qui s'incrémente au fur et à mesure.
C'est sur un départ comme sa qu'il faut partir ou je n'ai rien compris ?

______________


Du coup je me suis fais une petite classe pour lire plusieurs données (pour le moment ne traite que les BigEndian intValue)

Code:
package cap;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;

public class DataReader {
   
    private byte[] _data;
    private int _cpt;
   
    /**
     * Constructeur
     * @param data
     */
    public DataReader(byte[] data){
        this._data = data;
        this._cpt = 0;
    }
   
    /**
     * @param length
     * @return BigInteger.intValue
     */
    public int getInt(int length){
        ByteArrayInputStream bais = new ByteArrayInputStream(_data, _cpt, length);
        byte[] data = read(bais);
        _cpt = _cpt + length;
        return new BigInteger(data).intValue();
    }
   
    /**
     * Lecture des bytes d'un ByteArrayInputStream
     * @param bais
     * @return byte[]
     */
    private byte[] read(ByteArrayInputStream bais) {
         byte[] array = new byte[bais.available()];
         try {
            bais.read(array);
        } catch (IOException e) {
            e.printStackTrace();
        }
         return array;
    }

}
 
Dernière édition:

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#11
Ton code est absolument parfait ( d'un point de vue fonctionnel ), tu es sur la bonne voie.
 
Inscrit
20 Juin 2016
Messages
41
Reactions
2
#12
Je donne que des moitiés de réponses, mais au moins t'as trouvé une parade qui semble fonctionnelle.

Si je t'ai redirigé vers le ByteArrayInputStream, c'est qu'en java il existe un autre objet qui est le DataInputStream(InputStream in).

Et l'avantage du DataInputStream c'est qu'il a déjà quelques fonction de "lecture de byte" intégrée comme par exemple le readInt().

Par contre je ne vois pas où tu veux en venir avec une boucle qui s'incrémente ? (Pour lire toutes les données d'un packet ?)

Si c'est pour lire toutes les données d'un packet tu pourras constater qu'il y a plusieurs "type d'objet" à lire, et donc ce n'est pas possible de deserializer tous les packets avec une seule boucle, il faudra deserializer tous les packets différemment.

Je te conseil directement de ne pas utiliser directement l'objet DataInputStream, mais de faire toi même un objet "DofusDataInputStream" (par exemple) qui extends DataInputStream où tu pourras rajouter des fonctions de lectures propres à Dofus (comme par exemple readVarInteger(), à moins que c'est moi qui ai pas trouvé de correspondance), j'ai noté également que le readUTF() de l'objet DataInputStream ne correspond pas à celui pour lire les String des packets Dofus, donc mettre une fonction readString() ou readUTFDofus() dans cet objet sera bien utile (mais là aussi je peux m'être trompé et j'ai raté un truc).
 
Dernière édition:
Inscrit
15 Mai 2015
Messages
41
Reactions
0
#13
De mon côté j'utilise toutes les fonctions des objets DataInputStream et DataOutputStream en java. Toutes les fonctions sont les mêmes qu'en AS3.
Ils sont peut être sales mais si ça peut en aider certains voici les miens.
 

Pièces jointes

Dernière édition:
Inscrit
20 Juin 2016
Messages
41
Reactions
2
#14
Le fait d'avoir un objet qui hérite de DataInputStream (ou output mais vu que là l'auteur fait qu'un sniffer) ça économise toutes les lignes du style "readInt(); readBoolean()" etc...
 
Dernière édition par un modérateur:
Inscrit
19 Juillet 2016
Messages
14
Reactions
0
#15
IceRhal : Effectivement j'étais tombé aussi sur le DataInputStream, je vais peut être me renseigner plus su celui ci effectivement s'il a déjà des correspondances pour le read, car la j'ai besoin du readUTF pour un packet concernant les messages dans dofus.

harkhann : Merci je vais regarder sa de suite :)

Merci à tous de vos commentaires


Edit :

Pour ce qui est du reatInt() du DataInputStream il ne me donne pas le bon résultat contrairement à new new BigInteger(packet).intValue()


Je n'arrive pas à lire le contenu d'un message.. :

packet concerné 850 et 851 (test sur les messages privés)

851: receiver=cou je m appel g -> 850: content=MV

Le problème est que je ne connais pas la taille du message qui est contenu, la taille du pseudo peut varier, la taille du mesage reçu/envoyé aussi, comment gérer ce cas ?

Code:
public String read_utf(int length){
        ByteArrayInputStream bais = new ByteArrayInputStream(_data, _cpt, _cpt+length);
        byte[] data = read(bais);
        _cpt = _cpt + length;
        return new String(data, StandardCharsets.UTF_8);
    }
Code:
package com.ankamagames.dofus.network.messages.game.chat;

import io.DataReader;

public class ChatClientPrivateMessage extends ChatAbstractClientMessage {

    public static final int PROTOCOL_ID = 851;

    public String receiver;

    public ChatClientPrivateMessage() {
        super();
    }

    public void deserialize(DataReader reader) {
        super.deserialize(reader);
        this.receiver = reader.read_utf(8);
    }

    public String toString() {
        return PROTOCOL_ID + ": receiver=" + this.receiver + " -> " + super.toString();
    }

}
Code:
package com.ankamagames.dofus.network.messages.game.chat;

import io.DataReader;

public class ChatAbstractClientMessage {

    public static final int PROTOCOL_ID = 850;

    public String content;

    public ChatAbstractClientMessage() {

    }

    public void deserialize(DataReader reader) {
        this.content = reader.read_utf(8);
    }

    public String toString() {
        return PROTOCOL_ID + ": content=" + this.content;
    }
}
 
Dernière édition:
Inscrit
20 Juin 2016
Messages
41
Reactions
2
#16
La taille du message est indiqué avant le message par un short
 
Inscrit
19 Juillet 2016
Messages
14
Reactions
0
#17
Oui, je la récupère justement, elle est de 66 mais j'ai plein de charactère bizare .. et le packet n'est pas découpé en 2, tout le message (content & pseudo) tiens sur une seule réponse :

Code:
byte[] packet = hexStringToByteArray("0D4D42000477657368000A456C6D656E7461696E619B3CD84E7BD78B9218F2661023C24436601B39E45AA465C579D1EBF696ABE14EAEB26038E39E6E6BCD531F9CFE845402");
        System.out.println("lenght:" + "0D4D42000477657368000A456C6D656E7461696E619B3CD84E7BD78B9218F2661023C24436601B39E45AA465C579D1EBF696ABE14EAEB26038E39E6E6BCD531F9CFE845402".length());
        DataReader reader = new DataReader(packet);
     
        System.out.println(reader.getId().id); // 851
        System.out.println(reader.getId().size); // 1
        System.out.println("length: " + reader.length()); // 66
     
        System.out.println("String:" + reader.getStr(66));
        // Réponse de la console (sur 2 lignes:)
        // MB??wesh?
        // Elmentaina›<ØN{׋’òf#ÂD6`9äZ¤eÅyÑëö–«áN®²`8ãžnkÍSœþ
Ligne 1: message(wesh)
Ligne 2: destinataire(Elmentaina)


edit :

Ok j'ai de l'évolution avec DataInputStream et son readLine, mais ce n'est pas encore sa car il y a toujours les caracteres bizare (au moins la packet à l'air découpé en 2 partie comme il le faut)

Code:
ByteArrayInputStream bais = new ByteArrayInputStream(packet, 0, reader.length());
        DataInputStream dis = new DataInputStream(bais);
      
        try {
            System.out.println("String:" + dis.readLine());
            System.out.println("String:" + dis.readLine());
            System.out.println("String:" + dis.readLine());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
réponse :


String:
String:MB??wesh?
String:Elmentaina?<ØN{×??òf#ÂD6`9äZ¤eÅyÑëö?«áN®²`8ã?nkÍS?þ
 
Dernière édition:

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#18
C'est le principe de déserializer une information...bravo.
pardon , je suis debutant mais je t'assure que j'arrive a aller chercher une information sans rien deserialiser et sans meme avoir a traduire une classe dans un language , juste en regardant le fichier .as et en comptant , c'est comme ca que j'ai commencé , apres le reste j'y comprend rien avec les trucs de "parseur" et tout ces trucs la
j'espere un jour avoir ton niveau pour pouvoir faire un bot dofus
 
Inscrit
19 Juillet 2016
Messages
14
Reactions
0
#19
Ok , j'ai réussi à décrypter mon packet mais je ne sais même pas comment j'ai fais (en mettant des lenght aléatoire jusqu'à trouver les bons ...)

Console :
id: 851
size: 66
_cpt: 3
message: wesh
_cpt: 9
receiver: Elmentaina

DataReader.java : read_utf

Code:
public String read_utf(int length){
        String result = "";
        System.out.println("_cpt: " + _cpt);
        ByteArrayInputStream bais = new ByteArrayInputStream(_data, _cpt, _cpt+length);
        try {
            DofusDataInputStream dis = new DofusDataInputStream(bais);
            result =  dis.readUTF();
            dis.close();
            _cpt = _cpt + length;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
Code:
byte[] packet = hexStringToByteArray("0D4D42000477657368000A456C6D656E7461696E619B3CD84E7BD78B9218F2661023C24436601B39E45AA465C579D1EBF696ABE14EAEB26038E39E6E6BCD531F9CFE845402");
    
        DataReader reader = new DataReader(packet);
    
        System.out.println("id: " + reader.packetId); // 851
        System.out.println("size: " + reader.packetSize); // 66

    
        System.out.println("message: " + reader.read_utf(6));
        System.out.println("receiver: " + reader.read_utf(9));
sachant qu'avant toute chose je récupère dans le packet la taille et l'id au début, en incrémentant mon compteur (ici il passe à 3 car 2 bit pour l'id et 1 pour la taille dans notre cas)

Après je ne comprend pas pourquoi mon read_utf marche avec un length de 6 pour le message et un length de 9 pour 9 pour le receiver

Question : Comment est-ce qu'on peut savoir quel taille va avoir notre message / receiver ? je pense que ma technique ne marchera pas si le message n'est plus 'wesh' mais 'salut' car il y aura plus de caractères

edit: j'ai remarqué dans le byteArray qu'entre les 2 messages (message, receiver) il y a un 00, est-ce celui ci qui sépare différent message ?
0D4D : 851
42 : 66
00 :
0477657368 : wesh
00 :
A456C6D656E... : Elmentaina

C'est le même principe pour tous les packets multi données ?
 
Dernière édition:

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#20
C#:
/// <summary>
  ///  Read a string from the Buffer
  /// </summary>
  /// <returns></returns>
  public string ReadUTF()
  {
  ushort length = ReadUShort();

  byte[] bytes = ReadBytes(length);
  return Encoding.UTF8.GetString(bytes);
  }
Tu dois lire avec un ushort la taille de la chaine de texte.

wesh -> 4 caractères count 3
Elmentaina -> 10 caractères count 9
 
Haut Bas