0
votes

C ++ Sysenter X86 appelle à Assemblée en ligne

Je suis sur le point d'apprendre comment Sysenter sur X86 fonctionne. Et j'ai créé une application de console simple sur la plate-forme X86, qui devrait appeler la fonction NTWriteVirtualMemory manuellement dans l'assemblage en ligne.

J'ai commencé avec ce code ici, mais il semble que le compilateur ne comprenne pas l'opcode "Sysenter" alors j'ai décidé de _emit code> avec les octets pour Sysenter. (Je dois peut-être modifier quelque chose dans mes paramètres de projet?) Il compile, mais quand il est sur le point d'appeler la fonction Visual Studio me donne une erreur que mon RET est une instruction illégale lors de l'exécution et que le programme s'arrête. P>

Quelqu'un a des connaissances comment faire correctement? P>

#include <windows.h>
#include <iostream>



__declspec(naked) void __KiFastSystemCall()
{
    __asm
    {
        mov edx, esp

        // need to emit "sysenter" because of syntaxerrors, "Opcode"; "newline"
        _emit 0x0F
        _emit 0x34
        
        ret // illegal instructiona after execute?

    }

}

void Test_NtWriteVirtualMemory(HANDLE hProcess, PVOID BaseAddress, PVOID Buffer, SIZE_T sizeToWrite, SIZE_T* NumberOfBytesWritten)
{
    __asm
    {
        push NumberOfBytesWritten
        push sizeToWrite
        push Buffer
        push BaseAddress
        push hProcess

        mov eax, 0x3A // Syscall ID NtWriteVirtualMemory in Windows10


        mov edx, __KiFastSystemCall
        call edx

        add esp, 0x14 // 5 push *  4 bytes 20 dec

        retn
    }
}

void Test_NtWriteVirtualMemory(HANDLE hProcess, PVOID BaseAddress, PVOID Buffer, SIZE_T sizeToWrite, SIZE_T* NumberOfBytesWritten)
{
    __asm
    {
        push NumberOfBytesWritten
        push sizeToWrite
        push Buffer
        push BaseAddress
        push hProcess


        mov eax, 0x3a // Syscall ID NtWriteVirtualMemory in Windows10
        mov edx, 0x76F88E00
        call edx
        ret 0x14
    }
}



int main()
{
    std::cout << "Test Hello World\n";

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcessId("MyGame.exe"));
    if (hProcess == NULL)
        return false;

    DWORD TestAddress = 0x87A0B4; // harcoded
    DWORD TestValue = 4;
    Test_NtWriteVirtualMemory(hProcess, (PVOID)TestAddress, (PVOID)TestValue, sizeof(DWORD), NULL);


    CloseHandle(hProcess);

    return 0;
}


2 commentaires

Les numéros Windows SysCall peuvent changer en fonction du niveau de correctif de la machine. S'il vous plaît ne faites pas cela.


Oui, je sais que c'est juste à des fins de test.


3 Réponses :


1
votes

Étant donné que vous avez une instruction illégale sur l'instruction RET plutôt que sur l'instruction Sysenter, vous savez que l'instruction Sysenter a été décodée correctement par la CPU. Votre appel est entré en mode noyau, mais le noyau n'aimait pas l'invocation de votre système d'appel système.

Il s'agissait probablement de l'espace utilisateur pour aider à enregistrer certains registres car sysenter est très minime. Vérifiez le pointeur de la pile après avoir revenu du noyau lorsque vous vous trouvez à sens unique avant de laisser res exécuter.

Je ne spéculerais que comme le problème, mais j'enveloppe la porte SysCall dans un autre appel de fonction semble mal à mes yeux. Comme je l'ai dit dans les commentaires, ne faites pas cela parce que les numéros SysCall peuvent changer sur vous.

Sous Linux, les processus 32 bits appellent à travers la VDSO (une bibliothèque injectée dans leur espace d'adresses par le noyau) pour obtenir l'instruction optimale d'appel système, utilisée d'une manière qui correspond à ce que veut le noyau. ( sysenter ne conserve pas le pointeur de pile afin que l'espace utilisateur doit aider.)

Peut-être que si vous voulez jouer avec cette instruction, vous feriez mieux d'écrire un système d'exploitation Toy.

Désolé, ce n'est pas une tonne de réponse, mais ce n'est pas complètement déraisonnable.


3 commentaires

Merci pour l'information, mais qui peut me montrer comment le faire correctement alors ??


x86-64 gnu / linux a une utilisation glibc syscall directement, indirectant uniquement via la VDSO pour "Appels système" qui n'ont pas besoin d'entrer dans le noyau. ( getpid , clock_gettime , etc.) 32 bits x86 glibc indirecte via la VDSO pour que tout pour permettre à "la bibliothèque" du noyau, faire le côté de l'espace utilisateur optimal de la Sysenter danse ou utilisez 32 bits syscall sur Old AMD ou utilisez int 0x80 . blog.packagecloud.io / fre / 2016/04/05 / ... Donc, je pense que vous avez inversé "x86" et "x64" dans votre 3ème paragraphe.


@Petercordes: N'hésitez pas à éditer. C'est une réponse cachée de toute façon que OP ne veut que une réponse de Windows.



4
votes

Avez-vous une version 32 bits de Windows?

sysenter était le "successeur" de int 2eh et introduit lors de l'ère Windows XP.
Les versions 64 bits de Windows ne l'utilisent pas, en fait, a été supprimée depuis:

  1. sysenter et sysret est illégal en mode long dans une CPU AMD (indépendamment du mode de compatibilité).
  2. Le iA32_sysenter_cs MSR est laissé à zéro par une version 64 bits de Windows 1 .
    Cela provoquera une défaillance #gp lors de l'exécution de sysenter .
    Si vous avez une étape unique via votre __ kifastsystemcall Vous devez voir le débogueur Attraper une exception avec le code 0xc0000005 lors de l'exécution sysenter . .

    Ainsi, afin d'utiliser sysenter , vous devez avoir une version réelle de Windows 32 bits.
    L'exécution d'un programme 32 bits sur une version 64 bits de Windows ne fonctionnera pas, c'est le mode de compatibilité (fait via les machines WOW64).
    Si, outre avoir une version de Windows de 64 bits, vous avez également une CPU AMD, alors cela ne fonctionnera pas à la double fois.

    Windows 64 bit utilise syscall pour un programme 64 bits ou un appel indirect sur le champ WOW32RESERVÉ du champ Teb 2 , vous devez utiliser celles-ci.
    Méfiez-vous que la convention d'appel système 64 bits est légèrement différente de la part habituelle: elle suppose particulièrement le syscall est dans une fonction de son propre , il s'attend ainsi aux paramètres la pile à décaler par 8. De plus, le premier paramètre doit être dans r10 , pas rcx .

    Par exemple, si vous intégrez l'instruction SYSCALL , le premier paramètre de la pile (le cas échéant) doit être à RSP + 28H et non sur RSP + 20h .

    Le mode de compatibilité 32 bits SysCall Convention est également différent, vous devez définir les deux EAX et ECX sur des valeurs spécifiques.
    Je n'ai pas creusé ce que ECX est utilisé, mais il peut être lié à une optimisation appelée Turbo Thunks et doit être défini sur une valeur spécifique.
    Notez que, alors que les numéros SysCall sont très volatils, Turbo Thunks sont encore plus parce qu'ils peuvent être désactivés par l'administrateur.

    1 Je n'ai pas de source définitive pour cela, il ne s'agit que de zéro sur ma version de Windows et qu'il fait sysenter défaut .

    2 i.e. a appel dword [fs: 0c0h] , cela pointera sur un code qui passera à un descripteur de porte pour un segment de code 64 bits qui exécutera à son tour un syscall


4 commentaires

Mes Windows est une version 64 bits, ma console est 32 bit et mon jeu est trop 32 bits. J'ai essayé de remplacer appel edx avec l'appel appel DWORD PTR FS: [0xc0] . Il se déroule mais me gagne une violation d'accès sur la fonction ..


Prenez votre version 32 bits de ntdll.dll et désassemblable NTWriteVirtualMemory , vous devez voir quelles valeurs à mettre dans Tous les registres qui sont nécessaires ( Cela inclut edx , ex et ECX , dépend de la version de Windows).


merci je l'ai fait, voici une image des octets [link] imgur.com/a/v6fv1a8 . Je fais tout cette assemblée similaire, mais cela ne compile pas vraiment -> "Violation d'accès". J'ai ajouté le code ci-dessus que j'ai utilisé.


Vous n'avez pas appuyé sur l'adresse de retour, ntwritevirtualmemory a l'adresse de retour de l'appelant en haut de la pile lors de la saisie. De plus, je ne suis pas sûr que la codage d'une adresse fonctionne pour toutes les pistes (je ne sais pas si Windows fait ASLR sur des fichiers binaires 32 bits). Si j'étais vous, je ferais un programme simple qui appelle ntwritevirtualmemory normalement, puis entrez-le en progressant dans le programme de défaillance, en vérifiant les valeurs de la pile et de l'enregistrement. Cela mettrait en évidence les divergences.



0
votes

Faire des appels système dans X86 Windows est différent de X64. Vous devez spécifier la longueur correcte des arguments dans res em> sinon, vous obtiendrez des instructions illégales et / ou d'exécuter ESP.

En outre, je ne vous recommande pas d'utiliser l'assemblage en ligne, l'utiliser à l'intérieur d'un. fichier ASM ou comme shellcode. p>

pour faire un appel correct str fort> X86 sur x86 Windows: p> xxx pré>

pour faire un CORRECT STRAND> X64 System Call On x64 Windows: P>

mov eax, SYSCALL_INDEX
mov r10,rcx
syscall
retn


0 commentaires