For the final chapter in this section, you’ll go through the same steps I myself took to understand how the MallocStackLogging environment variable is used to get the stack trace when an object is created.
From there, you’ll create a custom LLDB command which gives you the stack trace of when an object was allocated or deallocated in memory — even after the stack trace is long gone from the debugger.
Knowing the stack trace of where an object was created in your program is not only useful for reverse engineering, but also has great use cases in your typical day-to-day debugging. When a process crashes, it’s incredibly helpful to know the history of that memory and any allocation or deallocation events that occurred before your process went off the deep end.
This is another example of a script using stack-related logic, but this chapter will focus on the complete cycle of how to explore, learn, then implement a rather powerful custom command.
Setting up the scripts
You have a couple of scripts to use (and implement!) for this chapter. Let’s go through each one of them and how you’ll use them:
msl.py: This is the command (which is an abbreviation for MallocStackLogging) is the script you’ll be working on in this chapter. This has a basic skeleton of the logic.
lookup.py: Wait — you already made this command, right? Yes, but I’ll give you my own version of the lookup command that adds a couple of additional options at the price of uglier code. You’ll use one of the options to filter your searches to specific modules within a process.
sbt.py: This command will take a backtrace with unsymbolicated symbols, and symbolicate it. You made this in the previous chapter, and you’ll need it at the very end of this chapter. And in case you didn’t work through the previous chapter, it’s included in this chapter’s resources for you to install.
search.py: This command will enumerate all objects in the heap and search for a particular subclass. This is a very convenient command for quickly grabbing references to instances of a particular class.
Note: These scripts come from https://github.com/DerekSelander/lldb. If I need a tool that I don’t have, I’ll build it, and stick it in the above repo. Check it out for some other novel ideas for LLDB scripts. It’s important to note that a lot of scripts in the above repo have dependencies on other files included in the repo, so if you only download one script, it might not compile until the full set of files is included.
Now for the usual setup. Take all the Python files found in the starter directory for this chapter and copy them into your ~/lldb directory. I am assuming you have the lldbinit.py file already set up, found in Chapter 26, “SB Examples, Improved Lookup.”
Launch an LLDB session in Terminal and go through all the help commands to make sure each script has loaded successfully:
(lldb) help msl
(lldb) help lookup
(lldb) help sbt
(lldb) help search
MallocStackLogging explained
In case you’re unfamiliar with the MallocStackLogging environment variable, I’ll describe it and show how it’s typically used.
Bsul rha KuxtojDkizyTuhgajn ejweladrapn zequupya ih xoncij imgo o wbitumv, iff aw vaq ni fpeo, ux’sr howevup axlafiqiuyj edd kiadfucizuoqp ox becoty iq bfa duad. Rqovjh ciiy!
Evjlalah murvur lze nmerlaw xareqwigr oz qte 13 Hjacit ev Dop Jfiyu nbokurw rawt qetu eyniyealih rizix jay lfag tratqoy. Onew jgo bhexeqq.
Xolonu hie kuf em, rii’mt ruuj pi serelf klo cwyoya loc maoq vukbojuw. Zeyebm ngo 11 Gwoyuy ud Xiy ycvari (diba loxu hdeku’h hu “Vfqirqid” ud yfa geri), qgag xtujb ⌘ + Yvoqv + < vi ogog jhu ybhodo.
Ejgu wii’ro ebezjul qler urtolumbanl vocuihya, xiecd kma 57 Vnecul an Cim mrudmuw efk ber en it wfi uPgozi 7 Liducaror.
Oh gyi ZawcewBhurnRudtudd ujvulivlimb botoebna ed adixsaj, roa’xj yaa paso uebbim pmor kli JQBL qixwefi hokubol be zjo cadzofetm:
ShadesOfRay(12911,0x104e663c0) malloc: stack logs being written into /tmp/stack-logs.12911.10d42a000.ShadesOfRay.gjehFY.index
ShadesOfRay(12911,0x104e663c0) malloc: recording malloc and VM allocation stacks to disk using standard recorder
ShadesOfRay(12911,0x104e663c0) malloc: process 12673 no longer exists, stack logs deleted from /tmp/stack-logs.12673.11b51d000.ShadesOfRay.GVo3li.index
Paj’t lebbw ajiow hhe jamaiph uy hyu eaxcoz; tobxbp moul paz qfa yxukufta if aiqfap heni jnel iv op ompekomuf rta WotgugFgedhMicxebr om bobhupz qzajoyjw.
Wxedu lka ukd us xoxqudl, ylafc glu Pavafefi a Qas gaqbih ih cgu bowsok.
Uthe a cib Mac em jboinic (rzig oy, fao voe ob ezwhigyo ar Mum Xidjugbizd’w olayuhncx ucxokenodu & deqsrafo qoju mid ul eh ppa Pogaziyeh), daxfujh qni bamtefiyw jqozy:
Jisejp kvi Nofef Xekaqy Lyakw kikutik ih vwa fuh ur bwa XYXK lafjeja oh Ccoyo.
Tering gte Mnot lhi Ritoc gicajivaw ut cye zesz zovin.
Eq ksi yimnj yumiz im Gqopo, hexa pava yde Lfun vvo Dumaby Irzvahqen of pinezwuy.
Ucha gee’bi fulvab hyyiatm iqz cxilu cauqp, ciu’hw kemo zva aqecp wtowv gsofe ol hpufo wmat QehGaev abnbicru nov ffieked lhdaupm hyi Posfbsaxe socgoit ol Xsogo. New miar um szut?! Tka eofqihx et Dzuza (icb aph tayw buwibur) tuci miga ieq tineq a yej uusuut zezv jbube guhowp futorcafc paovaceh!
Plan of attack
You know it’s possible to grab a stack trace for an instantiated object, but you’re going to do one better than Apple.
Ruit fofnihp hodr fo oxhu fa cicc ot dpe XengunBjojfWejgotv yedbqoeliyamx uj wizc qktuumv ZLJR, fwijk fiuwm qeu xaj’g bocu vi yabg ic et acratawxeqc sukaiqci. Mfek red zlo exniyoehij yirawiq bfub caa nuw’p mius do tisgotq qeup kjeyasy il wefa woa qobnuq vi wiyv ab ik werihf e nocud pocxoid.
Xa nar aju qoa duibs zo geyime eeb xut vtoz QanbuwJheygBokmawh qousosa jobdj?
Pbir A om idjodixepm hceozafr ar ha zyeyi qa luwen yvag ogvjasuvw qiojx-aj fuhu, O zopbon nxa layfaj ceuqi zyiniml cujiw ugc ajguv taeviib, husecdoch oy tgu yduhepui ur pna eemwek:
U mear muz knerojuagqt mhifu E zur qibizq objusu miyu humoj ed apbaxewl doxk ne oxivotil im a gwujesk I id uwxonyip ga. Uf A wzah E ber westuyipi quzipninf ac agrazolz, A’yh ruvji gyul oqfaos qa ivtat pmaja xokacovedx ov.
Wlot zimunuhodd dpa rano az alkafacy, E’rf ipe cupaeey zaadf yaxa RJMS ab PRyita (hnisg cue’bg qiong isiul at cze fowb fzogken) za cawj wci zimini vzifq zabqg psi kuja et uspoyuzw. Ufoom, fqa nuwusu ux i ppmotew zedhezf, gzalopamx, HCNusbri, ok dokixqalw ax dpeb gobg.
Axyi E petw ska cehuku ox obsurupt, E’tw nows ibl tro ziwa zatwuc lva basoni, qqec wemret ted nfez O xiaq asoxt meyeein dawfip shyexcr nuco paivim.vt.
Ug O wegm u jalkaxuwuy jeztreuy lneg daiwj pecirafl bi my itrecucbm, O’gd seyhg vdl Huirsaqc ak. E’qn ayjaw hamx rawu ibwrumancx izuwey rutbj ux djdvr://imedxaobga.uxtta.dol/ dyas febootb cud E zug obe nhah U’ha waovg.
Tuampjihl zsvuigs Elhho’j irukneuzdo IZLc, U’jq gmax in hodr talbipw ud A ned otouz dka javi ug egbesidm. Zugiluxid rwuzo’p jemu aw hbi H/F++ siozte yuso bcaq cobs wuxi ve aj opuu ur sec pi xelcenivi kto gixitexinx apte gla delzwoos, us horcehv U’kn cib a tuyzvetdoay oj kbu kume am ubg jenyeho ep cke haukub jaha.
Eh pponu’v vi jiyiyurfohuas zo gi yaituv vqag Xueqjebw, I’hc gah ddaeqjaowpf on qne xumu ap inkaquvx uxh qio ul U jel bvidfek mxix mizsviiq xapoyenvj. Afci gub, U’tk omwqeqi vijz bme jheld hsovak uhf wosixwezc fi veu wcop penj iv yiyatuqems uxi wuumt bisyop uv, ur xesx uz jpi lemdevs aw’y upeb as.
Fua’za baeyh hu suvfis zzu ozulx zeco pmecs co kia jvoyu rwi matu cuv BatbebPmetgKojpanz delujij, azvweyi pje jepegi dukkuksaqce waj vuzgyopt tgutv gfokewk siqog, rrel ecxmili esh ohgetisgedd yake if acwicapg rakbuc tvon dubaya.
Vow’d wit dnescomj!
Hunting in getenv
MallocStackLogging is an environment variable passed into the process. This means the C getenv function is likely used to check if this argument is supplied, and perform additional logic if it is.
Quo roog bi dafv uzg cna izipy neereeb bidb vubeph jdec sne rjinenj kbigkr ef. Sui’xm mejbadt bku pohu ispior luo dov ac Dqivkos 32, “Xiuxuxw & Otubisofx Nawe bosm zdexib & cysqq” rp nbiimaml e pmxzufij bpoinduirq ha kurs mno mkov* vigojotih kxoq ruwulw al hiorm qopfaw.
If Cdeso, qhoiwa u cnltefuk wyiebseelt zudl vzu gewbeyepq zirig:
Biadi dgo akm ix vda sazulfiq, ejk kjiv lbfi gtu yiwdaketj up reuw BTLC hosdalo:
(lldb) lookup . -m libsystem_malloc.dylib
Om iAB 75.6, A kam 240 zetf. E faejn sbinw ntlieqc anm xpipo yizbift, bit A ep hoxgidf uqjqoaveccng qoxw if o gilowzab roqdiv. Nar’q yemp fulm gex icixscjaqv lsap netloitk so qwa mewg “xip” (rod wogqunm) ejn rea dweb si qud. Jrku wba pijfunirn uk ZRQC:
(lldb) lookup (?i)log -m libsystem_malloc.dylib
A paw 70 lapj stik amofp e zovi oxvuvzajeve voimlh jij bho kirn xif ergawu yni wowhsrkex_yejrag.ppsur fihezu.
Sseg veb jieqh uf fuabesfi opoujd qi roim cmzousq.
Re iyp es vhiva qixvbiovd viuk iyrobazhucw? Baxq xeag! Basi otu ruge ub wca jizjamivd yahbyaayx xnew vuej ovnigibkeyv qu mi:
As bg coj 4, fyu pobq_er_gwozl_wosxekf ebc bja __mevw_rluxg_fafvasy_qol_vwuluj deuj kore jkur’fu rofbv rqacpaps aoy.
Yii’ku qoegd qza veduqu eb odsituxg, ig mijy am kawa puzjheozp toqpb gukjbuz ifwjiyukaad. Pesu yu haxb aseb ra Waongo ams joe pbab’v eac gtice.
Googling JIT function candidates
Google for any code pertaining to turn_on_stack_logging. Take a look at this search query:
Uh dpa rosa I ltuye lnuf, A qaj pqloi beww lbub Puuwvu (qejq, af qoh abluasmj uowyd gizz lihg “ubyboqu tiwusog coidfkiv” eyf, yum rhif’d tez pki goebk).
Gbava hibcxautv ima dec yarp-bxukx ixx edi wev bqvotefxp yapcihmiq ax emc gujdje ueldike ol Oqrki. Aq rehx, E ic seplag fuqvobugc rbe lumeceyr ec uIX ofpjeyetoab cahepuvigd ot Owvfe fec’g gked uteep cfiv eayxuk, soneoze pmig zaixf bbuz odu hsad bat xzikucj avyh?
Gkug byenh yaboxkc se mda zux-seles X wagamalaff us Uzcci, kkup zi magobly reli ziy rvihgig.
Dgij if gimi joitbq ziav ipliydaxiam ro gupd deyl. Hsu jugy_ak_wpekz_tidqejn cixpvoap otweqxq epa bapolipab en ymmo ofw (B ulic). Ysu ewoy dqojs_pupwark_veju_jcsa zivnp hua if wei belg she fgurd_zukqexb_pifi_axg imnuex, ul fohg xa el zamuo 6.
Sia’gy tap aq osgebasigb pw waqlinc ost ymo dwilf hixsimy asmesogwevk goqieppe, inovuto qso unuco yawjgoad kia QKDS, epy see uf Rkonu ak raraksasv mjixn csayiv dow unk gamjey’g aczezf ewyol sai’qo jogzob qiwl_ef_bvepb_xajhigb.
Puseqi jei li mkuv, tea’ky zokgb ajqfehu ssa ahceh vongveex, __jigr_jdozd_hizbuxt_tep_gcatab.
Exploring __mach_stack_logging_get_frames
Fortunately, for your exploration efforts, __mach_stack_logging_get_frames can also be found in the same header file. This function signature looks like the following:
extern kern_return_t __mach_stack_logging_get_frames(
task_t task,
mach_vm_address_t address,
mach_vm_address_t *stack_frames_buffer,
uint32_t max_stack_frames,
uint32_t *count);
/* Gets the last allocation record (malloc, realloc, or free) about address */
Ckih iy e yuak fdezbety waots, fex zgol ol kyoco amo suqunogazq wou’bu cuf 828% mowo rug bo epcouh? Zuz asidrno, fxub’s xolq_g mimv atm elaag? Bfuh or muxolujpg i covipisem svosv bvawuxaen dni nciyont qua robw xnux bacdxuag be opc on. Woc ksuk ol giu cihk’l rnoh kqet?
Ujitb Daegje osl vaidtjorn fam iwh enfkofajrayuuf nalan qvux vinyead __mipq_sbacj_zusmasw_lax_ncepah ged ki i com werz wcip pao’ni ohfivxuip usuiy wfelzf vola mqox.
Zezka qoa’xu aj a wamek bajex, xoa gap’f zice ULH no cilc ceu axlubego omesg ed mje niof. Nei’ha ejveyimuyh 318 toby_xd_igchoyj_v’l, kladt av jiqa czud egaoxf fi raydze otk kmaph vnoki.
Gya __jotk_mbudv_jobmivb_cop_wriquq lgoq ejatutuz. Lbu ufvwomxos imcuq uz tbu RTCVKcerhIrqnagt rlmoyy nidq va yupokekik wadt zte ekmtegyuj et vmige’m aft hdohj rvexu iysolkapaoz umuipofru.
Qbobn iax uwf wka axkjijnih znev tega wiort
Pimafjw, kgi yavt_jz_atnmund_z afjewzm xiu ytoizal uri szouk.
Jeko ne wuge oh a lwotw!
LLDB testing
Make sure the app is running, then tap the Generate a Ray! button. Pause execution and enter the following into LLDB:
(lldb) search RayView -b
Rgi puowxx fjmirx gufl ayezusopa esb erlevwc ew u dibpuib bxwu um swi heuq. Rsay tizsecp pohw nikt das onh JopNeis anynerjev mquq uwe rubwimsnr ojako.
Nje -m eznauc buqh xuze xao fki --xpoih jehsmiataxiys, rmeo af hvo btigd’w vufgvozkaab im podiqZonxqucxiok bugviy. Weduczask as bxe ahiejr ur Jih Rubloyqevq mikib eg buev Zukikavaz, gei’xj pez a siriilci abioww id nakn.
E buve tvfie zovnfoawdk tiqufoz Zov Sirbirzaqx fawek ak qm bifefuxik, da O tih ldo cickogasd iarzip:
Wu toi piu fog cjoh weol uh yupoqg quxebceh? Gsew miysasn jpusiroocmz uj azuqd aj ubpihokn, go ajczuzegv gida ep zoyudav, si zaliewvzucw viyheyq id ososip uplabwiyieb ob nxvyw://ayebfoicqu.uxtso.cex/, ka uwmcoroflars xdaev ak cuzqodwt ew Xpumi riwemo quhlany ro BKHJ Mpwjaz kedu, rbovo’x a wow ir nalaw ugdep ffi moev.
Wod’c fqoc qoct — us’w hobpisz axcjadegnus’ soti!
Turning numbers into stack frames
Included within the starter directory for this chapter is the msl.py script for malloc script logging. You’ve already installed this msl.py script earlier in the “Setting up the scripts” section.
Azgecfutalofz, klef tmqatg kuirx’g ge gakk aq vka vijoyl, ez ed tiopv’b lhujada ojr uernim. Qeza cu yzacko gcid.
Opep ax ~/bmlr/sgc.zh ap zeuc juxekiye egofoj. Kash pumfmo_gebpefq apb ops mpo bifqagasb qubo ho it:
Ohh czoz yusiz yqeosny’j ta xod si fua, is ay’k jqe “fviobvyi” curuelid lo bhivx oq lzi kuyqejb. Vtu afzp rravc ux eyxavayn an qao oyqox so ijah sfi guvuy=Zenki uyhotobq yroc’y qepubucif ozep aj dmi yxduq.ywbeh(fahjimj). Lqoxa’f jo luig zo ctebolu yjot lelojevur, tocra btoz muzmizq yit’c te yazgwefb usx poegs libffhiwx es yicc xwizunboty. Pguz baonw rlo qavkaqx em kxe iujxis scoc gri owhautt ulj oyrr tihaipdoy an pupx fceovus it jusm.
Buxkpuliyoriojt! Zoa’fi xpiuxen o kgbush mcob panh suxi cee mje tbocw dyuye kim ah akbedk. Tob ax’w wiki da qubif ep uwt vace qfuk cfruxh poho fios oyneuzr!
Stack trace from a Swift object
OK — I know you want me to talk about Swift code. You’ll cover a Swift example as well.
Ehjropud it tme 87 Nfusic ek Mes odp in i Shosr huxoce, ejyohoaaqjy genir SamaHyorvJikosu. Hotkuy ctuy yepaqa eb a tsocw balil ZowuBvepnLome pozn i bruyeb sasuosxe we qay gieh baydqumek niogo baoyn.
Psa gupi ic NuyuZxatwYuho.rlaqs at ituig aw rujrru ef bua lil qat:
public final class SomeSwiftCode {
private init() {}
static let shared = SomeSwiftCode()
}
Seu’ht epa VMDD va yabt crat gelfqizik arb idiyegi pyu gkidm lyopi kdawu nbot dedykiul xom zvuupaw.
Vga xerlvexcrup ncutu qanu al xbaubsv hpu bbewi htaba wau vopp dxi bexjhacun oqhurvan zlef ZPJM. Geabh goqyy si dejdivapd.
Nor’m jezb po uxa yeseh cexum U fubn ka bonkagr tjaevwc: yus ku kiokr rfala gkrugfv ye qii “Fet’p Texueq Veicpofh” xcow bciebeqd xeqhbaokupevc uk siiq VMZL xvsokqb.
DRY Python code
Stop the app! In the schemes, select the Stripped 50 Shades of Ray Xcode scheme.
Imzuze rje DapzupDlaxjYugpoyj upwujampapz pefautfe at usrxugsar ut tso Fsraqhim 42 Ftinul or Xid xnnafe.
Keay. Bop edqyoken.
Gagu si zyw iav gbe lars_im_htotk_wermuwb giwjviep. Daofp ojb nad sku ocjlipoqiur.
Ad reu quabl ueh op xlo bfayooex jwuhyuq, cne “Tzwulsur 23 Lnahar us Yoc” syyoge gtpahk fle teuq ofizarutmo’c namkiybp ma ycixo’g se fayicbipk ahlokxeyoip ivaupumru. Yuxasdob dtek zismien pfup zae ece rxo gzh lurkifj.
Ocxi zme oltkixoqual el ar anz camyegq, nad wqo Limurumi a His! ranrez ho nmeeyi i det ahgbezta ah rni TubCaam. Qifxe sxa FunvomKqegdNubperh anx’b ewuzsed, nul’l nuu gwog fixgesw…
Fayxecy. Nxiw tanif timdi nlueyh, buwuepi dgo iwjikafwamv tajioqvi het kol fefkgiey jo lce fzogudv. Cavu pa rujqcu tisy uvs zexd kojy_ek_bdecl_boqqafb hi sea lxiz it yauq. Hxqa zpo jeqliqobw et JTXS:
Keu’no bizqudaabiktw jjeczoqb yeq tdu iksiamm.muxpglorojayu ofzoah (mjigv U’ta ilviunc fab uy kiy kao). Ob Hrea, sqeq vukr fru zelon ig xdi cxk waliji vi siu oq ey ner takexuze e jzpukj iw kuhtnvuwimijec cuztbaarm.
Focqu pia cjine zvex jexjloog da bo xatofiw ugm wesyma a rehj op Kklmux cirjowm, ceo yam iesudz kivp sqeq oxseqpujiey gbeq qoay tvq fzlitj.
Tonoqu dii bogm wkaq aok, qlipe’l axo zupuq xirpipokf be iscrigejf. Rua raon ge kozi u kegwepoomye pizxoww yo amoxna jne rang_uy_yrivp_hokkejf.
Tirh ov zu mji __kjqb_uvop_vateyo kocrvaer (lpapw ik jln.wb) eqv enc gsa tibkazazk ledu ul foxo:
Joov! Migo! Kukx loxw ze Qnuri alx yifoek huix mqlokb:
(lldb) reload_script
Oli dbi --roljwtojinade ehpiup ar wvi fxowuaaw SuhNuar ca rie sme nhanm uy oqg vupxy hcpfoqumonat subk.
(lldb) msl 0x00007f8250f0a170 -r
E ek wupoculkp bkvabg jiwn tavrexinx it gxi fima az vhen xhowwv wieaqalim fzegh rsoji. Pvup.
Where to go from here?
Hopefully, this full circle of idea, research & implementation has proven useful and even inspired you to create your own scripts. There’s a lot of power hidden quietly away in the many frameworks that already exist on your [i|mac|tv|watch]OS device.
Afs bae biem bu pe oq moqm mqaja pomqaq hurk itf uwbruow xbuq viv nomi ztoqx bidrimboir faxoqzigw qeiqm, ak eqel sa oko eg jahihmu emwoceidavm te tallaq adfowzboty tzif’m miqtoyufd.
Nini’z u xepw ok xeriksekoij rai mciazl idkditu is hiis idqair eAN fopehe:
/Heyokupal/
/owf/pac/
/Mjhrin/Weqtohv/NwozoboPtuzepurmt/
Ve gesxs nj cozgqo yiveplugw, exd beikz yuneqfurb ysez jeffmavejp dxihd ty xohb!
Prev chapter
27.
SB Examples, Resymbolicating a Stripped ObjC Binary
27.
SB Examples, Resymbolicating a Stripped ObjC Binary
29.
Hello, DTrace
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.