=====================================================================
4 . Craking
=====================================================================
Voici
un hors-série tel que vous n'en avez jamais vu. Dans ce numéro spécial,
on va pas parler de " un peu " à " très " technique.
Ce Best Of Cracking est fait pour ceux qui, à force de lire ce mot, sont
démoralisé car il n'y pige rien. Au sommaire :
- Newbie: ASM
For Cracking: cours d'ASM
- Introduction au Reversing, le " Cracking
légal ".
- Création de votre propre KEYGEN pour DreamWeaver.
-
For Elite : le Cracking EXCLUSIF du système WFP (Windows File Protection)
sous Win 2000.
- CRACKING BIOS PASSWORD: comment craquer le mot de passe BIOS
?
Cette
série d'article est là pour vous tendre la main et vous faire grimper
la montagne qui vous sépare des débutants .
Ready for Cracking
? Let's go .
Salut les Toons. Pour débuter cet HS CRACKING, commençons cool par un petit cours sur l'ASM indispensable. Vous ne pourrez cracker bien sans ça. Ready? Let's go!
GENERALITES
---------------------------
-
Comment un cracker peut lire un programme et le modifier, indépendamment
de son langage originel?
Quand un programmeur réalise une application,
il l'écrit avec un langage ayant une syntaxe propre. Puis, il le compile,
c'est-à-dire qu'il transforme le code source spécifique au langage
en "code machine", ou assembleur. Le langage des processeur d'Intel
est l'assembleur ix86. Il y en a d'autre comme celui des Ti-92 (assembleur Motorola
68000). Nous, on va s'intéresse à l'assembleur i386, qui est quasiment
identique à celui de ix86.
- un fichier sur votre disque dur est "en
assembleur". En l'ouvrant sous Edit, vous n'aurez pas des instructions d'assembleur,
mais les caractères ASCII correspondants à celle-là. Pour,
pouvoir traduire le programmeur en code machine compréhensible par l'homme
,il faut un "désassembleur". On va utiliser le meilleur, W32Dasm
8.9, qui permet de désassembler
les applications Windows.
- A l'époque
de MS-DOS (et des Goupils tout naze), le système d'exploitation avait une
bibliothèque d'interruption à disposition des programmes. AInsi,
le fonction 9 de l'interruption 21h permet afficher un message à l'écran.
Sous Windows, pour faire une comparaison TRES grossière, l'API remplace
les interruptions. ex: la fonction de l'API GetWindowText(HWND, LPTSTR, int) copie
le texte d'un contrôle vers un buffer.
- Pour comprendre comment marche
un programme déjà compilé, il faut un désassembleur.
Mais un débuggeur permettant d'exécuter les instructions en assembleur
pas-à-pas, du style Turbo débuggeur (de Borland). Le meilleur est
Soft-Ice. On exécute le programme, et, par une simple combinaison de touches,
on le stoppe quand on veut. Le crackeur peut placer des "breakpoints"
pour que le programme s'arrête s'il exécute une certaine action (comme
l'affichage d'un message d'erreur parce qu'on a rentré le mauvais numéro
de série:). Sous Windows, on peut le faire sur n'importe quel programme
avec le multitâches. Les breakpoints sont donc indispensable parce qu'on
on n'est pas sur, quand on exécute Soft-Ice, que le processus en cours
appartient au programme à craquer. on reviendra dessus plus tard.
FONCTIONNEMENT
D'UN ORDINATEUR
------------------------------------------------------------------------
L'alphabet
d'un ordinateur est limité à 0 et 1 qui correspond à un état
électrique, éteint, allumé, état qui est représenté
par un bit. Pour étendre les possibilités, on les réunis
ensemble pour former un octets (ou BYTE, 8 bits), un mot (ou WORD, 16 bits) ou
un double mot (ou DWORD, 32 bits). Le processeur doit exécuter des données
numériques ou des caractères (l'ensemble des caractères et
de leur combinaisons est appelé la SEQUENCE ASCII) via des instructions
(un ensemble d'instruction est appelé un "set" d'instructions).
**DONNES
NUMERIQUES**
C'est plus complexe pour elles. Sur un byte (ou octet) on pourrait
représenter 256 (2^8) nombres mais ce n'est pas suffisant. Il faut ensuite
que le système puisse supporter les opérations arithmétiques,
les nombres négatifs...
**LE BINAIRE**
On connaît la base
10 ou décimale qui permet d'obtenir tous les nombres souhaités en
combinant simplement une série de chiffres entre 0 et 9. Pour le binaire,
on a que deux signes : 0 et 1, on est donc en base 2. La méthode est de
combiner une série de 0 et 1, puis multiplier cela le plus à droit
pas 2^0, et, de gauche à gauche, par 2^1, 2^2... ce qui donne
base 2
base 10
00000011 = 1 = 1*2 + 1*1
00001011 = 11 = 1*8 + 0*4 + 1*2 + 1*1
00011011
= 27 = 1*16 + 1*8 + 0*4 + 1*2 + 1*1
(2^0 est toujours égal à
1, mais si en plus vous ne connaissait pas les maths ;)
Sur 1 Byte (8 bits),
le nombre maximum qui peut être représenté est: 11111111 =
255 = 2^8-1. Pour avoir plus, on devra utiliser plusieurs bytes et on aura cette
forme : ((2^nb de bits)-1). ex: 2^32-1 pour 4 bytes...
**LES NOMBRES NEGATIFS**
Pour
les nombres relatifs, comme on a que deux possibilités (+ ou -), le signe
sera déterminé par 1 bit. On admet alors que, par convention, le
bit de fauche d'un ensemble de bits sera le bit de signe : 1=+ et 0=-. On a donc
2^7 bits représentables pour un bytes, 2^15 pour un WORD... donc 2^(nb
bits - 1) représentables.
**L'HEXADECIMAL**
Une dernière notation
est l'hexadécimal, en base 16. Comme on travaille en souvent avec des chiffres
sur 2 bytes (16 bits), on est sujets à moins d'erreurs en prenant une base
16, ce qui réduit la quantité de chiffres à manipuler. 16
étant une puisse de 2, la conversion binaire/hexa est simple : à
quatre signe binaires correspond un signe hexa. Comme on a que 10 chiffres les
autres seraient les 6 premières lettres de l'alphabet soit A(=10),B(=11),C(=12),D(=13),E(=14),F(=15)
et 10h=16 (h veut dire hexa). exemple : 9h=09;10h=0A;11h=0F
**LA MERMOIRE**
C'est
une série d'emplacement numérotés contenant chacun un nombre.
Le numéro d'un emplacement (un byte) est une adresse. Sur les PC, la mémoire
est divisée en zone de 65536 bytes appelées segments. L'adresse
d'un byte comporte alors deux éléments : un numéro de segment
et un déplacement ou offset calculé par rapport au début
du segment; on a donc: Segment:Offset.
exemple : 0A000H :00000H (adresse de
la mémoire vidéo). Le microprocesseur peut soit consulter soit modifier
le contenu d'un emplacement, c'est tout. Les adresses sont toujours numérotés
L'ASSEMBLEUR
------------------------------
Une
instruction ASM s'appelle une "mnémonique". Le processeur travaille
avec des registres.
---1. Les registres---
Ce sont des petits emplacements
mémoire dans le processeur qu'il manipule comme le veut le programmeur.
Normalement, leur taille est 16 bits (8 bits=1 octet). Avec les 386, ils font
32 bits. Pour utiliser les 32 bits, il faut placer un "E" avant le nom
du registre. Il y a 4 classes de registres:
a)
Les registres de travail (ax, bx, cx, dx)
ax : l'accumulateur, pour les opérations
arithmétiques
bx : registre de base
cx : le compteur, pour les instructions
de boucles, du genre "loop"
dx : le registre de "data"
chak1
est divise en 2: ax en al et ah, bx en bl et bh, etc
b)
Les registres de segment
CS : code segment. Il contient l'adresse du segment
de mémoire qui contient le code machine
DS : data segment. Il contient
l'adresse du segment ayant les data du programme
SS : stack segment. Il contient
l'adresse du segment de pile
ES : extra segment. Il contient l'adresse d'un
segment supplémentaire
c)
Les registres d'offset
Ces 5 registres contiennent une valeur à combiner
avec un registre de segment pour former une adresse mémoire segment:offset
SI
: source index, pour les opérations sur les chaînes de caractères.
Il est associé à DS pour former l'adresse DS:SI
DI : destination
index. associé à DS ou à ES pour opérations sur les
chaînes de caractère.
IP : Instruction pointer. associé
à CS pour pointer sur l'1struction suivante à exécuter. Impossible
à modifier directement.
BP : base pointer. Associé à SS,
il permet d'accéder à la pile (stack) lors d'appels de sous programmes.
SP
: associé à SS, SS:SP indique le dernier élément de
la pile.
d)
Le registre de flags
- Le registre FLAG est un registre d'état. Il sont
utiliser lors de saut conditionnel entre autres. Ce registres est manipulé
bit par bit, chaque bit étant appelé "indicateurs". On
des indicateurs d'état et de contrôler. Voyons la signification de
chaque bit:
- Indicateurs d'état
0 : "Carry" : CF. Il est
mis à 1 s'il y a eu retenue lors de la dernière instruction arithmétique.
2
: Parité : PF. Il est mis à un si le résultat d'un opération
contient un nombre pairs de bits 1.
4 : Retenue auxiliaire : AF.
6 : Zéro
: ZF. Il est activé si le résultat d'une opération donne
0 et le restera jusqu'à la prochaine opération.
7 : Signe : SF.
Il est activé si le résultat d'une opération donne un nombre
négatif.
11 : Overflow : OF. Il est mis à 1 si le signe d'un
opération change alors qu'il ne devrait pas. ex: 2+2 = -4.
- Indicateur
de contrôle
8 : Trap : TF.
9 : interruption : IF.
10 : direction
: DF. Il est modifié par une instruction CLD ou STP (on verra, pas de souci...)
Un registre écrit entre crochets ne représente pas un suite de bits,
mais le contenu d'une adresse qu'il pointe.
Les registres a 32 bits on un E
devant leur nom (EAX, EBX, ECX, EDX). Remarquons que AX= 655365 au maximum et
AL=255, de plus la partie haute du registre ne peut être modifiés
séparément. Donc, on n'aura jamais EBH ou ECL. Les 3 autres catégories
de registres n'ont pas de partie 8 bits et peuvent être étendus à
32 bits en précédent leur nom d'un "E" également.
Il existe deux types de programmes (on verra cela plus tard) : les COM et les
EXE. La différence est qu'un COM ne peut utilsier pas plus d'un segment
de la mémoire (64K) et donc les 4 registres CS, DS, SS, ES ont la même
valeur. Les EXE, eux, peuvent travailer avec plusieurs segments. Passons maintenant
aux instructions de base.
---2. Les instructions de base---
*
L'instruction la plus connue est sans doute l'instruction MOV. Elle permet de
copier (et non pas déplacer) le contenu d'un registre dans un autre, ou
de copier un nombre dans un registre, etc
forme : mov dest,src
ex
: mov ax,bx copie le contenu de bx dans ax
mov bx,4 met "4" dans
bx
mov
[bx],4 : met 4 à l'adresse sur laquelle pointe bx. Le problème est
que on ne sait pas si "4" doit être considéré comme
un
octet, deux octets, 4 octets... Lorsque l'on fait mov bx,4 on sait que l'opération
se fera sur 16 bits, car c'est la
taille du registre bx. Ici, il faut préciser
comme suit :
mov byte ptr [bx],4 ou
mov word ptr [bx],4
un word = un mot, c'est à dire deux octets (bytes)
*
L'instruction CMP
Elle compare des registres ou des emplacements de mémoire.
Selon le résultat, elle va changer quelques indicateurs. Si les
deux
opérandes sont égaux, par exemple, le zéro flag va entre
autre être mis à zéro. On pourra gérer ce résultat
par un saut
conditionnel.
ex : cmp ax,bx
*
Les instructions INC et DEC
Ajoute 1 à la valeur d'un registre. L'instruction
dec fait l'inverse
inc ax
*
L'instruction ADD
add ax,bx ajoute à ax le contenu de bx
*
L'instruction NOP
Nop veut dire non opérate (c'est aussi un super cracker
;), le processeur ne fait rien et l'ignore. Elle est tres utile pour
patcher
certaines instructions gênantes dans un logiciel.
*
L'instruction AND
Elle effectue un ET logique en traitant les deux opérandes
bit à bit... Un et logique donne 1 si les deux opérandes sont à
1
* L'instruction
OR
Elle effectue un ou logique. Elle retourne 1 si un des deux opérandes
est à 1.
Elle est souvent utilisée pour tester qu'un registre
est à 0. Or ax,ax ne renvoie 0 dans ax que si tous les bits de ax sont
à
zéro. Le zéro flag est affecté, et permet un branchement
conditionnel.
*
L'instruction XOR
Elle effectue un ou exclusif. Il faut que l'un des bits soit
à 1, mais pas les deux.
*
L'instruction TEST
Elle effectue un ET logique, mais ne modifie pas les opérandes.
Seuls les indicateurs le sont. C'est un excellent moyen de
vérifier
qu'un registre est à zéro. (par test eax, eax par exemple)
---3.
Les instructions de branchement---
*
L'instruction JMP
Elle effectue un saut à l'adresse spécifiée.
Le programme continuera son exécution à l'adresse spécifiée.
Elle est
l'équivalent de la commande goto des langages de haut niveau.
*
L'instruction CALL
Elle appelle un sous programme à l'adresse spécifiée.
Celui-ci doit se terminer par une instruction RET qui dira au
processeur de
reprendre le programme après le dernier CALL.
*
Les sauts conditionnels
Ils testent les flags pour savoir si un saut doit avoir
lieu ou non.
JE
ou NZ : saute si le zéro flag est à 1
JNE ou JNZ : saute si le
zéro flag est à 0
CMP
ax,bx met le zéro flag à 1 si les deux registres ont la même
valeur
JE 12345 saute à l'adresse 12345 si le zéro flag est à
1
Il y a BEAUCOUP d'autres sauts conditionnels. Mais je ne peux tous vous les détailler ici.
---4. La pile---
La
pile est une zone mémoire qui sert à stocker temporairement des
données. On peut rajouter une donnée en l'empilant, et en
lire
une en la dépilant. On ne peut donc que lire la dernière donnée
sur la la pile. C'est une structure de type LIFO : Last In First Out. Le dernier
élément de la pile est à l'adresse SS:PP. Il ne faut pas
modifier PP directement, il faut utiliser les instructions d'empilage et de dépilage.
L'instruction d'empilage est push push ax ajoute la valeur de ax à la pile
L'instruction
de désempilage est pop pop ax met dans ax la valeur du dernier élément
de la pile
====================
Voilà,
j'espère que vous vous êtes un peu familiarisé avec l'assembleur.
Pour commencer à cracker, vous n'avez pas besoin de
connaître
tout ce cours. Achetez un livre de référence sur l'assembleur et
vous apprendrez au fur et à mesure, en craquant.
Pas de souci, le prochain
article sera "CRACKING : PAS A PAS". Faites moi confiance, je viens
de cracker Paint Shop Pro 7.02 et Winzip 8 ;-)
D'ailleurs, on est parti pour
une première approche de cracking.
Le cracking est l'art de déplomber des logiciels protégé ou limité en contournant le système de protection. Ne vous êtes-vous jamais demandé comment certains hackers font pour avoir les numéros de série de certains logiciels ? Il est possible de récupérer le code d'enregistrement dans le programme. Cette technique s'appelle le reversing. Démonstration.
INTRODUCTION
--------------------------------
La
cracking a pour but de contourner les protections par code d'enregistrement ou
par "time limit", dispositif intégré dans le logiciel
qui le bloque au bout d'une certaine période d'essai. En cracking, on distingue
deux types d'attaques différentes:
- le dead listing, qui consiste à
inverser la routine de vérification d'un numéro de série,
en faisant passer tous les mauvais pour des bons (et donc le seul bon pour tous
les mauvais!)
- le patching dont le but est de désactiver tout ce qui,
dans le programme, l'assimile à un shareware (nom inconnu, nag screen...)
pour feinter le logiciel qui croira qu'on lui a donner le numéro de série
et donc qu'il se débloquera tout seul.
Tout cela demande d'analyser
le programme en assembleur. Cela reste légal tant qu'on s'adonne à
ces arts dans un cadre strictement personnel. Le reversing, lui, a pour but de
s'infiltrer dans le programme pour déniche et décoder le serial
number (et ce n'est sûrement pas en lisant des revues qui en jettent pleins
la vue et tête de mort se mêlent avec les BD qu'on y parviendra).
Pour
cela, il faut une protection simple, c'est-à-dire un code qui est toujours
le même (les autres protections, c'est pas la même sauce...) Avant
de foncer directement dans le tas tête baissée, on va d'une part
examiner une méthode de cracking d'un programme, simple, classique, que
connaît pour crackeur qui se respecte (crackeur de son propre logiciel dans
le but de s'en faire une copie de sauvegarde, évidemment, et à des
fin strictement personnel), puis, on abordera la technique du reversing.
METHODE
UN
--------------------------
La victime de notre attaque sera le logiciel
Task Lock 3 qui contient un simple serial number en guise de protection. C'est
un logiciel vieux, ce qui évitera le piratage idiot que certains pourrait
faire suite à la lecture de cet article (ce type de protection est de plus
en plus bannie pour sa flagrante inutilité) ; de toute façon, le
but est uniquement de comprendre la méthode. Nous aurons besoin de l'un
des plus puissants débuggeur au monde : SoftICE.
Evidemment, on arrivera
à rien si l'on ne récupère pas quelques infos indispensable
sur le logiciel-cible, sur sa nature, sa structure et l'agencement de sa protection.
Dans notre recherche, on apprend entre autres que c'est une application 32 bits
tournant sur Windows 9x et, dans le menu Register, une boîte de dialogue
nous demande le code d'enregistrement. Dans l'aide on apprend qu'il est possible
de s'enregistrer soit individuellement, soit en plate-forme, donc on aura logiquement
deux recherches à effectuer pour cracker le programme.
Le moins idiot
est de poser un points d'arrêts (on suppose que nos lecteurs savent se servir
d'un debugger... un point d'arrêt, ou breakpoint, et un sorte de repère
que l'on implante dans le logiciel sur une fonction précise et qui se déclenche
quand cette fonction est activée, afin de dénicher où elle
est appelée et ainsi de pouvoir falsifier la routine de vérification
de mot de passe, par exemple) sur la fonction "GetDlgItemtext" (...
et qu'il connaissent les API Windows, bref qu'il ne soient pas des abrutis en
informatique). SOus SoftICE, pour agir ainsi, utilisez la commande "BPX +
le-nom-de-la-fonction-ou-de-son-adresse-mémoire" :
:bpx getdlgitemtexta
Si
un message d'erreur (du style "No LTD") apparaît, c'est qu'une
tierce application tournent en tâche de fond. La commande "bl"
permet d'afficher la liste des breakpoints.
Voila : ce point d'arrêt
interceptera tous les appels de la fonction GetDlgItemtextA. Comme celle là
permet d'afficher une boîte de dialogue, elle bloquera le programme avant
qu'il n'affiche le message d'erreur pour nous informer que le numéro de
série est invalide. On repèrera ainsi l'endroit approximatif où
est validé le serial. Donc, maintenant, sous Task Lock, tentons un code
et... ça marche (sinon, c'est que notre breakpoint pointe une mauvaise
fonction).
Parenthèse : pour supprimer le breakpoint, il faut utiliser
la commande
: bc 0
et pour le réactiver, remplacez "bc"
par "be".
Dirigeons-nous alors vers l'endroit où la fonction est appelée par
F11 : nous sommes dans SGLSET.EXE.
La première ligne dans la fenêtre
de code doit avoir cette allure :
CALL [user32!GetDlgItemTextA]
Déplacez-vous
via Ctrl + HAUT. J'ai mis des commentaires, mais vous avez intérêt
à apprendre l'assembleur si vous êtes à la rue... sinon :
pas d'assembleur pas de cracking et pas de reversing :(
RET
PUSH EBP // début de la fonction
MOV EBP, ESP
SUB ESP
PUSH ESI
LEA EAX, [EBP-34] // EAX = EBP - 34
PUSH EDI
MOV ESI, ECX
PUSH 32 // sauve la longueur max. acceptée
PUSH EAX // sauve la valeur
EAX
PUSH 000003F4 // sauve l'identificateur de contrôle
PUSH DWORD
PTR [ESI+1C]
CALL [user32!GetDlgItemTextA] // appel de la fonction
On
note que le texte est sauvegardé en EAX et que EAX est égal à
EBP - 34. Donc, regardons la valeur "EBP - 34" en tapant :
:d ebp-34
La valeur s'afficher dans la fenêtre de données. Maintenant,
il faut dégotter l'endroit où notre code est comparé au code
valable pour enregistrer le logiciel. Donc, on remonte dans le programme, instruction
par instruction via F10 jusqu'à ce que l'on trouve quelque chose à
propos de EBP-34 ... On obtient très vite ça :
LEA
EAX, [EBP+FFFFFF64] // EAX = EBP-9C
LEA ECX, [EBP-34] // ECX = EBP-34
PUSH
EAX
PUSH ECX
CALL 00403DD0 // appel une fonction
ADD ESP, 08 // efface
l'info sauvée
TEST EAX, EAX
JNZ 00402BC0 // (JNZ = Jump if Not Zero)
: saute à l'adresse 00402BC0 si différent de 0
On a une comparaison de chaîne de caractères fonctionnant ainsi :
si les chaînes sont égales, le flag passe à 0, sinon non.
C'est ici que les codes d'enregistrements sont comparés.
Calculons ce
qui se cache derrière notre valeur, [EBP+FFFFFF64]. SoftIce gérant
très mal les nombres négatifs, donc, il faut le faire manuellement.
Un peu de connaissance en hexa et on obtient :
100000000 - FFFFFF64 = 9C
Pour
savoir se qui se cache derrière EBP-9C, tapons:
: d ebp-9c
La fenêtre
de données nous donne une longue suite de nombre: c'est le bon code. Mais,
si vous avez suivi, on a dit qu'on avait deux types d'enregistrements donc deux
serials. Par conséquent, après avoir noté le code obtenu,
on remonte avec F10 encore jusqu'à obtenir autre chose concernant EBP-34,
et finalement on arrive à ça:
LEA
EAX, [EBP-68] // EAX = EBP - 68
LEA ECX, [EBP-34] // ECX = EBP - 34
PUSH
EAX // sauve EAX
PUSH ECX // sauve ECX
CALL 00403DD0 // appel une fonction
ADD ESP, 08 // efface l'info sauvegardée
TEST EAX, EAX
JNZ 00402BFF
// saute si différent de 0
Et à l'adresse EBP-68 on trouve quoi? Mais oui, notre code d'enregistrement. Il ne reste plus qu'à le faire. Tout devrait fonctionner.
METHODE
DEUX
-------------------------------
Nous venons de voir comment craqué
facilement un programme. On va voir maintenant comment obtenir le code d'enregistrement
légal du logiciel. Entendons-bien : ce n'est pas du cracking, mais du reversing
: examiner le programme, sans le toucher, afin d'y récupérer le
numéro de série. Bien sûr, cela n'est à faire que sur
vos propres logiciels. A bon entendeur...
Changeons. Le programme-cible, cette fois, est Command Line 95. C'est une application
32 bit avec un code d'enregistrement tout bête. On fait comme Tasklock pour
les breakpoints, on en pose deux : à la fois sur GetWindowTextA et sur
GetDlgItemTextA
: bpx getwindowtexta
: bpx getdlgitemtexta
Allez
vous enregistrer et le programme bloque sur GetDlgItemTextA. On se sert de F11
pour retourner à la fonction d'appel. Ensuite, on se sert de CTRL + HAUT
pour arriver au code suivant :
MOV
ESI, [ESP+0C] // longueur max.
PUSH 1E
PUSH 0040A680
PUSH 000003ED
PUSH
ESI
CALL [User32!GetDlgItemTextA] // appel de la fonction
Le
nombre 40A680 semble intéressant, voyons sa valeur :
: d 40a680
Dans
la fenêtre de données, on obtient, si un nom n'est pas saisi :
PUSH
00
PUSH 00
PUSH 000003F6
MOV EDI, 0040A680
PUSH ESI
CALL [User32!GetDlgItemInt]
// appel de la fonction (elle est similaire à GetDlgItemText)
Cette
fonction nécessite une référence de la boite d'édition.
Il est stocké en EAX et si l'on regarde la fenêtre de registres,
on peut lire :
EAX = 00003039
Convertissons le chiffre hexadécimal
3039 via la commande :
: ? 3039
et l'on s'aperçoit que cela vaut
"0000012345" en Déc et "09" en ASCII : c'est le code
"bidon" qu'on a entré tout à l'heure. Dans le suite de
logiciel, on remarque que ce code est sauvegardé:
MOV
[0040A548], EAX
MOV EDX, EAX
En dessous, on note que le code est calculé...
MOV
ECX, FFFFFFFF // calcul de la longueur de la chaîne
SUB EAX, EAX //
REPNZ
SCASB //
NOT ECX //
DEC ECX // ECX contient la valeur de la longueur
MOVSX
EAX, BYTE PTR [0040A680]
IMUL ECX, EAX // ECX = ECX * EAX
SHL ECX, 0A //
décalage logique à gauche de 0A
ADD ECX, 0002F8CC // ajoute
2F8CC au résultat
MOV [0040A664], ECX
... puis validé.
CMP
ECX, EDX // comparaison des codes
JZ 00402DA6 // si égal à 0,
saut
Pour
connaître, le code, il suffit donc de connaître, non la valeur de
EAX, mais de ECX :
: ? ECX
Pour notre code, ça donne : "0000901324".
Donc le bon code est : 901324. Enregistrez-vous avec celui-là et... ca
roule.
LA
MORALE
----------
C'est archi simple. Il suffit de rentrer un code bidon,
de repérer l'endroit où il est utilisé dans le programme
et de le suivre pour voir ce qu'il devient. C'est pas compliqué, mais très
utile pour comprendre l'architecture d'un programme en assembleur. Donc, la solution
est : NE CRACKER PAS, faites du reversing sur votre propres programmes, c'est
pas trop dur et instructif. Evidemment, quand on s'en prend à des logiciels
plus commercial, du style Paint Shop Pro et compagnie, ce n'est plus une mince
affaire... mais, vous le constaterez bientôt, rien n'est impossible. L'architecte
des Twin Towers l'a très bien compris: rien n'est indestructible ;)
***************
Question
: Comment faire pour planquer des fichiers sur Internet quand on ne possède
pas de site ?
Réponse : utiliser les FTP de prestigieuse université
(allemande et anglaise) qui n'ont AUCUNE protection FTP. Jugez plutôt:
ftp.rz.uni-wuerzburg.de
(université allemande)
ftp.mcc.ac.uk (Manchester Computing - Royaume-Uni)
ftp.gwdg.de
(Univ allemande )
ftp.cs.ubc.ca (Computer Science University of British Columbia)
Ces
trois sites acceptent n'importe quel anonyme se balader sur leur site... Sympa,
les gars! Mieux que Microsoft, faut faire fort!
Vous
connaissez les numéros de séries juste pour les récupérer
sur le Web pour vos programmes... Mais comment ça marche, en fait? Voici
l'ultime article bilan sur les Sérial Number.
I.INTRODUCTION
----------------
De nos jours, l'idée de gratuité n'existe plus. Chaque développeur
protège donc ses progs afin de se faire de l'argent en les diffusant en
version shareware en général.
IL faut bien faire la différence
entre version d'essai transformable en version complète, de la version
de démonstration, qui n'est (théoriquement) que tout ou partie de
la version licenciée.
En général, il suffit d'entrer
un sérial dans la boîte d'enregistrement pour transformer le shareware
en version définitive. Ce sérial peut se communiquer par téléphone,
courrier, mail...
Il y a différents types de shareware :
-les times
limits (version d'essai à durée déterminée):le prog
est utilisable pendant une période limite (en général 30
jours, 1E en hexa)
-les fonctions désactivées ou manquantes:
le prog n'est pas utilisable dans son intégralité.
Le sérial
peut être composé d'une combinaison numérique, alphabétique,
alphanumérique ou de chaîne séparé par des tirets (-).
Il peut être unique ou personnalisé à partir des critère
Nom: un code différent est généré pour chaque user.
Des logiciels comme Super Snooper lisent toutes les chaînes alphanumériques
contenues dans un exécutable afin de dégotter le serial sans avoir
a éditer le prog avec un logiciel hexa.
Prenons le cas du programmes DreamWeaver.
Le code est en toute lettre, non
codé, dans l'exécutable. A défaut de Super Snooper, un désassemblage
de DreamWaever.exe avec Wdasm me donne ce sérial dans l'une des "
String data références " !
Dans certain cas, le programme va attendre l'entrée d'un numéro de série comportant des caractères spéciaux, comme les séparateurs (-):
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409850(U)
|
:0040983A
3BCF cmp ecx, edi -> edi = nombre de caractères du code
:0040983C
7314 jnb 00409852	 -> jump vers vérification du code
:0040983E
803A2D cmp byte ptr [edx], 2D -> recherche de " - "
:00409841
7506 jne 00409849 -> sinon continue
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409847(C)
|
:00409843
42 inc edx -> caractère suivant
:00409844 803A2D cmp byte ptr [edx],
2D -> [edx] = notre code
:00409847 74FA je 00409843 -> boucle
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409841(C)
|
:00409849
8A02 mov al, byte ptr [edx]-> un caractère dans AL
:0040984B 41 inc
ecx -> compteur de boucle
:0040984C 42 inc edx -> caractère suivant
:0040984D
8841FF mov byte ptr [ecx-01], al -> réécrit le code ailleurs
:00409850 EBE8 jmp 0040983A -> boucle
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040983C(C)
|
:00409852
53 push ebx
:00409853 C60100 mov byte ptr [ecx], 00
:00409856 6A32 push
00000032
:00409858 8D4E44 lea ecx, dword ptr [esi+44]
:0040985B E885CF0100
call 004267E5
:00409860 50 push eax -> notre UserName
:00409861 8BCD
mov ecx, ebp
:00409863 E8088DFFFF call 00402570-> calcul du sérial
number :)
:00409868 8BF8 mov edi, eax
:0040986A 6AFF push FFFFFFFF
:0040986C
8D4E44 lea ecx, dword ptr [esi+44]
:0040986F E8B2CF0100 call 00426826->
comparaison avec notre code
:00409874 85FF test edi, edi
:00409876 0F84C200000je
0040993E-> vers " code invalide "
:0040987C 53 push ebx début
de code valide
:0040987D 8BCD mov ecx, ebp
:0040987F C785F400000001000000
mov dword ptr [ebp+000000F4], 00000001
:00409889 C785F800000000000000 mov dword
ptr [ebp+000000F8], 00000000
* Possible StringData Ref from Data Obj ->"RegistrationKey"
En
0040983A, la cible va vérifier que ce code comprend bien des "-"
-> cmp byte ptr [edx],2D
(2D étant égal au symbole "-").
Donc notre code doit en comporter (deux précisément). Si vous entrez
un numéro de série du genre "1234-1234-1234", vous passerez
tous ces tests avec succès.
Un peu plus loin un call 00402570 va calculer
le numéro de série d'après le nom que vous aurez entré.
A suivre, vous verrez un call 00426826. C'est lui qui va contrôler la validité
de votre code, et en cas d'inexactitude, créer un branchement par un je
0040993E -> code invalide
Si on inverse le saut (je -> jne), on verra
avec plaisir le bel écran "Code accepté". Pour autant
vous n'aurez pas trouvé la solution, mais seulement comment ne pas arriver
dans la routine "Code Invalide".
III.LES
BOITES D'ENREGISTREMENT
--------------------------------
La saisie du sérial
se fait majoritairement par le biais d'une boite d'enregistrement comportant autant
de champs que de données à entrer (Nom, Compagnie, Numéro
de série...). Bien souvent, un message "Code invalide" sanctionnera
l'entrée d'un sérial erroné. L'accès à cette
boite l'enregistrement pourra être proposée de façon systématique,
et apparaîtra à chaque lancement de l'application, être accessible
par l'un des menus de la barre des tâches du programme, soit directement,
soit via le menu "A propos", ou par une combinaison de touche. L'accès
à cette boite pourra dépendre de l'état d'un drapeau Utilisateur
Licencié ou non.
Les
boites d'enregistrement les plus usuelles peuvent être classées en
quatre catégories:
- les boites à champ unique
- les boites
à champs multiples
- les boites sans bouton de validation
- les boites
sans écran de validation
IV.
ARCHITECTURE
----------------
La saisie du ou des champs
Une fois les
informations demandées entrées dans les champs de la boite d'enregistrement,
le programme va s'occuper d'en saisir le contenu. Pour cela, il va utiliser des
API Windows comme
Hmemcpy
GetWindowText
(A)
GetDlgItemText (A)
Reference To: USER32.GetDlgItemTextA, Ord:00EDh |
:0040980B
FF15DCAA4400 Call dword ptr [0044AADC] -> saisie d'un champ
:00409811 83F80E
cmp eax, 0000000E -> 14 caractères
:00409814 8BF8 mov edi, eax ->
pousse le nombre de caractères entrés dans edi
:00409816 0F8C35010000
jl 00409951 -> jum vers " code invalide "
"* Possible StringData
Ref from Data Obj ->"0123456789ABCDEF-" |
:0040981C 6854624400
push 00446254 -> push le bon sérial
:00409821 53 push ebx -> push
notre code
:00409822 E8BD020100 call 00419AE4 -> compare des deux
:00409827
83C408 add esp, 00000008 -> dépile
:0040982A 3BC7 cmp eax, edi ->
vérifcationn du code
:0040982C 0F851F010000 jne 00409951 -> s'il
est mauvais... " code invalide "
Dans
cet exemple, la saisie se fait par GetDlgItemTextA, et à la sortie de cette
API, le programme contrôle que le code comprend bien 14 caractères
(0E en hexa), et sinon file en procédure code_invalide. Ensuite, les push
ebx et 00446254, qui poussent notre code sur la pile, vont être comparé
dans le call suivant...
Dans un listing désassemblé, une recherche
sur la chaîne GetWindowTexta (par exemple), ou en consultant la liste des
fonctions importées, peut permettre de localiser la routine de saisie du
sérial, tout en sachant que cette API peut également être
utilisé par d'autre boite de dialogue.
Le code que vous avez entré va être saisi par le programme. Pour cela il fait presque toujours appel à Hmemcpy, l'une des API Windows, qui elle même peut-être appelée par GetdlgItemText(A), ou GetWindowText(A). Des breakpoints (à l'aide du logiciel Soft-Ice) posés sur ces deux dernières fonctions Windows donnent souvent de bons résultats, mais Hmemcpy à l'avantage. Quand vous tapez un Bpx hmemcpy, vous vous "enfoncez" loin dans les procédures Windows, et il n'est pas rare d'avoir à taper une douzaine de fois sur F12 pour finir par quitter le dernier Kernel, le dernier User, et enfin revenir au programme sur lequel votre intérêt s'est porté.
Une fois saisi, votre code va être mis dans un registre, et plus souvent dans une adresse mémoire du genre [00407632], ou [ebp-14]... Il faut toujours être curieux de ce qui peut se trouver dans ces adresses, et ne pas hésiter à taper un "d ebp-14", pour en interroger le contenu qui s'affichera dans la fenêtre des Datas de Soft-Ice.
Il y a ensuite les API de traitement des Strings:
lstrcmpiA
GetFileAttributesA
lstrcpyA
DeleteFileA
lstrcmpA
(Suivant
la structure de l'application (16 ou 32 bits), il faudra, ou non, inscrire le
"A" à la fin). Sans chercher à détailler ce que
font chacune de ces API, voici un exemple pour la fonction lstrcpyA. Elle compare
deux chaînes de caractères ("Case Sensitive"), et retourne
une valeur.
int
lstrcmp
LPCTSTR lpString1 // adresse de la première string
LPCTSTR
lpString2 // adresse de la seconde string
Paramètres
lpString1 ->
Pointe sur la première chaîne non nulle à comparer.
lpString2
-> Points sur la seconde chaîne non nulle à comparer.
Cela
se traduira par une routine de ce genre ci:
0157:004011DD 50 PUSH EAX <-
pousse votre code sur la pile
0157:004011DE 6830604000 PUSH 406030 <- pousse
le bon code sur la pile
0157:004011E3 FF1520924000 CALL [KERNEL32!lstrcmp]
<- les compare
0157:004011E9 85C0 TEST EAX, EAX <- vérifie si
ils sont identiques
0157:004011EB 0F8580000000 JNZ 00401271 <- va en code
invalide
je vous laisse imaginer l'intérêt qu'il y a à faire un "d eax" et un "d 406030" avant le call lstrcmp...
**La
vérification du format**
Suivant la forme des caractères attendus
dans les champs de la boite d'enregistrement, le programme va vérifier
la validité des chaînes saisies. Ainsi, il pourra contrôler
la présence, ou non, d'informations dans ces champs, et leurs formats.
Comme il est rare que votre "vrai" nom contienne des ! ou des chiffres,
la routine de contrôle se branchera sur la procédure adéquat,
et pourra générer un message d'erreur. Il en sera de même
si le numéro de série attendu est essentiellement de type alphabétique
alors que vous avez inscrit un sérial numérique. Il peut également
être attendu un ou plusieurs séparateurs (-), et finalement la longueur
de votre nom, ou du numéro de série peut être contrôlé.
:0040788D
:0040788F
:00407891
:00407893
:00407895
:00407897
:00407899
:0040789B
:0040789C
:0040789D
:0040789E
:004078A0 8A02
3C61
7206
3C7A
7702
2C20
8806
42
46
4B
85DB
75EB mov al, byte ptr
[edx]
cmp al, 61
jb 00407899
cmp al, 7A
ja00407899
sub al,20
mov
byte ptr [esi], al
inc edx
inc esi
dec ebx
test ebx, ebx
EXPLICATIONS:
jne
0040788D Prend une lettre dans [edx], et met là dans al. On compare al
avec 61h (soit le "a" minuscule ASCII). On jump vers la procédure
00407899 si al est inférieur à 61h ou vers la procédure 00407899
si supérieur. On enlève les espaces si on en trouve ( 20h = "
"). O place al dans [esi] afin de reconstruire une chaîne ailleurs
edx=edx+1
(incrémente edx pour la lettre suivante)
esi=esi+1 (incrémente
pour la deuxième chaîne)
ebx=ebx-1 (ebx = nombre de caractères
du code )
ebx est-il égale à zéro (plus de lettres à
lire ?)
On recommence si ça n'est pas le cas, ou on continue.
Vous aurez remarqué que votre code est réécrit ailleurs, et qu'il est probable que ce soit sur cette nouvelle adresse que les contrôles suivants s'effectueront.
**La
génération du code**
L'ingéniosité des auteurs
dans la génération des codes peut être des plus navrantes
jusqu'au plus paranoïaque. Dans l'exemple suivant, et grâce à
VBDis, un décompilateur Visual basic, vous aurez l'intégralité
du source saisissant, générant (en gras) et vérifiant votre
sérial
If
Texte1.Text = "" Or Texte2.Text = "" Then
MsgBox ("Renseignez
les deux cadres S.V.P."), 24, "ENREGISTREMENT"
Exit Sub
End
If
Texte1.Text = UCase$(Texte1.Text)
ReDim l0028(40)
l002E = 0: l0028(l0032)
= 0
For l0032 = 1 To Len(Texte2.Text)
l0028(l0032) = Int((Asc(Mid$(Texte2,
l0032, 1))) * l0032 * Len(Texte2.Text) + 46397& / Len(Texte2.Text) + 6) *
152
l002E = l002E + l0028(l0032)
Next l0032
Etiquette2.Caption = l002E
+ Left$(Texte2.Text, 2)
If UCase$(Texte1.Text) <> UCase$(Etiquette2.Caption)
Or Texte1.Text = "" Then
MsgBox ("ERREUR DE CODE"), 64,
("ENREGISTREMENT")
Texte1.Text = ""
Texte2.Text = ""
Open
"cdgratis.ini" For Output As #2
Print #2, "LICENCE NON ENREGISTREE"
Print
#2, "76614840LI"
Close #2
Unload Me
Else
l0026 = "LE
CODE EST CORRECT. "
l0026 = l0026 + Chr$(10)
l0026 = l0026 & UCase$(Texte2.Text)
l0026
= l0026 + Chr$(10)
l0026 = l0026 & " S'EST ENREGISTRE CONVENABLEMENT."
Open
"cdgratis.ini" For Output As #2
Print #2, Texte2.Text
Print #2,
Texte1.Text
Close #2
MsgBox l0026, 48, "BIENVENUE A CD GRATIS!!!"
l003C
= "RELANCEZ CD GRATIS POUR METTRE A JOUR"
l003C = l003C + Chr$(10)
l003C
= l003C & "VOTRE ENREGISTREMENT"
MsgBox l003C, 64, "VERSION
ENREGISTREE"
End
End If
Dans un autre exemple, voici la partie basse de la routine de génération du sérial:
:0040281B
B81F85EB51 mov eax, 51EB851F > pousse 51EB851F dans EAX
:00402820 F7E7 mul
edi > ???????????????
:00402822 8BF2 mov esi, edx > EDX sauvé
dans ESI
:00402824 8B542414 mov edx, dword ptr [esp+14]
:00402828 C1EE05
shr esi, 05 > décalage à droite de 5
:0040282B 8BFE mov edi,
esi > ESI sauvé dans EDI
:0040282D 52 push edx > pousse notre
code sur la pile
:0040282E 81F721332153 xor edi, 53213321 > ou logique entre
code(h) et 53213321
:00402834 E817390100 call 00416150
:00402839 8B8D94000000
mov ecx, dword ptr [ebp+94]> place un code dans ECX
:0040283F 83C404 add
esp, 00000004 > rétablie la pile
:00402842 3BC1 cmp eax, ecx >
compare notre code(h) avec ECX
:00402844 7411 je 00402857 > saute vers code
valide
:00402846 8B442414 mov eax, dword ptr [esp+14] > notre code en décimal
:0040284A
50 push eax > pousse notre code sur la pile
:0040284B E800390100 call 00416150
> conversion en hexa
:00402850 83C404 add esp, 00000004 > rétablie
l'état de la pile
:00402853 3BC6 cmp eax, esi > compare les 2 sérials
:00402855
757B jne 004028D2 > saute vers code invalide
:00402857 E8508F0300 call 0043B7AC
> début de la proc code valide
V.ALORS?
--------
Alors,
j'espère que cet article vous a permis d'y voir claire sur les keygens.
ON est parti d'un programme assez commercial et on a finit par lui tirer le numéro
de série du nez! Comme quoi, la protection, même dans les logiciels,
c'est du bluff! Avec les outils nécessaire, de bonnes connaissance et un
bon cerveau (une conscience peut aussi être utile;) on peut arriver à
tout!
Beaucoup de programmes permettent de protéger son ordinateur par implémentation
de mots de passe. Certains, comme Access Denied, vont jusqu'à se charger
avant Windows, afin d'assurer une sécurité optimale. Mais, depuis
le temps des dinosaures, les mots de passes les plus usités en ce qui concerne
la sécurité d'un PC et qui sont actifs dès le démarrage
du PC, sont les mots de passes BIOS. Dès que ce dernier est activé,
il bloque la machine, avant, tout démarrage d'un quelconque OS (DOS, Windows
).
Dès lors, la question cruciale est : peut-on craquer un mot de passe BIOS?
Evidemment,
sinon cet article n'aurait aucune utilité. Mais comment ? Certains, d'entre
vous, en connaisseurs, s'écriront qu'il suffit simplement de retirer la
pile CMOS et attendre suffisamment longtemps afin de vider les condensateurs,
ce qui aurait pour effet de faire gicler le mot de passe. Un petit court-circuit
du CMOS permet même d'accélérer le processus.
Certes. Admettons
maintenant que vous êtes dans l'incapacité d'ouvrir la machine en
question (qui a dit celle de mon pire ennemi ???;). Il existe évidemment
des méthodes plus software. Quelques connaissance en ASM seront préférable
pour mieux comprendre la suite. Mais, avec mon article HS CRAKING (paru précédemment),
vous êtes au top ! Le but est de formuler une routine pour récupérer
le password BIOS. Vous comprendrez ainsi la programmation système en assembleur
et serait plus à même d'optimiser ce fichier, bref de vous débrouiller.
Cette routine faite maison est destiné aux possesseurs d'Award Modular
Bios (les plus courants). Elle est agrémenter de quelque explications sur
les points importants de la routine. Let's go.
------------------
;***CRACKING
AWARD MODULAR BIOS - For Hacker New Magazine***
.MODEL TINY
.CODE
ORG 100h
;***
Program start: ***
start:
jmp real_start // jump au début réel du prog
;***
global data: ***
db " ///CRACK POUR AWARD BIOS-StiG///", 13, 10
pw_1
db 13, 10, "* Password nécessaire pour entrer dans le Système",
13, 10, "$"
pw_2 db 13, 10, "* Password nécessaire pour
entrer dans le Setup", 13, 10, "$"
pw_3 db 13, 10, "* Supervisor-password
DESACTIVE", 13, 10, "$"
pw_4 db 13, 10, "* Supervisor-password
ACTIVE", 13, 10, "$"
pw_5 db 13, 10, "* User-password DESACTIVE",
13, 10, "$"
pw_6 db 13, 10, "* User-password is ACTIVE",
13, 10, "$"
;format:
length, "cmdl":
;-------------------------------
p_show db 4,
"SHOW" //commandes de paramètres
p_soff db 8, "SUPEROFF"
p_son
db 7, "SUPERON"
p_system db 6, "SYSTEM"
p_setup db 5,
"SETUP"
p_uoff db 7, "USEROFF"
p_uon db 6, "USERON"
num_params EQU 7
help
db 13, 10, "Usage: AW-CRACK [SHOW | SUPERON|SUPEROFF | USERON|USEROFF | SYSTEM|SETUP]"
db 13, 10
db 13, 10
db 13, 10, " SUPERON|SUPEROFF,"
db 13,
10, " USERON|USEROFF: ... // active ou désactive le password du BIOS!"
db 13, 10, " WARNING!: ne jamais l'activé avec un password inconnu!,"
db 13, 10
db 13, 10, "Ce programme fonctionne UNIQUEMENT avec les Award
Modular BIOS"
cmdl
db 128 dup (?)
db "$"
;***
print_msg: ***
print_msg:
mov ah, 09h
int 21h
ret
;***
parse_cmdl: ***
;
;return: AX: 0000h = SHOW
; 0001h = ON, 0002h = OFF
;
0003h = SYSTEM, 0004h = SETUP
; FFFFh = erreur... (paramètre de cmdl
inconnu)
parse_cmdl:
;***
Copie le premier command-line : ***
mov si, 80h // PSP: command-line (cmdl)
lea di, cmdl
lodsb
xor cx, cx
mov cl, al // CX = length of cmdl
lodsb
rep movsb
;***
upcase command-line: ***
lea di, cmdl
lea si, cmdl
mov cl, al
uploop:
lodsb
cmp al, 97 // 'a'
jb upok
cmp al, 122 // 'z'
ja upok
sub al, (97-65
upok:
stosb
loop uploop
;*** compare les cmdl-parameters: ***
lea si, p_show
xor ax, ax // retourne la valeur
mov cx, num_params // différents cmdl-params possible
comp_loop:
push cx
push ax
lea di, cmdl
lodsb
xor cx, cx // récupère sa longueur
mov cl, al
repe cmpsb
mov bx, cx
add si, cx
pop ax // récupère la valeur
pop cx
or bx, bx
jz done
inc ax
loop comp_loop
error:
mov ax, 0ffffh //ERREUR
done:
ret
;±±±
read_CMOS: ±±±
read_CMOS:
mov dx, 70h // lit dans
le CMOS à la position de AL
out dx, al
inc dx
in al, dx
ret
;±±± write_CMOS: ±±±
write_CMOS:
mov dx, 70h // écriture AH dans le CMOS à la position de AL
out dx, al
inc dx
mov al, ah
out dx, al
ret
;±±±
show_info: ±±±
show_info:
;*** Supervisor-password désactivé/activé? ***
mov al, 11h // lit la position 5eh du CMOS
call read_CMOS
lea dx, pw_3 // supervisor-password désactivé
and al, 02h
jz pw_superdisabled
lea dx, pw_4 // supervisor-password activé
call print_msg
jmp pw_level
pw_superdisabled:
call print_msg
;***
User-password désactivé/activé? ***
mov al, 5eh
// lit la position 5eh du CMOS
call read_CMOS
lea dx, pw_5 // user-password désactivé
and al, 01h
jz pw_userdisabled
lea dx, pw_6 // user-password activé
call print_msg
jmp pw_level
pw_userdisabled:
call print_msg
jmp show_done
pw_level: // écrit sur le password-level
mov al, 11h // lit la position 11h dans le CMOS
call read_CMOS
lea dx, pw_1 // niveau du système
and al, 01h // password: niveau du Système/Setup
jnz pw_system
lea dx, pw_2 // niveau du setup
pw_system:
call print_msg
show_done:
ret
;±±±
do_checksum: ±±±
do_checksum: // calcule des nouveaux
checksum du CMOS et les écrit dans le CMOS
mov cx, 2dh - 10h + 1 // CMOS-reg. (10h - 2dh) + 1
xor ah, ah
xor bx,
bx
checksum_loop:
mov dx, 70h
mov al, 2dh + 1
sub al, cl // al = registre dans le CMOS
out dx, al
inc dx
in al, dx // lit le CMOS-reg
add bx, ax // ajoute 2 checksum
loop checksum_loop
mov dx, 70h
mov al, 2eh
out dx, al
inc dx
mov al, bh
out dx,
al
mov
dx, 70h
mov al, 2fh
out dx, al
inc dx
mov al, bl
out dx, al
ret
;±±± do_checksum_ext: ±±±
do_checksum_ext:
// calcule des nouveaux checksum du CMOS et les écrit dans le CMOS
mov cx, 79h - 42h + 1 // (42h - 79h) + 1
xor ah, ah
xor bx, bx
check_loop_ext:
mov dx, 70h
mov al, 79h + 1
sub al, cl // al = registre dans le CMOS
out dx, al
inc dx
in al, dx // lit reg
add bx, ax // ajoute 2 checksum
loop check_loop_ext
mov dx, 70h
mov al, 7ah
out dx, al
inc
dx
mov al, bh
out dx, al
mov dx, 70h
mov al, 7bh
out dx, al
inc dx
mov al, bl
out dx,
al
ret
;±±±
real_start: ±±±
real_start: // début du programme
(enfin:)
push cs // DS = CS
pop ds
push cs // ES = CS
pop es
;***
Affiche le copyright ***
lea dx, copyr
call print_msg
call parse_cmdl
cmp ax, 0000h //display password-info
je pwd_info
cmp ax, 0002h //active le supervisor-passwordwd
je pwd_superenable
cmp ax, 0001h //désactive le supervisor-passwordd
je pwd_superdisable
cmp ax, 0003h //installe le password au niveau du système
je pwd_system
cmp ax, 0004h //set password to setup level
je pwd_setup
cmp ax,
0006h // active l'user-password
je pwd_userenable
cmp ax, 0005h // désactive l'user-password
je pwd_userdisable
jmp helpscreen
;***
display pwd-information ***
pwd_info:
call show_info
jmp back2dos
;***
Installation du password au niveau du setup ***
pwd_setup:
mov al, 11h
// lit 11 h dans le CMOS-reg
call read_CMOS
and al, NOT 1 // installe
le password au niveau du setup
mov ah, al
mov al, 11h // écrit
11 h dans le CMOS-reg
call write_CMOS
call do_checksum
lea dx, pw_2
call print_msg
jmp back2dos
;***
Installation du password au niveau du setup ***
pwd_system:
mov al, 11h
call read_CMOS
or al, 1 // installe le password au niveau du système
mov ah, al
mov al, 11h
call write_CMOS
call do_checksum
lea dx, pw_1
call print_msg
jmp back2dos
;***
Activation du supervisor-password du BIOS ***
pwd_superenable:
mov al,
11h
call read_CMOS
or al, 2 // active le PWD-bit
mov ah, al
mov
al, 11h
call write_CMOS
call do_checksum // calcule le nouveau checksum du CMOS
lea dx, pw_4
call print_msg
jmp back2dos
;***
Désactivation du supervisor-password du BIOS ***
pwd_superdisable:
mov al, 11h
call read_CMOS
and al, NOT 2 // Désactive le PWD-bit
mov ah, al
mov al, 11h
call write_CMOS
call do_checksum
lea dx, pw_3
call print_msg
jmp back2dos
;***
DUMMY JUMP ***
pwd_userdisable:
jmp real_userdisable
;***
Activation de l'user-password du BIOS ***
pwd_userenable:
mov al, 5eh //
lit 5eh dans CMOS-reg
call read_CMOS
or al, 1 // active le PWD-bit
mov ah, al
mov al, 5eh // écrit 5eh dans CMOS-reg
call write_CMOS
call do_checksum_ext // calcule du nouveau checksum du CMOS
lea dx, pw_6
call print_msg
jmp back2dos
;***
Désactivation de l'user-password du BIOS ***
real_userdisable:
mov
al, 5eh
call read_CMOS
and al, NOT 1 // désactive le PWD-bit
mov ah, al
mov al, 5eh
call write_CMOS
call do_checksum_ext
lea dx, pw_5
call print_msg
jmp back2dos
;***
affiche l'écran d'aide ***
helpscreen:
lea dx, help // affiche l'écran
d'aide
call print_msg
; jmp back2dos
back2dos:
.exit 0 // retour à 2 dos
END start
------------------
Voilà. C'est tout. Comme vous le noterez, ce n'est pas du tout compliqué, fallait juste y penser. L'essentiel est expliqué. Il a été testé : il est très fonctionnel. Tapez un mot de passe au pif et ça fonctionne (évidemment, le magazine t moi ne sauront être tenus responsables des dégâts éventuellement causé par l'utilisation d'un tel code, cela coule de source !!)
Pour le compiler, utilisez TASM (ça se trouve très bien sur le Net).
Appelez le programme "killpwd" par exemple et tapez la commande
tasm
/m killpwd (pour tasm v.4.0). Cette routine pourrait très bien servir de
sous-programme pour un futur logiciel plus évolué.
Avec un tel
programme, si vous devenez amnésique, vous pourrez déjà sauver
votre machine. Malheureusement, cette technique est utilisé également
par les pirates afin de prendre le contrôle d'un ordinateur. Face à
cela, une seule parade existe, définitive : enclencher le cavalier derrière
sur votre carte-mère (regardez votre mode d'emploi) afin de protégé
votre BiOS en écriture. Non seulement, il ne sera jamais modifier ou flasher,
mais encore vous serez prévenu lors d'une telle tentative, ce qui aura
pour effet de démasquer le virus furtif.
Have
fun your cracking now :::>