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
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
É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é :)
Viktor, köszönöm a részletes infókat. :)