Afficher les chaînes de caractères situées dans un processus ou un dump
Récupérer la liste des chaînes de caractères (string) présentes dans la mémoire utilisée par un exécutable peut être intéressant (Mise en place d’interning par exemple).
Cet article montre plusieurs manières de récupérer ces chaînes de caractères directement dans un processus live ou un dump.
Dans les exemples ci-dessous, l’application console (.NET) récupère un mot situé sur une page web. Le but est de retrouver ce mot en mémoire.
Process Explorer
Avec un processus live, Process Explorer donne accès aux chaînes de caractères que ce soit en mémoire ou à l’intérieur du binaire. La récupération des chaînes de caractères dans le binaire fonctionne mais celle en mémoire affiche une liste vide pour les processus .NET.
J’ai tenté de poser la question sur le forum dédié à Process Explorer mais mon message est resté sans réponse : http://forum.sysinternals.com/strings-into-net-memory_topic29299.html.
Process Hacker
De la même manière que Process Explorer, Process Hacker permet de récupérer les chaînes de caractères en mémoire ou dans le binaire.
Process Explorer dispose d’options plus avancées permettant de filtrer les chaînes de caractères :
-
Taille minimum des chaînes à afficher
-
Mémoire privée ou mappée
En comparant les résultats de Process Hacker avec les résultats de !Strings de SOSEX (plus loin dans l’article), on s’aperçoit qu’il ne cherche pas les objets .NET mais fait simplement une recherche des chaînes imprimables en mémoire (voir section sur la commande “s” plus loin dans l’article). Si une des chaîne est contenue dans un objet .NET (comme par exemple une instance de String ou de Byte[]), un “!lno ” (SOS) permet de retrouver l’objet .NET associé.
Une fois ces premiers filtres appliqués, il est possible de filtrer sur le contenu des chaînes de caractères.
En appliquant un filtre “Contains” sur le mot “SingleWord”, on retrouve 8 occurrences de notre chaîne caractères.
Strings.exe
Avec un dump du processus, il est possible de récupérer les chaînes de caractères avec Strings.exe et de les exporter dans un fichier texte pour une éventuelle analyze dans Excel ou autre.
Un seul filtre est disponible dans Strings.exe, la taille minimale des chaînes de caractères (3 par défaut).
C:\>strings.exe -n 10 -q D:\Temp\StringsApplication.dmp > D:\Temp\StringsApplication.txt
Explications :
Paramètre | Explication |
---|---|
-n 10 | Permet de ne récupérer que les chaînes de plus de 10 caractères |
-q | Retire l’entête que met Strings.exe par défaut lorsqu’il affiche la liste des chaînes. |
SOSEX
SOSEX, l’extension développée par Steve Johnson pour faire du debug .NET dans WinDbg propose la commande !strings pour récupérer les chaines de caractères dans un processus live ou un dump (.NET).
Les paramètres de !strings sont intéressants puisqu’ils permettent d’appliquer quelques filtres un peu plus avancés comme le choix de la génération minimale des chaînes ou encore la taille maximale des chaînes à récupérer.
Un autre avantage de SOSEX est de pouvoir utiliser les chaînes trouvées pour effectuer d’autres opérations en mémoire (récupération des roots des chaînes avec gcroot par exemple).
Attention, !Strings ne cherche que les chaînes dans le “managed heap”, c’est à dire la mémoire .NET.
0:000> !strings /m:SingleWord /n:10 /x:20
Address Gen Length Value
—————————————
029e0b6c 0 10 SingleWord
—————————————
1 matching string
Explications :
Paramètre | Explication |
---|---|
/m:<Text> | Permet de spécifier le pattern à chercher |
/n:<Int> | Taille minimale de la chaîne de caractères |
/x:<Int> | Taille maximale de la chaîne de caractères |
Recherche en mémoire avec WinDbg
La command s
disponible nativement dans WinDbg permet de rechercher un pattern en mémoire.
Ici on peut s’en servir avec les options sa
(ASCII) et su
(Unicode) pour rechercher notre chaîne de caractères.
0:000> s -[w]u 0x0 L?0xFFFFFFFF "SingleWord"
029e0b74 0053 0069 006e 0067 006c 0065 0057 006f S.i.n.g.l.e.W.o.
029e0eec 0053 0069 006e 0067 006c 0065 0057 006f S.i.n.g.l.e.W.o.
029e1230 0053 0069 006e 0067 006c 0065 0057 006f S.i.n.g.l.e.W.o.
0:000> s -[w]a 0x0 L?0xFFFFFFFF "SingleWord"
029d74e7 53 69 6e 67 6c 65 57 6f-72 64 00 00 00 00 00 00 SingleWord……
029e04b8 53 69 6e 67 6c 65 57 6f-72 64 00 00 00 00 00 00 SingleWord……
029e08c4 53 69 6e 67 6c 65 57 6f-72 64 00 00 00 00 00 80 SingleWord……
029e09f8 53 69 6e 67 6c 65 57 6f-72 64 00 00 00 00 00 00 SingleWord……
029e10f8 53 69 6e 67 6c 65 57 6f-72 64 0d 0a 00 00 00 00 SingleWord……
Explications:
Paramètre | Explication |
---|---|
[w] | Permet de ne chercher que dans la mémoire accessible en écriture. |
0x0 | Adresse de début de la recherche |
L?0xFFFFFFFF | Taille de la recherche |
Si on compare ces résultats à ceux donnés par Process Hacker, on retrouve le même nombre d’occurrences mais avec des adresses mémoires différentes. Si on regarde plus attentivement la taille des chaînes affichées dans Process Hacker, on s’aperçoit que les chaînes avec une longueur de 10 (taille de “SingleWord”) ont la même adresse mémoire de chaque côté.
Pour retrouver les adresses mémoires il faut faire un peu de calcul. Si on prend l’adresse 0x029d74e7 affichée par la commande “s”
0:000> s -[w]a 0x0 L?0xFFFFFFFF "SingleWord"
et que l’on regarde ce qu’il y a juste avant,
0:000> ? 029d74e7-0x20
Evaluate expression: 43873479 = 029d74c7
0:000> da 029d74c7
029d74c7 "bytes..Vary: Accept-Encoding…."
029d74e7 "SingleWord"
on retrouve la chaîne “Accept-encoding” présente également dans le 1er résultat remonté par Process Hacker.
Pour retrouver l’adresse mémoire présentée par Process Hacker dans WinDbg, il faut simplement remonter de la taille indiquée par Process Hacker (365), y soustraire la taille de “SingleWord” (10) et faire la soustraction avec l’adresse indiquée par la commande “s”. On doit donc partir de 0x029d74e7 et remonter de 355, soit 0x****163.
0:000> ? 0n355
Evaluate expression: 355 = 00000163
0:000> ? 0x029d74e7-0x163
Evaluate expression: 43873156 = 029d7384
0:000> da 029d7384
029d7384 "HTTP/1.1 200 OK..Set-Cookie: 60g"
029d73a4 "pBAK=R1224199043; path=/; expire"
029d73c4 "s=Sat, 01-Jun-2013 13:09:57 GMT."
029d73e4 ".Date: Sat, 01 Jun 2013 12:06:17"
029d7404 " GMT..Content-Type: text/html..C"
029d7424 "ontent-Length: 10..Connection: k"
029d7444 "eep-alive..Set-Cookie: 60gp=R233"
029d7464 "7168536; path=/; expires=Sat, 01"
029d7484 "-Jun-2013 13:19:02 GMT..Server: "
029d74a4 "Apache/2.2.X (OVH)..Accept-Range"
029d74c4 "s: bytes..Vary: Accept-Encoding."
029d74e4 "…SingleWord"
CLrMD
Depuis début mai, une nouvelle librairie .NET fournie par Microsoft permet d’analyser des dumps ou des processus lives. Des informations sur cette librairie sont disponibles ici (FR) et ici (EN).
Grâce à cette librairie, il est très facile de récupérer tous les objets .NET, de vérifier leurs types, récupérer leurs valeurs, etc.
Comme pour SOSEX on ne cherche ici que dans le “managed heap” (mémoire .NET).
using (DataTarget dataTarget = DataTarget.LoadCrashDump(@"D:\Temp\StringsApplication.dmp"))
{
String dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation();
ClrRuntime runtime = dataTarget.CreateRuntime(dacLocation);
ClrHeap heap = runtime.GetHeap();
foreach (ulong obj in heap.EnumerateObjects())
{
ClrType type = heap.GetObjectType(obj);
if (type.Name.Equals("System.String") == true)
{
String value = type.GetValue(obj).ToString();
if (value != null && value.Contains("SingleWord") == true)
{
ulong size = type.GetSize(obj);
Console.WriteLine("{0,12:X} {1,8:n0} {2} {3}",
obj,
size,
type.Name,
value);
}
}
}
}
Console.WriteLine("Finished");
Console.ReadKey();
Avec cette librairie, on peut imaginer beaucoup de possibilités, le dé doublonnage, l’export directement dans Excel pour ressortir des statistiques, etc.