*************************************************************************************** ********************************* CRACKING par TiPiaX ********************************** ***************************************************************************************

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