Décoder les images de charme des CD-ROM de magazines

Introduction:


Si vous avez 30 ans ou plus, vous avez surement connu les magazines d'informatique fournis avec CD-ROM dans les kiosques de presse.
Sur ces CDs on retrouvait la plupart du temps une interface graphique qui servait de loader pour installer divers programmes stockés sur le CD.
Souvent les CDs étaient accompagnés d'une zone charme avec quelques sets de photos de strip-teases, et si vous vouliez voir le contenu un peu plus charnel, il fallait payer via le 3617, ou par téléphone.


1


Revenons à notre époque maintenant, 2021, le numéro de tel n'est plus attribué et on peut oublier le minitel. On va donc devoir trouver par nous même un moyen d'accéder au reste du pr0n chiffré stocké sur le cd.


Les outils


Pour appliquer ce tutoriel il vous faudra...




I: Démarrage:


On va commencer par voir à quoi ça ressemble, et après on ira explorer la galette.
On va dans l'espace charme, un disclaimer nous demande de confirmer notre âge en tapant 'Oui', puis on arrive sur 'Visocharme'
Un genre de nag-screen surgit par-dessus l'interface de visiocharme pour nous informer de comment obtenir un code.
On remarquera aussi l'icône de la fenêtre qui laisse pensé qu'il y-a une technologie Macromedia (maintenant Adobe) derrière l'application.
On ferme la fenêtre et on rentre un code bidon puis on appuie sur OK, et... rien ne se passe.

1


Parcourons le CD-ROM pour voir comment tout ça est construit.
À la racine on retrouve notre loader "HackerCD_8.exe" et a coté des fichiers en .DXR, on a donc du Macromedia Projector.
Le dossier 'codexpress' semble contenir les photos de l'espace charme.
On y retrouve aussi un fichier "code.sys" avec l'attribut 'caché' ainsi que InstallOCX.exe, surement pour installer les dépendances du lecteur d'image.


1


Pas d'exécutable pour visiocharme, celui-ci doit être intégré dans l'exécutable principal ou dans un des fichiers .dxr
Le fichier "code.sys" et chiffré, les photos aussi. Sous un éditeur hexa on notera que la structure des premiers octets sont identique entre les photos.
Ça me laisse penser que ça pourrait être un XOR ou quelque chose du genre. (Ça se retrouvait beaucoup à cette époque.)..
On verra bien.



II: Trouver la routine de vérification


On lance le débogueur puis on charge HackerCD_8.exe, vu que l'application utilise tout l'écran, on va faire ALT+F5 ou bien depuis le menu du débogueur: Windows>Alway on top.
Histoire d'avoir notre débogueur toujours au premier plan, même si Alt+Tab va bien aussi pour passer de l'un a l'autre, y'a deux écoles.


1


Une fois tranquille avec ça on lance complètement le programme avec F9, puis on bascule sur les modules avec Alt+E, ou bien depuis le menu.


1


Macromedia projector a unpack sur notre disque dans un dossier temporaire tout sont bazar pour géré le son, les images, le texte...


1

On retourne sur l'application puis on va sur visiocharme, ensuite on retourne dans olly voir les modules si y'a du neuf.
Et effectivement, y'a de nouvelles choses, notamment "CryptViewer.ocx" exécuté depuis.. /system32/ ?!
Sans doute que "InstallOCX.exe" a été exécuté en caché.
Vraiment les mecs on honte de rien a installé des ocx dans un répertoire système sans en informé l'utilisateur...


1


Bon.. voyont voir ce fichier qui semble prometteur vu sont nom, peut être que ça nous éclairera sur le chiffrement des images.
Allez hop, on double click sur la ligne "CryptViewer.ocx" dans les modules et on se retrouve sur ça plage.
On lance un scan de la plage pour y voir plus clair avec Ctrl+A ou bien: clic droit>Analysis>Analyse code
Une fois ça fait on va regarder les strings pour se faire une idée de ce fichier.
Clic droit>Search for>All referenced strings


1


Les strings nous confirment qu'on est dans la bonne direction.

ASCII "*.jpg"
ASCII "CRYPTER2001"
ASCII "Code invalide !"
ASCII "CODE"
ASCII "code.sys"


1


Aller hop, on double-clic sur "Code invalide !" et on arrive sur ça position.
On remonte un peut et on place un breakpoint au début de ça procédure avec F2, ensuite on retourne sur visiocharm rentré un code bidon puis on valide..
Le débogueur break!
Et ce qu'on est déjà trop bas dans le code? il n'y a plus qu'a tracer pour le savoir.


1



III: Comprendre la routine de vérification


On trace tranquillement avec Step over (F8)
On observe des mouvements de notre code entre les registres et des buffers puis on arrive dans une boucle.
Un string qui ressemble a un code et envoyer dans EAX, sur la ligne suivante notre code bidon et transféré d'un buffer a EDX, puis on entre dans un CALL.


1


Nous aussi on va rentrer dans ce call avec Step Into (F7) une fois dans le call, pas de surprise, EAX et comparer a EDX.


1


On continue a tracer pour sortir du call, puis la boucle reloop, ça recommence, mais cette fois avec un autre serial.
On va regarder dans la fenêtre de dump l'adresse du serial, vu qu'il est envoyé via un pointeur qui fait EAX+4, il y en a certainement d'autres.
Et effectivement il y en a plein. On se balade un peu dans le dump et voilà.


1


Ça fait un paquet de code, 1 par set.
Il n'y a plus qu'a testé ça dans l'interface voir ce qu'il se passe, on essaye un code un hazard..
Et... Oh yeah boy!


1


Voilà, donc c'est simplement de la protection par serial, ou les bons serials sont stockés dans le fichier 'code.sys' sans doute déchiffré puis comparés.

Du coup par curiosité j'ai testé avec un CD un peu plus récent. (PC Pirate 22)
Dans celui-ci, un exécutable additionnel et fournit avec: 'viewer.exe' dans le même dossier on retrouve aussi un fichier "code.sys" avec attribut caché.


1


La routine et également assez reconnaissable a ce que l'on a vu précédemment.
On a une fonctionnalité en plus: au bout de trois mauvaises tentatives un appel sur PostQuitMessage et effectuer pour terminer le processus.


1


Du coup j'en profite pour regarder comment la routine de décodage fonctionne, et...
C'est du xor pour le code.sys.
Pour tomber dessus, j'ai mis un breakpoint sur toutes les API ReadFile.

1


Après avoir récupéré le contenu de code.sys via ReadFile, on tombe plus tard dans la routine de décodage du fichier.
On a un MOV EDX,A5A5A5A5 puis on entre dans une boucle de xor, qui au démarrage place les bytes a décoder dans EAX, puis il effectue un XOR des bytes avec EDX (A5).


1


Vous pouvez utiliser Hiew, et mettre un masque xor avec A5 pour décoder les fichiers code.sys.


1


J'ai testé avec Hacker CD 8, PC Pirate 22, aini que l'encyclopédie des utilitaires PC 19, la clé était la même.
Pour le décodage des images et bien... c'est la même clé/routine qui est utilisée.
Maintenant que l'on sait ça, on peut écrire un décodeur, ça nous évitera de devoir rentrer tous les codes et d'utiliser leur visionneuse d'image.

Ah, chose rigolote en plus: on a un serial maitre qui déverrouille toutes les images dans PC Pirate 22.
Chose qu'on ne retrouve pas pour Hacker CD 8.


IV: Faire un décodeur d'image


ça change un peut des keygens :)
Alors, on construit une boucle avec FindFirstFile/FindNextFile et un filtre "*.jpg"
Puis dans cette boucle, on a juste a ajouté après FindFirstFile un call a une procédure de xor qui va traité le fichier puis le réenregistrer.
Ensuite il n'y a plus qu'à passer au fichier suivant avec FindNextFile.


xordecoder.asm:

.486
.model flat, stdcall
option casemap :none ; case sensitive

comment /*
Tested successfully with:
- ENCYCLO_UT_19_CD (L'encyclopédie des utilitaires PC 19)
- UTPM_3 (Utilitaire PC Pratique)
- HACKERCD_8 (Hacker CD 8)
- PC_PIRATE_5 (PC Pirate 5)
- PCPR_22 (PC Pirate 22)
- PCPR_28 (PC Pirate 28)
- JPMN_4 (Japan Mania 4)
/

include                 \masm32\include\windows.inc
include                 \masm32\include\user32.inc
include                 \masm32\include\kernel32.inc
include                 \masm32\macros\macros.asm

includelib              \masm32\lib\user32.lib
includelib              \masm32\lib\kernel32.lib

WndProc                 proto  :DWORD,:DWORD,:DWORD,:DWORD 
List                    proto  :DWORD,:DWORD
ScanForParticularFiles  proto  :HWND
CryptFile               proto  :HWND
Crypt                   proto  :DWORD,:DWORD,:BYTE

.const
IDD_DIALOG              equ 1000
IDB_QUIT                equ 1001
IDB_CRYPT               equ 1002
IDC_GROUPRESULT         equ 1003
IDC_GROUPPATH           equ 1004
IDC_STATICFound         equ 1005
IDC_LISTBOXJPG          equ 1006
IDC_EDITPATH            equ 1007
IDC_COUNTER             equ 1008

.data
szTitle                 db "3617 DB22 pr0n Dcoder v0.1",0
szIDBCrypt              db "dÉCHIFFRER LES IMAGES *.jpg",0
szIDCGroupFound         db "iMAGES TRAiTÉES",0
szIDCGroupPath          db "cHEMiN DU DOSSiER CONTENANT LES iMAGES",0
szStaticFound           db "TOTAL:",0
szIDBQUit               db "QUiTTER",0
szIDCcounter            db "0",0

Dect                    db "%d",0
szFilter                db "*.jpg",0
cnt                     db 0
bKey                    db 0A5h ; ¥

.data? 
hInstance               HINSTANCE ? 
ThreadID                dd ?
CountJPG                dd ?
hthread                 dd ?
hFile                   dd ?
dwFileSize              dd ?
dwBytesDone             dd ?
hMemory                 dd ?
hBuffer                 dd ?
dpath                   db 256 dup (?)
hDir                    db 256 dup (?)
fpath                   db 256 dup (?)
cuntBuffer              db 8 dup(?)

.code
start:
    invoke GetModuleHandle, NULL 
    mov hInstance,eax 
    invoke DialogBoxParam,hInstance,IDD_DIALOG,NULL,addr WndProc,NULL 
    invoke ExitProcess,eax 
    
WndProc proc hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    .if uMsg == WM_INITDIALOG
        ; Set the dialog controls texts. Done here in the code instead of resource
        ; file to reduce the required bytes (strings in the rc file are UNICODE not ANSI)
        invoke SetWindowText,hWin,addr szTitle
        invoke SetDlgItemText,hWin,IDB_CRYPT,addr szIDBCrypt
        invoke SetDlgItemText,hWin,IDC_GROUPRESULT,addr szIDCGroupFound
        invoke SetDlgItemText,hWin,IDC_GROUPPATH,addr szIDCGroupPath
        invoke SetDlgItemText,hWin,IDC_STATICFound,addr szStaticFound
        invoke SetDlgItemText,hWin,IDB_QUIT,addr szIDBQUit
        invoke GetCurrentDirectory,1024,addr hDir
        invoke SetDlgItemText,hWin,IDC_EDITPATH,addr hDir
        invoke SetDlgItemText,hWin,IDC_COUNTER,addr szIDCcounter
        xor eax, eax
        ret
    .elseif uMsg == WM_COMMAND
        .if wParam == IDB_CRYPT
            invoke RtlZeroMemory,addr dpath,sizeof dpath
            invoke GetDlgItemText,hWin,IDC_EDITPATH,addr dpath,sizeof dpath
            invoke SetCurrentDirectory,ADDR dpath
            mov CountJPG,0
            invoke wsprintf,addr cuntBuffer,addr Dect,CountJPG
            invoke SetDlgItemText,hWin,IDC_COUNTER,addr cuntBuffer
            invoke CreateThread,NULL,NULL,offset ScanForParticularFiles,hWin,NULL,ADDR ThreadID
            mov hthread,eax 
        .elseif wParam == IDB_QUIT
            invoke EndDialog,hWin,0
        .endif
    .elseif uMsg == WM_CLOSE
        invoke EndDialog,hWin,0
    .endif
    xor eax, eax
     ret
WndProc endp

List proc hWin:HWND, pMsg:DWORD
    invoke SendDlgItemMessage,hWin,IDC_LISTBOXJPG,LB_ADDSTRING,0,pMsg
    invoke SendDlgItemMessage,hWin,IDC_LISTBOXJPG,WM_VSCROLL,SB_BOTTOM,0
    Ret
List EndP

ScanForParticularFiles proc hWnd:HWND
    LOCAL fnd      :WIN32_FIND_DATA
    LOCAL hFind    :DWORD
    invoke FindFirstFile,addr szFilter,addr fnd
    .if eax != INVALID_HANDLE_VALUE
        mov hFind, eax
        .repeat
            invoke GetCurrentDirectory,1024,ADDR hDir
            invoke lstrcat,addr fpath,addr hDir
            invoke lstrcat,addr fpath,chr$("\")
            invoke lstrcat,addr fpath,addr fnd.cFileName
            invoke List,hWnd,addr fpath
            inc CountJPG
            invoke wsprintf,addr cuntBuffer,addr Dect,CountJPG
            invoke SetDlgItemText,hWnd,IDC_COUNTER,addr cuntBuffer
            invoke CryptFile,hWnd
            invoke RtlZeroMemory,addr fpath,sizeof fpath
            inc cnt
            .if cnt == 25
                mov cnt,0
            .endif
            invoke FindNextFile,hFind,addr fnd
        .until eax == 0            
        invoke FindClose,hFind    
    .endif  
    ret          
ScanForParticularFiles endp

CryptFile proc hWnd:HWND
    invoke CreateFile,addr fpath,GENERIC_READ OR GENERIC_WRITE,0,0,OPEN_EXISTING,0,0
    mov hFile,eax
    .if eax == INVALID_HANDLE_VALUE
        jmp err0rz
    .else
        invoke GetFileSize,eax,0
        mov [dwFileSize],eax
        push eax
        invoke GlobalAlloc,GMEM_MOVEABLE,eax
        mov [hMemory],eax
        invoke GlobalLock,eax
        mov [hBuffer],eax
        push eax
        invoke ReadFile,[hFile],eax,dwFileSize,OFFSET dwBytesDone,0
        pop edx
        pop ecx
        mov ah,bKey
        invoke Crypt,[hBuffer],[dwFileSize],[bKey]
        invoke SetFilePointer,[hFile],0,0,FILE_BEGIN
        invoke WriteFile,[hFile],[hBuffer],[dwFileSize],OFFSET dwBytesDone,0
        invoke GlobalUnlock,[hMemory]
        invoke GlobalFree,[hMemory]
        invoke CloseHandle,[hFile]
    .endif
    ret
err0rz:     
    invoke MessageBox,NULL,chr$("Error opening file!"),chr$("Error"),MB_ICONERROR
    ret
CryptFile endp

Crypt proc pszBuffer:DWORD, dwSize:DWORD, Key:BYTE
doxor:
    mov al,[edx+ecx]
    xor al,ah
    mov [edx+ecx],al
    dec ecx
    .if ecx == 0FFFFFFFFh ; -1
       ret
    .else
       jmp doxor
    .endif
Crypt endp

end start

xordecoder.rc:

;This Resource Script was generated by WinAsm Studio.

#define IDD_DIALOG 1000
#define IDB_QUIT 1001
#define IDB_CRYPT 1002
#define IDC_GROUPRESULT 1003
#define IDC_GROUPPATH 1004
#define IDC_STATICFound 1005
#define IDC_LISTBOXJPG 1006
#define IDC_EDITPATH 1007
#define IDC_COUNTER 1008

IDD_DIALOG DIALOGEX 0,0,237,161
FONT 8,"MS Sans Serif"
STYLE 0x10c80800
EXSTYLE 0x00000010
BEGIN
    CONTROL "",IDB_CRYPT,"Button",0x50010000,17,40,203,16,0x00000000
    CONTROL "",IDB_QUIT,"Button",0x50010000,161,135,57,13,0x00000000
    CONTROL "",IDC_GROUPRESULT,"Button",0x50000007,7,68,224,87,0x00000000
    CONTROL "",IDC_GROUPPATH,"Button",0x50000007,7,6,224,59,0x00000000
    CONTROL "",IDC_LISTBOXJPG,"ListBox",0x50010140,17,83,201,47,0x00000200
    CONTROL "",IDC_STATICFound,"Static",0x50000000,17,135,27,10,0x00000000
    CONTROL "",IDC_EDITPATH,"Edit",0x50010080,17,22,204,13,0x00000200
    CONTROL "",IDC_COUNTER,"Static",0x50000000,47,135,43,10,0x00000000
END



make.bat:

@echo off
\masm32\bin\rc /v xordecoder.rc
\masm32\bin\ml.exe /c /coff /Cp /nologo xordecoder.asm
\masm32\bin\link.exe /SUBSYSTEM:WINDOWS /RELEASE /VERSION:4.0 /OUT:Decoder.exe xordecoder.obj xordecoder.res
del xordecoder.res
del xordecoder.obj
pause

Une fois compilé, ça ressemble à ça:

1



Placer ce programme dans le même dossier contenant vos images et appuyer sur déchiffrer.
Il n'y a pas de récursivité pour les sous-dossiers.
Vous pouvez maintenant admirée les filles du CD.

1


Regrettable tout de même que pour de la presse Française tout les séance photos contenus dans ses CD sont des filles de l’Europe de l'Est.




Xylitol, 29/08/2021




Copyright (C)- xtx Team (2021)

XHTML valide 1.1 CSS Valide !