introduction
Dans cette histoire, je vais vous raconter une aventure passionnante qui m'a amené à résoudre une énigme que je me suis posée. La solution est un petit détail dans le mécanisme du chargeur d'applications 32 bits dans Windows 7 et supérieur, et le processus de résolution est un long voyage d'un guerrier qui suit le chemin du cœur.
Si vous êtes venu sur cette page à la recherche d'une réponse à une question, regardez le spoiler ci-dessous, car le contenu principal peut intéresser ceux qui essaient simplement de comprendre le mécanisme SEH.
Tout le problème était que j'ai utilisé une description incorrecte de la structure dataDirectories tirée de Wikipedia. À la place du champ boundImport, il existe en fait le champ loadConfigTable , qui pointe vers la structure IMAGE_LOAD_CONFIG_DIRECTORY32. Cette structure contient le champ SEHandlerTable. S'il est égal à zéro, alors / SAFESEH est désactivé. S'il s'agit d'un pointeur virtuel vers la table des gestionnaires sécurisés, seuls les gestionnaires spécifiés dans la table fonctionneront. Le tableau est une liste de décalages relatifs à l'adresse virtuelle de la section .text. Le nombre de gestionnaires est défini dans le champ SEHandlerCount.
Comment tout a commencé
En pensant à un moyen de protéger mon programme contre la copie, je me suis souvenu de l' article de Chris Kaspersky, dans lequel j'ai appris l'existence de techniques anti-débogage. En essayant en vain d'implémenter l'exemple que Chris a analysé dans mon programme, je me suis heurté à un mur de confusion de la part de Windows. Le problème était que Windows refusait d'utiliser mon gestionnaire d'exceptions, le considérant comme "dangereux".
Plus ou moins de détails sur SEH que j'ai pu glaner dans cet article . Mais, néanmoins, jusqu'à ce que j'examine moi-même ce mécanisme avec une loupe et des outils, j'avais des idées très vagues sur sa structure. J'ai déroulé les chaînes de gestionnaires, défini des points d'arrêt sur eux, observé l'ordre de leur exécution, pris en compte les valeurs de retour, etc.
Arriver au point
( Microsoft Visual C++ )
int main()
{
__asm
{
mov eax, DWORD PTR SS : [0]
}
}
, eax 0.
, OllyDbg.
«access violation when reading 0x00000000».
, , 0 - 6 . Eip, ( ). 6 : 36 A1 00 00 00 00.
, __try, __except .. .
!
, - :
struct _EXCEPTION_RECORD* exceptionRecord,
void* establisherFrame,
struct _CONTEXT* contextRecord,
void* dispatcherContext
exceptionRecord – , , , contextRecord – ( Eip). - __cdecl, :
typedef enum _EXCEPTION_DISPOSITION
{
ExceptionContinueExecution,
ExceptionContinueSearch,
ExceptionNestedException,
ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;
:
EXCEPTION_DISPOSITION __cdecl ExceptionHanler(
struct _EXCEPTION_RECORD* exceptionRecord,
void* establisherFrame,
struct _CONTEXT* contextRecord,
void* dispatcherContext
)
{
contextRecord->Eip += 6;
MessageBoxA(0, "Exteption was handled", "Success!", 0);
return ExceptionContinueExecution;
}
Eip 6 , ! : ExceptionContinueExecution – . , Eip + 6 .
- . , . , , . - , : Next Handler. Next , ( , ). Handler -. TIB (thread information block), , fs:[0]. .
main:
int main()
{
__asm
{
push ExceptionHanler // -
push fs:[0] //
// , 2 :
//
mov fs:[0] , esp // ,
// fs:[0]
mov eax, DWORD PTR SS:[0] // 0
add esp, 8 // , 8 ( )
}
}
, - /SAFESEH , , - fs:[0]. , .
– 0 «» !
, . . /SAFESEH:NO.
, , :
«» . .
, -, , ? ? , … , , /SAFESEH, , , mov fs:[0], esp, -, , ? , /SAFESEH .
, - « ». , ? ? , , ? …
, …
, , crt0 ( main), ntdll.dll. , fs:[0]! , , ?
. , /SAFESEH, , , fs:[0] JMP ExceptionHandler ( ). ! ! , «»? , . .
entry point main EXE , /SAFESEH /SAFESEH:NO, , WinApi , . . , , . .
crt0 -. , ! push main, ret. , main, ret «» main main , crt0! ( JMP, )
, ! , : EXE, , , .
, PE ? - LoaderFlags? … , rdata. rdata , , ? , …
, - , . ! , , , -, , . , . , rdata , importTable, debug boundImport. , /SAFESEH! dataDirectories . , , - , /SAFESEH , « EXE ».
, «» , EXE . - . , 2 , , , . , , , ( 3-) .
, «» , mov eax, DWORD PTR SS : [0] play. . play.
! ntdll.dll.
. 0x1341d20 rdata 0x1be0, , EBX – 0x1000. , imageBase + 0x1000 ! - . 0x1be0, 0x2080 0x2351 . ! !
0x1341d20 0x1be0 0x1000 … !
! Windows, . ntdll.dll, !
, .
, . , - , – 3, .
- -.
! , /SAFESEH , /SAFESEH:NO!
, ?
… - , … Total Commander?!
, PE ? boundImport. Microsoft PE .
… , Microsoft boundImport. - -? ?
, .. , except… .. , .sxdata - . . sxdata? . boundImport, - -.
... , , pdata . , ? , boundImport, , .
... The Load Configuration Structure. ! , IMAGE_LOAD_CONFIG_DIRECTORY - , SEH.
, -. , , boundImport IMAGE_LOAD_CONFIG_DIRECTORY32 . ! , .
C'est tout, tout le secret était que boundImport dans l'en-tête PE (décomposé selon le tableau de Wikipedia) pointe vers la structure IMAGE_LOAD_CONFIG_DIRECTORY32. Cette structure contient des champs qui changeront radicalement le fonctionnement du programme ! Maintenant, nous pouvons créer en toute confiance notre propre table de gestionnaires et y ajouter uniquement ce que nous pensons nécessaire !
Peut-être que quelque part dans les profondeurs de la documentation, il y a des informations selon lesquelles boundImport est déjà mal appelé sur ma plate-forme ? Ou l'information que son rendez-vous a changé ? Peut-être que boundImport a été exclu ou déplacé ?