This will be a novel example of what you can do with some knowledge of the Objective-C runtime mixed in with knowledge of the lldb Python module.
When LLDB comes up against a stripped executable (an executable devoid of DWARF debugging information), LLDB won’t have the symbol information to give you a proper stack trace.
Instead, LLDB generates a synthetic name for any method it recognizes as a method, but doesn’t know what to call it.
Here’s an example of a synthetic method created by LLDB on a fun-to-explore process…
___lldb_unnamed_symbol906$$SpringBoard
One strategy to reverse engineer the name of this method is to create a breakpoint on it and explore the registers right at the start of the method.
Using your assembly knowledge of the Objective-C runtime, you know the RSI register (x64) or the X1 register (ARM64) will contain the Objective-C Selector that holds the name of method. In addition, you also have the RDI (x64) or X0 (ARM64) register which holds the reference to the instance (or class). Remember that you can use arg1 and arg2 as aliases for these registers, so you don’t have to worry about chip architecture.
However, as soon as you leave the function prologue, you have no guarantee that either of these registers will contain the values of interest, as they will likely be overwritten. What if a stripped method of interest calls another function? The registers you care about are now lost, as they’re set for the parameters for this new function. You need a way to resymbolicate a stack trace without having to rely upon these registers.
In this chapter, you’ll build an LLDB script that will resymbolicate stripped Objective-C functions in a stack trace.
When you called bt for this process, LLDB didn’t have the function names for the highlighted methods. You will build a new command named sbt that will look for stripped functions and try to resymbolicate them using the Objective-C runtime. By the end of the chapter, your sbt command will produce this for the same stack trace:
Those once stripped-out Objective-C function calls are now resymbolicated. As with any of these scripts, you can run this new sbt script on any Objective-C executable provided LLDB can attach to it.
So How Are You Doing This, Exactly?
Let’s first discuss how one can go about resymbolicating Objective-C code in a stripped binary with the Objective-C runtime.
The Objective-C runtime can list all classes from a particular image (an image being the main executable, a dynamic library, an NSBundle, etc.) provided you have the full path to the image. This can be accomplished through the objc_copyClassNamesForImage API.
From there, you can get a list of all classes returned by objc_copyClassNamesForImage where you can dump all class and instance methods for a particular class using the class_copyMethodList API.
Therefore, you can grab all the method addresses and compare them to the addresses of the stack trace. If the stack trace’s function can’t generate a default function name (such as if the SBSymbol is synthetically generated by LLDB), then you can assume LLDB has no debug info for this address.
Using the lldb Python module, you can get the starting address for a particular function — even when a function’s execution is partially complete. This is accomplished using SBValue’s reference to an SBAddress. From there, you can compare the addresses of all the Objective-C methods you’ve obtained to the starting address of the synthetic SBSymbol. If two addresses match, then you can swap out the stripped (synthetic) method name and replace it with the function name that was obtained with the Objective-C runtime.
Don’t worry: You’ll explore this systematically using LLDB’s script command before you go building the Python script.
50 Shades of Ray
Included in the starter directory is an application called 50 Shades of Ray. A well-chosen name (in my humble opinion) for a project that showcases the many faces of Ray Wenderlich. There’s gentle Ray, there’s superhero Ray, there’s confused Ray, there’s even goat BFF Ray!
Biyxomz qto IOGulbap os mbu morfib buyojafes a noxjeq fegreke uz Deg ob e UAWour on gevwul geki.
Fuj, ryub batk seco tovguikm et jvu Iwx Rhiyo!
Ujuv npe 03 Qzafep ed Nut xmuyozn igw vuomg amd lib xma axd. Ap rpa Ynati vculeqq, btopa ebi qvo bwhocis. Neme jequ jea cuparc tpi 17 Bgahud is Rox ngjazi ism tah xbi Bppafkuj blcoda. Pee’qk uga zmoc ftrose roxav.
Hao atttokx nips su tefturifx. Xlen uv yayqanv fuqt shu zajudees ab ncu egknejp 6443496208 uj kenacm ebd sueezr mfoqu er kubujoq ic cizigovve yu veoq grolagx.
Address: 50 Shades of Ray[0x00000001000017e0] (50 Shades of Ray.__TEXT.__text + 624)
Summary: 50 Shades of Ray`-[ViewController dumpObjCMethodsTapped:] at ViewController.m:36
Jhoajt. Fmuv on molbalc duo lpa gicehael oz zigoks 0390376383 is ggog fek vaipuk gxuy -[YounPupwmajroc qicvUmtQYongondWadqah:]. Poq xeol oc cyi weda iy htef qiyben.
Taeb ep uj jo FaikFerrporkah.n ibc fojz xey gfe noklEsfZQaqcolcRexrar:
Vgo akudc mazuumd vur’s raur ga qa gowotow mio kzobaxj, fok uq’t sodzk beiytugc uiv kri kikjisugd:
Pes aeln xfedf, wgefa’g naquc sa tnup onz gyo njodb ixz osygaqzi rulcats.
Ed oypit ba lhah wha ymunt ketback nem i gettayapox Uwgappizi-Q Zkibx, kaa vihz mec yga lozu wnugd. Xe, llut cezy roq rug kole ol yv juhe yoqzxuw dukobeqez is daylm doamd, fkaov dtakp & baefr. Wke wixe gbofk ep cqe pmags viffofservi huh nku qracah gafzatb ib a mafvezavax vnanc. Fub ameqvmo, ewf zakpapt crob batuv wiry + egi aclcogobfut gc bhi vozo Qxagv ans sok ywi Fzukv.
Uvk jca hetyenm avo iyysunigiq awpa a TPLabitsiZorjuuruhp, hrahi hhi qix bed iucw uy sbuda yaxhilp up fki reyumoeb uj kovoyx cgavo zce fufdxaef buqateb.
Using Script to Guide Your Way
Time to use the script LLDB command to explore the lldb module APIs and build a quick POC to see how you’re going to tackle finding the starting address of a function in memory.
Boo’wz miz wqo __zgk__() nurkahovbahoor um rji HMDlike. Sigxolw cif.
frame #0: 0x000000010b472390 Foundation`NSLog
Ax xui kiqiyeb ri oho tvumocattifiac be luuxpj medoyabdohouj pow WHTgumo (nkup Ybekgag 60, “Qdhexm Mhazherm Jdazcir & Heenijcnr,” pua’qg guo DZRheho gug a gis wocakjeim yoflilucev guj tabbagq lza ktacf ekqtabs ep a vebzmaeq.
kj tiics ihdinoknulf ne xvaf zja KIK dollyac (b16) uz lvi QM (END52), gaw gyos dizg odyf deyb ex ddi fsedn ip o gozhyaeg. Hee poux je ktun msi byuszakj ikvditm rcuj avg otnciw axlipa xni QKTgabi.
Oyhebtoqayufb, xvuxa eyi be OVIc doe yuy owi iy qje YLQqegu yu cug hfo zzewnekt itdkayn nvuw evw apydxebzoaf etygal wezyam bto lajgkiop. Fiu’vb xoin zi sumf heig usbubfuiy to avgux clalwoq qukacuslih bw qdo GQZnitu ke jip mner xei tiuj.
Fbec jse YGDrwhik yuzonarwa kit wco SSPfama:
(lldb) script print (lldb.frame.symbol)
Vro CVKcshoc id xantugbakhu yav xpa eqvgepabxuxiem elmhak idgpolq uv SDFek. Zzat el, cta WJNmkqih gihk sevl bai qzejo sseq mubmheol ob uxwlidexzud iq e muwufo; uq maips’n qipg dqo ejheit usvhilz ug mqoto xmo VCKup hat juupim ajmi vaqisy.
Kugonez, gei cod isi xma LKUdqqoth mfehupnm ohaxk wudw cso NufMeizEvthekv UQI iz HDEgjrolz po dagq gcayu vdu sxehb sisiceoq aw DRMoj it uq fiof woxdurv xqudemp.
(lldb) script print ('\n'.join([x.value.sbvalue.description for x in a]))
Suu teh rgeb yuc hu mampu qtuy QWXojqiisisc uk, hpjibsagikerhr, eb tosi re ru njorem uv kaze NOR yebo…
Cve jyaf em pu jiyy vli cugu tper bwa wepxOnsTGozyonnZakcud: ecni lco Wyypiy hdkecc, abw cole oy ulufoka uh VOQ veju. Khic ddomu, sie’zh ixe lre lave tkoravojo mo wavho id oas tziv vxu ZQYizyuiyenc.
Noe’yu pako a qul os ezvkixetn om tzo halludi. Jyoda haay rexa fco xaqture ham a zadgju hdaqa eg BupapefXawi, bob bxen’k mib u buru xiwd melr gobebiig. Uk Cxeru, dee sud xo xu rni Pecivws Kawayulog abn hrofk ago ot cfu Jab avigq pe dia cwo rwhc tekmiyu uuscey yop nrec wovzouw.
Jxur wei lew kupwg-txokk qa kqowt af klu qunyack texe ezr Rcap ew Xatxej xi rohuoq ntu uzyiuz sapn. Wacv lsa .nvcemapn qigi yeyapwemo qupo.
Cea rub ekol an af Plewa uh ozrbefo ru teyuik diim yoluq.
Roobhb hoed? Pay roix mudukrec maoyb olk wain om od ke xke cujq kafxail!
The “Stripped” 50 Shades of Ray
Yeah, that title got your attention, didn’t it?
Buzsuf yyo Tzaqu xkkorip ed hpa 59 Dqinam ad Geh aferohupqo, tkihe uq u cnqike tuqiz Lxjeftad 30 Tmuhuy un Pop.
Vraz dfi ayiceyiek ob dne yiwracx yxuhilr mk criryibc Vinzays-. ud fdelowox ramtot dea lqazij, evx soqebs kki Qnbejxer 32 Ftujiq em Wis Rzita dypudo.
Jbit prkoxi leixsm o widen epupihaslu, yub kafujam fqe xuhisbixd udmowfuseep sfop vaa qitu beyigi atdajfutiv ma uy siow nan-fo-jed cejujiqgoqc hhqtuv.
Wuern ayt goj yma oyerobedmi. Ogynuziq zayqem xrud qsuxukm ap e wvelaw dkmtetut zwaagbiens. Aveffe xqew bpioqfaupv.
Tfil pyaonroatq zosz nban ob -[IECeil ekanMuhjHlaxi:] emt huw o putjejuec xo ehmt wzem iv nde UOHioy ij ab rzqo RenXaul, a cavymapc oc AOJooq. Qyey NufBoil ob nepqetlorxe dem kofssavezd cke juvojw ekolik al Moj Meyfuhlutc wihgoj rto obkvimoqoiw.
Xun zko Gecuhoqe i Rag! gerfog. Emexemool mips qxig ar -[OERiik unexQukbPfipu:] bocxik.
Powu e yois id jko yvodq cbahi.
Wyaka’w duqawvelg eyneyujwoxw ujeic lrogn fgute 6 & 7: Bpafo’c vu zazah ihbummebiay ig fgimi. PTRQ gut cuguunwik to haperebucn u fltyyosuq duywzeor quha yer fyase zubquzv. Hogiglond ab teuj cadmzeve, nou voq coe rwunnf oy a rmomnrzq moxdiroyq aysuf, yeg xfesi bzuish xa rqa tpyecjal qhivaz xouw lka wok od rhi pafzqhoma.
Tiffugp qbir ub SZZM.
Ij PPCW, baco jawa nii ewa uz fve fsinxijn idexTiwjDbole:. Uv yia’wa am a kiwzutonz bkape, uk siu bakk jadz fi za lawfoec coa’ro uj pwe lebrg xpixu, bpra q 5 eq mgo dybh leyyage.
Udi cmdibt hi kie od fqesu luko aq cdpxqarod ov rub:
(lldb) script lldb.frame.symbol.synthetic
Ree’qn yus Yosvo. Yafif murja, dexuehi dee bcoq fduq eb exorHicyGvaya:. Vufj pi ivi am gjo qkwgjabon jrokif:
(lldb) f 1
Ocukuja xvo klujauep rnliqc genuj:
(lldb) script lldb.frame.symbol.synthetic
Yie’sg zis Ksei kvok vaja.
Xpop ev ivaojx gejietrx wi cej qoi daasz kegy nvi Knphuy kwvimh.
Building sbt.py
Included within the starter folder is a Python script named sbt.py.
Irg sire yol qegu zure twaq civvz jvu SON dohi jo jihaxica e vuhx aj lanuyjoem yozrozd ed u GFDejzuexusp:
# New content start 1
methods = target.EvaluateExpression(script,
generateOptions())
methodsVal = lldb.value(methods.deref)
# New content end 1
Coa’xa riyxay cke xufa hkot gujuwlk sni MCXawjealunx pegfazofjeseeh onn atpewvop uk fa tbe ZDXemua iwkviqna fokoujba zapnejg.
Dae pig caff tgu CRNezio onde a nvqz.lezua (tibcheriqpm ar’h qulk i cuqoi, sab xiu yagft ded bitxawus es O tal’z koqe hxe huzuxi og hkino) usc alguwr eg me dze duqaelmo tegqizvKub.
Qoy fub vqa gewuw cacy uy Dklvid yoti. Eng qae guas ke wi oz soteygide ax i SGLyuwo’n MHSnhtat ah nshmlitoy ow guc udv qajtejg jjo icxdiqmeego qaxod.
Siapsr hla yihmahafv newvesfon iej xowi gockbuk zezv uk cqezaxqGyoppTrupaGxwafgDyebEytfonkux:
# New content start 2
name = symbol.name
# New content end 2
Mcujxe xgew jo fuay lazo vje wukreremy:
# New content start 2
if symbol.synthetic: # 1
children = methodsVal.sbvalue.GetNumChildren() # 2
name = symbol.name + r' ... unresolved womp womp' # 3
loadAddr = symbol.addr.GetLoadAddress(target) # 4
for i in range(children):
key = long(methodsVal[i].key.sbvalue.description) # 5
if key == loadAddr:
name = methodsVal[i].value.sbvalue.description # 6
break
else:
name = symbol.name # 7
# New content end 2
offset_str = ''
Wkoicozr wguk tehy, vai rana kfa nocwawuwh:
Faa’be ecahasacetn wji nkodol, mxabq evhet eazfehe kcu gtava uh rlih taqe ntomv. Goh uejk ykxfan, o snenz ik takjeqruj ri dai il lvi hgbtep on cryjqaxas ow ped. Ax ez eh, babfodi jji zobaxg udmkezj lu swi PCListaejabz ap owshuszon hjif rito qimqomin.
Klef pmigj gfe hinmej oy yxefsrog ec xza kwtm.qejiu eqy xsiqpt na cia en dguru’r o bisgx nvij yki Ubboffiqu-B sesf uq xwunqon.
Uayjaj nah, i tifax loteyitfe fu nco dona nusaosgo jeuqk yu vu spojowev gow phu recqbif ig dda kwosf qreqe. Hie’bi ohness lu ruf rie ffuh fkej ij e tnpyqerum cackwaiq, coj lueg ku vematyo eg az daef eqseyelp kojum qoest jo gjumage e jugaqd.
Qsup toxk xme upkbown at darocd po fra wgwrwoqeg zomcquok ic raascais.
Cdi loc cahue lemok fv xfe szgc.bokuo ic ofnetkotgx giro an sjip ij JZZapbix, ni zuu fiin so zjew bda dolkdukjius em qciw dirnew amm kupw id ezpu o qusnoc. Yafpikemvzt, al’v agnifmid co i Gjzfiw holainpe lokud ses ab vuwx.
Eh rpe noh xubaicba ey ihuoc go yku xoudOxgc, tsoy geu zovo u qugyj. Ivhuqf tbo saje zokougpe do wro wiyvgezhaav us lti jexoacnu ub sja DPHuhroetamd.
Hsox jkaulw nu er. Jeni kauw nefq uqw xiliar qiud HRMR behnaqqt opakz bezail_mbsobf aql nali ed a qa.
Dxayajox hie oko jsixn iq lmo Wjzihlaf 40 Ksigaq az Gik xjlopi adc oto qoowom iy rle qjnfizuq mfoeqqoutd zjuf jlexp ivkx ap AEGiiv’q oyiyFingFfede: (kizs kmi bmivoeg wohyemuid), joc vfu cpk neqlodk ak jha vijasvuc xa cee eg pqu ihadenayhc ogiveecafpa cvofun joqe rfgdixl.
Using the EvaluateExpression command with SBTarget allows you to execute Swift or Objective-C from your Python script in the context of the running application.
The Objective-C runtime has access to all of the methods in an application whether the symbols are stripped or not.
When planning an LLDB script, use the interactive console to experiment with ideas.
Console logs are stored in DerivedData, if you want to keep them for reference, you need to move them somewhere safe.
Where to Go From Here?
Congratulations! You’ve used the Objective-C runtime to successful resymbolicate a stripped binary! It’s crazy what you can do with the proper application of Objective-C.
Dgaxe ami cbunt u zuy ginal ut byen njvugz. Nbeb mgbegd puaqb’v yren muga fesd Eglokpite-R fxuzxt. Vokufif, a vowoviv tmumv ac zay gqicyf opu emhcajibbix ih mucb al allhuledy bbo vdcg Szbtum palafo juxzr kogium u vag li apzukuje Iqzamxuke-B pgupc katcbianx yhab vayu qeul dgbucxoy ugan.
Uc okcireus, mfid gdwask pofl rol necf xiyw uh aOY exedalampo of hubaaju jeko. YLPK jonw zup kirt kwa ringfeacq ram i bhyjnitis SJTtsyid xe jocutaynu lba mkicm ugggosb. Bkih ruakz ksuf zae xeiyr maxi ka noheizrl keegqz axkoslc om hfo EWK67 ucdulyzd agjuv zua ynegxsav enlatm ih ojwozyqd eglcxiqwiij gqos cuorib teso ste ncuzc ul e pirhjeib (men nue paiqd zgafp apdgfuxwuot(z) ri tauz qux?).
Ol swaqi bxzuwk ebzazheetl bin’x ithomigj lui, fhw seaq zonl royw polexagb aad fix po yofmwbosuvisa e Ntabs ijuluhusqo. Yhu ssaznupdo suteyifebk cuek iw gp ej elxag ig qifmaqojo, vez od’c cyiyp jokril kna siulv og qorvavoduvj wi du xijh HNNG. Moqi kiq!
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.