RegisLG a écrit :J'ai plus l'impression qu'il s'agit de C++ que de C, c'est la définition de la méthode DecodeTp de la classe cTP, non ?
Tu as tout à fait raison , c'est bien de C++ qu'il s'agit et c'est bien la définition de la méthode DecodeTp de la classe cTP.
Dobro>
Ton code ne semble pas loin d'être le bon. Quelques corrections sont toutefois à apporter.
Mais aussi simple que paraisse cette méthode en C++, sa compréhension nécessite quand même une analyse poussée.
Nous allons en effet découvrir quelques limitations de PureBasic et, surtout, comment les contourner.
1 - Histoire de signes...
Code : Tout sélectionner
void cTP::DecodeTp(const unsigned char *in, unsigned char *out)
Voyons les forces en présence :
- un paramètre "const unsigned char *in" qui signifie une chaîne de caractères (spécifiquement ici, plutôt un tableau d'octets) non modifiée par la méthode en question,
- un paramètre "unsigned char *out" qui signifie une chaîne de caractères (spécifiquement ici, plutôt un tableau d'octets) qui contiendra le résultat de la méthode en question.
La première ligne est déjà sujette à interprétation.
En fait, Dobro, tu as raison : le caracatère '*' signifie pointeur mais dans le contexte de définition seulement; en fait :
Code : Tout sélectionner
int* pvaleur; // définit un pointeur sur un entier long signé et
printf("Valeur = %d", *pvaleur); // affiche la valeur pointée par "pvaleur"; "pvaleur" contient l'adresse de la valeur entière longue.
Pour en revenir à notre première ligne, nous avons d'abord un cast (changement de type ou transtypage) du pointeur *in en un pointeur vers un entier long non signé.
Ensuite, toujours sur cette première ligne, ce nouveau pointeur vers un entier long non signé est déréférencé, donc on y lit une valeur entière longue non signée.
Cette valeur lue est stockée dans la variable entière longue non signée "var2".
Ouf ! La première ligne a livré ses secrets.
Arrêtons-nous un moment à ce stade pour faire deux remarques :
- un entier long est codé sur quatre octets et un tableau d'octets est codé par un ensemble d'octets; donc "var2" contient la valeur des quatre premiers octets du tableau d'octets "in"; par conséquent, celui-ci doit au moins contenir quatre octets;
- PB ne gère pas les types non signés, à part pour le type .c (caractère). Ceci est une première limitation et nous verrons comment la contourner.
Ensuite arrive une boucle. Juste une correction, Dobro : en fait, la valeur finale 13 ne fait partie des valeurs

La bonne écriture en PB est donc:
Ensuite, on incrémente chacun des pointeurs ("in" et "out") de quatre octets (soit un entier long) pour pointer sur les 4 octets suivants, c'est-à-dire sur l'entier long suivant.
Par conséquent, il faut que "out" pointe lui-aussi sur un tableau d'octets.
Ensuite, un calcul est fait sur "var2" et elle est modifiée en conséquence.
2 - X-OR, le shérif, shérif de l'espace !
Ensuite, les quatre octets suivants dans "in" sont transformés en un entier long qui XORé avec "var2".
Le résultat est stockée dans l'entier long non signé "var1".
On lève ici une autre limitation de PB : le XOR binaire n'existe pas dans le langage. Nous verrons la solution plus loin.
Enfin, "var1" et "i" sont utilisées dans un calcul dont le résultat est transformé en entier non signé et stocké dans les quatre octets pointés par "out".
Ouf !
Deux remarques post-analytiques :
- les tableaux "in" et "out" doivent comporter un nombre d'octets divisible par 4 (à cause des entiers longs non signés) et être au moins longs de 4 + (4 * 13) = 56 octets,
- à mon humble avis, les quatre premiers octets du tableau "in" constituent une sorte de "clé" de décodage.
3 - Can you translate, please ?
Passons maintenant à la traduction ligne à ligne du code C++ en PureBasic et voyons sur quels écueils nous tombons (déjà signalés plus haut).
Code : Tout sélectionner
;void cTP::DecodeTp(const unsigned char *in, unsigned char *out)
Procedure DecodeTp(*pin.c, *pout.c)
"void" nous indique qu'aucune valeur de retour n'est attendue.
Nous avons vu plus haut que le type .c (caractère) en PB est le seul qui soit non signé; il est par conséquent tout à fait logique de l'utiliser ici.
Code : Tout sélectionner
; unsigned int var2=*((unsigned int *)in);
var2.l = PeekL(*pin)
Lire les 4 premiers octets de "in" et les stocker dans une variable entière signée (pas le choix avec PB).
Notre boucle, pas trop compliquée à convertir
On se positionne 4 octets plus loin dans "in" et "out".
Attention : veillez à bien avoir décochée l'option du compilateur "Activer le support Unicode" sinon, le type .c (caractère) fait deux octets au lieu d'un.
Code : Tout sélectionner
; var2=(var2<<3) | (var2>>(32-3));
var2left.l = var2 << 3
; Méthode assembleur => plus concise que la méthode PB
; var2right.l = var2
; !SHR dword [p.v_var2right], (32 - 3) ; Car le >> de PB garde le signe, ce que
; nous ne souhaitons pas
; Méthode PB => on reste en PB, pas besoin d'assembleur
var2right.l = (var2 >> 1) & %01111111111111111111111111111111 ; Retirer le bit de signe
var2right >> ((32 - 3) - 1)
var2 = var2left | var2right
Le >> (décalage de n bits à droite) de PB conserve le signe de notre "var2", ce que nous ne souhaitons pas.
Il existe deux solutions :
- une purement PB : on effectue un premier décalage en conservant le signe, on élimine ensuite ce signe et on effectue les autres décalages,
- une en assembleur : l'instruction assembleur SHR ne conserve pas le signe ce qui nous convient tout à fait.
Pour utiliser l'une ou l'autre des méthodes, vous pouvez commenter/décommenter les lignes correspondantes.
Code : Tout sélectionner
; unsigned int var1=*((unsigned int *)in) ^ var2;
var1.l = PeekL(*pin)
!MOV eax, dword [p.v_var2]
!XOR dword [p.v_var1], eax ; Car PB n'a pas de OU exclusif binaire
Le XOR binaire n'existe pas en PB, on passe par l'assembleur pour nous aider
Code : Tout sélectionner
; *((unsigned int *)out)=(var1<<(i+2)) | (var1>>(32-(i+2)));
var3left.l = var1 << (i + 2)
decalage.b = (32 - (i + 2))
; Méthode assembleur => plus concise que la méthode PB
; var3right.l = var1
; !MOV cl, byte [p.v_decalage]
; !SHR dword [p.v_var3right], cl ; Car le >> de PB garde le signe, ce que nous ne souhaitons pas
; Méthode PB => on reste en PB, pas besoin d'assembleur
var3right.l = (var1 >> 1) & %01111111111111111111111111111111 ; Retirer le bit de signe
var3right >> (decalage - 1)
var3.l = var3left | var3right
PokeL(*pout, var3)
Mêmes remarques que précédemment (pour "var2"), sauf que l'on ajoute ici la variable "décalage" car elle est le résultat d'un calcul sur "i".
On finit ensuite par inscrire la valeur de "var3" dans "out".
On oublie pas le Next...
et le EndProcedure !
Voici donc le code complet avec test qui correspondrait à cette analyse, si elle s'avère juste :
Code : Tout sélectionner
;void cTP::DecodeTp(const unsigned char *in, unsigned char *out)
Procedure DecodeTp(*pin.c, *pout.c)
; =============================================================================
; Transformer les 4 premiers octets de "in" en entier long (peut-être une clé ?)
; =============================================================================
; unsigned int var2=*((unsigned int *)in);
var2.l = PeekL(*pin)
; =============================================================================
; Décoder chaque quaduplet de "in" dans "out"
; =============================================================================
; for(int i=0; i<13; i++) {
For i.l = 0 To 12
; =============================================================================
; Se positionner sur les 4 octets suivants dans "in" et "out"
; =============================================================================
; in+=4; out+=4;
*pin + 4 : *pout + 4
; =============================================================================
; Recalculer "var2"
; =============================================================================
; var2=(var2<<3) | (var2>>(32-3));
var2left.l = var2 << 3
; Méthode assembleur => plus concise que la méthode PB
; var2right.l = var2
; !SHR dword [p.v_var2right], (32 - 3) ; Car le >> de PB garde le signe, ce que
; nous ne souhaitons pas
; Méthode PB => on reste en PB, pas besoin d'assembleur
var2right.l = (var2 >> 1) & %01111111111111111111111111111111 ; Retirer le bit de signe
var2right >> ((32 - 3) - 1)
var2 = var2left | var2right
; =============================================================================
; Calculer "var1"
; =============================================================================
; unsigned int var1=*((unsigned int *)in) ^ var2;
var1.l = PeekL(*pin)
!MOV eax, dword [p.v_var2]
!XOR dword [p.v_var1], eax ; Car PB n'a pas de OU exclusif binaire
; =============================================================================
; Quelques calculs avec "var1" et "i" dont le résultat est stocké dans les
; quatre octets courants de "out"
; =============================================================================
; *((unsigned int *)out)=(var1<<(i+2)) | (var1>>(32-(i+2)));
var3left.l = var1 << (i + 2)
decalage.b = (32 - (i + 2))
; Méthode assembleur => plus concise que la méthode PB
; var3right.l = var1
; !MOV cl, byte [p.v_decalage]
; !SHR dword [p.v_var3right], cl ; Car le >> de PB garde le signe, ce que nous ne souhaitons pas
; Méthode PB => on reste en PB, pas besoin d'assembleur
var3right.l = (var1 >> 1) & %01111111111111111111111111111111 ; Retirer le bit de signe
var3right >> (decalage - 1)
var3.l = var3left | var3right
PokeL(*pout, var3)
; }
Next
; }
EndProcedure
; Tester la procédure
If OpenConsole()
Dim in.c(55)
Dim out.c(55)
; Initialiser et afficher le contenu "in"
PrintN("Contenu du tableau 'in' : ")
For i.l = 0 To 55
in(i) = 255 - i
Print(RSet(Hex(in(i)), 2, "0") + " ")
Next
; Décoder
DecodeTp(in(), out())
; Afficher le contenu "out"
PrintN("")
PrintN("")
PrintN("Contenu du tableau 'out' : ")
For i.l = 0 To 55
Print(RSet(Hex(out(i)), 2, "0") + " ")
Next
Input()
CloseConsole()
EndIf
End
Je sais que ce topic est très long mais il soulève des aspects intéressants et surtout des solutions qui sont, somme toute, assez simples.
Pour ceux qui sont arrivés jusqu'ici, bravo ! Parce que je sais que les longs topics peuvents être rébarbatifs

Vous pouvez prendre une aspirine, vous l'avez bien méritée !!!
Pour une question située dans le forum "Débutants", je trouve qu'on est allé bien loin dans la technique de PB !!!
Si un modo trouve judicieux de déplacer ce sujet sur ASM, je comprendrai aisément
N'hésitez pas à me corriger ou me questionner si quelque chose vous paraît faux/erroné ou flou/pas clair.
On est tous ici pour apprendre et/ou enseigner
linkerstorm
NB : j'ai vérifié la validité de mon code en créant le code C correspondant
