Reversing mIRC |
Voilà c'est mon premier cours pour la team TipiaK, je vais m'occuper
de la partie reversing et maybe cracking et maybe coding asm aussi je sais
pas encore :o)
Pour l'instant ce cours va s'attaquer à une cible connue mais néanmoins
facile : mIRC ...
Peu importe la version que vous utiliserez , le but ici n'est pas de cracker
une protection (yen a pas :)) mais plutôt de vous apprendre comment
réfléchir à partir d'une source d'un programme que vous
n'avez plus et d'optimiser cette merde de mIRC pour qu'il réponde à
vos attentes... tel est le but du reversing ...
Je ne vous cacherais pas que pour reverser il faut déjà avoir de solides connaissances en asm, et puisque je ne m'occupe que de Windows pour l'instant, il vous faut connaître ce système d'exploitation un maximum ... ne vous inquiétez pas, vous apprendrez vite du moment que vous êtes un petit peu curieux ...
Bon
pour vous y aider, vous devrez avoir les logiciels suivants à portée
de main ... ne me DEMANDEZ PAS où on peut se les procurer, faites une
recherche sur internet point.
Voilà c'est bon vous avez tout ? alors c'est parti ! :-)
Le but de ce tutorial sera de pouvoir changer le CTCP version REPLY .
Note : j'utilise la version 5.7 de mIRC ! Certains offsets peuvent changer
d'une version à l'autre ...
Evidemment vous pouvez changer tout ce que vous voulez , ou presque , du moment que vous connaissez bien votre cible ...
Donc on va d'abord désassembler. Utilisez IDA pour ce faire, bon je ne suis pas là pour faire un tutorial sur IDA donc j'assume que vous savez cliquer sur file/open et sélectionner un fichier n'est ce pas ? :o)
A
l'aide d'IDA recherchez les strings ref intéressantes ...
Note: d'après la RFC 1459 sur le protocole IRC, le CTCP est envoyé
sous forme de NOTICE nick. Vous pouvez chercher soit NOTICE soit la version
reply "normale" de mIRC à savoir "mIRC32 ..."
Vous
le trouverez normalement en 4F3EDB (pour la version 5.7 du moins ...). Et
que voyez vous avant ? un NOTICE %s : !!!! donc nous sommes tombés
sur la réponse directement :-)
A l'aide des xref, remontez à la source ... DATA XREF reference offset
445DD2. Bien :-)
Bon maintenant essayons de changer directement la version reply de mIRC en 4F3EDB. Pour ce faire vous avez deux solutions, ou bien utiliser un hexéditeur et faire une recherche sur tout le fichier ... c'est bourrin mais bon ca peut marcher ou alors utiliser le PE format pour déterminer le raw offset de la data et modifier ensuite directement celle ci . Bon pour la première méthode je ne vous ferais pas de dessin sur comment faire par contre pour la deuxième je vais vous expliquer un chtit peu ... :o)
Utilisez un PE editor genre ProcDump mais bon beaucoup d'autres sont valables aussi ...
Utilisez
le PE viewer de ProcDump et choisissez mIRC32.EXE. Maintenant vous devez trouver
l'espace mémoire dans lequel se trouve la data XREF ... N'oubliez pas
que l'EIP = imagebase+virtualoffset !
Donc soustrayez 400000 à 4F3EDB pour obtenir le virtual offset ...
Virtual offset = F3EDB donc :)
La
section data à pour vitual offset F1000 et pour taille 35000 ce qui
nous fait : 126000 à la fin de la section ... or F3EDB appartient bien
à l'interval F1000-126000 non ? :)
Donc nous avons trouvé la section . Maintenant trouvons le raw offset
... le raw offset de la section = F0600.
Pour obtenir l'offset de la data il nous suffit simplement de faire un "produit
en croix" ...
Raw
offset section (F0600) = Virtual offset section (F1000)
Raw offset data (?) = Virtual offset data (F3EDB)
Donc : en admettant que le fichier n'est pas packed , Raw offset data = Raw offset section + (Virtual offset data - Virtual offset section) ... ROD = F0600+(F3EDB-F1000) = F34DB ... voilà ... allez à cet offset et admirez la magie :)
Bon
maintenant changez le version reply (en fait tout ce qui est après
le mot VERSION c'est à dire mIRC connerie ... :o))
N'oubliez pas que votre chaine doit être ASCIIZ donc terminée
par un caractère ASCII 0 (null) sinon ca va pas donner ce que vous
voudrez ... :o)
Bon redémarrez maintenant ... n'oubliez pas de faire une sauvegarde
de l'original au cas où tout partirait en couille ... En outre votre
nouvelle chaîne ne doit pas dépasser la chaîne initiale
...
Bon on essaye ... et hop merde ca ne marche pas !!! :-(
Quand
un client modifié essaye de faire un version echo, il n'y a pas de
version reply mais lorsque quelqu'un nous fait un version echo on ne sort
rien non plus :)
En ce qui concerne les ping echo et ping reply ca ne marche plus du tout non
plus :'(
Bon il doit y avoir forcément des vérifications des fois qu'on
serait des bad boyz :)
En recherchant d'autres occurences de la version reply on ne trouve rien de bien intéressant ... donc il faut trouver le maillon faible de cette "protection" ...
Pour éviter d'avoir à chercher pendant des heures LA ligne de code qui change tout , on va passer à la phase II: le live approach :)
Le principe est simple, utiliser un débogueur genre SoftICE pour savoir ce que le code fait exactement et quand il le fait ... il n'y a pas d'anti SI donc ca sera un jeu d'enfant ... enfin encore faut il savoir comment on procède :)
Tapez sous SoftICE:
:bpx wsprintfa
Cette API est utilisée très régulièrement dans le programme et va nous permettre d'accéder directement au VM du programme (un VM c'est grosso modo le process). Donc quand vous essayerez une nouvelle fois le CTCP version, le formatage de la ligne étant fait grâce à wsprintfa, vous serez averti directement, faites alors F12 pour revenir au programme lui même et là faites un:
:d 4F3EDB
Vous
retrouvez notre super phrase modifiée :)
Maintenant tapez:
:bpm 4F3EDB r
Ce qui va poser un breakpoint système sur cette adresse, le R veut dire READ donc comme cette string va être vérifiée par le programme, elle sera lue et donc à chaque tentative de lecture nous serons là pour voir ce qu'il en est ... sympa non ? :o)
F5 pour continuer l'exécution et voilà où nous tombons :
CODE:00445DD2
064
mov esi, offset aNoticeS_1 ;
"NOTICE %s :" ; le fameux message
CODE:00445DD7 064
mov edi, offset byte_513C45 ;
la destination pour la copie
CODE:00445DDC 064
mov eax, edi ; sauvegarde
du registre
CODE:00445DDE 064
mov ecx, 0Bh ; 11 dword =
44 bytes
CODE:00445DE3 064
repe movsd ; copie ...
CODE:00445DE5 064
movsb ; copie le dernier byte donc 45 caractères
max
CODE:00445DE6 064
pop edi
CODE:00445DE7 060
pop esi
CODE:00445DE8 05C
push 173Eh ;
c'est une valeur à vérifier dans le call
CODE:00445DED 060
push offset byte_513C45 ; la chaine
copiée
CODE:00445DF2 064
call sub_4206C4 ;
et voilà la superbe routine qui vérifie :)
CODE:00445DF7 05C
mov [ebp+var_C], eax ; EAX=1
tout va bien
CODE:00445DFA 05C
cmp [ebp+var_C], 0 ; EAX=0
=> bad boy on arrête ...
CODE:00445DFE 05C
jz short loc_445E3A
C'est
bien tout ca :)
Allons voir ce qui se cache dans ce call 4206C4 ...
CODE:004206C4
sub_4206C4 proc near
; CODE XREF: sub_445D18+DAp
CODE:004206C4 000
; sub_464594+B0p ...
CODE:004206C4
CODE:004206C4 arg_0
= dword ptr 8
CODE:004206C4 arg_4
= dword ptr 0Ch
CODE:004206C4
CODE:004206C4
push ebp
CODE:004206C5 004
mov ebp, esp
CODE:004206C7 004
push ebx
CODE:004206C8 008
xor ecx, ecx
CODE:004206CA 008
mov eax, [ebp+arg_0] ; premier
argument : l'offset de la chaine a lire
CODE:004206CD 008
jmp short loc_4206DF
CODE:004206CF ; ---------------------------------------------------------------------------
CODE:004206CF
CODE:004206CF loc_4206CF:
; CODE XREF: sub_4206C4+1Fj
CODE:004206CF 008
and edx, 0FFh ;
on isole le caractère
CODE:004206D5 008
xor ebx, ebx ;
EBX=0
CODE:004206D7 008
mov bl, [eax+1] ;
on prend le caractère d'après
CODE:004206DA 008
add edx, ebx ;
on ajoute le caractère à edx
CODE:004206DC 008
add ecx, edx ;
puis à ecx ...
CODE:004206DE 008
inc eax
; on passe au caractère suivant
CODE:004206DF
CODE:004206DF loc_4206DF:
; CODE XREF: sub_4206C4+9j
CODE:004206DF 008
mov dl, [eax]
; dl = caractère
CODE:004206E1 008
test dl, dl
; est ce 0 ?
CODE:004206E3 008
jnz short loc_4206CF ;
non alors on jump
CODE:004206E5 008
cmp ecx, [ebp+arg_4] ;
on compare ECX à la valeur à trouver ...
CODE:004206E8 008
jz short loc_4206EE ;
c'est bon ? => good boy
CODE:004206EA 008
xor eax, eax
CODE:004206EC 008
jmp short loc_4206F3 ;
EAX=0 bad boy
CODE:004206EE ; ---------------------------------------------------------------------------
CODE:004206EE
CODE:004206EE loc_4206EE:
; CODE XREF: sub_4206C4+24j
CODE:004206EE 008
mov eax, 1 ;
la bonne valeur : GOOD BOY !
CODE:004206F3
CODE:004206F3 loc_4206F3:
; CODE XREF: sub_4206C4+28j
CODE:004206F3 008
pop ebx
CODE:004206F4 004
pop ebp
CODE:004206F5 000
retn 8
CODE:004206F5 sub_4206C4
endp
Voilà ... c'est plutôt ridicule comme protection ... un petit algo qu'il nous est facile de contourner juste en traçant le programme et ensuite de changer la valeur du PUSH 173E normal en 445DE8.
Là plusieurs façons de patcher ... en noppant le jmp en 4206EC par exemple ... EAX=0 puis 1 donc c'est parfait :)
Voilà, vous testez et tout rentre dans l'ordre ... bon ben c'est fini :)
He ben oui pour ceux qui veulent encore s'emmerder la prochaine fois qu'ils
voudront changer leur CTCP version REPLY directement sur le fichier ... :)
Et
c'est là la magie du reversing lorsqu'on s'y connait un peu ... jusque
là on pouvait considérer cette opération comme un "crack",
d'ailleurs il serait possible de faire un programme qui cherche pour chaque
version l'offset dans le fichier, change en ce que vous voulez et recalcule
à l'aide de l'algorithme et puis hop c'est fini :)
Mais bon on va faire encore mieux , on va modifier le programme lui même
pour pouvoir changer le ctcp reply directement dans le menu des options !!!
:o)
Attention ici on va avoir besoin d'un cerveau 8o)
Le
problème va être de trouver un emplacement suffisamment grand
pour mettre notre ressource ...
Un simple CTCP VERSION reply en static et une editbox feront l'affaire. Par
contre nous aurons besoin d'un peu d'espace dans le code ... puisque la routine
en 4206C4 devient inutile, nous allons la remplacer par notre propre routine
:o)
Mais
ne croyez pas que ce soit aussi facile que ca !
Si on veut un patch parfait , il faudrait que l'information soit enregistrée
sur le disque dur !
Dans la base de registres ce serait parfait ou au pire dans un fichier .INI
:-(
Je me suis emballé trop vite :'-(, mIRC utilise toujours un fichier .INI pour stocker ses informations ce qui est plus long à extraire et en ce qui concerne les ressources ce serait inapplicable !
Nous
voilà donc confronté à plusieurs possibilités
qui ne nous arrange pas vraiment ... :-/
Dans ces cas là, le mieux est de choisir la "moins pire" solution ,
c'est à dire d'appeller un programme via /run, par exemple, qui changerait
en mémoire les informations nécessaires, c'est à dire
la data et patcherait le call pour qu'il renvoie toujours la bonne valeur
.
Quelque soit la méthode utilisée, ce ne pourra rester qu'une méthode provisoire, puisqu'il n'est pas dit que ce genre de patch soit valable sur tous les mIRC antérieurs et surtout postérieurs, même par une recherche de chaîne et non par une recherche d'offset raw ou virtual, il sera toujours possible de changer l'algorithme ou le système de vérification pour que tout cela devienne inutile.
C'est pour cette raison que ce tutorial ne contient pas de "solution miracle" pour pouvoir vous la péter avec votre nouveau versoin reply malheureusement, mIRC est trop merdique pour faire quoique ce soit de valable donc xchat roulaize et si le coeur vous en dit vous pouvez toujours coder votre propre client irc :o)
Il reste néanmoins une solution provisoire pour appliquer vos CTCP reply directement depuis la base de registres ... elle pourrait être portable sur tous les mIRC puisqu'elle utilise la base de registre et elle pourrait rentrer dans notre routine ... C'est pour ne pas vous laisser sur le carreau sans code source que je vais développer cette méthode maintenant ...
Bon aller en route ... après une petite dépression tout à
l'heure sur le fait que l'on ne puisse pas faire un reverse vraiment "l33t"
8o) , il est néanmoins possible avec vos skillz de faire un joli truc
tout mignon tout plein :-)
Nous
avons plusieurs manières d'arriver à nos fins comme je l'ai
expliqué dans la partie précédente, j'en ai choisi deux
en particulier ...
Je vais vous fournir l'explication de ces deux programmes ...
Je ne fournis ici aucun code source sinon le temps de vous expliquer comment
ca fonctionne et tout vous serez dégouté de la lecture ! :o)
Je ne programme qu'en assembleur en outre ce qui ne semble pas être
le langage privilégié de nos jours (malheureusement!) donc cela
risquerait encore plus d'accroitre l'ennui ...
Je
vais simplement vous expliquer la démarche "intellectuelle" à
avoir ...
Voilà ce que vous devrez faire ...
Voilà pour cette première méthode ...
La deuxième méthode consiste à utiliser la base de registres
pour crééer votre clé (Version par exemple) qui sera
checkée à chaque fois que le programme devra renvoyer un ctcp
version reply ... l'avantage c'est que vous pouvez modifier la réponse
sans avoir besoin de fermer mIRC et de le relancer !
C'est assez simple là, plus besoin de calculer le nouveau code pour
que la version reply soit acceptée puisque cette routine remplacera
la précédente !
D'autre part elle peut tenir sur les 35h bytes de la procédure ...
C'est la méthode que je préfère ...
Si vous avez besoin de plus amples informations sur ces programmes vous pouvez toujours me demander par mail ou via IRC ... :-)
C'est toujours mieux que rien mais bon il y a bien d'autres méthodes
d'arriver à vos fins ...
Si vous voulez toujours vous accrocher a mIRC ... je vous donne quelques idées
de programmes :
Le reversing c'est aussi apprendre... Si jamais vous vouliez faire votre propre
client IRC, prenez mIRC comme base pour toutes vos opérations internet,
par exemple le CTCP version REPLY que l'on doit envoyer en réponse
à un CTCP version REQUEST ... Vous pouvez toujours regarder certaines
parties de code, elles vous éviteront pour sûr la fastidieuse
lecture de la RFC 1459 !
Voilà
c'est fini pour ce premier tutorial, je ne sais pas si vous avez tout compris,
j'ai essayé d'être le plus clair possible mais il n'est pas dit
que tous mes lecteurs auront le même niveau alors toutes les suggestions
sont welcome évidemment !
--
James Bond 007
-- Ecrit le 1/08/2000