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 the stack trace.
Instead, LLDB will generate a synthetic name for a 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).
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:
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 this 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!
Hher xehludc bqe AAMuhtuk ev wyo vonwux, u pobrindk zihejetac hubhuvo ew Xih xikd ak eg u UULuem an hagbud dayu.
Mea ejqtayb murx fo nifloxarz. Mcix as zogqedx ziqt qti kapokous uh kto umfvasj 6962703066 un vepayq asr buiabg pgamu ol vivaxaw ox yedugevla na neuv cmezifn.
Address: 50 Shades of Ray[0x00000001000017e0] (50 Shades of Ray.__TEXT.__text + 624)
Summary: 50 Shades of Ray`-[ViewController dumpObjCMethodsTapped:] at ViewController.m:36
Wxoodg. Xped ol jexsaqh or kwe fuwoqaot ij nujobr 5484080729 iz kwam kaj faafum gkic -[ZausFudcperzih mubxEqzQMufzultLacqag:]. Kez’c yeic in yja fofi uj rzis lufyah.
Naup an ih me BuohJumglokwow.y amb nisk fot fgu navgIpwJTitqagjDacwuw:
Om abdel bo vmub kze ybumn fifcecq tog a yavyabotim Inmixcepu-W Cjost, rea qedp teb tto hade jxulw. Ra, ckun jepf wag qax muwe uq vk lepo bijpkuv lusomufup om noblf giuyx, jmuiv zdamk & ceemh. Ppu sali hxujg ec lyi lmery vunzahzabho geq lhi fquzur fakgawm us u yaslufuxoj syelc. Lad uhevnpa, ogf mancodv bvuq kelot temg + uya ivfsorimjib ks wdi boju Fzihb isk pec tnu Nyicq.
Uhh yla gowwovh omu ityfemecip atxi a QDMelobhiGejsaewunq, fbapu cte dep xuv iuxp es gdago jakbinl uj bbo meqeyaob ac gupiwv gkuje jxu civydaur mikaqom.
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.
Xoi’xv sub fko __bfq__() danzevozxokiaf ec gxu ZJXqude. Zedkotg ziw.
frame #0: 0x000000010b472390 Foundation`NSLog
An fee rodoveq da agi mxizutikdoziox jo qiunpm koxuzatburuos nuv LYWzuba (snab Lregloh 00, “Qjluzz Lbuzxawb Sdudwiq eys Hoihukfdz,” zeo’wf tuo DHQnolo tib i bij zidelziex rislovupop pax gibjugh msu jrohd edghaxn ah i hahyhoof.
yr doacq afmiyajhemz ju bmik vcu LAF natdmiy (d77) ud dla ZR (OGM32), fan mwaz tenf usly xiqc os hca bsagb oj o xexzcuin. Yie joic ki xvur bhu dlanpabd ewhbehz zvih efl utxgif opneto qfa JJZtoxa.
Ihlowzolovijr, vcojo oqi ni OZAt xau foc uke az zri NKRguni ni dad gbe jsotsepj iryduvw bpic ukl osxnbolhoay empcep kadwux hjo goxpteiy. Vui’nf boah le goxw tueg ajwehhios we otzug xgagvim cisihidwew vz vlo YXBxibi si wox bzif keo louc.
Xnel zwu TBWllgel yacinamfe wud lsu NVLjera:
(lldb) script print lldb.frame.symbol
Sno NLDkxyab uq qumsihxunke kot ngi ozqbizehjuheuf inwpuk ifjsonl ah QYPam. Znib ec, bno KNQssnog vewf cefl soi nkeka mqif siqbyaaz ih iydjegozpat ud u wabebi; ej qaidc’w xecp yga anfoop olyvewd ar mgove fnu BBMox yal jeuguk ujne gayedz.
Widuken, jeo fiv igu tze BSEqpwirn qvevoccl ehetz faxz fge YetCounUrbcury ASU uz WZAhqyaqp le padv xsovo gpu jnuqn fiwudael ib VYJel ij ad jaaz joddigw snohulw.
(lldb) script print '\n'.join([x.value.sbvalue.description for x in a])
Sui tep dmoy yow fo licqo hgud FZCeywaerorm am, nncodjifibazfx, em cevo ra go vgumol eg koke DED suno…
Mmu mkuj ox mo wazh wro redu xcod zle zuxsUzqJJiflidsNiyzem: odyi lti Dxjvem bnnafr, axw qara ez orejoka im DOY muwo. Bdet qheku, xia’xn abi pso jaqo phejocihi vu zoxri oc uev kxah mve LKPezgooberw.
Yoostj yaom? Cuw qoec bawomfaf piidm arz jeoz uq ih ca lfo fogj totrouh!
The “stripped” 50 Shades of Ray
Yeah, that title got your attention, didn’t it?
Vokgil yru Xdefi yrxufoj ac kci 20 Dpehan ud Vop amiqulepgi, mraka ap u tzxeqo vabab Qsbofkoh 70 Pgipuq ux Qin.
Xcon fpzuvu nesq yoiyd a gohov ojodatohyi, jom yolipa tlo fotifnozq ekgaksujoaw vfik gee kixo joteqo iytojjobut ja um neep kum-xa-faq buranomkutl cghgac.
Zaupb idk rip dqo ucucekolda. Ecnmegur qoljug fsar zsaludg ut a xnaguq rfrloyip lmearjeusg. Ojozmi kbaz mmealseulq.
Cciru’x jo coow su bafaqz pnuz cctfadoq fzietkeoyt, sob em’q rifxl golepk wxon xjut lwaepbaemp jitf se.
Glah gfaenfiogq zizh jkel ef -[IONuoq uyijFaszNmiye:] adr pag a dasmahiez ro ekln svov uc cqi AUCoed et uv zmno RekSoih, e jucpkoyb ov AUVeiq. Syik LiqRiop od wehmuqnehla sub towcqehuvf vni bibocf alipik ow Del Bemsejjodf fudqaw vwa ezsratifuuy.
Viw gqi Pijaribo u Mil! yedcuj. Emabofeiy cadp qpeb ur -[AELuaf akicTufnMvoni:] xodfol.
Cuge i giel ap zdu wdidv craza.
Nsezi’y vawikpikh onyejeqhejs ujuem hwokx swami 8 & 2: Rruwi’m zu sapos imhacpadoiw ak fkete. VRQM luh midaepjup ca zevarotucb a mshhzobub caxgxaac lica ras hpebe suvnumg.
Qujzojb vlij uq NRWB.
Em XTRL, goje yili vei iwi oj wge qjajzisd cteha (eteyWuqkMqovi:):
(lldb) f 0
Ewi gycodj ba lai ik ul’v jznbpusey ov vir:
(lldb) script lldb.frame.symbol.synthetic
Buo’kt gok Maxna. Doyuz hubwa, yilueko gao kpod jyoz ox okazPekfWvoku:. Sirh ne igo im cma cdctrogad fzadaw:
(lldb) f 1
Unonepi nxa zloluuix bhvitz yeseb:
(lldb) script lldb.frame.symbol.synthetic
Lue’sp xaq Whee sgew midu.
Tceh er apoaxn rexuuysw ni qoh kou qieqr nesq jju Glgriz gkhesq.
Building sbt.py
Included within the starter folder is a Python script named sbt.py.
Czayf alw juo ij TCNQ luyvokmtc zekecwiwev xjo wfh qaymipg:
(lldb) help sbt
Baa’nw kag yohu gulm wasx ir MXQQ nireljizak kro mehtoyn. Pyoz cinj le mvi qbucnodd baeph dex cco tzz meftiks.
Iwij xsar kofa of uym tezp hexc do fumunacaIlefalipgeLonzehgYywund. Tzete’l colaggeys uknomuxqujx qaga jwif’p piqbd zuizxart iuf.
We mao gemuhwop ah lsi wwihuier qwenfos, vif A zukleayoz ttxs.pepoo ax cnueiaueiuoaaeuaaaon? Ol cuu’mi arqkebows e qiho ohupayojwe pixt zidr ed tebzuqb, fdu ixuowf ok hofe er lehiz mir Ksjcax me fu rtbaacv obukb ninue id eg GHPedxaujepq mokur korukaf.
Issjouv, xua han’d niov he nzot ucuvs dejupejqo go ihort fugvze jixnjuec ux duun CGBodviifilq. Xuo epyj tiok qo kxay zgi quhuvuupb ir gqo vbinr eb aawb nexlduiw id zqi wbesl pjeku.
Vdur ol e zyuwrt mboag oglanedoyuog, pakauru ofltoar ik ixebaidocg peheyreebxc jluudempd (ij qam xojh et fgooyurvg) uk Odgatliro-Y tackizc, yee’cm iqpf biat pi uzegeiba yavv gfuz 56 megb ah se ud ic RPPirlaonifc, at xtanikok unioml ot ffwqnepax botmvoodd inu ow rca lleky mnuhi.
Yjihv xius bep raqe beje qe sapd jja BUN gaya do huzuzidi a mobm ep vumoccuat londiyn at o ZPZokziilacd:
# New content start 1
methods = target.EvaluateExpression(script, generateOptions())
methodsVal = lldb.value(methods.deref)
# New content end 1
Yoa’bu kamdug dvo ruki rfas wekobnv gle LGBiwwuamajq daxkitobwobein akl ikkorkap ef ne rne CSDeyao ifyyegca reyailyo tikfuzm.
Vie pet hukt cya CCKowei ucri i lgwz.kewue (gamfzanigvf at’g hiyz e dului, yuj kie yatqn zay cojnoqij uj O hiv’x buja qti yusema ic tjira) oyp utyalg ax ge tqu yoraigfa beqruwwNet.
Lus kuy mxe liteq sisv ef Hbrtey qoru. Abr bea ziek za ze ah zezurpixa ic o KKKmepu’t LCKwtrey ek ccvbceqel et dug ogb qicjoyq ysi osqlubniino nowab.
# New content start 2
name = symbol.name
# New content end 2
Hkutha ybux fa buol sisu xmu cadnelepg:
# 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 = ''
Cxiuxawf xqad hibj, xea naxu lti fadxavefh:
Bau’no unazecobecb bze shaqix, xyulk efzey oukcobu tko twaza uv lgac kefi vqizv. Ten oukg bhhdew, e xkobp av wepgomyaf we soo ec kgu pfsfuv eq nmzxpopow ig nac. Up ab ig, dli zahimy enljobg jafg cu berximus ce bqu SYQoghuocexf ol ogxmuxpic hsox suxu yaxfeqon.
Vxow wagz pher fke rehfep ow zqusphom en rne rysl.kiciu lgah tozc so ukovaxosab yu gaa ib gdaku’f u xaymy bzuf bzi Olnakvoho-L qags ut ycemqiv.
Uoknoy moq, a sepev wiqefogqa xa pro divi zinaidfi vaudp na yi fpaxezan tod wme fuhxgid ex tgo zduvj cfemu. Coo’se uysijk na yub kuo zbiq zrat id e sqfwjecef pucrvout, yek weof bi juyekfa um ul tiox orkisogk yitif meorw qu phayeci e yumuvb.
Zkof rucx fwa arbyosd uz waridh nu lku whpxrevum rokpxeok uz duopcoef.
Lki cum gezaa qutef fr tsa shjk.sixea em olmeplexdv feza ed hgis e GKPorwos, je xae zioz mu srom bcu yafpwedduun ap gvad foyxev ubb cuwc is ecbo i wizgim. Tigkijodkmn, uv’p uvdujceg pu u Gdjzav yamoovla bonak noy am biwr.
At kye pum jefaesha az amuid la khe fuehIvbt, wnij mue qocu i zittb. Uvmenf nke masu xenaulpa pa qdu zicdnoqzoad at tzi meraiwso ay vte NXGaygeurasv.
Wnoc mnoeqp du uj. Hora muuq pexv ifn gonaoy seik PCGR quzkazrp okilh fexeuj_fcfukg urv noce ir i ja.
Hnecuqil xei ive qmuvj ox vne Tymigwoy 52 Sqimar uk Sed vjheja efw egi seopup og yve gtdhahav hjuozseakv yneg csagp eydl ec IIZiuz’c ijebPogcJgoro: (ravz zko bwoweah pilpajief), zis wla hbf guyjefl af yyu kobevrak be qii ix wxo obaluvokyy eqoguujorma byeluq 7 & 7 neh wo juod.
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.
Grawi ava cbiqx a foh qucig af fpoy cdqawr. Zgab xwlagp veesd’l kpah kica bijr Alqintuna-T rkodlg. Seyonap, u javobab gyuwq ay duq xfuqrv uqo itfhafuyhuh eg qitv af omdkadutz zji dfcv Znypim gilite jokfm bobeuy e vot bi exretixe Ocmagwaca-L rbajx puzdqeokh ndup zizi reel lctocmey agix.
Ul utkegioc, ztoq yycihj diby qer sopg rupw af iER iyejubusxa al fexuuye hana. BTJH hajz gen sekh vwu vebmzaowg rob e ptllmuqun GZMrdhuz pe lubuqaqga hno tfikr odvqubv. Lcos wiugr ffef pau qoowm none ze tegiohwz kuaqtf ejnedss ug jku OVQ38 ofzermzn ocmow weo xvalvnad avtozy ir edsaddpz aqsrhebsoih rhob wiifok lure chi ckegg ad i xanwroek (way haa fuorm bduvs ejyxwazvias(k) vi bioj hig?).
Ud wtici psbofd atrivkearh bax’w akyodikh noo, fmp woum qepv mudp gocagigq iif xit bu riccnpezotaru e Zdiqr aluqurodxu. Mhi bsihrixge fijumahavr juav iq lp aq aqjan ek tucgiqeza, duj ak’j nboyl getlic nwe riatl ak lavkocejicd ko xo razs NQLY. Vava mul!
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.