SuspendThread WOW64 en suspension dans le code du kernel

MISE À JOUR : Microsoft doit encore le réparer dans Windows 8.1.

EDIT : Cela s’est avéré être un bogue dans WOW64 – GetThreadContext () peut renvoyer des contenus obsolètes lorsque le thread est suspendu en mode long ring-3 (mode utilisateur). J’ai suggéré à Microsoft d’utiliser ring-2 pour effectuer la traduction. SuspendThread ne suspendrait alors que les threads dans ring-3 (comme c’est le cas actuellement – pas de modifications nécessaires), et un crash / fault / exploit dans ring-2 n’affecterait pas le kernel – cela n’affecterait que ring-2 et ring- 3.

De telles modifications nécessiteraient le changement de quelques fonctions WinAPI telles que Wow64Get / SetThreadContext, etc. Cela briserait les applications reposant sur des fonctionnalités non documentées, mais on peut s’y attendre. Certes, la traduction serait plus lente car il faut quelques cycles de CPU pour passer de ring-3 à ring-2 (en fonction de la famille de CPU) mais je pense que le rôle du système d’exploitation est avant tout d’assurer un fonctionnement correct. La traduction ajoute déjà des frais généraux aux applications exécutées sous WOW64, de sorte que vous devez vous y attendre.

J’espère que Microsoft corrigera ce problème – sinon les débogueurs / applications Mono / GC Boehm / applications qui s’appuient sur GetThreadContext () sous WOW64 ne fonctionneront pas (pour commencer, j’ai vu les débogueurs afficher la trace de stack obsolète).

EDIT2 : Mauvaises nouvelles. D’après ma conversation avec Alexey de MSFT ( ici ), il semble que cela ne soit pas du tout résolu, de peur que le correctif ne vienne briser les applications qui reposent sur des fonctionnalités non documentées.


Question originale

  • Certaines personnes semblent confuses à propos de ce qui suit. J’ai d’abord pensé que c’était dû à SuspendThread en train de suspendre un thread en code en mode kernel. Ce n’était pas Ce qui suit était simplement mon soupçon initial qui s’est avéré n’avoir rien à voir avec la cause réelle, à savoir le contenu obsolète renvoyé par GetThreadContext() .

De MSDN:

Suspending a thread causes the thread to stop executing user-mode (application) code.

Ce que j’ai trouvé, cependant, c’est que mon application 32 bits sous Windows 7 exécutée sous WOW64, Thread A appelant SuspendThread sur Thread B, peut le suspendre pendant qu’il exécute du code 64 bits (ce qui n’est pas du code utilisateur). EIP montre le fil suspendu arrêté à

 wow64cpu!X86SwitchTo64BitMode: 00000000`759c31b0 ea27369c753300 jmp 0033:759C3627 

avec son ESP ayant changé (je le sais car, alors que l’ESP pointe vers la même page que la stack de ce thread, il a une adresse beaucoup plus élevée que le pointeur de stack actuel). Si je mets un point d’arrêt à l’instruction renvoyée ci-dessus, puis que le thread reprenne, j’ai constaté que l’ESP repasse à la valeur avant l’appel X86SwitchTo64BitMode (qui est le pointeur de stack correct). J’ai également constaté que lorsque l’on passe à la même fonction, je ne peux jamais obtenir une valeur ESP plus élevée pour une adresse donnée à un moment quelconque de l’étape. En fait, lorsque vous effectuez un pas simple, la valeur ESP ne change jamais avant et après l’appel X86SwitchTo64BitMode.

De plus, je me suis assuré que SuspendThread réussit en vérifiant (DWORD) -1.

Tout cela m’amène à croire que le thread est suspendu en code en mode kernel.

Qu’est-ce qui pourrait amener le système d’exploitation à suspendre un thread pendant qu’il exécute du code en mode non utilisateur? Comment puis-je empêcher cela? Cela m’empêche essentiellement d’obtenir le pointeur de stack actuel de Thread B. Notez que lorsque l’application s’exécute en dehors de WOW64 (sur le système d’exploitation natif x86), aucun problème de ce type n’existe.

J’ai confirmé qu’il s’agissait d’un problème de système d’exploitation renvoyant un contenu obsolète lorsque GetThreadContext est appelé sous WOW64.

Plus d’infos ici .

Merci à tous ceux qui ont tenté de répondre à cette question. Je travaille avec MS pour résoudre ce problème.

Voir cette explication: GetThreadContext dans Wow64

Cet article explique que la transition entre les modes x86 et amd64 se fait en mode utilisateur.

Que fait votre thread en mode utilisateur? Il semble que ce soit déjà en mode kernel lorsque vous appelez SuspendThread . Est-il possible qu’il exécute une fonction système au moment où vous le suspendez?

Qu’est-ce qui pourrait amener le système d’exploitation à suspendre un thread pendant qu’il exécute du code en mode non utilisateur?

De nombreux appels système ou bibliothèque peuvent entraîner un basculement vers le mode kernel. Et comme le kernel Windows est conçu pour être réentrant dans la plupart des cas, le passage d’un thread à un autre alors que le premier est en mode kernel est assez normal.

Comment puis-je empêcher cela?

Juste une idée: Créez un thread qui exécute une boucle vide (par exemple for(;;); ) et suspendez ce thread. Celui-ci ne doit pas être suspendu en mode kernel.


Aussi, pourquoi est-ce important pour vous que les registres ESP etc. soient corrects? J’espère que vous écrivez une sorte de débogueur ou quelque chose de lié, parce que c’est ce que SuspendThread est pour.

Techniquement, lorsqu’un thread ne s’exécute pas du tout, il n’exécute ni le code en mode kernel ni le code du mode utilisateur. Donc, vos observations ne contredisent pas la déclaration.

Beisdes, vous ne devriez pas jouer avec ça. Ce serait un bug du système d’exploitation si vous (en mode utilisateur) pouvait contrôler si le code du mode kernel était exécuté.