[ - Intro - Explications - L'outil expliqué - Liens - Notes de fin - ] |
[
- Tutoriaux : Bases |
Je
vais aller un peu plus vite cette fois, car on a vu le principal avant.
Le désassemblage nous donne ceci :
//********************
Program Entry Point ********
:00401000
6A00
push 00000000
:00401002
6800304000
push 00403000
*
Possible StringData Ref from Data Obj ->"ENREGISTRE-MOI SINON JE ME FACHE
"
->"!!!"
|
:00401007
6812304000
push 00403012
:0040100C
6A00
push 00000000
*
Reference To: USER32.MessageBoxA, Ord:01BBh
|
:0040100E
E829000000
Call 0040103C
:00401013
6A00
push 00000000
*
Possible StringData Ref from Data Obj ->"Cour n"
|
:00401015
6837304000
push 00403037
*
Possible StringData Ref from Data Obj ->"Mon premier Crack : Le saut inconditionnel"
|
:0040101A
6850304000
push 00403050
Cette fois pas de test eax,
eax mais directement notre Nag-screen, suivi du programme.
Là, il s'avère
qu'on ne peut pas détourner une condition vu qu'il n'y en a pas
!
La solution envisageable
que nous avons vu précédemment est le NOP.
:00401000
6A00
push 00000000
:00401002
6800304000
push 00403000
:00401007
6812304000
push 00403012
:0040100C
6A00
push 00000000
:0040100E
E829000000
Call 0040103C
devient
:00401000
9090
nop ( 2 x )
:00401002
9090909090
nop ( 5 x )
:00401007
9090909090
nop ( 5 x )
:0040100C
9090
nop ( 2 x )
:0040100E
9090909090
nop ( 5 x )
Evidemment, ça marche
mais c'est lourd et pas très pro !
On modifie pas moins 19
bytes ! Il faut donc réfléchir et voir en assembleur ce qui
pourrait nous aider.
L'idéal serait de
pouvoir sauter toute cette partie : de 00401000
( début du Nag ) à 00401013
exclu ( début du programme ).
Que cela ne tienne, fesons
un saut sans conditions : un jmp ( jump )
On a vu précédemment
que pour un saut court, l'opcode était : EB+distance.
Pour avoir cette distance,
on va utiliser Jumpgen qui va se charger de nous donner l'opcode complet.
Lançons cet outil
et passons nos informations.
NB: ne prennez pas 68k à moins que votre processeur soit du style Motorola 68000 ce qui serait TRES étonnant ; )
Donc, on a EB11.
Fesons la modification sous
Hexworkshop et relançons le programme.
Ca marche...
Si on désassemble
notre programme cracké, cela donne la chose suivante :
//********************
Program Entry Point ********
:00401000
EB11
jmp 00401013 <===
notre saut
*
Possible StringData Ref from Data Obj ->"VILAIN NAG-SCREEN"
|
:00401002
6800304000
push 00403000
*
Possible StringData Ref from Data Obj ->"ENREGISTRE-MOI SINON JE ME FACHE
"
->"!!!"
|
:00401007
6812304000
push 00403012
:0040100C
6A00
push 00000000
*
Reference To: USER32.MessageBoxA, Ord:01BBh
|
:0040100E
E829000000
Call 0040103C
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401000(U)
|
:00401013
6A00
push 00000000 <===
notre saut et on atterit ici.
*
Possible StringData Ref from Data Obj ->"Cour n"
|
:00401015
6837304000
push 00403037
*
Possible StringData Ref from Data Obj ->"Mon premier Crack : Le saut inconditionnel"
|
:0040101A
6850304000
push 00403050
Toutes les instructions du
Nag-screen ont été sautées. Bref, c'est ce que l'on
voulait et en modifiant 2 bytes au lieu de 19 !
Petite chose : il vous est
inutile d'utiliser NOP pour complèter l'opcode.
Je m'explique ; ici, on
a :
00401000
6A00
push 00000000
devient
00401000
EB11
jmp 00401013
donc 6A00
---> EB11 parfait ( 2 bytes pour 2 bytes )
Mais si c'était push
00403012 ( 6812304000)
au lieu de push 00000000 (
6A00 ) :
00401000
6812304000
push 00403012
On aurait
00401000
EB11
jmp 00401013
00401002
304000
des instructions correspondantes à ces opcodes
Bref, on ne patche pas complètement
l'opcode original puisqu'on laisse des déchets ( 304000
).
On pourrait faire
00401000
6812304000
push 00403012
devient
00401000
EB11
jmp 00401013
00401002
909090
nop ( 3 x )
Notre opcode original est
complètement patché...
Mais c'est inutile !
A la lecture du programme,
quand les bytes EB11 apparaissent, il n'y a pas de problèmes, cela
correspond à notre saut. Peu importe qu'on est les opcodes suivants
qui soient détruits, la lecture ne tombera jamais sur eux !
Calculer soit-même l'opcode d'un saut court.
Jumpgen le fait très
bien et vous permet de choisir votre type de saut ( jmp, jnz, jz, ja, etc.
)
On a vu que pour les sauts
courts, on avait :
1 byte pour définir
le type de saut + 1 byte pour donner la distance.
ex :
EB11
= jmp+distance
7511
= jnz+distance = jne+distance
7411
= jz+distance = je+distance
Donc pour définir
notre type de saut, il faut se reporter sur le fichier help que je vous
ai mis dans le package.
Reste à calculer
la distance.
Si l'on reprend l'exemple
d'en haut, on doit faire un saut jump ( EB ) de 401000
jusqu'en 401013.
Calculons la distance entre
les 2 avec la calculatrice hexa / déci / bin d'hexworkshop.
401013
- 401000 = 13
Problème, on a vu
que Jumpgen nous donnait EB11 et non pas EB13.
Il y a une différence
de 2 bytes...
En fait c'est simple à
comprendre.
00401000 EBXX jmp 00401013
Quand la lecture de l'instruction
est faite et avant qu'elle soit exécutée, on est après EBXX
donc en 401002 !
C'est donc à cet
endroit que le saut se fait ( enfin pour être plus exacte que le
registre EIP va être incrémenté de notre distance ).
Donc 401013
- 401002 = 11.
On retrouve bien EB11
de Jumpgen.