L'idée a jailli un après midi grâce à une série de hasards ...

Je venais de faire un petit loader pour SC et je m'etais donc penché a cette occasion sur injmem, l'injecteur de virtualabs, afin de voir comment il marchait et essayer de l'améliorer avec lui.

Kaspersky le détectant, j'ai regardé la liste des apis hookées par notre ami russe et j'ai debuggé un peu injmem.

Je me suis vite aperçu que virtu se faisait avoir à cause de WriteProcessMemory, n'ayant pas trouvé d'alternatives , j'ai un peu oublié l'affaire

Et là **PAN** , une semaine après, un haiklr (hihi) de lucidité "Et si on obligeait le programme a s'auto injecter !?"

Pour injecter le code en effet je n'utilise pas d'apis propres a l'injection comme CreateRemoteThread , OpenProcess/Thread , WriteProcessMemory, je n'utilise que des apis de debug.

L'injection se deroule comme ceci :

  1. On scanne Kernel32 dans le processus injectant afin de trouver les adresses de 3 opcodes (nop , retn , push eax) et de quelques fonctions utiles.
  2. On scanne les processus , on repère le processus cible et on scanne ses modules de facon à trouver l'adresse où est loadée Kernel32.
  3. On debugge le processus cible via l'api DebugActiveProcess, ce qui nous permet d'avoir un handle sur le processus cible et ses threads.
  4. On adapte les adresses des opcodes précedemment recherchés et on injecte grâce à ces adresses et SetThreadContext

Par exemple , si je veux creer un espace memoire dans le processus cible , il me suffit d'obliger le processus cible à appeller VirtualAlloc.

Il faut donc que je push les arguments , pour ce faire , je mets dans eax la valeur à pusher et je fais pointer eip sur le "push eax" , je mets le trap flag à 1 et je lance, le programme breakera juste apres avoir executé le push eax et j'aurais alors pushé ma valeur.

Pour appeler l'api VirtualAlloc meme principe, ou presque, il me suffit de faire pointer eip vers le debut de l'api (après avoir pushé l'adresse du nop) , de mettre un HBP en execution sur le nop et de lancer le programme ,

Enfin, pour ecrire dans la mémoire allouée, plusieurs options s'offrent à vous , soit vous utilisez les apis comme createfile/readfile etc , soit vous utilisez un opcode de type mov.

Kaspersky n'aime pas que l'on ecrive dans la memoire fraichement allouée avec un mov [reg] , reg , j'ai donc utilisé (dans mon code de démo) un moyen detourné pour écrire en memoire , je deplace esp vers la zone à écrire + la taille du code et j'utilise une série de push ce n'est peu être pas tres beau mais ca a le merite de marcher ...

Enfin , Kaspersky n'aimant pas non plus que l'on fasse pointer eip sur une zone fraichement allouée , je fais un bete "push eip / retn"

(je n'ai pas testé d'autres methodes , alors faites vous plaisir ;) )

Pour DL le pack source + exe c'est ICI (sources en NASM et C)

Dans mon exemple , j'ai créé les fonctions principales qui sont tres simples à utiliser ...

pour pusher :

 push MaValeur
 call iPush

pour appeler :

 push addrMaFonction
 call iCall

pour remplir une zone memoire :

 push Size
 push addrBuffIn
 push addrBuffOut
 call iWriteMem

pour copier une zone memoire :

 push size
 push addrBuffOut
 push addrMem
 call iReadMem

pour lancer votre code injecté :

 push addrCode
 call iGo

Enfin un grand merci à

  • Kaine (pour les phottes et en plus comme ca, hop, God certified)
  • nats' et silma (pour le soutien ;) )
  • virtualabs (pour injmem)
  • Squallsurf (sinon il va pas etre content)
  • a la RRF en general :p
  • a tous ceux sur IRC et sur les differents forums que je frequente

voili voilou

Cette technique sera probablement hookée assez rapidement et n'a finalement pas enormement d'interet mais elle est zoulie et ca me suffit :p

[EDIT : Jeudi 07 Juin 2007] Ajout de la fonction iReadMem et "amélioration" de la fonction de recherche des opcodes , maintenant l'injecteur affiche les 16 premiers bytes injectés (pour faire un petit exemple de l'utilisation de iReadMem)

[EDIT : Samedi 09 Juin 2007] Mise à jour du code de recherche des opcodes, maintenant IINJ ne scanne plus que la section .text de kernel32 .

[EDIT : Vendredi 20 Juin 2008] Mise a jour des sources, le code en asm pourri est toujours disponible mais iinj a été recodé en C