| Reversing mIRC

# Introduction:

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.

- Softice 4.00 : la version 4 permet de pouvoir utiliser le débogueur même lorsqu'on est en ligne :)
- IDA 4.04 : c'est le désassembleur ULTIME pour tous vos programmes, bien mieux que w32dasm ...
- un hexéditeur : uniquement pour vos patchs comme d'hab.
- un cerveau : ABSOLUMENT nécessaire. Si vous n'avez pas la capacité de réfléchir sur un problème ou d'étudier un système de façon abstraite alors vous n'y arriverez jamais ...
- de solides connaissances en programmation système : dépend de la cible ... pour mIRC le minimum sur les dialog box est nécessaire et sur la programmation générale en assembleur (étant donné que vous ne pourrez pas modifier le programme dans un autre langage que l'assembleur ... vieux ? inutile de nos jours l'assembleur ?)
- quelques docs online : je citerais par exemple l'aide win32api.hlp que vous pourrez vous procurer partout ... ou encore pour les utilisateurs expérimentés la documentation intel developper manual volume III ou encore la winDDK ou SDK c'est selon le niveau ... ;-)

Voilà c'est bon vous avez tout ? alors c'est parti ! :-)

## Deep into gnisreveR !

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 :)

## Is it the end ?

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 ...

## The Coding Part

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 ...

- Patcher à l'aide d'un programme extérieur
- Utiliser la base de registres pour trouver la nouvelle version reply ...

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 ...

### I. Patcher à l'aide d'un programme extérieur

Voilà ce que vous devrez faire ...

1. Afficher une boite de dialogue très simple (en partant d'une ressource par exemple) et l'afficher (une EDITBOX suffit). Il faut juste demander le nouveau ctcp version reply ...
2. La chaîne à prendre ne doit pas dépasser la chaîne initiale de la version reply de mIRC à savoir 1E . Vous pouvez par exemple appeller GetDlgItemTextA avec 1Eh en size de votre buffer ... ce qui est la méthode la plus simple en assembleur ... maintenant si vous le faites en delphi jpeux pas vous dire ! :o)
3. Ripper l'algorithme du call précédent en sachant que [arg_0] = chaine copiée ... Je ne vous ferais pas de dessin sur comment faire là débrouillez vous un peu !
4. Patcher mIRC32.exe : évidemment cela enlève la possibilité de changer le ctcp version reply quand on est déjà connecté mais je pense que ce ne sera pas un trop gros inconvenient ! 8=) Pour le patcher, il vous faut connaitre les offsets donc ca dépend de chaque versioni de mIRC ... Vous n'aurez besoin de patcher qu'à deux endroits, l'offset de la data du ctcp version reply et le push juste avant l'appel du call (enfin le 2ème ...) . C'est juste la valeur à changer (n'oubliez pas que nous avons à faire aux processeurs intel avec le little endian format !).

Voilà pour cette première méthode ...

### II. Utiliser la base de registres pour trouver la nouvelle version reply ...

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 ... :-)

## Conclusion

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 :

- patcher en mémoire avec /run
- patcher dans le fichier avec un programme externe
- utiliser le fichier .INI même si le code source risque d'être LONG
- utiliser la base de registre (vous devrez vous créer une nouvelle clée en plus !)

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 !

mail : james_bond_coding@yahoo.com
IRC : #tipiak sur undernet

-- James Bond 007
-- Ecrit le 1/08/2000