Spørsmål:
Hvordan organisere tabeller i IDA Pro?
speeder
2016-01-21 00:29:57 UTC
view on stackexchange narkive permalink

Jeg bruker IDA Pro for å demontere en C ++ behemoth med 1600+ klasser, mange av dem har rene virtuelle metoder.

Noen klasser består også av flere baseklasser, i hierarkier 5+ nivåer dypt .

Ida PRO støtter å lage strukturer av pekere for å håndtere vtables, men noen av de siste klassene kan ha flere forskjellige vtables i samme "slot" på grunn av tung polymorfisme, så hvordan organiserer du vtables? Hvordan forteller du IDA at hvilken vtabell refereres det egentlig til i denne metoden eller den metoden?

Morsomt nok, jeg løste dette en gang for en klasse tung kjørbar ved å skrive min egen demonterer. I sin nåværende tilstand kan den samle klassemedlemmer og funksjoner fra flere DLLer. Men ikke en generell løsning: koden er avhengig av den bestemte kompilatoren koden ble skrevet med.
Hvorfor ble jeg nedstemt?
Selv om dette spørsmålet er ganske gammelt, prøv å bruke [HexRaysPyTools] (https://github.com/igogo-x86/HexRaysPyTools) for hexrays
En svar:
Ray
2017-10-29 01:37:24 UTC
view on stackexchange narkive permalink

Dette avhenger av kompilatoren som opprinnelig ble brukt, da hver skaper litt forskjellige oppsett. Du kan finne veiledninger for de fleste kompilatorer på nettet. Jeg kommer til å fokusere MSVC, da det er den jeg har erfaring med, og siden det gir en skjult kompilatorbryter som skriver ut hvordan klasser skal legges ut i minnet som jeg skal bruke til illustrasjon.

Som du kanskje allerede har gjettet, må du gjenskape C ++ - klasser med C-strukturer. Dette er mulig, men plagsomt, spesielt hvis du har så mange klasser som du sa. Noen tips for å gjøre det mindre irriterende:

  • Fokuser de du er interessert i.
  • Start med "base-most" klassene, f.eks. de øverst i hierarkitreet. Hvis du ødelegger noe der, kan det være dyrt å fikse det senere :; forestill deg å legge til et glemt medlem i noe sånt som en smart pekerbaseklasse som er arvet av hundrevis av klasser, og nå må du justere alle disse.
  • Det kan være lurt å definere struct kode> s med C-lignende kode i Lokale typer undervisningen først og ikke i Strukturer undervisningen. Følgende eksempler kan limes inn som lokale typer.
  • Hvis du er usikker på å reversere en struktur, ødelegger en konstruktør vanligvis vftable og utformingen av noen medlemmer; en funksjon som kaller det, kan gi totalstørrelsen på objektet ved å reservere nok byte til det.
  • IDA 7.0 hjelper deg mye ved automatisk å gjenkjenne og merke RTTI-data (hvis tilgjengelig) som ødelegger klassehierarkiet og vftables, men det markerer feilaktig hvilken vftable som hører til hvilken basisklasse i tilfelle flere arv, et problem IDA6-skriptet det er basert på hadde ikke. Jeg skrev den om i IDAPython for 7.0 for å fikse dette og andre MSVC-relaterte problemer, det kan også automatisk opprette strengene som forklart nedenfor.
  • IDA 7.2 har enda bedre støtte for automatisk å oppdage og gjenskape C ++ strukturer, men følgende svar ble skrevet med 7,0 i tankene og ved bruk av 7.2 navngivning.

Avhengig av hvor fancy polymorfismen din er, må C-strukturene dine være mer eller mindre fancy også. Så la oss begynne med de enkle sakene først og jobbe oss mot de mer kompliserte.


Ingen arv (basisklasse)

Den enkleste saken bruker ikke noen arv i det hele tatt, bare noen medlemmer og (rene) virtuelle metoder til å begynne med:

  klasse Animal {int _age; Dyr () {_age = 0; } int getAge () {return _age; } virtuelt tomrom setAge (int-verdi) {_age = verdi; } virtuelt tomrom makeSound () = 0;};  

MSVC-layout:

  klasse Dyrestørrelse (8): + --- 0 | {vfptr} // peker til vftable (s. nedenfor) 4 | _age // medlemmer av Animal + --- Animal :: $ vftable @: | &Animal_meta // ignorere meta for våre eksempler | 0 // den (rene) virtuelle metoden følg 0 | &Animal :: setAge 1 | &Animal :: makeSound  

IDA-representasjon:

  struct Animal; struct Animal_vtbl {void (__thiscall * setAge) (Animal * this, int value); ugyldig (__thiscall * makeSound) (Animal * this);}; struct Animal_mbrs {int _age;}; struct Animal {Animal_vtbl * __ vftable; Animal_mbrs __members;};  
  • Forklar erklær klassestrukturen for å bruke den i denne -parameteren til vftable.
  • Oppringningskonvensjonen __thiscall kreves for å lage klassemetoder i MSVC. Den sender implisitt en peker til klasseinstansen i ecx -registeret i tillegg til alle andre parametere.
  • Det er ikke nødvendig å oppgi navn på parametrene.
  • makeSound vil være en purecall , og setAge vil være en typisk ukjent sub som endrer medlemmet vårt.
  • Plass medlemmer i en egen struktur for arv (s. nedenfor).

Enkelt arv

La oss raskt avle en Hund som arver fra Animal , implementer makeSound -metoden, og legg til en ny virtuell metode for å angi pelsfargen:

  klasse Hund: offentlig dyr {int _furColor; virtuelt tomrom setAge (int-verdi) {_age = verdi; } virtuelt tomrom makeSound () {cout << "Woof Woof"; } virtuelt tomrom setFurColor (int farge) {_furColor = farge; }};  

MSVC-layout: Baseklassen Animal er ganske enkelt innebygd i klassen Dog . Den innebygde Animal vftable griper også alle de virtuelle Dog -metodene og legger dem til på slutten. Medlemmene av Dog vises bak Animal s medlemmer:

  klasse Hundestørrelse (12): + --- 0 | + --- (basisklasse Animal) 0 | | {vfptr} 4 | | _alderen | + --- 8 | _furColor + --- Hund :: $ vftable @: | &Dog_meta | 0 0 | &Dog :: setAge 1 | &Dog :: makeSound 2 | &Dog :: setFurColor // Lagt til bak dyremetodene!  

IDA-representasjon: La Animal -strukturer være urørt, vi legger til følgende:

  struct Dog; struct Dog_vtbl: Animal_vtbl {void (__thiscall * setFurColor) (Dog * this, int color);}; struct Dog_mbrs: Animal_mbrs {int _furColor;}; struct Dog {Dog_vtbl * __ vftable; Dog_mbrs __members;};  
  • Gjenbruk Animal vftable ved å la Dog vftable arve fra den (arve en struktur i IDA betyr ganske enkelt å forhåndsinstallere den), og legg deretter til Dog spesifikke virtuelle funksjoner.
  • Det samme skjer med medlemmene, det er grunnen til at jeg skilte dem tidligere.

Flere arv

Dette krever litt mind-mangling. For dette gjør vi det mulig å drepe hunden vår (beklager hvis det er grusomt for deg, jeg er dårlig til å lage glade eksempler):

  class Killable {bool _isDead; virtual void kill () {makeDeathSound (); _isDead = true; } virtuelt tomrom makeDeathSound () = 0;}; klasse Hund: offentlig Dyr, offentlig Drepbar {int _furColor; virtuelt tomrom setAge (int-verdi) {_age = verdi; } virtuelt tomrom makeSound () {cout << "Woof Woof"; } virtuelt tomrom setFurColor (int farge) {_furColor = farge; } virtuelt tomrom makeDeathSound () {cout << "Jeg vil kalle WWF, bark-blerg"; }};  

MSVC-layout: Som med Animal basisklasse, legger den den andre Drapbar basisklassen inn i Hunden klassen også, og holder Hunden medlemmene atskilt. Mens Dog -spesifikke virtuelle metoder fortsatt slås sammen med Animal vftable (også kalt den første baseklassen), Drapbar relaterte er i en egen Killable -relatert vftable, så vi har nå:

  klasse Hundestørrelse (20): + --- 0 | + --- (basisklasse Animal) 0 | | {vfptr} 4 | | _alderen | + --- 8 | + --- (basisklasse drepbar) 8 | | {vfptr} 12 | | _isDead | | <alignment member> (størrelse = 3) // siden _isDead er en 1-byte bool | + --- 16 | _furColor + --- Hund :: $ vftable @ Animal @: | &Dog_meta | 0 0 | &Dog :: setAge 1 | &Dog :: makeSound 2 | &Dog :: setFurColor // Hundemetoder fusjoneres fortsatt med Animal! Dog :: $ vftable @ Killable @: // Alle Killable-relaterte metoder her | -8 // offset for `denne` pekeren i drepbare metoder for å få en hundepeker
0 | &Killable :: kill 1 | &Dog :: makeDeathSound  

IDA-representasjon: Vi holder en Dog -spesifikk vftable i starten som gjenbruker Animal vftable internt, som de virtuelle metodene Dog er fortsatt lagt til Animal s vftable. Så følger Animal sine medlemmer som vanlig. Nå følger de urørte Killable -strengene, siden ingenting blir slått sammen med dem. På slutten følger våre Dog medlemmer. Hvis du sammenligner dette med forskyvningene som MSVC skrives ut, er det fornuftig:

  struct Killable; struct Killable_vtbl {void (__thiscall * kill) (Killable * this); ugyldig (__thiscall * makeDeathSound) (Killable * this);}; struct Killable_mbrs {bool _isDead;}; struct Killable {Killable_vtbl * __vftable; Killable_mbrs __members;}; struct Dog; struct Dog_vtbl: Animal_vtbl {void (__thiscall * setFurColor) (Dog * this, int color);}; struct Dog_mbrs {// Ingen flere basedyrmedlemmer da de er delt opp nå! int _furColor; }; struct Dog {Dog_vtbl * __ vftable; // Inneholder fremdeles dyremetoder. Animal_mbrs __members_Dyr; // Dyrmedlemmer kommer hit hver for seg. Killable_vtbl * __ vftable_Killable; Killable_mbrs __members_Killable; Dog_mbrs __members;};  

IDA 7.2 bruker litt annen navngiving for vftables som deltar i flere arv. Jeg synes det er plagsomt å håndtere manuelt, så vi bruker ikke det her.

La oss se hvordan dette ser ut i Hund :: ctor pseudokode:

  Dog * __ thiscall Dog :: ctor (Dog * this) {j_Dyr :: ctor ((Animal *) this); j_Killable :: ctor ((Killable *) &this->__vftable_Killable); this->__vftable = (Dog_vftable *) &Dog :: `vftable '; this->__vftable_Killable = (Killable_vftable *) &Dog :: `vftable '; returner dette;}  

Som typisk for konstruktører kalles baseklasskonstruktører først. Deretter er vftables som kreves for Dog angitt. Men noe gir ikke mening: Hvorfor er Dog :: vftable tilordnet __vftable_Killable vår? Vel, jeg brukte IDA 7.0s navngivning her, og det jeg tidligere nevnte er at det ikke merker hvilke vftable kart til hvilken basisklasse lenger (i motsetning til skriptet). Med IDA 6.0 eller IDAPython-skriptet mitt vil det si:

  Dog * __ thiscall Dog :: ctor (Dog * this) {j_Animal :: ctor ((Animal *) this); j_Killable :: ctor ((Killable *) &this->__vftable_Killable); this->__vftable = (Dog_vftable *) &Dog :: `vftable for Animal '; this->__vftable_Killable = (Killable_vftable *) &Dog :: `vftable for Killable '; returner dette;}  

Nå er ikke navnene de samme og gir mer mening, så ikke bli ødelagt av denne IDA 7-irritasjonen, dobbeltklikk navnene for å sjekke hvor de vil faktisk føre.

Jeg anbefaler ikke å sette den faktiske typen av vftables til deres lokasjoner / navn: Du får ingenting ut av det, det gjør bare demonteringsutgangen rotete.


Bonus: Klasser arvet fra klasser ved bruk av flere arv (wew)

Denne holdt meg litt forvirret i noen tid, kanskje fordi det ikke er dekket i de fleste opplæringsprogrammer på nettet som jeg stoler på, eller kanskje fordi jeg bare er dum. La oss arve fra Dog med klassen Terrier .

  class Terrier: public Dog {int _annoyanceLevel; virtuelt tomrom setAge (int-verdi) {_age = verdi; } virtuelt tomrom makeSound () {cout << "Bark Bark not Woof Woof"; } virtuelt tomrom irritere () {_annoyanceLevel ++; }};  

MSVC-layout: Det virker ikke så spesielt. Animal vftable still slår sammen de nye virtuelle metodene til Terrier , og alt annet har sin egen vftable:

  klasse Terrier-størrelse (24): + --- 0 | + --- (basisklasse Hund) 0 | | + --- (basisklasse Animal) 0 | | | {vfptr} 4 | | | _alderen | | + --- 8 | | + --- (basisklasse drepbar) 8 | | | {vfptr} 12 | | | _isDead | | | <alignment member> (størrelse = 3) | | + --- 16 | | _furColor | + --- 20 | _annoyanceLevel + --- Terrier :: $ vftable @ Animal @: | &Terrier_meta | 0 0 | &Terrier :: setAge 1 | &Terrier :: makeSound 2 | &Dog :: setFurColor 3 | &Terrier :: irritere // Animal tar til og med Terrier-metodene (grådig!) Terrier :: $ vftable @ Killable @: | -8 0 | &Killable :: kill 1 | &Dog :: makeDeathSound  

IDA-representasjon: Det ligner ganske mye på vår første Dog struct-opprettelse, bare at vi trenger å respektere den andre baseklassen av Dog også.

  struct Terrier_vtbl: Dog_vtbl {void (__thiscall * annoy) (Terrier * this);}; struct Terrier_mbrs: Dog_mbrs {int _annoyanceLevel;}; struct Terrier {Terrier_vtbl * __vftable; Animal_mbrs __members_Dyr; Killable_vtbl * __ vftable_Killable; Killable_mbrs __members_Killable; Terrier_mbrs __members;};  
Er "__thiscall" nødvendig for å fungere?
Ja, ellers er kallkonvensjonen til klassemetoder og dekompilatorutgangen dårlig formet. (kommentar satt i svar).


Denne spørsmålet ble automatisk oversatt fra engelsk.Det opprinnelige innholdet er tilgjengelig på stackexchange, som vi takker for cc by-sa 3.0-lisensen den distribueres under.
Loading...