Trouver l'addresse de retour d'une fonction API

cs_elpens Messages postés 260 Date d'inscription vendredi 2 décembre 2005 Statut Membre Dernière intervention 3 novembre 2007 - 21 sept. 2007 à 15:24
cs_elpens Messages postés 260 Date d'inscription vendredi 2 décembre 2005 Statut Membre Dernière intervention 3 novembre 2007 - 26 sept. 2007 à 08:32
Bonjour à tous,

J'aimerai trouver l'addresse de retour (mémoire) d'une fonction API, c'est pourquoi je vous demande votre aide...

Voilà comment je compte procéder:

1) Lancer l'application à l'aide de la fonction createProcess   //Jusque-là, ca va...
2) Trouver les frontières (boundaries) de l'import Table en mémoire
3) Trouver les frontières (boundaries) du Stub programm

4) Trouver le Byte FF dans le code et être sûr que l'on a bien affaire à l'instruction call (assembler)
5) Une fois la function call trouvée, contrôler quelle se trouve bien dans la plage mémoire de l'Import Table définie avant
6) Si oui, alors l'addresse suivante sera l'addresse de retour...

7) Trouver le Byte E8 dans le code (également l'instruction call)
8) Rechercher dans le registre (suivant E8) l'addresse qui nous permettera de vérifier si elle fait partie de la plage Stub
9) Si oui, alors l'addresse suivante sera l'addresse de retour...

Je voudrais réaliser cela en C++.

Je viens de débuter ce "challenge" et toute aide sera la bienvenue à partir du point 2 ;-)
Naturellement, si quelqu'un connait un autre moyen de procéder, je suis preneur.

Voilà, j'espère avoir été clair et vous remercie ne serait-ce pour avoir lu ce message jusqu'au bout.

Merci et bonne Prog.

 ElpenS

10 réponses

acx01b Messages postés 280 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 8 juillet 2014 6
21 sept. 2007 à 17:06
salut je n'ai pas bien compris ce que tu appelles adresse de retour
un call X c'est mettre le contenu d'eip dans la pile, incrémenter esp, et en même temps faire un jump X
0
cs_elpens Messages postés 260 Date d'inscription vendredi 2 décembre 2005 Statut Membre Dernière intervention 3 novembre 2007
22 sept. 2007 à 18:07
Désolé,

Ce que j'appelle addresse de retour est en fait l'addresse de l'instruction suivant le call

c-a-d.

0x00001234   call OpenFile   <-- call de fonction API
0x00001238   push eax  <-- @ de retour

Voilà ce que j'appelle @ de retour (Naturellement, l'addresse mémoire)

 j'espère avoir été un peu plus precis...
    
Merci

 ElpenS
0
acx01b Messages postés 280 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 8 juillet 2014 6
23 sept. 2007 à 18:24
ben non c'est pas très clair

tu veux connaître l'adresse du bout de code machine qui fait le call et ce qui suit ?

est-ce que ce code te convient ????

#include <stdio.h>


int i,j;


asm("func:");
asm("movl (%esp), %eax");
asm("ret");


asm("l1:");
asm("movl %eax, _i");
asm("call func2");
asm("ret");
asm("l2:");


asm("func2:");
asm("movl _i, %eax");
asm("addl _j, %eax");
asm("movl %eax, (%esp)");
asm("ret");


int main() {


    // on calcule la taille des 3 instructions situees entre l1 et l2
    asm("movl $l2, %eax");
    asm("subl $l1, %eax");
    // on enregistre dans la variable j
    asm("movl %eax, _j");
    // on appelle func qui va récupérer l'adresse du movl %eax, _i juste après
    asm("call func");
    asm("movl %eax, _i");
    // on appelle func2, qui va plcer notre adresse de retour calculée à la place de son adresse de retour
    asm("call func2");
    // ainsi le ret n'est pas effectué !
    asm("ret");
    printf("l'adresse de retour de func2 etait bien %d", i+j);
    return 0;
}
0
cs_elpens Messages postés 260 Date d'inscription vendredi 2 décembre 2005 Statut Membre Dernière intervention 3 novembre 2007
24 sept. 2007 à 08:43
Oui et non....

Le principe que tu utilises dans cet exemple est correcte. Seulement, mes fonctions call ne se trouvent pas dans mon code, mais dans celui du .exe

J'essaie de réexpliquer la chose:

- Dans un premier temps, je vais "executer" un .exe avec CreateProcess(myExe.exe,...)
- Dans mon myExe.exe, il y aura des appels de fonctions API   (call    ntdll.RtlRaiseException;)

Je voudrai donc détecter tout les call de fonction API, et retrouver l'addresse à laquelle ils reviennent une fois la fonction effectué

0x7C90EC5F     call    ntdll.RtlRaiseException;
0x7C90EC64      int3;
...

0x7C95300D call    ntdll.ZwQueryInformationThread; 
0x7C953012 mov     ( EAX, EBX );
...

Et ainsi de suite


Voilà, j'espère avoir éclairci un peu plus la chose

 ElpenS
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
acx01b Messages postés 280 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 8 juillet 2014 6
24 sept. 2007 à 12:33
une idée: ça pourrait être plus simple de carrément le désassembler ton exe sinon (puis de parser le listing asm ) ?
0
cs_elpens Messages postés 260 Date d'inscription vendredi 2 décembre 2005 Statut Membre Dernière intervention 3 novembre 2007
24 sept. 2007 à 15:33
Ouais, ca pourrait être une idee, mais j'ai aucune idee comment desassembler un exe en c++....

 ElpenS
0
acx01b Messages postés 280 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 8 juillet 2014 6
24 sept. 2007 à 17:34
j'ai regardé desassembleur sur wikipedia et je suis tombé sur un lien:

http://bastard.sourceforge.net/libdisasm.html

qui m'a l'air pas mal
0
cs_elpens Messages postés 260 Date d'inscription vendredi 2 décembre 2005 Statut Membre Dernière intervention 3 novembre 2007
24 sept. 2007 à 18:24
Ok, merci je vais jeter un oeil la-dessus!

Sinon, j'ai testé récupérer les différents call mais ma méthode ne fonctionne pas...

//Lance le process a tester
CreateProcess(TEXT(
"c:\\Microsoft Office\\OFFICE11\\MSACCESS.EXE"), 0, 0, 0, TRUE, CREATE_SUSPENDED, 0, 0, &startup, &procinfo);

// Execute le programme
ResumeThread(procinfo.hThread);

// position de dépard ('MZ')
DWORD myOffset = pimage_nt_headers->OptionalHeader.ImageBase;

// Ecrit dans memread la valeur
ReadProcessMemory(procinfo.hProcess, (LPVOID) myOffset, memread, 1, NULL);

// tant que la zone != 0xE8: call
while ((memread[0] != 0xE8) )
{
   // Est-ce dans les boundaries
    
if (myOffset <= pimage_nt_headers->OptionalHeader.ImageBase + pimage_nt_headers->OptionalHeader.SizeOfImage)
   {
      
ReadProcessMemory(procinfo.hProcess, (LPVOID) myOffset, memread, 1, NULL);
      myOffset++;
   }
}

Je sais qu'il a des choses (stupides) à améliorer, mais je voulais juste tester si je pouvais sortir les instructions call qui ont la valeur E8, mais c'est un echec.

Merci encore

 ElpenS
0
cs_juju12 Messages postés 966 Date d'inscription samedi 3 avril 2004 Statut Membre Dernière intervention 4 mars 2010 4
25 sept. 2007 à 21:00
Tu le récupères où et comment le pimage_nt_headers?
0
cs_elpens Messages postés 260 Date d'inscription vendredi 2 décembre 2005 Statut Membre Dernière intervention 3 novembre 2007
26 sept. 2007 à 08:32
Désolé, j'ai oublié de vous informer que cette partie fonctionne à présent...

CreateProcess(TEXT("c:\\Microsoft Office\\OFFICE11\\MSACCESS.EXE"), 0, 0, 0, TRUE, CREATE_SUSPENDED, 0, 0, &startup, &procinfo);

BYTE *myOffset = (BYTE*)pimage_nt_headers->OptionalHeader.ImageBase + pimage_nt_headers->OptionalHeader.AddressOfEntryPoint;

while(myOffset <= (BYTE*)pimage_nt_headers->OptionalHeader.ImageBase + pimage_nt_headers->OptionalHeader.SizeOfImage)
{
   BYTE callAddress[4];
   ReadProcessMemory(procinfo.hProcess, (LPVOID) myOffset, memread, 1, NULL);

   
if(memread[0] ==
'\xE8')
   {
      
for(
int iCount = 0; iCount <= 3; iCount++)
      {
         myOffset++;
         ReadProcessMemory(procinfo.hProcess, (LPVOID) myOffset, memread, 1, NULL);
         callAddress[iCount] = memread[0]; 
      }
      printf(
"0x%X\tcall %.2X %.2X %.2X %.2X\n", myOffset-4, callAddress[3], callAddress[2], callAddress[1], callAddress[0]);
   }

   ReadProcessMemory(procinfo.hProcess, (LPVOID) myOffset, memread, 1, NULL);

   if(memread[0] ==
'\xFF')
   {
      myOffset++;
      ReadProcessMemory(procinfo.hProcess, (LPVOID) myOffset, memread, 1, NULL);

      
if(memread[0] ==
'\xD7')
      {
         //Il faut aller chercher la valeur dans le registre, donc trouver une instruction move contenant le registre utilisé.....

      }
      
if(memread[0] ==
'\x15')
      {
         
for(
int iCount = 0; iCount <= 3; iCount++)
         {
            myOffset++;
            ReadProcessMemory(procinfo.hProcess, (LPVOID) myOffset, memread, 1, NULL);
            callAddress[iCount] = memread[0]; 
         }
   
         printf(
"0x%X\tcall %.2X %.2X %.2X %.2X \n", myOffset-5, callAddress[3], callAddress[2], callAddress[1], callAddress[0]); 
      }
   }
   myOffset++;
}
Cette partie fonctionne plus ou moins correctement, maintenant, il faudrait que je trouve les différentes pattern qui me permettent de retrouver les instructions call.
Comme vous pouvez le constater, je les recherche pour l'instant à l'aide de:

- E8 0x00 00 00 00
- FFD7                   //mais là il faut s'attaquer au registre... ouch
- FF15 0x00 00 00 00

Et il me semble qu'il existe plus de pattern, mais j'ai un peu de la peine à bien comprendre les instructions dans le manuel architecture d'Intel...

Voilà, merci pour vos conseils et vos idées!

Bonne journee

 ElpenS
0
Rejoignez-nous