Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.

November 26, 2010 / by Zsolt Soczó

.NET Stringek lementése Memory Dumpból

Mostanában elég sokat turkálok problémás webappok dumpjában. Leírom magamnak is, hogy lehet lementeni .NET stringeket a dumpból.
WinDbg dolgok következnek.

A nagy stringeket kilistáztatom a
!DumpHeap -min 100000 -type System.String
paranccsal.

Valamelyik heapről kinézek magamnak egyet, és az előbbi parancs kimenetének első oszlopában található címet felhasználva belenézek a du cím paranccsal.
Pl.
0:000> du 5ce31140
5ce31140 “*****<sitecore database=”SqlSer”
5ce31180 “ver”>.. <sc.variable name=”da”

Az elején a kuszaság (átírtam csillagokra, mert elrontotta a htmlt) a .NET Stringek adminisztrációja és az object header.
Ha szemre tetszik a string, akkor pl. ki akarom menteni fájlba.
Nézzük meg a szöveges rész előtti bináris részt (dd).

0:000> dd 5ce31140
5ce31140 793308ec 00040001 0002836c 0073003c
Az első 8 byte az object header (32 biten, 64-en ez asszem 16 byte), sync block és type leíró. Számunkra ez érdektelen. A 3. dword már érdekesebb, ez a string hozza karakterekben. Azaz bájtban ennek a duplája, mert 2 bytes unicode ábrázolást használ a .net.
Így stringünk hossza 0002836c*2 byte. A 0073003c már a < karakter (003c) és az s betű (0073), szokásos fordított Intel sorrendben. A szöveges tartalom tehát a 5ce31140+0c címen kezdődik (headert átlépjük), és 0002836c*2 a hossza. A tartalom fájlba írása már egyszerű: .writemem c:\temp\s1.txt 5ce31140+0c L0002836c*2 Kedvencem a WinDbg, de ezt már mondtam. :)

Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.

LEAVE A COMMENT

3 COMMENTS

  • Tóth Viktor November 26, 2010

    Apró javítások:

    1) a .NET-es referenciák kicsit trükkösen mutatnak az objektumra. Ugyanis nem a felhasznált terület elejére mutatnak, hanem a terület kezdete után 4 byte-tal. Tehát igaz, hogy az objektumot megelőzi két bejegyzés, amelyből az első a sync block index, de ezt a referenciák átugorják. Emiatt az első mező címe nem 8 hanem csak 4 byte-tal van eltolva a referencia által mutatott területhez képest.

    2) Bár az van a doksikban, hogy a másik bejegyzés a type object pointer, valójában ez a metódus tábla címe, könnyen meggyőződhetsz róla. Egyébként logikus is, mert a leggyakoribb művelet, amit az objektumokon csinálnak, az a metódushívás, így a metódustáblára van legtöbbször szükség (ráadásul a jitter után erre is csak a virutális függvényeknél van szükség). Ha a type object kell, azt a metódus táblából közvetve lehet megszerezni.

    szóval az obejct header a sync indexből és a metódustáblából ál, de csak a metódustáblát kell átugorni.

    3) A fentiek alapján a dumpodban:
    5ce31140 – a memória címe, amit nézel
    793308ec – a metódustábla címe (nyomjál rá egy DumpMT-t, meglásd működik)
    00040001 – annak a tömbnek a mérete, amiben a string az adatait tarja (m_arrayLength mező)
    0002836c – a string hossza karakterekben (m_stringLength)
    0073003c – az első két betű unicodban

  • Érsek Attila November 26, 2010

    Én erre mindig egyszerűen a !do -nofields parancsot használtam és ctrl+c-ctrl+v kombót, úgyhogy köszi, megy a helper scriptek közé :)

  • Soczó Zsolt November 30, 2010

    Viktor, köszönöm a részletes infókat. :)