ASDSEE version 3.0 Modèle 103 FR

En voulant désassembler ce soft, Wdasm ne va pas reconnaître, dans le PE Header, la signature d'un exécutable valable, et le Symbol Loader de SoftIce va lancer l'application sans s'arrêter sur la case départ...

Un petit tour par ProcDump s'impose, pour jeter un coup d'œil sur les caractéristiques des sections :

Vous aurez sans doute deviné que le packer d'ACDSEE est ASPack...
Et vous aurez probablement remarqué que dans cet exemple, toutes les sections ont C0000040 comme caractéristique (c'est une constante, car il faut que la section soit Readable, Writeable et Data). Ainsi, le programme peut lire le code compressé, et le décompresser dans la même section sans provoquer d'erreur fatale dans Windows), ce qui, normalement, vous empêche de désassembler l'exécutable, ou d'obtenir un break en passant par le Symbol Loader de SoftIce.
En modifiant la première section (.text), et en remplaçant C0000040 par E0000020 à l'aide de ProcDump, vous pourrez reprendre la main avec SoftIce, et obtenir un listing, sans les ressources (Strings Data...) dans Wdasm.

Petit rappel sur les attributs des sections :
0x20...... : signifie eXecutable
0x40...... : signifie Readable
0x60...... : signifie eXecutable + Readable
0x80...... : signifie Writeable
0xC0...... : signifie Readable + Writeable
0xE0...... : signifie Readable + Writeable + eXecutable

0x......20 : signifie contains Code
0x......40 : signifie Initialized data
0x......80 : signifie Unitialized data

Un attribut égal à E000020 va préciser au programme qu'il contient du code eXecutable, Readable et Writeable. Le " Toutes Options " Koa !

Voici comment vous y prendre pour modifier les caractéristiques des sections:
Dans ProcDump, en cliquant sur le bouton PE EDITOR, vous allez obtenir des informations sur le Soft compressé :
L'image Base qui semble toujours être 400000 et la valeur de l'Entry point.
En cliquant sur le bouton " Sections ", vous obtiendrez l'écran suivant :

Pour rappel : tout programme est divisé en sections, et chaque section possède une entrée dans le PE Header, ce qui veut dire que le loader possède lui aussi une section dans le PE Header. ProcDump va nous permettre de connaître les détails de celle ci ( celle contenant l'Entry Point):

Name     Virtual Size   Virtual Offset   Raw Size     Raw Offset
.aspack    0001B000       0015A000       0001A200      00085400   

La Virtual size de la section est 1B000, ce qui veut dire que la mémoire qui sera allouée pour cette section sera de 1B000 bytes. Le Virtual Offset de la section, et donc du code appartenant au loader, est de 0015A000, additionné à l'Image base qui vaut 00400000, ce qui nous donne une adresse virtuelle de 0055A000.

Une fois modifié les caractéristiques de la première section (.text), le Symbol loader de softIce va nous faire breaker sur l'EntryPoint de notre cible :

Entry Point

:0055A001    PUSHAD                   ; sauve les registres sur la pile
:0055A002    CALL      0055A577       ; va récupérer la valeur de EBP
:0055A007    JMP       0055A055       ; et continue...
:0055A009    ADD       [EAX],AL

Récupération de l'adresse en cours

:0055A577    MOV       EBP,[ESP]      ; récupère l'adresse de retour du call
:0055A57A    SUB       EBP,004439AB   ; la soustrait à l'adresse d'ASPack
:0055A580    RET

Quelques explications :
ASPack provoque un call. Le processeur va placer l'adresse de retour sur la pile et dans ESP. Le Mov EBP,[ESP] va récupérer cette adresse dans EBP.
Lors de la compilation d'ASPack, le programme s'est vu attribué une adresse d'origine (004439AB ).
Un sub EBP,004439AB, ou EBP contient l'EIP de retour, va placer la différence entre les offsets de la compilation d'origine et ceux de la nouvelle implantation au sein d'un programme hôte. Ainsi, un LEA EAX,[EBP+00443B72] va "corriger" la différence entre l'adresse où se trouvaient les adresses visées par ASPack dans sa version d'origine (00443B72) et celle ou elles se trouveront après avoir packé une cible (différence contenue dans EBP + adresse d'origine). Dans le cas d'ACDSee, EBP vaut 11665Ch.

ASPack décompresse les applications en plusieurs passes. Voici un exemple de passage de relais entre la première passe de décompression et la suivante :

1er passage de relais

:0055A0AC    MOV       [EBP+004439E5],EAX ; sauvegarde l'adresse contenue dans EAX
:0055A0B2    LEA       EAX,[EBP+00443B72] ; récupère l'adresse de destination 
:0055A0B8    JMP       EAX                ; saute à cette adresse
:0055A0BA    ADD       [EAX],AL           ; octets NULL

Mais le passage de relais à trouver est celui ci :

:0055A4DB    MOV       EAX,[EBP+00443A76] 
:0055A4E1    PUSH      EAX
:0055A4E2    ADD       EAX,[EBP+00444804]
:0055A4E8    POP       ECX
:0055A4E9    OR        ECX,ECX
:0055A4EB    MOV       [EBP+00443EA1],EAX
:0055A4F1    POPAD
:0055A4F2    JNZ       0055A4FC
:0055A4F4    MOV       EAX,00000001
:0055A4F9    RET       000C
:0055A4F9    RET       000C
:0055A4FC    PUSH      00000000
:0055A501    RET

Il est facile à trouver. Pour y arriver, il suffit, juste après que le programme ait marqué un break sur l'Entry Point, de rechercher un POPAD, suivie d'un ou plusieurs RET, en utilisant l'ascenseur de la fenêtre des codes.

Commentons un peu ces lignes :

:0055A4DB    MOV       EAX,[EBP+00443A76] ; charge 0A2AAF dans EAX

Le MOV EAX,[EBP+00443A76] va récupérer une partie de l'adresse (0A2AAF) de l'Entry Point du programme d'origine. Cette adresse est stockée en clair dans les codes d'ACDSee en :

.00510C60:  BE 16 65 0F-04 0E E1 FD-24 CF 8B FA-26 AF 2A 0A  
.00510C70:  AD 9F B0 FE-B6 F9 E6 2B-27 29 D3 70-0A E7 6F B4 

et en ([11665C+00443A76] = 0055A0D0) :

.0055A0D0:  0E 00 AF 2A-0A 00 00 00-00 00 00 00-00 00 00 10
.0055A0E0:  00 00 00 E0-0C 00 00 F0-0C 00 00 50-01 00 00 00

La première adresse de stockage est utilisée par l'application en :

:0055A879    MOV       DL,[ECX]     ; prend un bit de l'@ 510C6D
:0055A87B    INC       ECX          ; passe au bit suivant
:0055A87C    MOV       [ESP+0C],DL  ; stock le bit dans ESP+0C

Probablement à des fins de contrôles à ce qui m'a semblé, et la seconde adresse juste avant le passage final du relais. Ces bouts d'adresses se trouveront toujours placé aux mêmes endroits, quelques soit le programme compressé par cette version d'ASPack.

:0055A4E1    PUSH      EAX                 ; pousse 0A2AAF
:0055A4E2    ADD       EAX,[EBP+00444804]  ; ajoute ImageBase stockée en EBP+00444804
:0055A4E8    POP       ECX                 ; récupère 0A2AAF dans ECX
:0055A4E9    OR        ECX,ECX             ; vérifie qu'ECX n'est pas NULL
:0055A4EB    MOV       [EBP+00443EA1],EAX  ; PATCH le programme
:0055A4F1    POPAD                         ; restitue les registres
:0055A4F2    JNZ       0055A4FC            ; va vers Entry Point2 si ECX non NULL
:0055A4F4    MOV       EAX,00000001        ; EAX = 1 (Flag)
:0055A4F9    RET       000C                ; retourne à ASPack
:0055A4F9    RET       000C
:0055A4FC    PUSH      00000000            ; Adresse du PATCH ASPack
:0055A501    RET                           ; Goto Entry Point d'ACDSee

Le contenu de ces adresses est visible par un U CS:55A4DB dès le break sur l'Entry Point, le loader ASPack d'ACDSee n'étant pas, lui même, compressé comme ce sera le cas dans d'autres versions.

En posant un BPX 0055A4F1, vous verrez les effets du patch qu'ASPack s'inflige :

:0055A4F1    POPAD
:0055A4F2    JMP       0055BFBF
:0055A4F7    ADD       [EAX],AL
:0055A4F9    RET       000C
:0055A4FC    PUSH      004A2AAF            ; Entry Point du programme cible
:0055A501    RET

Dumper le programme en mémoire:

Lancez le programme/cible via le Symbol Loader de Softice . De cette façon SoftIce pourra prendre la main.
Posez un bpx sur le second RET (en 0055A501) et faites [F5] pour relancer le programme. Au break, passez en mode assemblage, et changez le RET par un JMP EIP. Ainsi, vous obligerez le programme à boucler sur lui-même.
Rouvrez ProcDump, et cliquez sur " Options " pour choisir " Rebuilt Import Table ", puis sélectionnez l'application dans la liste des taches actives de la fenêtre de ProcDump. Après quelques instants, vous pourrez sauver un joli dump du nouvel exécutable prêt a être patché si l'envie vous en prend, avec du beau code tout clean.

Rendre le fichier obtenu exécutable:

Le zoli exécutable obtenu ne va pas pour autant fonctionner. Il faut encore lui indiquer quel va être son nouvel Entry Point. C'est encore ProcDump qui va nous permettre de réaliser facilement cette modification.
Ouvrez ProcDump, et choisissez "PE EDITOR"

L'Entry Point dont vous aurez relevé l'adresse dans SoftIce (le contenu de EAX, soit 0A2AAF) va venir remplacer le précèdent Entry Point (15A001).
Relancez le programme...
Ca marche !
Tout ceci n'aura pris que quelques minutes...
Passons à la suite.

Désassemblez le Dump obtenu, vous obtiendrez les String Data Reférences.

Je me suis intéressé à celles qui me paraissaient les plus représentatives d'une version Shareware :

"Version d'évaluation"                   ; deux adresses
"Votre période d'essai est terminée"     ; une adresse

En regardant à ces trois adresses, un call/test/jump a tout de suite attiré mon attention :

:00414EEO       mov ecx, 004E9F98
:00414EE5       call 00498A90
:00414EEA       test eax, eax
:00414EEC       jne 00414F17
:00414EEE       lea ecx, dword ptr [esp+00000114]
:00414EF5       push 00000050
:00414EF7       push ecx
:00414EF8       call dword ptr [004CF29C]
:00414EFE       lea edx, dword ptr [esp+eax+00000118]
:00414F05       mov eax, dword ptr [004E9FD0]
:00414FOA       push edx

* Possible Reference to String Resource ID=00195: "Version d'évaluation"
I
:00414FOB       push 000000C3

la seconde String Data "Version d'évaluation" est le coupé/collé de la première :

:00429CEB       call 00498A90
:00429CF0       test eax, eax
:00429CF2       jne 00429D14
:00429CF4       lea eax, dword ptr [esp+08]
:00429CF8       push 00000050
:00429CFA       push eax
:00429CFB       call esi
:00429CFD       mov edx, dword ptr [004E9FD0]
:00429D03       lea ecx, dword ptr [esp+eax+0C]
:00429D07       push ecx

* Possible Reference to String Resource ID=00195: "Version d'évaluation"
I
:00429D08       push 000000C3

pour la troisième adresse, il ne faut pas hésiter à remonter un peu dans le Dead Listing :

:0043CEF5       call 00498A90
:0043CEFA       test eax, eax
:0043CEFC       jne 0043CFBF
:0043CF02       push ebp
:0043CF03       mov ecx, 004E9F98
:0043CF08       call 004991AO
:0043CFOD       mov ebp, dword ptr [004CF664]
:0043CF13       mov edi, eax
:0043CF15       test edi, edi
:0043CF17       jg 0043CF3A
:0043CF19       mov edx, dword ptr [004E9FD0]
:0043CF1F       lea ecx, dword ptr [esp+00000098]

* Possible Reference to String Resource ID=00150: "&Arrêter"
I
:0043CF26       push 00000096
:0043CF2B       push ecx

* Possible Reference : "Votre période d'essai est terminée"
I
:0043CF2C       push 00000253

Allons jeter un coup d'œil à ce call :

* Referenced by a CALL at Addresses:
|:00401C11   , :00407C33   , :00407E54   , :00414EE5   , :0041FD24
|:00420E09   , :00429CEB   , :0043CD85   , :0043CEF5   , :00497884
|:00497C1A
I
:00498A90       xor eax, eax
:00498A92       ret

En regardant à quoi pouvaient bien mener ces 11 adresses, j'ai pu constater que ce call était systématiquement lié à de méchantes choses sharewares...

Mieux! A la sortie de ce call, le test qui le suivait était toujours du type JNE (Jump if Not Equal). Il suffit donc qu'EAX soit égal à autre chose que 00 pour que le bug soit corrigé ?

En vérifiant avec SoftIce, j'ai pu observer qu'EAX pouvait avoir des valeurs très variables, mais qu'en empêchant la mise à zéro de ce registre, le programme fonctionnait très bien.

Il suffit alors de remplacer le XOR EAX,EAX par un NOP INC EAX, ou un NOP DEC EAX, voir par deux NOP...

Patcher le programme compressé :

Pour rajouter le code à la fin du code du programme compressé, vous devrez trouver une place disponible qui ne sera pas utilisée par ASPack lors de la décompression du programme d'origine.
Dans la mesure ou il y a toujours un peu de Padding à la fin de chaque section (des 0000 qui viennent compléter la taille de celle ci pour s'aligner sur un multiple du CODE), c'est en partant de la fin de la section dans laquelle on envisage de placer notre patch qu'il va falloir trouver une petite place pour se glisser :

Dernière section :

Name        Virtual Size   Virtual Offset   Raw Size       Raw Offset    
.rsrc         0001000         00175000      00000000        0009F600

le virtual offset de la dernière section est 00175000, ce qui veut dire que la fin de la section .aspack se trouvera juste avant 0055A000 + 00175000 = 00575000

En partant de l'adresse trouvée, il suffit de remonter jusqu'à trouver des bytes sur lesquels il sera possible d'écrire (ce qui n'est en général pas le cas des INVALID, à moins de modifier les caractéristiques de la section, combiné avec l'utilisation d'un hexEditeur).

:0055BFF7  0000                ADD       [EAX],AL
:0055BFF9  0000                ADD       [EAX],AL
:0055BFFB  0000                ADD       [EAX],AL
:0055BFFD  0000                ADD       [EAX],AL
:0055BFFF  00FF                ADD       BH,BH
:0055C001  FFFF                INVALID
:0055C003  FFFF                INVALID
:0055C005  FFFF                INVALID
:0055C007  FFFF                INVALID

Le patch que j'envisage de créer aura une taille de 15d octets. Il serait donc possible de s'installer en 0055BFF0. Par sécurité, et après avoir testé à l'aide d'un BPR 0055BFBF 0055BFFF RW que la place à squatter ne sera pas utilisée, je vais m'installer en 0055BFBF.

Patch

:0055BFBF  66C705908A49009048  MOV       WORD PTR [00498A90],4890
:0055BFC8  68AF2A4A00          PUSH      004A2AAF
:0055BFCD  C3                  RET
:0055BFCE  000A                ADD       [EDX],CL

Dans la mesure ou le loader n'est pas compressé, cette seule modification va suffire à détourner la protection et corriger le bug dont le programme était affligé.


Dernière petite chose, si vous souhaitez modifier les information apparaisant dans la boite ABOUT, vous pouvez aller dans la base de registre en:
[HKEY_LOCAL_MACHINE\Software\ACD Systems\ACDSeeF]

Et bidouiller à votre guise...