Spørsmål:
Hva er grunnen til at denne metoden kaller seg?
Daniel Sloof
2013-04-08 17:42:48 UTC
view on stackexchange narkive permalink

Mens jeg reverserte en 32-bits Mach-O-binær med Hopper, la jeg merke til denne særegne metoden. Instruksjonen på 0x0000e506 ser ut til å ringe en adresse rett under instruksjonen.

Hva ville være årsaken til dette? Er det en slags registerrengjøring?

Fem svar:
Dougall
2013-04-08 17:52:15 UTC
view on stackexchange narkive permalink

Dette er for posisjonsuavhengig kode. Instruksjonen call 0xe50b skyver adressen til neste instruksjon, og hopper deretter. Den hopper til instruksjonen som følger umiddelbart, noe som ikke har noen effekt. Neste instruksjon, pop eax , laster sin egen adresse inn i eax (da det var verdien som ble presset av call ).

Lenger nede bruker den en forskyvning fra eax:

  mov eax, dword [ds: eax-0xe50b + objc_msg_close]  

Verdien som trekkes fra, 0xe50b , er adressen vi flyttet til eax . Hvis koden ikke har blitt flyttet hvor som helst, vil eax-0xe50b være null, men hvis koden er flyttet til et annet sted, vil det være forskyvet. Deretter legger vi til adressen objc_msg_close , så vi kan referere til den, selv om koden har blitt flyttet i minnet.

Hopper er faktisk ganske smart om det, fordi instruksjonen bare sier (fra ndisasm):

  mov eax, [eax + 0x45fe75]  

men Hopper vet at eax inneholder verdien av instruksjonspekeren ved 0xe50b , så bruker den forskyvningen for å finne symbolet for deg.

newgre
2013-04-08 17:50:03 UTC
view on stackexchange narkive permalink

Dette er et ofte brukt "triks" for å bestemme adressen til instruksjonen etter samtalen , dvs. anropsinstruksjonen skyver returadressen på bunken, som i dette tilfellet tilsvarer 0xe50b . Etter popinstruksjonen inneholder eax den adressen. For eksempel brukes dette uttrykket for posisjonsuavhengig kode (bilde), men blir også ofte sett i forvirret kode.

Andre demonterere viser ofte denne kodesekvensen som ring $ + 5 (f.eks. IDA).

0xC0000022L
2013-04-27 22:26:06 UTC
view on stackexchange narkive permalink

Nå kan jeg umulig vite hva den eksakte årsaken er her, men det er en annen veldig god grunn, som ikke er nevnt så langt, for å bruke denne typen metoder: å kaste en demonter under statisk analyse.

Mekanikken til ring $ + 5 har blitt diskutert, så jeg antar at de er kjent nå - ellers referer til de andre svarene. I utgangspunktet som med alle samtaler på IA-32, blir returadressen (adressen til instruksjonen som følger samtalen ) push ed til stabelen og ret -instruksjonen inne i den ringte funksjonen vil antagelig gå tilbake til den adressen, forutsatt at bunken ikke har blitt knust i mellomtiden.

Lure statiske analyseverktøy

Hva vil til og med en sofistikert demonterer som IDA gjøre når den ser en ret opcode? Vel, det antar at funksjonsgrensen er nådd. Her er et eksempel:

IDA trips over this trick

Nå som ikke dette er første gang jeg har sett noe slikt, fortsatte jeg og slettet funksjonen, så IDA slutter å anta at det er en funksjonsgrense. Hvis jeg da ber den om å demontere neste byte ( 0Fh ) får jeg dette:

IDA trips over this trick #2

Hva demonteren ikke kan forstå og hva som er grunnen til at interaktive demontere som Hopper og IDA rocker så mye, er at det skjer noe spesielt her. La oss se på instruksjonene:

  51 push rcx53 push rbx52 push rdxE8 00 00 00 00 call $ + 55A pop rdx48 83 C2 08 add rdx, 852 push rdxC3 retn0F 5A 5B 59 cvtps2pd xmm3, qword ptr [rbx + 59h] 89 DF mov edi, ebx52 push rdx
48 31 D2 xor rdx, rdx  

De ledende byte er de faktiske byte i binær, etterfulgt av deres mnemoniske representasjon. Men vær spesielt oppmerksom på denne delen:

  ring $ + 5pop rdx; <- = ADDRadd rdx, 8push rdxretn  

Vi får adressen ADDR i rdx etter pop instruksjon ble utført. Vi vet dette mye fra beskrivelsen av mekanismen i de andre svarene. Men da blir det rart:

  add rdx, 8  

we add ... uhm eight bytes to that address ( ADDR + 8 ) og så skyver den til stabelen og kaller ret:

  push rdxretn  

Hvis du husker hvordan et -anrop fungerer, vil du huske at det skyver returadressen til stakken, og deretter overfører kjøringen til den ringte funksjonen, og den funksjonen kaller senere ret kode> for å gå tilbake til adressen som finnes på bunken. Denne kunnskapen blir utnyttet her. Den manipulerer "returadressen" før "returnerer" til den. Men når vi ser tilbake på demonteringen, finner vi til vår overraskelse (eller ikke;)):

  E8 00 00 00 00 ring $ + 55A pop rdx48 83 C2 08 add rdx, 852 push rdxC3 retn0F 5A 5B 59 cvtps2pd xmm3, qword ptr [rbx + 59h]  

La oss telle opcode-byte (i verktøyet ditt kan du også gjøre matte via forskyvninger, hvis du er så tilbøyelig):

  1. 5A
  2. 48
  3. 83
  4. C2
  5. 08
  6. 52
  7. C3
  8. 0F

Men vent litt, det betyr at vi bokstavelig talt overfører kjøring til midten av denne særegne cvtps2pd xmm3, qword ptr [rbx + 59h] ? Det er riktig. Fordi 0Fh er et av prefiksene som brukes ved koding av instruksjoner på IA-32. Så programmereren har lurt demonteren vår, men han vil ikke lure oss. Undefining av koden og deretter hopper over 0Fh prefikset vi får:

  51 push rcx53 push rbx52 push rdxE8 00 00 00 00 call $ + 55A pop rdx48 83 C2 08 add rdx, 852 push rdxC3 retn0F db 0Fh5A pop rdx5B pop rbx59 pop rcx89 DF mov edi, ebx52 push rdx48 31 D2 xor rdx, rdx  

eller:

No longer tricked thanks to reverse engineer intervening

Den tilsynelatende enkle fire-byte-instruksjonen 0F 5A 5B 59 er nå avslørt å være falsk og i stedet vi må ignorere 0F og deretter fortsette ved 5A , som dekoder som pop rdx .

Sjekk ut Anges utmerkede opodetabeller her for å finne ut mer om hvordan instruksjonene blir kodet på IA-32.

Jeg har sett noen applikasjoner (spesielt en anti-hacking-beskyttelse kjent som MetaFortress) som bruker denne teknikken som en måte å legge inn data i .text-området i en applikasjon. Bruk samtalen til å hoppe over de innebygde dataene, og bruk deretter returadressen fra samtalen som peker til de innebygde dataene.
QAZ
2013-04-08 17:52:04 UTC
view on stackexchange narkive permalink

En CALL -instruksjon har den effekten at den skyver en returadresse på bunken før den utfører kontrolloverføringen til anropsmålet.

I eksemplet ditt ovenfor vil instruksjonen CALL skyve verdien 0x0000E50B på bunken, før kontrollen overføres til 0x0000E50B. Instruksjonen POP på 0x0000E50B vil da skyve den siste verdien av toppen av bunken, inn i EAX. Denne verdien vil være POP instruksjonens egen adresse, på grunn av CALL instruksjonen som skyver returverdien.

Dette er en enkel teknikk for å få instruksjoner plassering i minnet på kjøretid.

En instruksjonsplassering kan ikke alltid beregnes av linkeren på kompileringstidspunktet, ettersom en binær kan flyttes i minnet på grunn av Address Space Layout Randomization (ASLR).

Svaret fra Dougall er overlegen. Koblinger håndterer ASLR via oppføringer i flyttetabeller. Denne mekanismen er ikke så mye for å bestemme plasseringen som for å bestemme den relative forskyvningen * forskjellen * mellom adressen den kompilerte koden forventer og den faktiske adressen ved kjøretid.
phuclv
2014-05-29 19:29:04 UTC
view on stackexchange narkive permalink

Som andre har sagt, er dette for å få gjeldende instruks adresse. Men det anbefales ikke, da det vil skade ytelsen fordi det ikke kommer tilbake hvor som helst, og forårsaker uenighet om returadresser i datastakken og i CPUens interne anropsstabel

Den anbefalte måten er

  GetCurrentAddress: mov eax, [esp] ret ... call GetCurrentAddress mov [currentInstruction], eax  

http://blogs.msdn.com/b/ oldnewthing / archive / 2004/12/16 / 317157.aspx

Årsaken er de "skjulte variablene" inne i prosessoren. Alle moderne prosessorer inneholder mye mer tilstand enn du kan se fra instruksjonssekvensen. Det er TLB, L1 og L2 cacher, alle slags ting du ikke kan se. Den skjulte variabelen som er viktig her er prediktoren for returadressen.

De nyere Pentium (og jeg tror også Athlon) -prosessorer opprettholder en intern stabel som oppdateres av hver CALL- og RET-instruksjon sterk>. Når en CALL utføres, skyves returadressen både på real stack (den som ESP-registeret peker på) så vel som til intern prediktorstabel for retur ; en RET-instruksjon popper den øverste adressen til returadresse-prediktorstakken så vel som den virkelige stabelen.

Returadresse-prediktorstakken brukes når prosessoren dekoder en RET-instruksjon. Den ser på toppen av prediktorstakken for returadressen og sier, "Jeg vedder på at RET-instruksjon kommer til å gå tilbake til den adressen." Den utfører deretter instruksjonene på den adressen spekulativt. Siden programmer sjelden fikler med returadresser på bunken, har disse spådommene en tendens til å være svært nøyaktige.



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...