comment effectuer un appel système direct sous Windows 7 X64 SP1 (mode x64)?

J’ai essayé de simuler le fonctionnement de l’instruction syscall sur Windows 7 X64 (SP1). Je programme donc un exemple GCC 64 bits avec MinGW64. Comme je le sais, pour Windows, tous les points d’entrée de syscall se trouvent dans ntdll.dll ou ntdll32.dll (dans ce cas, nous nous contentons de ntdll.dll).

Status = NtCreateFile(&FileHandle, // returned file handle (GENERIC_WRITE | SYNCHRONIZE), // desired access &ObjectAtsortingbutes, // ptr to object atsortingbutes &Iosb, // ptr to I/O status block 0, // allocation size FILE_ATTRIBUTE_NORMAL, // file atsortingbutes 0, // share access FILE_SUPERSEDE, // create disposition FILE_SYNCHRONOUS_IO_NONALERT, // create options NULL, // ptr to extended atsortingbutes 0); // length of ea buffer 

Ceci est la partie originale du code source écrit par C, puis je le réécris par gaz

 asm volatile ( "leaq %4, %%r9\n\t" "leaq %3, %%r8\n\t" "movq %2, %%rdx\n\t" "leaq %1, %%rcx\n\t" "movq %11,0x50(%%rsp)\n\t" "movq %10,0x48(%%rsp)\n\t" "movq %9, 0x40(%%rsp)\n\t" "movq %8, 0x38(%%rsp)\n\t" "movq %7, 0x30(%%rsp)\n\t" "movq %6, 0x28(%%rsp)\n\t" "movq %5, 0x20(%%rsp)\n\t" "movq %%r9, 0x18(%%rsp)\n\t" "movq %%r8, 0x10(%%rsp)\n\t" "movq %%rdx, 0x8(%%rsp)\n\t" "movq %%rcx, (%%rsp)\n\t" "movq __imp_NtCreateFile(%%rip), %%rax\n\t" "call *%%rax\n\t" : "=a"(Status) : "m"(FileHandle), "g"(GENERIC_WRITE | SYNCHRONIZE),"m"(ObjectAtsortingbutes),"m"(Iosb),"g"(0),"g"(FILE_ATTRIBUTE_NORMAL),"g"(0),"g"(FILE_SUPERSEDE),"g"(FILE_SYNCHRONOUS_IO_NONALERT),"g"(NULL),"g"(0) : "%rcx", "%rdx", "%r8", "%r9", "%r10","%r11" ); 

Jusqu’à présent, le programme fonctionne comme prévu: il a créé un fichier texte et écrit quelque chose dans le fichier.

J’utilise windbg pour désassembler le ntdll! NtCreateFile, et seulement vu (réécrit au format GAS AT & T)

  "movq $0x52, %%rax\n\t" "movq %%rcx, %%r10\n\t" "syscall\n\t" "ret\n\t" 

J’ai ajouté cette partie du code dans mon programme comme

 asm volatile ( "leaq %4, %%r9\n\t" "leaq %3, %%r8\n\t" "movq %2, %%rdx\n\t" "leaq %1, %%rcx\n\t" "movq %11,0x50(%%rsp)\n\t" "movq %10,0x48(%%rsp)\n\t" "movq %9, 0x40(%%rsp)\n\t" "movq %8, 0x38(%%rsp)\n\t" "movq %7, 0x30(%%rsp)\n\t" "movq %6, 0x28(%%rsp)\n\t" "movq %5, 0x20(%%rsp)\n\t" "movq %%r9, 0x18(%%rsp)\n\t" "movq %%r8, 0x10(%%rsp)\n\t" "movq %%rdx, 0x8(%%rsp)\n\t" "movq %%rcx, (%%rsp)\n\t" "movq $0x52, %%rax\n\t" "movq %%rcx, %%r10\n\t" "syscall\n\t" : "=a"(Status) : "m"(FileHandle), "g"(GENERIC_WRITE | SYNCHRONIZE),"m"(ObjectAtsortingbutes),"m"(Iosb),"g"(0),"g"(FILE_ATTRIBUTE_NORMAL),"g"(0),"g"(FILE_SUPERSEDE),"g"(FILE_SYNCHRONOUS_IO_NONALERT),"g"(NULL),"g"(0) : "%rcx", "%rdx", "%r8", "%r9", "%r10","%r11" ); 

maintenant le statut retourne toujours avec la valeur ‘0xc000000d’, le programme a échoué. Maintenant, j’ai plusieurs questions confuses:

  1. Comment les parameters stockés dans la stack du mode utilisateur passent-ils en mode kernel ici? puisque je ne vois rien se passe dans NtDll! NtCreateFile.

  2. Comment la valeur de retour correcte à atsortingbuer à %% rax? Cette partie est également erronée dans le cas du déassembly.

  3. Comment faire pour que mon code fonctionne correctement après avoir effectué un appel direct?

merci beaucoup pour votre aide précieuse.


OK, ici montre le code de travail

 asm volatile ( "leaq %4, %%r9\n\t" "leaq %3, %%r8\n\t" "movq %2, %%rdx\n\t" "leaq %1, %%rcx\n\t" "movq %11,0x50(%%rsp)\n\t" "movq %10,0x48(%%rsp)\n\t" "movq %9, 0x40(%%rsp)\n\t" "movq %8, 0x38(%%rsp)\n\t" "movq %7, 0x30(%%rsp)\n\t" "movq %6, 0x28(%%rsp)\n\t" "movq %5, 0x20(%%rsp)\n\t" "push $_end \n\t" "movq %%rcx,%%r10\n\t" "movq $0x52,%%rax\n\t" "syscall\n\t" "ret\n\t" "_end:\n\t" : "=a"(Status) : "m"(FileHandle), "g"(GENERIC_WRITE | SYNCHRONIZE),"m"(ObjectAtsortingbutes),"m"(Iosb),"g"(0),"g"(FILE_ATTRIBUTE_NORMAL),"g"(0),"g"(FILE_SUPERSEDE),"g"(FILE_SYNCHRONOUS_IO_NONALERT),"g"(NULL),"g"(0) : "%rcx", "%rdx", "%r8", "%r9", "%r10","%r11" ); 

ce n’est pas vraiment pénible de simuler l’appel / la reprise. Ici, j’ai utilisé une solution de contournement que Linus a déjà utilisée dans son Linux 0.11.

Je pense que vous avez tort concernant la profondeur de la stack. De nombreux arguments sont transmis via la stack. Syscall les attend exactement où ils se trouvent si l’appel de la bibliothèque est entre les deux.

Si vous ignorez l’appel de la bibliothèque et faites l’appel vous-même (ce que vous ne devez faire que pour l’expérimentation, pas pour des choses productives!), Il manque un élément sur la stack.

Donc, soit poussez une valeur fictive à la stack ou ajustez les décalages.

En détail, ce qui suit se produit dans le code d’origine:

  • Vous placez les arguments dans la stack (jusqu’à movq %%rcx, (%%rsp) ).
  • Vous effectuez un call à __imp_NtCreateFile . Cela met l’adresse de retour à la stack et effectue un transfert du %tip vers la fonction de bibliothèque.
  • La fonction de bibliothèque exécute alors essentiellement l’appel système.
  • Le kernel attend alors les données en dehors du sumt de la stack, car ledit appel a ajouté un élément.

Si vous faites le syscall vous-même, vous devez placer un autre élément pour compenser cette adresse de retour qui déplace la vue du kernel de la stack.