|
Comment découvrir la protection anti SoftIce:
En fait, c'est elle qui vient à nous: au lancement de Zip Studio, pour peu que vous ayez SoftIce d'actif,
le programme va planter. Comme le faisait remarquer Elraiser sur le forum d'ATP Team, cette partie de la protection
n'est pas correctement écrite.
Puisque que nous avons affaire à un Anti-SI la logique des choses veuille que nous lancions FrogIce. Il
est à noter que la version 4.0 de cet excellent outil semble mieux gérer les codes 07 (INT 68) que
la précédente.
Au lancement suivant, sous couverture de FrogIce, le programme affiche son "écran_bleu_de_la_mort":
SoftICE detection ** code 07, at FCF3:00002FFB(?)
Interrupt:68h >eax=00004300h ebx=00000001h ecx=0000FC04h
edx=000000FEh esi=8159332Ch edi=10000000h ebp=00A5FBE4h
Il s'agit donc d'un code 07. Voyons ce qu'en dit le "code.txt",
livré avec cet utilitaire:
|
Code 07
======
Method of detection of the WinICE handler in the int68h (V86)
(Note that FrogsICE will not be able to return the offset:segment of a 32-bit program using this method)
mov ah,43h
int 68h
cmp ax,0F386h
jz SoftICE_Detected
=> it is not possible to set a BPINT 68 with softice but you can
hook this int:
BPX exec_int if ax==68
(function called is located at byte ptr [ebp+1Dh])
|
Entre ces informations, et celles données par le "blue
screen", ça ne devrait pas être trop difficile de localiser cet Anti-Sice
Enter pour quitter l'écran bleu, et
POP!
Un second Anti Sice, toujours sur un code 07, et apparemment cette fois ci dans les codes de l'exécutable:
** SoftICE detection ** code 07, at FCF3:00002FFB(?)
Interrupt:68h >eax=00004300h ebx=00950000h ecx=0000FC04h
edx=000000FEh esi=815A64D0h edi=815932E8h ebp=00A5FDFCh
Bon!
Commençons par déterminer exactement qui tourne en arrière plan. Pour cela, ProcDump va très
bien faire l'affaire: Zip Studio étant en tâche de fond, il suffit de lancer ProcDump, de cliquer
sur le nom de l'application dans l'écran principal, et de regarder les Dll et fonctions utilisées
par celle ci. Il y en à 2:
c:\windows\system\mydocs.dll 7EA035A7 792A0000 00011000
c:\windows\system\shdocvw.dll 7EA035BB 77B20000 000E6000
c:\program files\zip studio\mpegdll.dll 7EA035EE 014C0000 0002E000
c:\windows\system\mlang.dll 7EA035... 7B780000 00077000
c:\program files\zip studio\zap studio.exe 7EA035E2 00400000 00422E00
c:\program files\zip studio\zstudio.dll 7EA035ED 10000000 00042000
c:\windows\s stem\wins ool.drv 7EA0359B 7FE40000 00009000
Maintenant que l'on connaît les DLL utilisées par Zip
Studio, il reste à les localiser:
Fichier 'C:\Program Files\ZIP Studio\_isreg32.dll'.
Fichier 'C:\Program Files\ZIP Studio\Mpegdll.dll'.
Fichier 'C:\Program Files\ZIP Studio\Zstudio.dll'
Et un nouveau p'tit coup de ProcDump va nous apprendre que seule _isreg32.dll
est non compressée, mais apparemment elle n'est pas utilisée. Les deux autres sont protégées
en lecture/écriture.
Le programme est compressé par UPX:
UPX0 00374000 00001000 00000000 00000400 E0000080
UPX1 000A7000 00375000 000A6600 00000400 E0000040
.rsrc 00006E00 0041C000 00006E00 000A6A00 C0000040
Pour en connaître la version, un coup d'œil dans un éditeur
hexadécimal va vous préciser qu'il s'agit de la version 0.84.
This file is packed with the P executable packer $..$Id: UPX
0.84 Copyright (C) 1
Comme pour tous les programmes compressés, les caractéristiques
des sections de l'exécutable vont être à changer en E0000020 si vous voulez obtenir par la
suite un fichier désassemblable.
Afin de compléter ce premier état des lieux, que se passe-t-il si vous isolez Zip Studio.exe dans
un autre répertoire?
Rien: il réclame Zstudio.dll et ne démarre pas.
Rajoutons la Dll demandée, et on relance l'application: il réclame Mpegdll.dll, mais le programme
démarre si vous cliquez sur le bouton de la messagebox.
Donc pour le moment, on peut "oublier" _isreg32.dll, malgré son nom prometteur...
Arriver jusqu'aux codes Anti-SoftIce:
Puisque l'on connaît l'adresse où se trouve l'Anti-Sice dans Zstudio.dll, et que les caractéristiques
des différents fichiers ont été modifiés pour permettre (théoriquement) un break
sur l'entry point de l'exécutable, il n'y a plus qu'à lancer le programme via le Symbol Loader de
SoftIce...
Oups!
Zip Studio démarre sans passer par la case départ...
Pas Glop!
On va utiliser une autre solution...
Et pour forcer le break sur l'Entry point de l'exécutable, il va suffir de remplacer le premier octet par
un CC (opcode pour INT 03) en 0081EE00, puis de taper un BPINT 03 dans SoftIce...
On relance Zip Studio.exe, et...
POP!
A nouveau "l'écran de la mort qui tue" de FrogIce!!!???
Enter pour le quitter, et le programme break sur l'INT 3!!!!!
Très honnêtement, c'est la première fois que je rencontre un programme ou l'une de ses dll
est lancée AVANT l'arrivée sur l'Entry Point de l'exécutable...
A ce sujet, TeeJi vous propose dans les lignes suivantes un excelent topo sur la gestion des DLLs:
|
Intro
Dans le cadre du Groupe de Travail sur les protections
Anti-Sice, j'ai eu l'occasion d'étudier la protection de ZipStudio. Ce programme contenait une protection
Anti-Sice de type 07 ( INT 68 ) contenue dans une DLL ( ZSTUDIO.DLL ). Notre problème était que la
détection de Softice se faisait avant même l'exécution de la première instruction du
.EXE. Nous nous sommes alors demandé comment, pourquoi et quand une DLL peut être exécutée
avant même l'exécution de programme. J'espère amener ici un élément de réponse
majeur. Un grand merci à Christal.
Qu'est-ce qu'une DLL ?
Sous Windows, les bibliothèques de liens dynamiques
( dynamic-link libraries DLL ) sont des modules qui contiennent des FONCTIONS et du DATA. Une DLL est chargée
lors de l'exécution de son module appelant ( .EXE ou une autre DLL ). Quand une DLL est chargée,
elle est mapée dans l'espace des adresses du processus appelant.
Rem
: Processus appelant et module appelant sont les .EXE ou .DLL qui utilisent les FONCTIONS exportées.
Les DLLs peuvent définir deux sortes de FONCTIONS:
Les FONCTIONS exportées et internes.
o Les FONCTIONS exportées peuvent
être appelées par un autre module3
o Les FONCTIONS internes peuvent par contre
n'être appelées que par la DLL elle-même.
Aussi, les DLLs peuvent exporter du DATA, mais il est plus
généralement utilisé par les FONCTIONS de la DLL.
Rem
: J'ai déjà eu l'occasion de voir une DLL qui ne possèdait pratiquement que des Ressources.
Le .EXE utilisant les Ressources de la DLL. Ainsi, tout les Référencements sous WDASM sont inutiles.
Les DLLs donnent un moyen de moduler les applications pour
qu'une fonctionnalité puisse être améliorée et réutilisée plus facilement.
Elles aident aussi à réduire la mémoire utilisée lorsque plusieurs applications utilisent
la même fonction au même moment, car elles se partagent le code.
L'interface de programmation des applications Win32 ( Application Programming Interface API ) est implémentée
sous forme de DLLs, ainsi tous les processus utilisant les API Win32 utilisent les liens dynamiques.
Qu'est-ce qu'il y a à l'Entry Point d'une DLL ?
Dans les DLLs, il existe une fonction qui commence à
l'EntryPoint de la DLL. Cette FONCTION est appelée par Windows lors de l'exécution d'une application
Win16-32. Cette FONCTION que Microsoft a appelée DLLEntryPoint nécessite 3 paramètres :
BOOL WINAPI DllEntryPoint
HINSTANCE hinstDLL, // handle to DLL
module
DWORD fdwReason, // reason for
calling function
LPVOID lpvReserved // reserved
1) Le premier paramètre : hinstDLL
Il ne nécessite pas beaucoup d'explications,
c'est juste le Handle de la DLL.
Mais nous pouvons faire quelques remarques :
o Ce Handle à la valeur de l'adresse de base de
la DLL.
o Et cette valeur est exactement la même que
le HMODULE de la DLL.
2) Le second paramètre : fdwReason
Ce deuxième paramètre est beaucoups plus
intéréssant pour comprendre comment, quand et pourquoi cette FONCTION DllEntryPoint est exécutée.
1er Valeur de fdwReason possible : DLL_PROCESS_ATTACH
Cette valeur indique à la FONCTION que la DLL est
en train d'être attachée à l'espace des adresses du processus courant. dfwReason possède
cette valeur dans 2 cas :
(a) Soit lorsque le
processus démarre ( avant l'exécution de la premiere instruction du processus ( .EXE généralement
) appelant )
(b) Soit lors de l'appel
à la FONCTION LoadLibrary
Rem
: LoadLibrary est une FONCTION et elle sera donc appelée lorsque le Processus sera en cours d'exécution.
Nous ce qui nous intéresse ce n'est donc pas le point (b) mais bien le point (a) !
Les autres valeurs de fdwReason possibles sont
o DLL_PROCESS_DETACH ( appelé soit par une FONCTION Exit ou par FreeLibrary )
o DLL_THREAD_ATTACH
o DLL_THREAD_DETACH
PS
: je ne donnerai pas d'explications sur ces différentes valeurs étant donné que leur
nom est
assez évocateur.
3) Le dernier paramètre : lpwReserved
Ce paramètre spécifie un peu plus l'initialisation
ou la "libération" de la DLL.
o Si fdwReason vaut DLL_PROCESS_ATTACH :
lpwReserved
est NULL pour un chargement dynamique
et non NULL pour un chargement statique
o Si fdwReason vaut DLL_PROCESS_DETACH :
lpwReserved
est NULL si DllEntryPoint est appelée en utilisant FreeLibrary
et non NULL si DllEntryPoint est appelée car c'est la fin du Process
Rem
: Nous savons maintenant que c'est la fonction DllEntryPoint de ZSTUDIO.DLL qui exécute l'Interruption 0x68.
Mais nous ne savons toujours pas pourquoi cette DLL n'est pas chargée par LoadLibrary... Continuons !
Mais pourquoi la DLL se charge avant le Processus ?
Pourquoi celui-ci n'utilise pas LoadLibrary pour charger
la DLL ?
Evidemment, c'est la question qu'on peut dès lors
se poser. Nous savons que quand une DLL est chargée, elle est mapée dans l'espace des adresses du
processus appelant. Je vous avoue que cela n'est pas plus clair pour vous que pour moi. Allons éclaircir
tout ca! Mais pour cela, nous allons devoir faire un petit détour vers la structure et le fonctionnement
d'un fichier PE.
Dans le Optional Header d'un fichier PE, il y a 16 bits ( DllCharacteristics ) utilisé pour avertir si le
fichier est une DLL et, théoriquement, quand DllEntryPoint doit être appelée mais cela ne semble
pas être utilisé par Windows et la Dll est toujours avertie de tous :
o Si le bit 0 vaut 1, la DLL est avertie de l'attachement
à un Processus (par exemple lors du chargement d'une DLL)
o Si le bit 1 vaut 1, la DLL est avertie du
dé-attachement à un thread (par exemple lorsque qu'un thread est terminé)
o Si le bit 2 vaut 1, la DLL est avertie de
l'attachement à un thread (par exemple lors de la création d'un thread)
o Si le bit 3 vaut 1, la DLL est avertie du
dé-attachement à un Processus (par exemple lors du 'déchargement' d'une DLL ).
Cela était juste pour information, si on repense
maintenant à la source : quand le compilateur trouve un CALL d'une FONCTION qui se trouve dans un autre
Module ( DLL, VxD, etc.. ) il va, dans le plus simple des cas, écrire une instruction CALL normale. Ce CALL
pointera vers une instruction JUMP propre a chaque FONCTION. Ce JUMP sautera lui-même vers l'adresse de la
FONCTION importée en utilisant l'Import Table.
L'Import Address Table ( IAT ) se situe à la fin de la section contenant le Code Exécutable du programme.
Cette IAT est constitué d'autant de DWORD ( 32 Bits ) qu'il y a de FONCTIONS exportées et se termine
par un DWORD NULL. Chaque DWORD correspond à l'adresse réelle de la FONCTION.
Par exemple
: si il n'y a qu'une FONCTION exportée de COMDLG32.DLL, IAT sera du style :
BFFA125F 00000000 <-- Fin de l'IAT
^ ^ ^ | ^ ^ ^
|-->
Addresse de la FONCTION
Si l'IAT se trouve en :406514, le Linker mettera
par exemple en :00404E72 :
* Reference To: comdlg32.CommDlgExtendedError,
Ord:0004h
|
:00404E72 FF2514654000
Jmp dword ptr [00406514]
Et pour appeler cette fonction, le programme fera
:
* Reference To: comdlg32.CommDlgExtendedError, Ord:0004h
|
:004014B8 E8B5390000
Call 00404E72
Donc pour résumer, dans l'ordre, lorsqu'un programme
voudra appeler une FONCTION, il y aura un CALL addresse_du_jump_ver_la_FONCTION à cette addresse il y aura
un JMP [addresse_de_l'addresse_reelle_de_la_FONCTION], l'adresse réelle de la fonction se trouvant dans
l'IAT.
MAIS, dans DLL il y a 'Liens Dynamiques', en d'autres mots,
les adresses des FONCTIONS exportées par les DLLs ne sont pas statiques et peuvent changer. L'IAT doit donc
être modifié en conséquence. Si l'IAT n'était pas changé, les adresses deviendraient
erronées et le programme ne fonctionnerait plus. De plus, pour connaître les adresses des FONCTIONS
Exportées par la DLL, il faut qu'elle soit préalablement chargée. Voilà donc pourquoi
les DLLs doivent généralement être chargées avant l'exécution de la première
instruction du processus appelant.
Pour que Windows sache quelle DLL charger et quelle FONCTION
maper, il lui suffit de lire dans l'Import Directory de l'exécutable.
Voici par exemple pour NotePad :
¢ßé ÔcaßÜXßÜ_ß
j ShellAboutA DragFinish DragQueryFileA N SHGetSpe
cialFolderPathA ¤ DragAcceptFiles l
ShellExecuteA SHELL32.dll ExitProcess ¶ G
etModuleHandleA @ GetStartupInfoA ð
GetCommandLineA t GlobalFree GetLocaleI
nfoA ß lstrcpyA Í
MulDiv @ CreateFileA GetLastError Ï lstrcatA ƒ FindClo
se ú FindFirstFileA _ lstrcmpA
9 GetProfileStringA þ lstrlenA RtlMoveMemor
y õ lstrcpynA ¢ LocalReAlloc
+ LocalLock  LocalAlloc + LocalUnlock ð _lclose
i _lwrite _ DeleteFileA Ð _lcreat Ë
_lopen È _lread Ê _llseek ¦ LocalFree ~
GlobalUnlock x GlobalLock m GlobalAlloc
GetLocalTime ^ GetTimeFormatA Õ G
etDateFormatA Ì lstrcmpiA KERNEL32.dll
© MoveWindow q InvalidateRect SetF
Juste après l'IAT se trouve le Nom des FONCTIONS
Exportées et le Nom de la DLL exporteuse.
Il y a encore un MAIS, les différentes FONCTIONS
importées ne doivent pas obligatoirement être référencées dans l'exécutable.
Si le programme désire utiliser une FONCTION non référencée contenue dans une DLL,
il doit utiliser la FONCTION LoadLibrary, et ensuite GetProcAddress pour récupérer l'adresse de la
FONCTION. Ainsi, la DLL n'est pas chargée avant l'exécution de l'exécutable. Pour libérer
la DLL, il lui suffit d'appeler la FONCTION FreeLibrary. La DLL sera alors déchargée et les appels
des FONCTIONS de cette DLL ne seront donc plus possibles.
Note Finale
Je sais que cela n'est pas simple à comprendre,
moi-même je ne suis pas encore sur d'avoir tout parfaitement compris. Je pense quand même en avoir
encore une fois apprit beaucoup. Pour terminer, je vous prie de m'excuser si une faute se serait glissée
dans ces quelques lignes, je ne demande qu'à les corriger.
Amicalement,
TeeJi ( teejee@hotmail.com )
|
Bravo TeeJi! Bon boulot...
Revenons à Zip Studio
Pour Breaker sur la DLL, il suffit désormais de placer un autre CC sur l'Entry Point de Zstudio.Dll...
Et on relance...
Aie!
RIEN!
Le programme démarre, le premier écran Bleu de FrogIce popup, break sur le CC en 0081EE00, que l'on
remplace par le 83 d'origine pour ne pas planter l'application, second Ecran Bleu, et le programme se lance...
Donc, je n'ai pas eu de break sur l'INT 3 placé sur l'Entry Point de la DLL.
Diable!
D'autre n'ayant pas eu ce problème, j'en suis venu à me rappeler un Chat avec TaMaMBoLo, qui protège
(jusqu'à la version 5) ces Tutoriels par un Anti Sice du même type que celui qui nous occupe cette
fois ci:
Il semblerait qu'avec certain processeur, la présence d'une INT 68 pose des problèmes. A chaque fois
que sur mon PC (Pentium K6-2 500 Mhz) j'ai un programme protégé par un Code 07, en ouvrant le répertoire
dans lequel le programme est placé, j'ai un mal de chien à obtenir l'affichage des icônes,
et tout le système est brutalement ralenti, alors que le programme n'est même pas encore lancé.
Et je ne vous parle pas du ralentissement CONSIDERABLE que j'accuse quand je lance l'application...
Et d'après TaMaMBoLo, ce problème a été rencontré sur d'autres machines...
Est ce la raison pour laquelle je n'obtiens pas de break sur l'INT 03, alors que d'autre n'ont aucunes misères?
La question est posée...
En tout état de cause, j'ai réussi à obtenir un break sur l'Entry Point de Zstudio.dll en
combinant le débuggeur de Wdasm (que je n'avais jamais utilisé) et SoftIce:
1- Pose d'un BPINT 3 dans Sice
2- Chargement du programme dans le débuggeur de Wdasm (project/debug/Load process)
3- Goto Address -> 1003E000, l'entry point de la dll
4- Patch -> int 3, puis Apply patch
5- Début du tracing over
6- Pop sur l'EP de la dll dans SI. OUF!
Here we are...
Pour ne pas faire crasher le système, pensez à remplacer le CC par 83, la valeur d'origine. Le plus
rapide est de taper "e 1003E00", de se placer avec le curseur de la souris sur le CC de la fenêtre
des Datas, de remplacer celui ci par 83, puis Echap.
017F:1003E000 833DE811041000 CMP DWORD PTR [100411E8],00
017F:1003E007 7408 JZ 1003E011
017F:1003E009 A1E8110410 MOV EAX,[100411E8]
017F:1003E00E FFE0 JMP EAX
Le tracing DANS SoftIce va pouvoir commencer.
L'écran de FrogIce va apparaître en traçant sur le call 1003E57A en 1003E060.
Il ne reste plus qu'à recommencer le All Process, pour pouvoir aller visiter ce call, puis un autre, et
vous finirez par atterrir ici:
10040139 B443 MOV AH, 43 > EAX = 4300
1004013B CD68 INT 68 > détection SI, et au retour
1004013D 8945FC MOV [EBP-04],EAX > place le résultat dans EBP-04
10040140 817DFC86F30000 CMP DWORD [EBP-04], 0000F386 > = F386? -> Sice actif
10040147 7507 JNZ 10040150 > sinon Xor eax
10040149 B801000000 MOV EAX;00000001 > eax = 1 si sice actif
1004014E EB02 JMP 00820F52 > saute le Xor eax
10040150 33C0 XOR EAX, EAX > eax = 0 si SoftIce est "absent"
10040152 5F POP EDI > etc jusqu'au RET
Les mêmes codes que ceux donnés par le "code.txt"
de FrogIce, et que je n'avais pas trouvés en faisant une recherche dans WDASM. Voici la confirmation que
cette partie de la DLL est compressée. Par contre comme ProcDump ne m'avait pas indiqué de compression
UPX sur cette DLL, il doit s'agir d'une autre bidouille.
Repartons à la chasse aux infos: (Contribution de Psyché)
En face de ce genre de protection, il faut recueillir le maximum d'informations,
pour en savoir un peu plus sur la cible visée:
UPX est une première information livrée par ProcDump.
L'option "propriété" de windows sur zstudio.dll, va donner d'autres éléments:
Commentaires: Amiga Module Plugin
Nom d'origine du fichier: npmod32.dll
Organisation: Olivier Lapicque
Une nouvelle petite promenade dans un éditeur hexadécimal
va révéler une autre surprise:
Zhang Dehua(Gleamd@usa.net)1999.3.1 ,This Program Protected
by CodeSafe...
Il y a donc aussi un crypteur d'appliqué à Zip Studio. Comme quoi, il ne faut jamais s'éviter
des recherches approfondies. Voyons ce que l'on peut rassembler sur Code Safe:
What is CodeSafe? (A lire: FruityLoops 1.40 by Ethan)
This program ,named "CodeSafe"(old name "Gleam"), could protect your program , include executable
file(.EXE) and Dynamic Link Library(.DLL),from being cracked or running without your permission.You may need it
in the case of below:
First,If you have a important program.You can use this program to lock your program with a password .Then before
the user run your program,he/her must know the correct password. ATTENTION : password locking DLL file is abnormal
.
Second,CodeSafe could "stealth" your "true" code and resource.If you are a developer ,you have
some critical code in your program,such as judge the correct of inputed SericlaNO or registration information.
Nowdays ,it is easy to crack.Now this program could "encript(not truely)" your code and/or resource.
Of course,To enhance this
function,CodeSafe have some code to Anti_Debug_Tools also,these function will be enhanced in the future version.
De là, il est facile de conclure que la protection anti-SI
est due à Codesafe, et que les dll, comme l'exécutable ont été cryptés, alors
qu'UPX ne compresse que l'exécutable. L'usage du Script d'Ethan pour ProcDump sur Zip Studio, ne donnant
rien, de tout façon, il faut continuer...
A ce stade, ce qui était important était le "pourquoi"
et "comment" de la protéction, et pas le "comment" la
cracker.
En recommençant le All Process à son départ, mais en ayant pris le soin de taper un "d
1004013B", vous allez tracer depuis l'Entry point de Zstudio.dll, jusqu'à voir les ?????? affichés
dans la fenêtre des datas être remplacés par CD 68 89. Ainsi vous pourrez repérer le
call dans lequel les codes à l'adresse 1004013B deviennent "propres".
En l'occurrence, le call en question est en 1003E060.
Un rapide détour par un éditeur hexadécimal va vous confirmer que les codes de ces adresses
sont accessibles, et non compressés.
Zuper!
D'autant plus que le JMP qui suit ce fameux call 1003E57A va nous permettre d'insérer un petit patch rapide et facile,
la place est disponible:
017F:1003E060 E815050000 CALL 1003E57A > décompression
017F:1003E065 EB28 JMP 1003E08F > passe les lignes suivantes
017F:1003E067 8B1578110410 MOV EDX,[10041178]
017F:1003E06D 2B1580110410 SUB EDX,[10041180]
017F:1003E073 52 PUSH EDX
017F:1003E074 A180110410 MOV EAX,[10041180]
017F:1003E079 50 PUSH EAX
017F:1003E07A E885010000 CALL 1003E204
017F:1003E07F 50 PUSH EAX
017F:1003E080 E8F5040000 CALL 1003E57A
017F:1003E085 6898160410 PUSH 10041698
017F:1003E08A E8F3020000 CALL 1003E382
017F:1003E08F E84C3F0000 CALL 10041FE0 > arrivée ici
017F:1003E094 E8DD200000 CALL 10040176 > test présence SI
La proposition de TeeJI:
Dans la mesure ou se travail a été réalisé collectivement, chacun à apporter
son écot. Voici une solution possible pour détourner l'Anti SI:
Ce call est suivit par un Jump.. je pensais le détourner.. mais cela n'est pas possible car c'est un Jump
Near codé sur 3 bytes.. On détournera donc le call suivant :
:1003E08F CALL 1003E213
J'ai trouvé du code vierge ( 00h ) pour mon patch en :10041FE0 ou je devrai y insérer ces instructions
:
MOV WORD PTR[1004013B],9090 | nop le INT68
JMP 1003E213 | redonne la main au call en 1003E213 que
| nous avons détourné
On modifie maintenant le CALL 1003E213 par CALL 10041FE0 et on écrit
le patch en 10041FE0
Résultat de l'opération.. Plus de problème d'Anti-sice..
Voici pour le premier Anti-SoftIce. Passons au suivant:
La deuxième détection, toujours un code 07, se trouve en 00820F39, dans une zone compressée
maison:
00820F39 B443 MOV AH, 43 > EAX = 4300
00820F3B CD68 INT 68 > détection SI, et au retour
00820F3D 8945FC MOV [EBP-04],EAX > place le résultat dans EBP-04
00820F40 817DFC86F30000 CMP DWORD [EBP-04], 0000F386 > = F386? -> Sice actif
00820F47 7507 JNZ 00820F50 > sinon Xor eax
00820F49 B801000000 MOV EAX;00000001 > eax = 1 si sice actif
00820F4E EB02 JMP 00820F52 > saute le Xor eax
00820F50 33C0 XOR EAX, EAX > eax = 0 si SoftIce est "absent"
00820F52 5F POP EDI > etc jusqu'au RET
A ce niveau il n'y a que l'embarras du choix:
- Noper l'INT 68 (ou faire un inc EAX, dec EAX)
- Faire un mov eax, 00 en 00820F49
- Forcer un jmp (EB07) en 00820F47 pour aller Xorer le EAX
- Eventuellement, placer un RET sur la première instruction de ce call
(Vous remarquerez que cette routine est un coupé/collé de la précédente. Mieux, la
différence entre l'adresse 1004013B (1er INT 68) et 00820F3B (le 2ème ) est exactement de F81F200,
et que cette différence s'applique aussi bien à la routine de décompression (1003E060 - F81F200
= 0081EE60). Ce qui tenderait à prouver que l'ensemble de la procédure décompression/détection/etc
a subie le même traitement CodeSafe...)
Ces adresses se trouvent dans un call 00820F30 en 00820F96. La décompression se fait dans le call 0081F37A
en 0081EE60. Il y a possibilité de patcher juste après, comme aux adresses du premier Anti-Sice.
Pour y arriver, il a suffit d'un BPINT 3 et d'un CC sur l'entry point de l'exécutable, et de tracer tranquillement.
Le break sur l'Int 3 se faisant "spontanément" le jumelage Wdasm/SoftIce n'a pas été
nécessaire.
017F:0081EE60 E815050000 CALL 0081F37A > décompression
017F:0081EE65 66C705470F8200EB07 MOV WORD PTR [00820F47],07EB
017F:0081EE6E EB1F JMP 0081EE8F > continu
017F:0081EE70 90 NOP > équilibre le nb d'octets
017F:0081EE71 90 NOP > modifié. Ce n'est pas
017F:0081EE72 90 NOP > indispensable…
017F:0081EE73 52 PUSH EDX
017F:0081EE74 A1801F8200 MOV EAX,[00821F80]
017F:0081EE79 50 PUSH EAX
017F:0081EE7A E885010000 CALL 0081F004
017F:0081EE7F 50 PUSH EAX
017F:0081EE80 E8F5040000 CALL 0081F37A
017F:0081EE85 6898248200 PUSH 00822498
017F:0081EE8A E8F3020000 CALL 0081F182
017F:0081EE8F E87F010000 CALL 0081F013
017F:0081EE94 E8DD200000 CALL 00820F76 > va tester SI
La compression UPX:
Il n'est pas très difficile de mettre la main sur la signature d'UPX. Toutes les versions que j'ai pu en
voir permettent de la trouver à la fin du listing désassemblé:
:0081B5EC 61 popad
:0081B5ED E98EF7CAFF jmp 004CAD80 > jump sur l'Entry point du prog d'origine
:0081B5F2 00000000000000000000 BYTE 10 DUP(0)
:0081B5FC 00000000000000000D42 BYTE 10 DUP(0)
Et c'est en 081B5ED que UPX passe le relais au programme d'origine.
"L'entrée" de la compression se fait en:
:0081B470 60 pushad > début du travail d'UPX
:0081B471 BE00507700 mov esi, 00775000
:0081B476 8DBE00C0C8FF lea edi, dword ptr [esi+FFC8C000]
:0081B47C 57 push edi
:0081B47D 83CDFF or ebp, FFFFFFFF
:0081B480 EB10 jmp 0081B492
:0081B482 90 nop
:0081B483 90 nop
:0081B484 90 nop
:0081B485 90 nop
:0081B486 90 nop
:0081B487 90 nop
Ces adresses ont pu être trouvées grâce à
un autre fichier (Notepad que Gnome avait compressé avec UPX 0.84), et qui lui, n'ayant pas de routine Anti
SI démarre par ces codes.
Une rapide recherche dans un éditeur hexadécimal a permis de mettre la main sur la correspondance
Notepad/Zip Studio.
Lorsque nous avions fait cela, nous étions encore à la recherche des adresses ou "coincer"
la détection SI, et avant de savoir que Zstudio.dll était lancé AVANT Zip Studio.exe.
Créer un DUMP de Zip Studio, devient alors très facile, et sans avoir besoin de SoftIce. Il suffit,
dans Wdasm, FrogIce étant actif, de poser un breakpoint sur 0081B470, et de remplacer le jmp 0081B492 par
un jmp 0081B480. D'utiliser ensuite ProcDump pour faire un Dump Full, avec l'option "rebuilt New Import Table",
et de replacer le nouvel entry point (0041B480). Le fait de reconstruire l'Import table va nous débarasser
de Zstudio.Dll de façon définitive.
Vous obtiendrez alors un exécutable de 4 237 ko (au lieu des 1 391 ko d'origine), et toutes les ressources
nécessaires (String datas références en tête) pour continuer "l'étude"
du schéma de protection, dans des conditions d'autant plus satisfaisantes que le Dump Obtenu NE S'OCCUPE PLUS DE LA DETECTION SOFTICE.
Mais le but du jeu étant de réussir un patch "propre" du programme d'origine...
TeeJi prend le relais…
Passons au .EXE ! Il est compressé par UPX mais en fait on
s'en tape car nous avons
pas besoin de le désassembler... Il suffit de lancer ZipStudio.exe ( il faut enlever
l'espace entre le 'Zip' et le 'Studio' dans le nom de fichier afin d'éviter des problemes
sous Sice ) Vous quittez.. et on voit le NagScreen. Vous faites CTRL-D pour aller sous
Sice, vous tapez TASK et vous voyez Zipstudi. Vous regardez maintenant les objets de
cette applicatiopn en faisant Hwnd Zipstudi et vous voyez dans la liste :
Window Handle hQueue SZ QOwner Class Name Window Procedure
*********************************************************************
06D8(1) 19D7 32 ZIPSTUDIO TPubFrm 334F:00000694
01E8(2) 19D7 32 ZIPSTUDIO Button 334F:00000AB4
C'est donc surement une application écrite en Delphi. Sous
Delphi chaque fenêtre est
une forme. Ici vous voyez la forme TPubFrm .. un nom élogieux qui dis TOUT ! :)
Le Handle de cette fenêtre est 06D8 chez moi mais cela change tout le temps. Mettez
un BMSG 06D8 WM_COMMAND et retournez sous Win.. Clickez OK sur le Nag et vous êtes de
retour sous Sice. apres quelques F12 vous vous retrouverez dans un bloc ou plusieusr calls
se suivent :
0177:004C95C3 E89C4AF6FF CALL 0042E064 <-- RETRECISSEMENT DE LA FENETRE
0177:004C95C8 A164A94E00 MOV EAX,[004EA964]
0177:004C95CD 8B00 MOV EAX,[EAX]
0177:004C95CF 33D2 XOR EDX,EDX
0177:004C95D1 E88E4AF6FF CALL 0042E064
0177:004C95D6 8D55F4 LEA EDX,[EBP-0C]
0177:004C95D9 8B83B8050000 MOV EAX,[EBX+000005B8]
0177:004C95DF E8B087F5FF CALL 00421D94
0177:004C95E4 8B55F4 MOV EDX,[EBP-0C]
0177:004C95E7 A164A94E00 MOV EAX,[004EA964]
0177:004C95EC 8B00 MOV EAX,[EAX]
0177:004C95EE 8B8024020000 MOV EAX,[EAX+00000224]
0177:004C95F4 E8CB87F5FF CALL 00421DC4
0177:004C95F9 A164A94E00 MOV EAX,[004EA964]
0177:004C95FE 8B00 MOV EAX,[EAX]
0177:004C9600 E82766F6FF CALL 0042FC2C <-- APPEL DU NAG
0177:004C9605 A19CAA4E00 MOV EAX,[004EAA9C]
0177:004C960A 8B00 MOV EAX,[EAX]
0177:004C960C E8BF85F6FF CALL 00431BD0 <-- QUIT ( JE SUIS PLUS CERTAIN )
Donc, à la place de nopper les 2 call ( RETRECISSEMENT et NAG ) on va simplement mettre
un ret en 0042E064 et en 0042FC2C ( 2 Bytes à modifier contre 10 :) Pour faire cela on va
simplement modifier le code au bout de la section, la ou UPX donne la main au programme :
:0081B5ED E98EF7CAFF JMP 0FFD56180 <-- JMP Original EP
On remplace par :
:0081B5ED C6052CFC4200C3 MOV b,[00042FC2C],0C3
:0081B5F4 C60564E04200C3 MOV b,[00042E064],0C3
:0081B5FB E980F7CAFF JMP 0FFD56180
REM : MOV b,[00042FC2C],0C3 correspond a MOV BYTE PTR[0042FC2C],C3 sous Sice !
On sauve et on est heueux :)
|