Créer un plugin pour ImpRec est relativement aisé, il suffit de créer une DLL qui exporte une fonction Trace avec le prototype suivant :

- DWORD Trace(DWORD hFileMap, DWORD dwSizeMap, DWORD dwTimeOut,
DWORD dwToTrace, DWORD dwExactCall);

et voila à quoi correspondent les différents arguments :

- hFileMap      : HANDLE of the file mapped by ImportREC
- dwSizeMap     : Size of the mapped file
- dwTimeOut     : TimeOut in ImportREC Options
- dwToTrace     : The pointer to trace (in VA)
- dwExactCall   : The EIP of the 'Exact Call' (in VA)
(this value is 0 when it is not an 'Exact Call')

En gros ImpRec créé une thread, cache la thread au debugger (ce qui est fort pratique si, par exemple, votre plugin utilise un tracer mais qui est bien embétant quand vous voulez debugger votre plugin ...), il load votre dll, appelle la fonction Trace du plugin puis unload la dll et tue la thread.

Votre Fonction Trace devra alors, à partir de l'adresse qui lui est fournie par le champ dwToTrace, retrouver l'adresse de l'API correspondante, créer une vue du file mapping a l'aide de MapViewOfFile, écrire l'adresse de l'API à l'adresse retournée, libérer la vue et retourner le code de réussite (oupa) c'est à dire 200.

Jusque là tout va bien. Le problème vient au moment où on a besoin de l'adresse de l'IAT pour retrouver correctement l'adresse de l'API, je me permet de m'auto citer (flemme de réécrire) :

Le gros frein avec ImpRec (et je ne comprends absolument pas pourquoi Mackt a conçu son système de plugin comme ça) c'est qu'il ne passe pas l'adresse de l'IAT au plugin il passe juste l'adresse qu'il faut résoudre Or je me base sur les adresses aux alentours de celle à fixer pour scanner uniquement les exports de la dll à laquelle l'import est censé appartenir (il y a certaines fonctions qui sont présentes dans plusieurs DLL windows avec exactement le même code et qui sont donc indiscernables par mon call-fixer qui ne sait pas choisir entre l'une et l'autre sans savoir à quelle dll appartient l'import obfusqué)

exemple :

GDI32.GdiSetLastError :

MOV EDI,EDI PUSH EBP MOV EBP,ESP MOV EAX,FS:[18] MOV ECX,[EBP+8] MOV [EAX+34],ECX POP EBP RETN 4

KERNEL32.SetLastError (forwarding de l'API NTDLL.RtlSetLastWin32Error) :

MOV EDI,EDI PUSH EBP MOV EBP,ESP MOV EAX,FS:[18] MOV ECX,[EBP+8] MOV [EAX+34],ECX POP EBP RETN 4

Comme vous voyez c'est exactement le même code, quand mon call fixer croise un import obfusqué qui une fois désobfusqué donne ce code, impossible de choisir entre les 3 APIs GdiSetLastError, SetLastError et RtlSetLastWin32Error alors que si je me base sur les adresses environnantes dans l'IAT je peux savoir quel export choisir

ImpRec ne me fournissant pas de pointeur sur l'IAT, je suis un peu coincé :D

(Posté sur le forum de DeezDynasty lien : http://deezdynasty.totalh.com/forum/viewtopic.php?f=1&t=700#p3055, la suite de la conversation éclairera ceux qui se demandent en quoi ca pose problème vraiment.)

Il a donc fallu que je code une petite fonction qui va se charger de retrouver l'IAT à partir de l'adresse de la fonction à résoudre, elle fonctionne globalement comme cela :

Pour toutes les Pages mémoires :

    Pour tous les DWORD d de la page mémoire :

        Si d == Adresse :

            Pour toutes les références de d en mémoire

                Si la référence correspond à un Call [d] ou un Jmp [d] et que d appartient à un module chargé

                    On retourne d

                Sinon on continue le scann de la page

        On passe au DWORD suivant

    On passe à la page mémoire suivante

Quand plus de pages mémoire on retourne 0

Une fois que nous avons l'adresse dans l'IAT correspondant à l'adresse que l'on nous demande de tracer, il est possible de retrouver la DLL à laquelle est censée appartenir l'import obfusqué, néanmoin ce n'est pas si simple :D, en effet certaines APIs ne sont pas "réellement" exportées par la DLL à laquelle elle correspond, si vous avez bien lu ce qui précède vous avez du remarquer la ligne suivante : KERNEL32.SetLastError (forwarding de l'API NTDLL.RtlSetLastWin32Error) en effet quand vous appelez SetLastError vous appelez en fait une fonction de NTDLL, RtlSetLastWin32Error grâce au mecanisme de l'export forwarding détaillé ICI (merci __ed ;) ).

Pour retrouver la DLL à laquelle correspond la rangée d'import il ne faut donc pas compter sur ces fonctions. J'ai recodé une partie de ma fonction qui sert au listing des exports des DLLs afin de repérer ces adresses "exportables" par plusieurs DLLs une fois cette fonction modifiée, voila le fonctionnement de la routine chargée de retrouver la DLL à laquelle est censé appartenir l'export :

  • On regarde les adresses situées en dessous de celle retournée par notre fonction chargée de retrouver l'IAT
  • Si l'adresse est "exportable" par plusieurs DLLs, on passe à la suivante
  • Si l'adresse appartient a une DLL et n'est "exportable" que par cette DLL, on a notre DLL et nous ne scannerons que les exports de cette DLL
  • Si l'adresse est nulle, on recommence en regardant cette fois les adresses situées au dessus
  • Si aucune adresse ne nous permet de retrouver la DLL à laquelle est censée appartenir notre API polymorphisée alors on scanne toutes les DLLs

Une fois arrivé ici, nous avons un call fixer en parfait état de marche, nous le testons donc et horreur ! il est EXTREEEEMEMEEEENT LEEEEEEENT.

Si vous avez suivit la façon dont ImpRec charge les plugins, vous avez du remarquer que le plugin est systématiquement unloadé du processus cible après chaque export fixé (ou non).

La fonction de mon plugin qui se charge de désassembler et dépolymorphiser le début de tout les exports de tout les modules chargés est lente et gourmande en ressource, dans mon call fixer je ne l'appelais qu'une seule fois pour tout les exports à fixer et je stockais la liste chainée dans une variable globale, ce qui ne devient plus possible pour mon plugin.

J'ai donc créé un file mapping qui servira à stocker une fois pour toute l'adresse de la liste chainée qui contient les exports désassemblé, à l'appel de ma fonction Trace, si le file mapping n'existe pas, je le créé et je scanns les modules, sinon je récupère juste l'adresse de la liste chainée. Enfin pour pouvoir utiliser mon plugin sur plusieurs processus en même temps, le nom du file mapping est associé auPID du processus courant avec un nom de la forme BABOON_SF_IMPORT_FIXER_%PID

Voili voilou !

Nous avons au final un joli plugin de 30Ko qui rebuild les imports polymorphisés de StarForce en un temps tout ce qu'il y a de plus raisonnable et ce de façon totalement automatique et générique :D

(pour être tout à fait honnete j'ai un vieux bug, à la reconstruction du 1er import protégé qui n'apparait pas quand je teste mon plugin avec olly et donc que je n'arrive pas à localiser. Le bug devrai se situer dans la fonction de recherche de l'IAT mais je ne vois absolument pas ce que ca pourrait etre étant donné qu'il ne bug que pour le tout premier import, ce bug ne gene pas vraiment, tous les autres imports sont reconstruit et il suffit de réuntiliser le plugin sur l'import non résolu pour qu'il le soit)

Comme d'habitude les sources et le plugin sont disponibles toujours avec la licence creative commons suivante : Creative Commons License

Bon j'ai conscience que mon post est un peu fouilli et peut etre pas tres clair, il a été ecris d'une seule traite et j'ai une grosse flemmingite :P

Néanmoin si vous avez des questions ou des remarques, n'hesitez pas, je tacherai d'y répondre et de corriger / modifier mon post si necessaire.

(Tient sinon, UNE thread ou UN thread ?)