2017-01-01 1 views
0

Je voudrais compiler les petites fonctions double(...) en tant que shellcode x64. J'ai déjà un programme de travail pour générer l'ensemble codé pour les opérations mathématiques simples comme a + b/a, où a et b sont double paramètres pour la fonction.Fonctions d'appel à l'intérieur du shellcode

Le code généré est chargé dans un tampon exécutable mmap et peut être appelé ultérieurement.

J'ai le problème suivant: Je voudrais appeler math.h fonctions comme sin, exp etc. dans mon shellcode généré. Comme tous les opcodes call utilisent en quelque sorte des adresses 32 bits ou des sauts relatifs, je ne peux pas facilement utiliser ces instructions. J'ai donc essayé de mettre en œuvre ma propre call -instruction cette façon:

lea rax, [rip+0x0] ;load instruction pointer into rax 
add rax, <offset-to-return-to> 
push rax 

moveabs rax, <adress-of-function> ;load the function pointer to rax 
jmp rax 

Ceci est mon code pour générer ces instructions:

//lea rax, [rip+0x0] 
insertAll(code,std::list<uint8_t>{ 0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00 }); 
//add rax, <offset-to-return-to> 
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC0, <offset-to-return-to>}); 

//push rax 
code.push_back(0x50); 

//moveabs rax, address-of-function 
uint8_t reg = 0; //rax 
uint8_t rexWPrefix = 0x48 + (reg > 8); 
uint8_t opCode = 0xB8 + (reg % 8); 
insertAll(code,std::list<uint8_t>{ rexWPrefix, opCode }); 
code.insert(code.end(),reinterpret_cast<uint8_t*>(&fabs),reinterpret_cast<uint8_t*>(&fabs) + 8); 

//jmp rax 
insertAll(code,std::list<uint8_t>{ 0xFF, 0xE0 }); 

Malheureusement, l'appel de fonctions de cette façon ne fonctionne pas, le programme se bloque avec une erreur SIGSEGV. Y a-t-il un problème avec mon code d'assemblage ou l'encodage de l'instruction? Quelle valeur doit avoir <offset-to-return-to>, pour que la fonction retourne à la bonne position? Clause de non-responsabilité: Je sais que ce n'est pas la meilleure façon de gérer la génération dynamique de code ... Je pourrais simplement compiler une bibliothèque dynamique et le charger avec dlsym. C'est juste une façon amusante d'apprendre à propos de l'assemblage/shellcodes et ne devrait pas être pris trop au sérieux :)

+2

est logique au premier abord, utiliser un débogueur pour voir où et pourquoi il fait défaut. PS: vous pouvez bien sûr fusionner le 'add rax' dans le' lea'. Assurez-vous d'utiliser un décalage correct. – Jester

+2

Qu'est-ce que "x64 shellcode" ?? Et C et C++ sont des langues différentes. Ne pas spammer les tags. – Olaf

+0

@Olaf: Je voulais dire, que j'utilise des instructions x86-64 pour le code. Cela peut être important pour l'instruction jmp car la taille de l'adresse est de 64 bits. – tly

Répondre

1

J'ai trouvé trois erreurs. L'instruction jmp n'est pas absolue, mais afaik RIP -relative. J'ai utilisé push + ret comme alternative parce que ret saute à une adresse absolue se trouvant sur la pile.

En outre, je ne savais pas qu'il est obligatoire pour l'appelant de réserver un espace d'ombre de 4 * 8 octets sur la pile. Les détails peuvent être trouvés here. Enfin, le code pour insérer le pointeur de fonction dans le code d'instruction était faux. J'ai accidentellement inséré les 8 premiers octets du code de fonction au lieu de la valeur du pointeur:

code.insert(code.end(),reinterpret_cast<uint8_t*>(&fabs),reinterpret_cast<uint8_t*>(&fabs) + 8); 

Ceci est le code de travail terminé:

//add rsp,0x20 --> shadow space of 4*8 bytes 
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC4, 0x20 }); 
//lea rax, [rip+0x0] 
insertAll(code,std::list<uint8_t>{ 0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00 }); 
//add rax, 18 
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC0, 18 }); 
//push rax 
code.push_back(0x50); 

//moveabs rax, address-of-function 
uint8_t reg = 0; //rax 
uint8_t rexWPrefix = 0x48 + (reg > 8); 
uint8_t opCode = 0xB8 + (reg % 8); 
insertAll(code,std::list<uint8_t>{ rexWPrefix, opCode }); 
void* address = reinterpret_cast<void*>(&my_abs); 
code.insert(code.end(),reinterpret_cast<uint8_t*>(&address),reinterpret_cast<uint8_t*>(&address) + sizeof(address)); 

//push rax 
code.push_back(0x50); 
//retq 
code.push_back(0xC3); 
//sub rsp,0x20 --> shadow space of 4*8 bytes 
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xEC, 0x20 });