|
Les Anti Soft-Ice |
||||
|
By PuLsar |
Softice 4.01 Un petit travail de reverse (première partie...)
Suite à mon dernier essai sur le tricks anti-sice il m'a semblé
intéressant de proposer un tut sur la façon de parer ces techniques. J'ai donc désassemblé
SoftICE pour tenter de le reverser et essayer d'en comprendre le fonctionnement :) Comme on connaît les bytes de la routine qui autorise les back-doors
dues a l'int 03h, dans IDA il n'y a plus qu'à chercher ces codes que l'on trouve a l'offset C00024B4 Woo une Cross reference :) allons voir :) Regardez les différents codes de détection de Sice: Je vous laisse le soin de patcher votre softice en exercice pour éviter
tout les zolis programmes comme Vbox qui utilisent un exception handler et l'int 03h comme protection :)) Pour le moment on sait pas encore que le call suivant est celui qui permet
d'afficher une chaîne de caractère mais on peut déjà s'en douter car elle prend comme
argument l'offset d'une chaîne de caractères terminée par un 0 En regardant au niveau de l'offset de FonctionAppellee, on trouve les lignes
suivantes que je commenterai ensuite:
Au début on ne trouve que des dd offset loc_C0XXXXXX, ce qui signifie
que ce call est basé par l'index ecx C'est le premier volet de reverse sur softice, il faut un peu en sentir le
code :) Héhé, on dirait que l'hypothèse n'atait pas si mauvaise
que cela, car on voit le "No embedded INT 1 or INT 3" suivit de notre fonction DisplayString2 :))
IDA ayant finit son travail, voici ce que j'ai pu découvrir :)
premier constat: Ce programme a sûrement été code en asm, les codeurs de Numega sont vraiment
des Gourous de la programmation low-level, leur travail est vraiment sensationnel
Comme je cherchais à enlever la méthode BCHK, il fallait trouver la routine qui manageait l'int 03h
Donc petit tour sous softice:
On tape IDT et on regarde un peu ce qu'il nous donne l'animal, et on dirait qu'il n'aime pas trop qu'on regarde
ses fonctions:))
IDTbase=800A0000 Limit=02FF
0000 IntG32 0028:C0001350 DPL=0 P VMM(01)+0350
0001 IntG32 0028:C0001360 DPL=3 P VMM(01)+0360 <-ici c'est l'int 01h
0002 IntG32 0028:C00046E0 DPL=0 P Simulate_IO+02A0
0003 IntG32 0028:C0001370 DPL=3 P VMM(01)+0370 <-ici la 03h
--------
|____________________ addresse de la routine qui contrôle l'int 03h
0004 IntG32 0028:00000004 DPL=3 P
0005 IntG32 0028:00000005 DPL=3 P
0006 IntG32 0028:C00013A0 DPL=0 P VMM(01)+03A0
0007 IntG32 0028:C00013B0 DPL=0 P VMM(01)+03B0
0008 TaskG 0068:00000000 DPL=0 P
0009 IntG32 0028:C00013C0 DPL=0 P VMM(01)+03C0
000A IntG32 0028:C00013E0 DPL=0 P VMM(01)+03E0
Regardez attentivement les offsets qu'il donne pour les int 01h et int 03h VMM(01)+360h et VMM(01)+370
Ca ne nous arrange pas trop parce que ces offsets tombent dans le Vmm et non dans softice comme ce serait souhaitable.
:(( or on sait que c'est softice qui manage ces routines pour les pbx (int 03h) et les bpm , le trace...(int 01h)
Donc il va falloir trouver nous même ces routines
On retape IDT et on regarde l'IDTbase=800A0000 (ces valeurs peuvent changer d'un Pc à l'autre), on fait
dd puis on tape d 800A0000.
(pour plus d'explication, referez vous à mon texte sur les intérruptions)
Voila mon IDT
0030:C000D474 00281350 C0008E00 0028AFDA C00EEE00 P.(.......(.....
0030:C000D484 00288BF6 C0038E00 0028AFE0 C00EEE00 ..(.......(.....
0030:C000D494 0028AFE7 C00EEE00 0028AFEF C00EEE00 ..(.......(.....
0030:C000D4A4 00288C14 C0038E00 002813B0 C0008E00 ..(.......(.....
0030:C000D4B4 00680000 00008500 00288CAA C0038E00 ..h.......(.....
0030:C000D4C4 002813E0 C0008E00 00288C23 C0038E00 ..(.....#.(.....
0030:C000D4D4 0028E7C4 C0028E00 00288C41 C0038E00 ..(.....A.(.....
0030:C000D4E4 00288C50 C0038E00 00288CB9 C0038E00 P.(.......(.....
0030:C000D4F4 00284720 C000EE00 00284728 C000EE00 G(.....(G(.....
0030:C000D504 00284730 C000EE00 00284738 C000EE00 0G(.....8G(.....
0030:C000D514 00284740 C000EE00 00284748 C000EE00 @G(.....HG(.....
0030:C000D524 00284750 C000EE00 00284758 C000EE00 PG(.....XG(.....
0030:C000D534 00284760 C000EE00 00284768 C000EE00 `G(.....hG(.....
0030:C000D544 00284770 C000EE00 00284778 C000EE00 pG(.....xG(.....
On a comme offset pour notre int03h C00EAFE0.
En faisant u C00EAFE0 pour voir ce qu'il y a, on trouve un JMP C0038C05
Puis u C0038C05 et cette fois ci on obtient PUSH XXXXXX
JMP C0031798
En faisant un u C0031798 on trouve une partie de code intéressant :)))
En effet on reconnaît vite des codes qui pourraient être à l'origine des méthodes 'BCHK'
et des magics word dans esi et edi..0028:C0031798 FC CLD
0028:C0031799 E8AAD50400 CALL C007ED48
0028:C003179E 2E803DCD3F08C001 CMP BYTE PTR CS:[C0083FCD],01
0028:C00317A6 7501 JNZ C00317A9
0028:C00317A8 C3 RET
0028:C00317A9 E8BC590000 CALL C003716A
0028:C00317AE 8D642404 LEA ESP,[ESP+04]
0028:C00317B2 81FD4B484342 CMP EBP,4243484B ;CMP EBP,'BCHK'
0028:C00317B8 0F84C7250700 JZ C00A3D85 ;JZ BCHK_ROUTINE
0028:C00317BE 6681FE4746 CMP SI,4647 ;CMP SI,'FG'
0028:C00317C3 752A JNZ C00317EF
0028:C00317C5 6681FF4D4A CMP DI,4A4D ;CMP DI,'JM'
0028:C00317CA 7523 JNZ C00317EF ;JNZ Fonction_Normale
0028:C00317CC E857060000 CALL C0031E28 ;Magic_Value_Fonction
0028:C00317D1 7316 JAE C00317E9
0028:C00317D3 C7052EE805C004000100 MOV DWORD PTR [C005E82E],00010004
0028:C00317DD C605B85A03C000 MOV BYTE PTR [C0035AB8],00
0028:C00317E4 E8EB060000 CALL C0031ED4
0028:C00317E9 E87B590000 CALL C0037169
0028:C00317EE CF IRETD
.........
Int03h: ; DATA XREF: HookInt+56 o
cld
call sub_C004FA64
cmp cs:byte_C0054CE9, 1
jnz short loc_C00024C5
retn
Les noms sont quelques peu modifiés.... pour permettre une meilleure compréhension :))HookInt proc near ; CODE XREF: LCOD:C000026C
p
var_8 = qword ptr -8
pusha
mov ebp, esp
sub esp, 8
mov ds:word_C000AD1C, fs
sidt [ebp+var_8]
mov esi, dword ptr [ebp+var_8+2]
mov ds:dword_C00066AF, esi
call sub_C0007D04
mov ecx, 0FFh
loc_C000798E: ; CODE XREF: HookInt+2B
j
mov ds:dword_C00062AF[ecx*4], ecx
loop loc_C000798E
mov eax, 1 ;01->int 01h? :)) oui c'est ca
mov dl, 60h ;dl=60 ->on hooke
mov edi, offset Int01h ;<- bizzare on appelle la meme fonction
call sub_C0007B97 ;pour notre int 03h
mov eax, 2
xor dl, dl
mov edi, offset loc_C0002A51
call sub_C0007B97
mov eax, 3 ;03=int 03h surement :)
mov dl, 60h
mov edi, offset Int03h ;<- là on trouve notre reference
call sub_C0007B97 ;on appelle Une Fonction qui hooke l'int 03h
mov eax, 6
xor dl, dl
mov edi, offset loc_C0001270
call sub_C0007B97
mov eax, 0Bh
xor dl, dl
mov edi, offset loc_C000134C
call sub_C0007B97
mov eax, 0Ch
xor dl, dl
mov edi, offset loc_C00014BA
call sub_C0007B97
mov eax, 0Dh
xor dl, dl
mov edi, offset loc_C0001517
call sub_C0007B97
mov eax, 0Eh
xor dl, dl
mov edi, offset loc_C000197B
call sub_C0007B97
mov eax, ds:dword_C00098FA
dec eax
imul eax, 0Fh
add eax, offset dword_C00098FE
lea eax, [eax+5]
mov ds:dword_C000ACC0, eax
mov eax, 41h ;on va hooker l'int 041h
mov dl, 60h ;héhé on retrouve le dl=60
mov edi, offset Int41h ;offset de notre int41h routine
call sub_C0007B97 ;Tjrs la meme fonction
call sub_C0007AAD
mov esp, ebp
popa
retn
HookInt endp ; sp = 20h
Et qu'y a t il dans l'int41??
Int 41h proc near ; DATA XREF: HookInt+D2 o
add esp, 4
cmp cs:byte_C0054CE9, 1
jz loc_C005401B
cmp cs:byte_C00067E8, 1
jnz short loc_C00539FA
cmp ax, 70h
jz short loc_C0053A0E
cmp ax, 4Fh ;ici si on appelle la fonction 4F de l'int41h
jnz short loc_C00539F9 ;les débuggers systemes renvoient 0F386 dans eax :)
mov eax, 0F386h ;la valeur magique:)
loc_C00539F9: ; CODE XREF: Int41h+25 j
iret
Voila pour le premier point... Vous êtes encore avec moi?
Alors c'est parfait on va pouvoir passer au second!!
Je vous propose de passer au gros morceau en attaquant ce qui me parait être le point principal de la fonction
qui traite ce qui est entré au clavier et qui redirige vers les différentes fonctions....
Une bonne chose à faire est d'aller chercher une string assez spécifique comme "Invalid Command"
que vous trouverez à l'offset C00135B5
Invalid_command: ; CODE XREF: sub_C0011B3D+1EA j
; LCOD:C007500F j LCOD:C0075179 j
; LCOD:C0075225 j
; DATA XREF: LCOD:C0016D47 o
mov esi, offset aInvalidCommand ; "Invalid command"
call DisplayString2
retn
On entre dans le call en regardant toutes les cross references faisant appels a cette fonction. A chaque fois esi
reçoit l'offset d'une chaîne de caractères, puis appel la fonction. On fera plus tard un petit
programme qui montrera que ca marche bien.
Maintenant qu'on a trouvé l'invalid command, il suffit de remonter les cross references.
Sur la XREF: sub_C0011B3D+1EA , on trouve quelque chose d'intéressant....
loc_C0011D1A: ; CODE XREF: sub_C0011B3D+1AE j
call sub_C000FD7F
call sub_C000FE15
shl eax, 2
call ds:FonctionAppellee[eax]
call sub_C000FE2D
FonctionAppellee dd offset Invalid_command ; DATA XREF: sub_C0011B3D+1EA
r
; LCOD:C007500F
r LCOD:C0075179
r
; LCOD:C0075225
r
dd offset AltScreen
off_C0016D4F dd offset BC_BD_BE ; DATA XREF: LCOD:C00751D2
r
dd offset BC_BD_BE
dd offset BC_BD_BE
dd offset BPINT
dd offset BPIO
dd offset BrkList
...........
........... ;Que des "dd offset XXXXXXXXXXX"
...........
dd offset Not_Done
dd offset Not_Done
dd offset Not_Done
dd offset Not_Done
off_C0016FF3 dd offset Not_Done ; DATA XREF: StatusBar+A6
o
CommandesPossibles db 2Eh ; . ; DATA XREF: GetFonctionCalled+5
o
; LCOD:C0017307
o
dd 3F3800h, 5E004130h
byte_C0017000 db 61h ; DATA XREF: sub_C0011AD0+7
w
aDdr db 'DDR',0
db 80h ; €
aAltkey db 'ALTKEY',0
db 36h ; 6
aAltscr_1 db 'ALTSCR',0
db 1 ;
aAnswer_0 db 'ANSWER',0
.......
.......
aD_3 db 'D',0
db 10h ;
aData_0 db 'DATA',0
db 3Ch ; <
.....
..... ;Ici il n'y a que des commandes suivie d'un byte special
aXrset db 'XRSET',0
db 47h ; G
aXt db 'XT',0
db 49h ; I
aZap db 'ZAP',0
db 52h ; R
(on le voyait par le code call ds:FonctionAppellee[eax]), et juste en dessous on trouve des strings terminées
par un 0 puis par un mystérieux byte, comme
aXrset db 'XRSET',0
db 47h ; G ;<- le mysterieux byte pour la string XRSET par exemple
aXt db 'XT',0
db 49h ; I ;<- le mysterieux byte pour la string XT
aZap db 'ZAP',0
db 52h ; R ;<- le mysterieux byte pour la string ZAP
Ce byte mystérieux va correspondre a la fonction qu'on va appeler ensuite, mais le problème est qu'il
n'y a pas que des multiples de 4 dans ces bytes, ce qui signifie que on ne tomberait pas sur des pointeurs valides
lors du "call ds:FonctionAppellee[eax]". Pourtant en regardant juste un peu plus haut on trouve:
call sub_C000FE15
shl eax, 2
call ds:FonctionAppellee[eax]
A à quoi peut bien correspondre ce shl eax,02 ?
C'est une multiplication par 4! Voilà qui fait notre affaire.
On va tester cette hypothèse. Imaginons qu'on tape ZAP la fonction sub_C000FE15 semblerait renvoyer la valeur
magique. Ca voudrait dire qu'on nous renverrait 52h, puis on multiplie le résultat par 4 et on l'ajoute
a l'offset de FonctionAppellee qui nous donne
C0016D47+52h*04=C0016E8F.
Puis en allant à l'offset donné par le dword en C0016E8F, on arrive à ceci:
ZAP: ; CODE XREF: LCOD:C007500F j
; DATA XREF: LCOD:C0016E8F o
mov edi, ds:dword_C00104BD
dec edi
dec edi
add edi, ds:dword_C00067E0
call sub_C004D7FC
call sub_C000B738
mov bx, 9090h
cmp ax, 1CDh
jz short loc_C001D946
mov bl, al
cmp ah, 0CCh
jnz short loc_C001D954
loc_C001D946: ; CODE XREF: LCOD:C001D93D j
mov ax, bx
call sub_C000B8F6
call sub_C000CBCD
retn
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
loc_C001D954: ; CODE XREF: LCOD:C001D944 j
mov esi, offset aNoEmbeddedInt1 ; "No embedded INT 1 or INT 3"
call DisplayString2
retn
J'espère que vous avez été suffisamment intéressé pour avoir envie de lire la prochaine édition :)
(Les contributions personnelles sur le reverse de SoftICE sont les bienvenues évidemment)
Greetz to:
Christal,Alsindor,Frog's Print,Spath,Acid_Burn,Stone,G-ROM,Elraizer,DXP,Fravia,ShroOm
Iczelion,ArseniK,Lucifer48,DXP,Nody,TeeJi,TaiefOon...and the others i've forgotten :)
Vous pouvez me joindre si vous avez des questions (ou si vous avez des sources asm a faire partager :))pulsar_c@geocities.com UIN:13411849
Pulsar Decembre 1999
(Ah j'allais oublier, j'ai fait un petit programme asm pour modifier une commande (ZAP en l'occurrence) et la rediriger vers une routine de votre choix.
Ce programme est joint avec le zip et les sources sont inclues.
Si vous souhaitez des commentaires, n'hésitez pas à me le demander, il y a certaines parties du code qui sont assez obscures:))