Les Menus
Hommage à +Spath
|
Intoduction : .text RVA: 00001000 Offset: 00000400 Size: 00001200 Flags: 60000020 .rdata RVA: 00003000 Offset: 00001600 Size: 00000600 Flags: 40000040 .data RVA: 00004000 Offset: 00001C00 Size: 00000400 Flags: C0000040 .rsrc RVA: 00005000 Offset: 00002000 Size: 00000800 Flags: C0000040 ProcDump: Directory Name VirtAddr VirtSize -------------------------------------- -------- -------- Export 00000000 00000000 Import 000030C0 0000008C Resource 00005000 00000608 Les ressources se trouvent dans la section .rsrc dont les caractéristiques ne permettent pas toujours l'écriture, ce qui n'est pas la cas ici (Data, Readable, Writeable) 04 .rsrc Virtual Address 00005000 > adresse de début
Virtual Size 00000608 > taille réel
Raw Data Offset 00002000 > offset de début
Raw Data Size 00000800 > taille avec Padding
Characteristics C0000040
Initialized Data
Readable
Writeable
La Virtual size de la section est 00000608, ce qui veut dire que la mémoire
qui sera allouée pour cette section sera de 0000608 bytes. Le Virtual Offset de la section est de 00005000,
additionné à l'Image base qui vaut 00400000, ce qui donne une adresse virtuelle de 00005000 + 00400000
= 00405000, l'adresse à laquelle la section .rsrc débute. .00405000: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 03 00 .00405010: 03 00 00 00-28 00 00 80-04 00 00 00-40 00 00 80 .00405020: 0E 00 00 00-58 00 00 80-00 00 00 00-00 00 00 00 Et dans HexworkShop, à l'offset 2000 0000 0000 0000 0000 - 0000 0000 0000 0300 0300 0000 2800 0080 - 0400 0000 4000 0080 0E00 0000 5800 0080 - 0000 0000 0000 0000
01 00 04 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ............... 00 00 00 00 01 00 26 00 - 46 00 69 00 6C 00 65 00 ......&.F.i.l.e. Si vous attaquez le programme par une recherche sur le nom d'un Item, pensez à
le faire en respectant le Wide Char Format. 0,&File
1000,&Open > 1000d = ID
0, > séparateur
1001,&Save
0, > séparateur
1010,&Exit
0,&Window
1800,&Tile
1801,&Cascade
1802,&Arrange Icons
1803,&Next Window$09F6 > touche [F6]
1804,C&lose All
0,&Help
1900,&About
0,SoftIce
32001,Enable
32002,Disable
String : Le symbole '&' placé
devant une lettre signifie que cette lettre sera soulignée dans le menu (la plupart du temps pour indiquer
un raccourci clavier) La plupart du temps, pour des questions de facilité, un éditeur de
ressources (Type Ressources Editeur de Symantec) a été utilisé pour créer ces menus
(ou les boites de dialogues...). Voici un extrait du script du fichier rsrc.rc tel qu'il a été édité
par ResEdit . Vous remarquerez qu'à partir du fichier exécutable, ExeEscope a réussi à
retrouver les mêmes informations. Nous verrons comment... BEGIN
POPUP "&File", , , 0
BEGIN
MENUITEM "&Open", 1000
MENUITEM "" , , 0x0800 /*MFT_SEPARATOR*/
MENUITEM "&Save", 1001
MENUITEM "" , , 0x0800 /*MFT_SEPARATOR*/
MENUITEM "&Exit" , 1010
END
POPUP "&Window", , , 0
> le Menu PopUp est Normal (ni grisé, ni désactivé) Normal (00) 0000 0000 0000 0000 0100 2600 5700 6900 ..........&.W.i. 6E00 6400 6F00 7700 0000 0000 0000 0000 n.d.o.w......... Mais nous aurions pu avoir: Grayed (01) 0100 0000 0000 0000 0100 2600 5700 6900 ..........&.W.i. 6E00 6400 6F00 7700 0000 0000 0000 0000 n.d.o.w......... Disabled (02) 0200 0000 0000 0000 0100 2600 5700 6900 ..........&.W.i. 6E00 6400 6F00 7700 0000 0000 0000 0000 n.d.o.w......... Vous remarquerez que le statut du Menu-PopUp (Grayed, Disabled...) se trouve 8 bytes
avant le nom du menu en question. Normal (00) 0000 0000 0000 0000 0807 0000 0000 2600 ..............&. 5400 6900 6C00 6500 0000 0000 0000 0000 T.i.l.e......... mais si le script avait été celui ci: Grayed (01) 0000 0000 0100 0000 0807 0000 0000 2600 ..............&. 5400 6900 6C00 6500 0000 0000 0000 0000 T.i.l.e......... Ou encore: Checked (08) 0000 0000 0800 0000 0807 0000 0000 2600 ..............&. 5400 6900 6C00 6500 0000 0000 0000 0000 T.i.l.e......... Grayed et Checked (09) 0000 0000 0900 0000 0807 0000 0000 2600 ..............&. 5400 6900 6C00 6500 0000 0000 0000 0000 T.i.l.e......... On retrouve le même principe pour les Items de Menus que pour les menus PopUp MF_ENABLED (00h) : l'action peut être utilisée.
MF_GRAYED (01h) : l'action est grisée et ne peut être utilisée.
MF_DISABLED (02h) : l'action n'est pas grisée, mais un clic ne donne rien
(pas de message WM_COMMAND d'envoyé).
Et elles peuvent être combinées entres-elles, par exemple, pour griser
et désactiver un item, vous utiliserez généralement 03h (MF_GRAYED + MF_DISABLED) MENUITEM "&Cascade", 1801
MENUITEM "&Arrange Icons", 1802
MENUITEM "&Next Window\tF6", 1803 = 0x070B -> identificateur 070B
0B07 0000 0000 2600 4E00 6500 7800 7400 ......&.N.e.x.t. 2000 5700 6900 6E00 6400 6F00 7700 0900 .W.i.n.d.o.w... Une recherche dans le listing désassemblé de Wdasm sur la valeur de cet identificateur va permettre de trouver le début de son traitement: :00401C0F 817D100C070000 cmp dword ptr [ebp+10], 0000070C :00401C16 7555 jne 00401C6D
00002350 0C07 0000 8000 4300 2600 6C00 6F00 7300 ......C.&.l.o.s. 00002360 6500 2000 4100 6C00 6C00 0000 0000 0000 e. .A.l.l....... :00401C6D 817D106C070000 cmp dword ptr [ebp+10], 0000076C :00401C74 0F8537020000 jne 00401EB1
0000 0000 6C07 0000 8000 2600 4100 6200 ....l.....&.A.b. 6F00 7500 7400 0000 0000 0000 0000 0000 o.u.t...........
Ca va être le boulot de la procédure WinMain (Cf source ASM) qui va
faire directement appel aux APIs suivantes: StartLoop:
invoke GetMessage,ADDR msg,NULL,0,0
cmp eax, 0
je ExitLoop
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
jmp StartLoop
ExitLoop:
> valeur retournée: msg.wParam
:00401610 817D0C11010000 cmp dword ptr [ebp+0C], 00000111 :00401617 0F85A6060000 jne 00401CC3 WM_Command est facilement identifiable par sa valeur 00000111. C'est le début
de la gestion des événements (mais qui peuvent aussi bien être liés à une Dialog
Box...). c'est aussi un excellent indicateur, facile à trouver par une recherche sur 00000111... .elseif wParam == 1001
jmp @F
szTitleS db "Save file as",0 > cette partie du code se traduira
szFilterS db "All files",0,"*.*",0,"Text files",0,"*.TXT",0,0
> par des opcodes semblant ne pas avoir de sens
> On trouve souvent des BYTE 065h...
@@:
invoke FillBuffer,ADDR szFileName,length szFileName,0
invoke SaveFileName,hWin,ADDR szTitleS,ADDR szFilterS
cmp szFileName[0],0 > si [cancel] est sélectionné
je @F > fin du traitement de l'événement
> sinon le nom du fichier retourné est dans szFileName
:00401946 817D10E9030000 cmp dword ptr [ebp+10], 000003E9 > Item (1101d) sélectionné ?
:0040194D 756F jne 004019BE > non -> suite
:0040194F EB2D jmp 0040197E > oui -> traitement
Traitement de la fonction " Save as " :0040197E 6A00 push 00000000 > NULL
:00401980 6804010000 push 00000104 > longueur de szFileName
:00401985 68B7404000 push 004040B7 > adresse de szFileName
:0040198A E882FAFFFF call 00401411 > récupère le nom du fichier
* Possible StringData Ref from Code Obj ->"All files"
|
:0040198F 685E194000 push 0040195E > "All files"
:00401994 6851194000 push 00401951 > "Save File As"
:00401999 FF7508 push [ebp+08] > Handle de la DialogBox
:0040199C E80FFAFFFF call 004013B0 > vers GetSaveFileNameA
:004019A1 803DB740400000 cmp byte ptr [004040B7], 00 > Buffer Vide ?
:004019A8 7414 je 004019BE > jump si [cancel] est sélectionné
A la sortie de cette routine, nous avons le path et le nom du fichier à enregistrer. :00401BD8 6A00 push 00000000 > option (0 = menu activé) :00401BDA 68017D0000 push 00007D01 > ID du menu (32001) :00401BDF FF75F8 push [ebp-08] > handle (hWmemu) :00401BE2 E8DD040000 Call USER32.EnableMenuItem dont voici ce qu'en donne le Win32Help: EnableMenuItem(
HMENU hMenu, // handle du menu
UINT uIDEnableItem, // menu item à activer, désactiver ou griser
UINT uEnable // statut de l'item de menu (flag)
);
Paramètres: :00401623 E8AE0A0000 Call USER32.GetMenu :00401628 8945F8 mov dword ptr [ebp-08], eax (-> handle) HMENU GetMenu ( HWND hWn // handle qui identifie la fenêtre ); De la même façon, vous avez également SetMenu et GetSubMenu qui peuvent être utilisés. :00401D0A FF3504404000 push dword ptr [00404004] > handle du menu :00401D10 FF7508 push [ebp+08] > handle de la fenêtre :00401D13 E812040000 Call USER32.SetMenu :00401D18 6A01 push 00000001 > position du menu (1er rang) :00401D1A FF3504404000 push dword ptr [00404004] > handle du menu :00401D20 E8BD030000 Call USER32.GetSubMenu :00401D25 89856CFFFFFF mov dword ptr [ebp+FFFFFF6C], eax
SetMenu(
HWND hWnd, // handle de la fenêtre
HMENU hMenu // handle du menu
);
HMENU GetSubMenu(
HMENU hMenu, // handle du menu
int nPos // position du menu Item
);
hMenu DeleteMenu(
HMENU hMenu, // handle du menu
UINT uPosition, // menu item identifier ou position
UINT uFlags // menu item flag
);
hMenu BOOL RemoveMenu(
HMENU hMenu, // handle du menu
UINT uPosition, // menu item identifier ou position
UINT uFlags // menu item flag
);
Les paramètres sont identiques à la fonction précédente. Virtual Size 00000608 Raw Data Offset 00002000 Raw Data Size 00000800 Nous avons vu dans la première partie que le code de la section .rsrc commence
à l'offset 0x2000 pour finir à l'offset 0x2800, mais que la taille du code étant de 0x0608,
il doit être possible de squatter quelques octets à partir de l'offset 0x2610 GetClientRect(
HWND hWnd, // handle de la fenêtre
LPRECT lpRect // adresse de la structure pour les coordonnées clientes
);
Maintenant, jetons un coup d'œil dans Wdasm : :00401DDE FF3508404000 push dword ptr [00404008] > ha ! ha ! :00401DE4 E8E7020000 Call USER32.GetClientRect Il y a fort à parier que le Handle de la fenêtre s'y trouve (Oui, je
sais...) :0040159A E8250B0000 Call USER32.CreateWindowExA :0040159F A308404000 mov dword ptr [00404008], eax > ici " mov hWnd, eax " pour HandleWindow. Donc [00404008] va contenir le Handle
de la fenêtre et ce tant que l'application ne sera pas fermée... HWND CreateWindow(
LPCTSTR lpClassName, // pointeur pour enregistre la " class name "
LPCTSTR lpWindowName, // pointeur vers le nom de la fenêtre
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // largeur de la fenêtre
int nHeight, // hauteur de la fenêtre
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // handle to menu or child-window identifier
HANDLE hInstance, // handle to application instance
LPVOID lpParam // pointer to window-creation data
);
Au retour de cette fonction, EAX contient le handle de la fenêtre. :0040163B 837D1033 cmp dword ptr [ebp+10], 00000033 > ID 3eme bouton :0040163F 754E jne 0040168F :00401641 EB11 jmp 00401654 Les 2 sauts suivants étant codés sur 4 octets alors qu'il m'en faut
5, j'opte pour écraser le cmp dword [ebp+10]. :00405610 837D1034 CMP DWORD PTR [EBP+10],34 > restauration :00405614 0F85C9C0FFFF JNZ 004016E3 > saut si <> :0040561A FF3508404000 PUSH DWORD PTR [00404008] > handle fenêtre :00405620 E8F4CDB4BF CALL USER32!GetMenu > récupère handle menus :00405625 6A00 PUSH 00 > push NULL :00405627 6668027D PUSH 7D02 > Item " disable " :0040562B 50 PUSH EAX > push handle menus :0040562C E835CDB4BF CALL USER32!DeleteMenu > efface Item :00405631 E972C0FFFF JMP 004016A8 > retour à la normale Et Valà ! SoftIce (désactivé)
Enable (désactivé)
Disable (Activé)
va devenir
Cracked (Activé)
&Gretz (Activé)
Key Gen (Activé)
Avec traitement des événements survenant à Gretz et Key Gen. :00401B12 817D10017D0000 cmp dword ptr [ebp+10], 00007D01 > événements ? :00401B19 7574 jne 00401B8F > non -> continue :00401B1B 833D5642400000 cmp dword ptr [00404256], 00000000 > début traitement Snips---------- Snips------------------------------ :00401B80 C7054940400000000000 mov dword ptr [00404049], 00000000 > Flag :00401B8A E922030000 jmp 00401EB1 > fin de la routine 00401B80 - 00401B1B = 0x65. Je dispose de 101 octets pour m'exprimer. 0137:00401B1B 6A00 PUSH 00 > MB_OK 0137:00401B1D 68C0574000 PUSH 004057C0 > titre 0137:00401B22 68D0574000 PUSH 004057D0 > message 0137:00401B27 6A00 PUSH 00 > handle de la fenêtre propriétaire 0137:00401B29 E8AB1DB6BF CALL USER32!MessageBoxA 0137:00401B2E E97E030000 JMP 00401EB1 Il me reste 77 octets de disponibles, et en fait il serait plus "économique"
d'y loger mes deux chaînes de caractères (titre et message) en remplacant 004057C0 par 00401B33 et
004057D0 par 00401C33... * Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401A3E(C)
* Possible StringData Ref from Data Obj ->"Glop! Glop! No SoftIce"
|
:00401A4F 6843424000 push 00404243
:00401A54 E88B040000 call 00401EE4
:00401A59 E96B040000 jmp 00401EC9
Il pourrait être intéressant de savoir pourquoi ce programme se réjouit tant de ne pas avoir SoftIce... :00401A32 E80B070000 Call 00402142 :00401A37 833D5A42400001 cmp dword ptr [0040425A], 00000001 :00401A3E 750F jne 00401A4F Une comparaison de [0040425A] avec 1 ? * Possible StringData Ref from Data Obj ->"\\.\SICE"
|
:00401F12 680B424000 push 0040420B > \\.\SICE
:00401F17 E844020000 Call KERNEL32.CreateFileA
:00401F1C 83F8FF cmp eax, FFFFFFFF > si Good EAX = -1
:00401F1F 7402 je 00401F23 > pas Glop !
:00401F21 33C0 xor eax, eax > Glop ! Glop !
Un classique Meltice (Quelle originalité !). :00401624 833D4D40400000 CMP DWORD PTR [0040404D],00 > test :0040162B 7513 JNZ 00401640 > non -> saute :0040162D E8E6080000 CALL 00401F18 > call Sice_Detection :00401632 85C0 TEST EAX,EAX > EAX = 0 ? :00401634 750A JNZ 00401640 > pas Glop ! :00401636 C7055A42400001000000MOV DWORD PTR [0040425A],00000001 > Glop ! Glop ! :00401640 817D0C11010000 CMP DWORD PTR [EBP+0C],00000111 > WM_Command Donc pour désactiver la détection Sice (et pouvoir la réactiver)
il va falloir s'intéresser de très prés à [0040404D]. On voit ici que si ce flag est
à 1, le programme n'ira pas vérifier la présence de SoftIce ! :00401B2A 817D10017D0000 cmp dword ptr [ebp+10], 00007D01 :00401B31 7574 jne 00401BA7 Voilà l'entrée du traitement de cet Item dont le rôle actuel
n'est que de désactiver la détection SI. :00401BF4 6A00 PUSH 00 > MB_OK :00401BF6 681C404000 PUSH 0040401C > titre :00401BFB 68D71B4000 PUSH 00401BD7 > message :00401C00 FF7508 PUSH DWORD PTR [EBP+08] > handle fenêtre :00401C03 E83A050000 CALL USER32!MessageBoxA > SI désactivé :00401C08 6A00 PUSH 00 > actif :00401C0A 68017D0000 PUSH 00007D01 > Item visé :00401C0F FF75F8 PUSH DWORD PTR [EBP-08] > handle menu :00401C12 E8E3040000 CALL USER32!EnableMenuItem > item activé :00401C17 6A01 PUSH 01 > inactif :00401C19 68027D0000 PUSH 00007D02 > Item visé :00401C1E FF75F8 PUSH DWORD PTR [EBP-08] > Handle menu :00401C21 E8D4040000 CALL USER32!EnableMenuItem > Item désactivé
.si Flag_contrôle_SI = 0
message "Détection SoftIce Activée"
mov Flag_SI-détection , 01
mov Flag_contrôle_SI, 01
.sinon
message "Détection SoftIce Désactivée"
mov Flag_SI-détection , 00
mov Flag_contrôle_SI ,00
.endif
mais comme il y a besoin de plus de place de disponible (ne serait-ce que pour les
deux Message Box), que celle qu'il est possible de prendre, on va squatter à la suite de notre précédente
modification, en 00405636. :00405636 803D4D40400000 CMP BYTE PTR [0040404D],00 :0040563D 7526 JNZ 00405665 :0040563F 6A00 PUSH 00 :00405641 681C404000 PUSH 0040401C :00405646 68D71B4000 PUSH 00401BD7 :0040564B 6A00 PUSH 00 :0040564D E8DCEAB4BF CALL USER32!MessageBoxA :00405652 C6055A42400000 MOV BYTE PTR [0040425A],00 :00405659 C6054D40400001 MOV BYTE PTR [0040404D],01 :00405660 E97CC8FFFF JMP 00401EE1 :00405665 6A00 PUSH 00 :00405667 683D404000 PUSH 0040403D :0040566C 685A1B4000 PUSH 00401B5A :00405671 6A00 PUSH 00 :00405673 E8B6EAB4BF CALL USER32!MessageBoxA :00405678 C6054D40400000 MOV BYTE PTR [0040404D],00 :0040567F E95DC8FFFF JMP 00401EE1 Et vous voici avec un bel interrupteur ON/OFF sur l'item " Key Gen "... Permettre la sauvegarde d'un fichier à partie d'un des PushButton de la barre
des outils. :004016BF 837D1034 CMP DWORD PTR [EBP+10],34 :004016C3 754E JNZ 00401713 :004016C5 EB11 JMP 004016D8 > procédure de traitement de l'événement et la sélection de l'Item " Save " nous fait atterrir ici : :004018FD 817D10E8030000 CMP DWORD PTR [EBP+10],000003E8 :00401904 7570 JNZ 00401976 :00401906 EB2C JMP 00401934 > procédure de traitement Il est alors on ne peut plus facile de brancher de 004016C5 directement vers 00401934 par un jmp long. |
Merci à +Spath pour l'aide qu'il nous apporte à travers ses écrits de grande qualité
Bonne journée