2014-07-10 1 views
1

Je voudrais vider une mémoire de fonctions (void) dans un tableau d'octets (unsinged char[]). En aval, une fonction fictive doit être pointée sur le tableau d'octets et la fonction fictive doit être exécutée.Mémoire de vidage d'une fonction

La fonction que je veux vider:

void CallMessageBoxExA() 
{ 
    message = "ManualMessageBoxExA"; 
    caption = "Caption"; 
    pAddr = GetProcAddress(GetModuleHandle(L"User32.dll"), "MessageBoxExA"); 

    __asm // Call MessageBoxA 
    { 
     push dword ptr 0 //--- push languageID: 0 
     push dword ptr 0 //--- push style: 0 
     push dword ptr caption //--- push DWORD parameter (caption) 
     push dword ptr message //--- push DWORD parameter (message) 
     push dword ptr 0 //--- push hOwner: 0 
     mov eax, pAddr 
     call eax //-- call address of the function, which is currently in EAX 
    } 
} 

Dumping la mémoire:

string DumpMemory(void *pAddress, int maxLength) 
{ 
    string result = ""; 
    const unsigned char * p = reinterpret_cast< const unsigned char *>(pAddress); 
    cout << "Memory location: 0x" << hex << (unsigned int)p << endl; 
    for (unsigned int i = 0; i < maxLength; i++) { 
     string code = ""; 
     stringstream ss; 
     ss << hex << int(p[i]); 
     ss >> code; 
     result += code; 
    } 
    return result; 
} 

Lorsque l'on regarde à l'emplacement de mémoire DumpMemory imprime sur la console, ollydbg montre une instruction JMP à cet endroit:

CPU Disasm 
Address Hex dump   Command         Comments 
00281627 $-/E9 044C0000 JMP CallMessageBoxExA 

Est-ce le bon emplacement de mémoire, ou dois-je suivre le JMP?

saut de l'emplacement de mémoire conduit à:

CPU Disasm 
Address Hex dump   Command         Comments 
00286230 /$ 55   PUSH EBP         ; ASM.CallMessageBoxExA(void) 
00286231 |. 8BEC   MOV EBP,ESP 
00286233 |. 81EC C0000000 SUB ESP,0C0 
00286239 |. 53   PUSH EBX 
0028623A |. 56   PUSH ESI 
0028623B |. 57   PUSH EDI 
0028623C |. 8DBD 40FFFFFF LEA EDI,[EBP-0C0] 
00286242 |. B9 30000000 MOV ECX,30 
00286247 |. B8 CCCCCCCC MOV EAX,CCCCCCCC 
0028624C |. F3:AB   REP STOS DWORD PTR ES:[EDI] 
0028624E |. C705 A8562900 MOV DWORD PTR DS:[message],OFFSET 00291D ; ASCII "ManualMessageBoxExA" 
00286258 |. C705 AC562900 MOV DWORD PTR DS:[caption],OFFSET 00291D ; ASCII "Caption" 
00286262 |. 8BF4   MOV ESI,ESP 
00286264 |. 68 041E2900 PUSH OFFSET 00291E04      ; ASCII "MessageBoxExA" 
00286269 |. 8BFC   MOV EDI,ESP 
0028626B |. 68 D01D2900 PUSH OFFSET 00291DD0      ; /ModuleName = "User32.dll" 
00286270 |. FF15 00602900 CALL DWORD PTR DS:[<&KERNEL32.GetModuleH ; \KERNEL32.GetModuleHandleW 
00286276 |. 3BFC   CMP EDI,ESP 
00286278 |. E8 5BB2FFFF CALL 002814D8       ; [_RTC_CheckEsp 
0028627D |. 50   PUSH EAX         ; |hModule 
0028627E |. FF15 04602900 CALL DWORD PTR DS:[<&KERNEL32.GetProcAdd ; \KERNEL32.GetProcAddress 
00286284 |. 3BF4   CMP ESI,ESP 
00286286 |. E8 4DB2FFFF CALL 002814D8       ; [_RTC_CheckEsp 
0028628B |. A3 B0562900 MOV DWORD PTR DS:[pAddr],EAX 
00286290 |. 6A 00   PUSH 0 
00286292 |. 6A 00   PUSH 0 
00286294 |. FF35 AC562900 PUSH DWORD PTR DS:[caption] 
0028629A |. FF35 A8562900 PUSH DWORD PTR DS:[message] 
002862A0 |. 6A 00   PUSH 0 
002862A2 |. A1 B0562900 MOV EAX,DWORD PTR DS:[pAddr] 
002862A7 |. FFD0   CALL EAX 
002862A9 |. 5F   POP EDI 
002862AA |. 5E   POP ESI 
002862AB |. 5B   POP EBX 
002862AC |. 81C4 C0000000 ADD ESP,0C0 
002862B2 |. 3BEC   CMP EBP,ESP 
002862B4 |. E8 1FB2FFFF CALL 002814D8       ; [_RTC_CheckEsp 
002862B9 |. 8BE5   MOV ESP,EBP 
002862BB |. 5D   POP EBP 
002862BC \. C3   RETN 

POINTAGE la fonction factice au tableau d'octets:

void(*func_ptr)(); 
func_ptr = (void(*)()) &foo[0]; // make function point to foo[] 
(*func_ptr)(); // Call the function 

Est-ce la bonne façon de faire le point de la fonction factice au tableau d'octets?

À quel point la fin de la fonction est-elle atteinte? Dois-je simplement vérifier les différents opcodes de retour (C3 -> retour près de l'appelant, CB -> renvoyer loin à l'appelant, ...)? PS: Une solution simple (par exemple pas très élaborée) est préférée car je suis nouveau en C++.

Éditer: Je veux réaliser ceci dans un environnement de Windows.

+3

[Ce n'est pas possible de manière portable.] (Http://en.wikipedia.org/wiki/Harvard_architecture) Si vous voulez un conseil spécifique à la plate-forme (il ressemble à Windows), spécifiez la plate-forme. –

+3

Je recommanderais de développer vos compétences C++ avec quelque chose de beaucoup moins compliqué. –

+0

Ce que vous cherchez à faire est une chose * TRES * puissante qui est utilisée par une poignée de développeurs dans le monde (surtout ceux qui écrivent des runtimes JIT pour les langues). Comme point de référence, dans mon propre cercle, en tant que développeur C++ de 10 ans, je suis le seul que je connaisse personnellement qui l'ait jamais essayé. –

Répondre

1

Vous devez stocker la fonction "copié" sur un bloc de mémoire alloué en utilisant VirtualAllocEx. Sur les systèmes d'exploitation modernes, il y a un peu sur chaque page qui déclare si son contenu est exécutable ou non. Ceci est utilisé pour minimiser les dommages des dépassements de tampon. Par défaut, votre mémoire n'est pas exécutable. Si vous utilisez VirtualAllocEx avec le mode de protection PAGE_EXECUTE_READWRITE, vous pourrez écrire dans un bloc de mémoire, puis l'exécuter.

En ce qui concerne votre question «quand arrivez-vous à la fin d'une fonction», cela ne répond pas réellement. Il existe des modèles communs que vous pouvez rechercher, mais x86 n'a aucun moyen d'identifier la "fin" d'une fonction.

+0

Assurez-vous également de vérifier l'alignement de vos données lorsque vous essayez de l'exécuter. Je ne me souviens pas si x86 a des exigences d'alignement sur ses opcodes, mais si c'est le cas, vous devez vous assurer qu'ils sont pris en compte. –

+0

Et puis vous devez également appliquer des corrections en raison du mouvement du code. Et détecter les tables de saut et les réparer aussi. Cela se transforme rapidement en problème d'arrêt. –

0

Il semble que vous ayez besoin de suivre le saut. Lorsque vous suivez le saut, le code que vous voyez correspond à ce que vous avez compilé ci-dessus.

En outre, votre DumpMemory utilise l'adresse de pAddressIn. Votre fonction passe une variable appelée pAddress. Soit c'est une faute de frappe, soit vous faites référence à une variable déclarée ailleurs. Je suppose que vous avez voulu utiliser pAddress.

La mémoire que vous allouez peut nécessiter des privilèges spéciaux pour pouvoir s'exécuter. En l'état, la mémoire que vous allouez avec les données de fonction brutes sera marquée comme "données". "Data Execution Prevention" peut l'arrêter en fonction de votre environnement.

+0

Merci, c'était une faute de frappe. –

Questions connexes