Hoppa yfir í efnið

Tól til kvikrar greiningar

Kvik greining (e. dynamic analysis) felst í að skoða forrit á meðan það er í keyrslu.


GDB (GNU Debugger)

GDB er helsta kembiforritið á Linux. Með því getum við:

  • Sett rofstaði sem stöðva keyrslu á ákveðnum stöðum.
  • Skoðað minni og gista á meðan keyrslan stöðvast.
  • Keyrt eina vélarskipun í einu.

GDB-viðbætur

GDB er öflugt en getur verið óaðgengilegt í grunnuppsetningu. Þrjár vinsælar viðbætur bæta við yfirliti yfir gista, stafla og kóða:

Viðbót Uppsetning
pwndbg https://pwndbg.re/stable/setup/
GEF https://hugsy.github.io/gef/install/
peda https://github.com/longld/peda#installation

Í þessum leiðbeiningum notum við pwndbg en skipanirnar eru að mestu þær sömu í öllum þremur viðbótunum.

Grunnskipanir

gdb ./challenge          # Opnar forrit í GDB

Innan GDB:

Skipun Flýtilykill Lýsing
run r Keyrir forritið
run < input.txt Keyrir með inntaksskrá
break main b main Setur rofstað á main
break *0x401234 b *0x401234 Setur rofstað á vistfang
continue c Heldur áfram eftir stöðvun
next n Keyrir að næstu frumkóðalínu án þess að fara inn í föll
step s Keyrir að næstu frumkóðalínu og fer inn í föll
nexti ni Keyrir eina vélarskipun án þess að fara inn í kallað fall
stepi si Keyrir eina vélarskipun og fer inn í kallað fall
finish Keyrir þar til núverandi fall lýkur
attach <pid> Tengist ferli sem er í keyrslu
set follow-fork-mode child Fylgir dótturferli þegar fork() er kallað
quit q Hættir úr GDB

Skoða minni og gista

# Skoða gista
info registers          # Sýnir alla gista
print $rax              # Sýnir gildi rax
print/x $rax            # Sýnir í sextándakerfi

# Skoða minni með x skipuninni: x/[fjöldi][stærð][snið] [vistfang]
#   Stærð: b=1 bæti  h=2  w=4  g=8
#   Snið:  x=sextándakerfi  d=tugakerfi  s=strengur  i=skipanir
x/10gx $rsp             # tíu átta bæta gildi við rsp (sextándakerfi)
x/s 0x402000            # Strengur á vistfangi
x/20i $rip              # Næstu 20 smalamálsskipanir

# Sérstakar pwndbg-skipanir
telescope $rsp          # (einnig: tele) Sýnir staflann á læsilegan hátt
disassemble main        # Sýnir smalakóða falls

# Minniskort forritsins
info proc mappings       # Sýnir hvaða svæði eru hlaðin (stafli, hrúga, libc o.fl.)

Breyta minni og gildum í gistum

set $rax = 0            # Setur rax í 0
set *0x404000 = 0x1234  # Skrifar á vistfang

Dæmi: Greining á lykilorðsathugun

gdb ./challenge
b strcmp          # Stöðva þegar strcmp er kallað
r                 # Keyra
# ... forritið biður um lykilorð, slá inn 'test' ...
# Kembiforritið stöðvast við strcmp
x/s $rdi         # Skoða 1. frumbreytu (inntakið okkar)
x/s $rsi         # Skoða 2. frumbreytu (rétta lykilorðið)

ltrace

ltrace hlerar köll í bókasafnsföll á meðan forritið keyrir.

ltrace ./challenge

Dæmi um úttak:

puts("Sláðu inn lykilorðið: ")  = 23
fgets(0x7ffd..., 64, stdin)      = 0x7ffd...
strcmp("test\n", "swordfish\n")  = -1
puts("Rangt lykilorð")           = 15

Tip

ltrace sýnir okkur oft lykilorð og samanburðargildi beint. Því er gagnlegt að prófa ltrace ./challenge snemma í greiningunni.


strace

strace hlerar kerfisköll, það er samskipti forritsins við stýrikerfið.

strace ./challenge
strace -e openat,read,write ./challenge  # Sía eftir tegund kalls

Gagnlegt til að sjá:

  • Hvaða skrár forritið les
  • Nettengingar
  • Minnisúthlutun

perf: hliðarrás byggð á vinnumagni

perf getur talið skipanir sem örgjörvinn framkvæmir. Þetta má nota í verkefnum sem byggja á hliðarrás tengdri vinnumagni, þar sem forritið vinnur meira eftir því sem fleiri stafir eru réttir.

Segjum að við þekkjum fyrstu stafina í fánanum, til dæmis gg{. Þá getum við prófað jafn langan rangan streng og kannað hvort munur sé á fjölda skipana.

perf stat -e instructions ./challenge <<< "gg{AA"
perf stat -e instructions ./challenge <<< "AAAAA"

Ein mæling getur verið villandi vegna breytileika milli keyrslna. Við endurtökum því hverja ágiskun að minnsta kosti tíu sinnum við sambærilegar aðstæður og berum saman miðgildi skipanafjöldans:

for i in {1..10}; do
    perf stat -x, -e instructions ./challenge <<< "gg{AA"
done

Ef munurinn helst greinilegur yfir endurteknar mælingar getum við fundið afganginn af fánanum, einn staf í einu. Bakgrunnsálag, slembni og mismunandi upphafsstilling forritsins geta annars falið eða líkt eftir merkinu sem við leitum að.


Að breyta tvíundaskrá

Stundum er einfaldast að breyta tvíundaskránni beint í stað þess að skilja allt reikniritið.

Dæmi: Breyta hoppi

Ef forritið gerir jne wrong_path þar sem við viljum alltaf fara í correct_path:

# Með radare2
r2 -w ./challenge      # -w = skrifhamur
s 0x401234             # Hoppa á vistfang jne-skipunarinnar
pd 1                   # Athuga kóðun og lengd skipunarinnar
wx 9090                # Aðeins ef pd sýnir tveggja bæta stutt jne-stökk

Hér gerum við ráð fyrir að correct_path sé leiðin sem keyrslan heldur áfram eftir ef stökkið er ekki tekið. Stutt jne-stökk er tvö bæti en nærstökk (e. near jump) er oft sex bæti. Við megum því ekki afrita wx 9090 blint: fyrst staðfestum við lengd skipunarinnar og skrifum nákvæmlega jafnmörg NOP-bæti. Best er að vinna á afriti af tvíundaskránni.

# Með Python og pwntools
from pwn import *
elf = ELF('./challenge')
elf.asm(0x401234, 'jmp 0x401260')  # Breyta skipun á vistfangi
elf.save('./challenge_patched')

Í Binary Ninja getum við hægrismellt á línu og valið Patch. Best er að gera það í smalamálsýninni.

Að fella út skipanir með NOP

NOP (e. No Operation, aðgerðarkóði 0x90) breytir engu og keyrslan heldur áfram í næstu skipun. Við getum stundum notað NOP-skipanir til að fella út athuganir. Við verðum þó að skrifa jafn mörg bæti og upprunalega skipunin tók, svo við skemmdum ekki næstu skipun.

; Upprunalegt
0x401234:  cmp  rax, rbx
0x401237:  jne  fail       ; 75 27
0x401239:  ...             ; rétta leiðin

; Eftir breytingu
0x401234:  cmp  rax, rbx
0x401237:  nop             ; 90
0x401238:  nop             ; 90
0x401239:  ...             ; keyrslan heldur alltaf áfram hér

Samanburðurinn er enn keyrður en niðurstaða hans hefur ekki lengur áhrif. Óháð því hvort gildin eru jöfn heldur keyrslan áfram inn á réttu leiðina.


Æfingar

Verkefni til að æfa kvika greiningu, GDB og breytingar á tvíundaskrám:

  • Wiretap: Við fylgjumst með hvaða bókasafnsföll forritið kallar á meðan það keyrir.
  • Disappearing Ink: Við ákveðum hvar stöðva eigi keyrslu til að skoða gildi sem eru aðeins til staðar tímabundið.
  • Tumblers: Við könnum hvort breytingar á inntaki hafi mælanleg áhrif á keyrslu forritsins.
  • Detour: Við greinum stýriflæði forrits og skoðum áhrif breytinga á tvíundaskránni.