Küsimus:
Kuidas käituda eemaldatud kahendfailidega GDB-ga? Pole allikat, pole sümboleid ja GDB näitab ainult aadresse?
0xC0000022L
2013-04-27 08:13:34 UTC
view on stackexchange narkive permalink

Mul on GDB, kuid kahendkoodil, mida soovin, et inseneri dünaamiliselt ei oleks, pole ühtegi sümbolit, see tähendab, et käivitan utiliidi file , mis näitab mulle eemaldatud :

  ELF 64-bitine LSB käivitatav fail, x86-64, versioon 1 (SYSV), dünaamiliselt lingitud (kasutab jagatud libse), GNU / Linux 2.6.18 jaoks, eemaldatud  

Millised valikud mul on, kui keskkond, kus see töötab, ei võimalda IDA Pro kaug-eksemplaril ühendust luua gdbserver -ga? Lühidalt: teie keskkond on piiratud, kuna see võimaldab teil seda teha, kuid teil on vana usaldusväärne gdb ja binaarne insener.

unstrip on tööriist, mis võib proovida taastada teadaolevate raamatukogukõnede kaotatud sümbolite nimed.
üks vastus:
0xC0000022L
2013-04-27 08:13:34 UTC
view on stackexchange narkive permalink

Kasutatavad kokkulepped pluss esialgsed märkused

Kärpin GDB väljundit lühiduse huvides, kuna see näitab autoriõigusi ja muud teavet alati seansi alguses. Väljundi taasesitamisel alustan esimesest viipareast (gdb) või juhul, kui esimesest ehtsast väljundreast täidetakse automaatselt käske.

Selleks GDB viipale sisestatud käskude eristamiseks on neil juhtpilt (gdb) nagu reaalses maailmas. Shelli käsu korral pole see kas üldse eesliide või $ , kuna see näib olevat kombeks enamikus unixoid-süsteemides.

Kui kasutan konkreetset käsku, näiteks vim minu toimetajana võite loomulikult kasutada oma lemmiktoimetajat. Olgu selleks emacs või nano , ma ei mõista teid üle;)

Alustamine

See jaotis käsitleb keskkonna gdb seadistamist ja protsessi alustamist. Lisan ka mõned uustulnukad uustulnukatele.

Nipid, mida peaksite teadma

GDB-l on kena viip, mille korral teie kursor peatub pärast programmi pausi või alati, kui olete astumine või mõni muu selline.

  • Pärast GDB käsu käivitamist vajutage RETURN (aka ENTER ) vajutades sama käsk uuesti. See on kasulik, kui astute läbi koodiga step või next ja soovite lihtsalt ükshaaval jätkata.
  • Käsud saab lühendada seni, kuni need on üheselt mõistetavad. Mõne sageli kasutatava käsu jaoks on olemas konkreetne lühikirjeldus, mis on mitmetähenduslikkusest hoolimata ülimuslik:
    • b break (vaatamata bt ja backtrace )
    • c või cont jaoks keep (vaatamata catch , kõne ja nii edasi)
    • n jaoks next (vaatamata ni ja nexti )
  • Käsu call abil saate helistada tegelikele raamatukogu funktsioonidele või isegi silutud programmi funktsioonidele. See tähendab, et saate proovida käitumist või sundkäitumist.
  • GDB-d saate käivitada arvuga gdbtui või gdb -tui , et saada - väidetavalt mugavam - visuaalsema teksti kasutajaliides. Selle ülaservas kuvatakse lähtekood ja allpool viip (gdb) . Sellele paigutusele saate ka üle minna, käivitades käsu layout src käsul (gdb) .
  • GDB-l on käsurea lõpuleviimise funktsioon sarnaselt paljusid kestasid, nii et kasutage oma huvides vahelehte ja kasutage alati help või help [keyword | käsk] alati, kui vajate abi.
  • shell võimaldab teil shellis käske täita, et saaksite käske käivitada oma GDB seansi sees. Arenduse ajal võiks näiteks olla shell make .
  • print , uurima ja display know mitmesugused vormingud ( / FMT ), mida saate kasutada väljundi loetavamaks muutmiseks.
  • Allikataseme silumisel saate väärtuste kuvamiseks kasutada C-tüüpi heiteid. Kujutage ette C-koodi void * taga (mida GDB tunneb sellisel juhul tänu sümbolitele). Lihtsalt valage (char *) ja printige see: print (char *) muutuja .

Protsessi käivitamine

Kuna me tahame binaarset dünaamiliselt analüüsida, peame selle kõigepealt käivitama.

Käsurida

Saame seda teha otse käsurealt, läbides mitte ainult tee binaarse juurde, aga ka argumendid, millega soovime seda alustada. Kogu protsess näeb välja järgmine:

  $ gdb --args ./exe argument1 argument2  

Piisavalt lihtne. Seejärel saate viipast (gdb) anda käsu run (lühike r ), et käivitada ./exe käsureal antud parameetritega. Ma eelistan seda meetodit, kuid teie läbisõit võib erineda.

Starting a process using the described method

GDB viip

GDB käivitamine ja (gdb) viip, kasutage binaarkaardi laadimiseks käsku file ja seejärel käsku run , et käivitada see argumentidega, mille soovite edastada:

  $ gdb (gdb) fail exe (gdb) run argument1 argument2  

alternatiiv ülaltoodule oleks set args -i kasutamine järgmiselt:

  $ gdb (gdb) fail exe (gdb) set argumendid argument1 argument2 (gdb) käivitamine  

Starting a process using the described method

Saate vaadake igal juhul ka seda, millised argumendid run edastaksid alustatud protsessile, väljastades järgmise:

  (gdb) show args  

btw: kui mõtlesite keskkonnamuutujate kohta, kasutage GDB sisseehitatud käsku help kui help set ja help show . Kursorid: seatud keskkond VARNAME = VALUE ja näitavad keskkonda [VARNAME] ja keskkonna VARNAME seadistamata .

Phew, aga miks kas programm peatub SIGSEGV -ga (segmendi viga)?

Noh, me ei tea seda veel, kuid tundub, et see väike metsaline tahab õiget ravi . Kuna me harjutame kaitsvat arvutust, ei taha me käivitada midagi, millest me ei tea palju, eks? Alustame siis otsast peale. Kui see oleks olnud pahavara, peame masina loputama ja hetktõmmise uuesti installima või taastama, kui see on VM-i külaline.

Kõigepealt tahame käivitada käsu info järgmiselt:

  (gdb) infofail  

Jälgige:

info file command in GDB

On kaks olulist teavet, meie jaoks kõige olulisem on rida:

  Sisestuspunkt: 0x400710  

olgu, nii et saame sellele ühele seada katkestuspunkti ja seejärel käivitada protsessi soovitud argumentidega.

.gdbinit võit

Aga oota, see muutub juba tüütuks. Pole ühtegi lihtsat meetodit nende sammude mingil moel automatiseerimiseks? Tegelikult on. Faili nimega .gdbinit saab käivitamisel GDB-le käske anda. Faili saate edastada ka GDB-käskudega, kasutades (shell) käsureal olevat argumenti -x . Kui mul on arvukalt projekte, asuvad need tavaliselt alamkaustades, kus iga fail on .gdbinit .

Side-note: -nx takistab .gdbinit sisu käivitamisel käivitamist.

Nii et me teame, milliseid argumente soovime edastada, ja teame katkestuspunkti aadressi, see tõlgib järgmisele failile .gdbinit :

  file exebreak * 0x400710run argument1 argument2  

Väljund, mille saan, kui käivitan gdb ilma muude argumentideta on järgmine:

  Breakpoint 1 at 0x400710Breakpoint 1, 0x0000000000400710 in ?? () (gdb) 

Tore! Kuid see näeb välja teisiti ...

Assamblee ja GDB

Nii et olete harjunud nägema järgmist rida, mida kavatsete täita, ja siis oma usaldusväärset vana (gdb ) viip. Aga pole midagi sellist. Selle binaarse ja lisaks sümbolite jaoks pole meil allikat. Doh! Niisiis mõtiskleme vilkuva märkega (gdb) -viibel ja mõtleme, mida teha. Ärge pahandage, GDB saab hakkama ka koostekoodiga. Ainus probleem, vaikimisi on see minu arvates ebamugav AT&T assamblee süntaks. Eelistan Inteli maitset ja järgmine käsk käsib GDB-l just seda teha:

  (gdb) set demonteerimismaitse intel  

Assamblee koodi kuvamine

Ja kuidas see meile monteerimiskoodi näitab? Noh, sarnaselt TUI-režiimiga (kontrollige märgendiviki ), kasutades järgmist käsku:

  (gdb) layout asm  

ja kui olete nii kaldunud, siis ka:

  (gdb) paigutusregistrid  

mis näitavad teile ka registrisisu ülevaade.

Käivitame selle uuesti

Nii et lõpuks on meie jaoks järgmine .gdbinit :

  fail exebreak * 0x400710set demonteerimine-maitse intellayout asmlayout regsrun argument1 argument2  

Ja kui alustame gdb argumentideta, jõuame lõpuks selleni:

GDB with asm and regs layout

Armas. Nii et koodist läbi astudes näeme demonteerimist. Võiksime selle järeldada siin, kuid muidugi on veel rohkem trikke, mida õppida, miks mitte minna natuke kaugemale.

MÄRKUS: valge / halli taustaga registrid näitavad, et väärtus on muutunud. Mitte liiga sisukas, kui me just programmi käivitasime, kuid võib-olla on kasulik hiljem koodi läbimisel.

btw, kui eelistate ekraaniomandi salvestamist

... ja teil on seda vähem visuaalne, alates GDB 7.0-st saate kasutada: automaatne kuva :

  display / i $ pc  

või lühem disp / i $ pc kus vorming / i , saate seda kõige paremini meelde jätta, kui mõelda "juhend" ja $ pc olla käskude kursor, tuntud ka kui programmiloendur - seega pc.

Samuti on hea teada

Mõnikord võib kokkupanekul astudes regs ja asm vaated häiritakse. Vana hiilguse taastamiseks täitke lihtsalt vastavad käsud layout uuesti:

  (gdb) layout asm (gdb) layout regs  

"Silumine" koostetasandil

Selgub, et kui olete monteerimisrežiimis, siis mõned käsklused, millega olete lähtekoodi silumisel harjunud, lihtsalt ei tööta. See on mõistlik, sest üks allikarida tähendab tavaliselt tosinat või enamat juhist. Käskudel next ja step on aga käsutaseme vasted:

  • nexti (lühikirje ni ... keegi teine ​​mõtleb võsastamisest?)
  • stepi (shorthand si )

Ülaltoodud lahtivõtmise põhjal teame:

  0x40072d mov rdi, 0x40f961  

ja kõigil praktilistel eesmärkidel on see funktsioon main . Muidugi, kui peaksite pahavara tagasi töötama, peaksite olema ettevaatlikum, kuid antud juhul on see nii. Lisame sellele aadressile katkestuspunkti ( 0x40f961 ) sisestuspunkti asemel:

  break * 0x40f961  

Kui me uurige (lühike x ) koodi, kus me praegu oleme, näeme:

  (gdb) x / 5i $ pcx / 5i $ pc = > 0x40f961: push rbp 0x40f962: mov rbp, rsp 0x40f965: mov eax, 0x0 0x40f96a: call 0x40911f 0x40f96f: pop rbp  

Olgu, kõne on see, mida me tahame järgida, seega astume sellest sisse, kasutades si . Funktsiooni sisestamisel näeme kohe käskude kursori juures uut kõnet :

  (gdb) x / 5i $ pcx / 5i $ pc = > 0x40911f: call 0x400b8c 0x409124: push rbp 0x409125: mov rbp, rsp 0x409128: push r10 0x40912a: push r11  

call viib meid funktsiooni juurde, mis kutsub ptrace (PTRACE_TRACEME, ...) , miks ta seda siis teeks?

  0x400bab kõne 0x4006b8 <ptrace @ plt>  

Noh, see on vana silumisvastane trikk, mida Mellowcandle on kirjeldanud siin teises Q&A-s:

Aga kuidas me sellest mööda saame? Peaksime call üle kirjutama funktsioonile, mis kutsub ptrace () välja koodiga nop või millelgi muul.

Siin muutub GDB veidi kohmakaks. Kuid me võime kasutada set , nii et tehke seda ka meie jaoks. Kontrollime kõigepealt käskude baidid:

  (gdb) x / 10b $ pcx / 10b $ pc0x40911f: 0xe8 0x68 0x7a 0xff 0xff 0x55 0x48 0x890x409127: 0xe5 0x41  

0xe8 on kõnejuhis ja me teame nüüd, et see on 5 baiti pikk. Nii et laseme selle nop välja. ( x / 10b $ pc tähendab programmi loenduri 10 baiti uurimist - vaikevorming on juba kuusnurkne).

Nii et me teeme peatudes 0x40911f :

  (gdb) set write (gdb) set {unsigned int} $ pc = 0x90909090 (gdb) set {unsigned char} ($ pc + 4) = 0x90 (gdb) seatud mahakandmine  

ja kinnitage lappitud asukoht:

  (gdb) x / 10i $ pcx / 10i $ pc = > 0x40911f: nop 0x409120: nop 0x409121: nop 0x409122 : nop 0x409123: nop 0x409124: push rbp 0x409125: mov rbp, rsp 0x409128: push r10 0x40912a: push r11 0x40912c: push rbx  

Suurepärane. Nüüd saame selle täita.

Alternatiivid antud meetodile

  1. alternatiiv lappimiseks: set {unsigned int} 0x40911f = 0x90909090 , millele järgneb set {unsigned char} 0x409123 = 0x90
  2. Selle asemel saate manipuleerida programmiloenduriga (käsuosuti):
    • set $ pc + = 5 või selgesõnalisem set $ pc = $ pc + 5
    • jump * $ pc + 5

Paremad viisid veel töötava programmi manipuleerimiseks / lappimiseks

On ka alternatiivseid (ja palju paremad) meetodeid, näiteks see on Tavis Ormandy poolt. Kopeerin allolevat makrot assemble (juhul kui see läheb teisest kohast võrguühenduseta):

  define assemble
# ärge sisestage rutiini uuesti, kui kasutaja tabab sisestusklahvi, ärge korrake, kui ($ argc) kui (* $ arg0 = * $ arg0) # kontrollige, kas meil on kehtiv aadress, viidates sellele alla, # kui meil pole, põhjustab see rutiini väljumine. end printf "Juhised kirjutatakse aadressile% # x. \ n", $ arg0 else printf "Juhised kirjutatakse stdouti. \ n" end printf "Sisestage juhised, üks rea kohta. \ n" printf "Lõpeta reaga öeldes just \ "end \". \ n "kui ($ argc) # argument on määratud, koondage juhised määratud aadressil mällu # shell nasm -f bin -o / dev / stdout / dev / stdin \ <<< "$ (kaja" BITS 32 "; lugedes -ep '>' r && test" $ r "! = end; \ do echo -E $ r "; valmis)" | hexdump -ve \ '1/1 "komplekt * ((märkimata märk *) $ arg0 +% # 2_ax) =% # 02x \ n"' \ > ~ / .gdbassemble # laadige fail, mis sisaldab komplekti juhiste allikat ~ / .gdbassemble # kõik tehtud. shell rm -f ~ / .gdbassemble else # no argument, installi käsud stdout shell nasm -f bin -o / dev / stdout / dev / stdin \ <<< "$ (kaja" BITS 32 "; lugedes -ep '>' r && test "$ r"! = lõpp; \ tee kaja -E "$ r"; valmis) "| ndisasm -i -b32 / dev / stdin endenddocument assembleKomplekteeri juhised nasmi abil. Lõpule viitamiseks tippige rida, mis sisaldab lõppu. Kui aadress on määratud, sisestage sellele aadressile juhised. Kui aadressi pole määratud, prinditakse kokkupandud juhised stdout. Põhiaadressi määramiseks kasutage pseudokäsku "org ADDR". end  

Jällegi ei kirjutanud ülaltoodud skripti koodilõik mitte minu, vaid Tavis Ormandy - vaadake ülaltoodud linki.

See lõpetab selle väikese Q&A.

suurepärane kirjutus! vaid üks märkus: -q kui cmd arg vabaneb autoriõiguste kraamist
Arvasin, et tean `gdb`d päris hästi, aga õppisin palju. Aitäh!
See ** AWESOME ** vastus päästis mu elu mitu korda. Aitäh ja veelkord aitäh.


See küsimus ja vastus tõlgiti automaatselt inglise keelest.Algne sisu on saadaval stackexchange-is, mida täname cc by-sa 3.0-litsentsi eest, mille all seda levitatakse.
Loading...