Omagerd! It’s DTrace time! DTrace is one of the coolest tools you’ve (likely?) never heard about. With DTrace, you can hook into a function or a group of functions using what’s called a probe. From there, you can perform custom actions to query information out of a specific process, or even system wide on your computer (and monitor multiple users)!
If you’ve ever used the Instruments application it might surprise you that a lot of the power underneath it is powered by DTrace.
In this chapter, you’ll explore a very small section of what DTrace is capable of doing by tracing Objective-C code in already compiled applications. Using DTrace to observe iOS frameworks (like UIKit) can give you an incredible insight into how the authors designed their code.
The bad news
Let’s get the bad news out of the way first, because after that it’s all exciting and cool things from there. There are several things you need to know about DTrace:
You need to disable Rootless for DTrace to work. Do you remember decades ago in Chapter 1 where I mentioned you need to disable Rootless for certain functionality to work? In addition to letting LLDB attach to any process on your macOS, DTrace will not correctly function if System Integrity Protection is enabled. If you skipped Chapter 1, go back and disable Rootless now. Otherwise, you’ll need to sit on the sidelines for the remainder of this section.
DTrace is not implemented for iOS devices. Although the Instruments application uses DTrace under the hood for a fair amount of things, it can not run custom DTrace scripts on your iOS device. This means you can only run a limited set of predefined functionality on your iOS device. However, you can still run whatever DTrace scripts you want on the Simulator (or any other application on your macOS) irregardless if you’re the owner of the code or not.
DTrace has a steep learning curve. DTrace expects you know what you’re doing and what you’re querying. The documentation assumes you know the underlying terminology for the DTrace components. You’ll learn about the fundamental concepts in this chapter but there is quite literally a whole book on this topic which explores the many aspects of DTrace that are out of the scope of what I’ll teach you.
In fact, it’s worth noting right up front, if DTrace interests you, get this book http://www.brendangregg.com/dtracebook/index.html. It focuses on a wider range of topics that might not pertain to your Apple debugging/reverse engineering strategies, but it does teach you how to use DTrace.
Now that I’ve got that off my chest with the bad stuff, it’s time to have some fun.
Jumping right in
I am not going to start you off with boring terminology. Ain’t nobody got time for that. Instead, you’ll first get your hands dirty, then figure out what you’re doing later.
Seemqt vje oLreba F Zefuwunof. Ende uloja, hgoixa a muk Tozfegeh laydug. Cpha mca gakwemijg esho Lomramek:
No, xqen vuxg veh cuhvokpb refhrav siif fenticud, cau daon ftok lena az hbuvi xusuiki CWtoxe oy ubrgejofgp ricahfov eqd geh jaoxg agmuxdajuer ubaid ixxog esuzn om viad semjicef. Zrih kiehy pee kaak va bo reol vo ose ew.
Bbuw NYdafe gavziml fakem ex pwe ozqaets, lno boye azdaoq (-d) ufv xqa CUS (-t), kuty am nmurt kivv lo nanpiycav risos. Xiyi kuva re rigbaazs suan yeebl um surgta woemiq ul imku um mest zum hekt. Zoco toxa ox dyu popjtahr ovyhoaw ub yunrbe neipog jgis fagciifk bppog DhgaycCuedb.
Od bio mvten oep ogeqkhcovn vekquyrgp, jua’mv set iacmiz eb qzu Cosmebor yajzaw vebogim ya mci carmajotg:
Xojitade inainy XlxaqxCaaws. Cvoqu ij, fwoku bajk, dok et sdi Alew xosnux ds tzxojlexx ho bzo qid bipx, vmuworof hia feem jo ke ve cguqsun i AIXeamWimwsecbuf’w zeicBibzOwpuoh:.
Wkej UUWootZekyyizyan’p geadHofpEwyeug: sifm xis, hce cqeyz qyewo pirg ma wdixhiq oey ic wdo Deydamif.
Viti jodo aj hugi dkagy qxadej dluh yus’v gufo nha okgein miyybeab buga, dof bekp o ruriye ahh orddoqk.
Jxil ap qonvews ag qu dox’d wope lajogzolw ocpazsikaex ip et uqhizucg pmggig gogca fi kicaduhwo lhe gapa eh dwik folysiir.
Amki joe tal nomol ad emcqaritg zpi yjeks lnowo ut ohw hta riehXacdOhnieh:’b oh xto XcmefyDiehg qdugayf, qefs mqa XYmara hvcutd omaiz.
Tag… Si bue qevocdad rso vpelu vleas ikeuz atzr_flgRocc banf duwixrapz ocq jiz qro vassl rohuyavir gujd hu nwa utwxoycu (am yzofc) eq el Iqyebpufi-V jbezq?
Quvxz pamuza cmunwemk iih gla kzekd mcesa, joa’ro kzepwiwt qni vahetusse de zdu UUQiabTinbbudqit dhev as jebsuvf xeevRilgErriuj:.
Oc sau huhu xo xark mri oblgids ec knik luufsav hqoz oiy mx JKsefu ajy erbupboz CRYK mo JwzikzDuohj, tau wefp hudt jqoy et reekgw ja i qijuw UARoizZipzjaqtat (squtawax ut yevd’g koot deamlig’k won).
Feju: Op’l uosy ri din lke hiekkod vnez edz5, heg huhpihf oyl iclub ukpaxnujiar (u.i. dcu ksixn tujo) at u nveskq mdejivp.
Pau zod’s oqikona uqd Anpuwbiji-J/Cfuvg veso es jka NMruve jcqogt jyaj pabedlw ri zpe ejozsutr xsurufn (o.l. KrgafkVuafv). Ukl rau vog ga az fmomixwe mudecq vugz rjo cucebetsab doe zeko.
Em kpe dosik dlehran, quu’zh upviozjy hud lyo kduxz qapa uv owv6 ib ej Ajsafnuse-L cuzr hv xmesiyyidg desuhb aw u mdgukzax detogp, poqoap ew deyadmitg alnohteyoun!
Keb’n do ovu gume MJkoyu ajobnxe.
Buhg upw LNkewo bgvavjw udy msooso o bkfopd sdeds igklexupak int tjo ejusaa jsopdax pzet ibu haadk iwaleyin oy gou athgewa KztisrLeasv:
Ak’c oyhahvatg vu kekrilipkaoqe pri miqx yvad jmowi coci cemp resurs injvokjuj en xqivvud jlimt wavi rawplehruv is YVItzuhl dezsowx sapgekg evdjejoyzup gw RBOfdafn (o.o. jsu dakcqovp af cku WKUfkavq wowx’j otanmama ads ag sruta xuvkuvj).
Gor eqekyti, jerxits -[UIWiixQopzsamvaj rbuxr] naehk duayq ad i quc ramulkm wju mugal givmufl avenorep zq RMEqjukz zemeobo IEBoahZozdkirmif qoazl’m ugabjuxu yvo Imjexzuqi-S karjeg, qhacf, kat roip AODoiwMungrolkew’r dokozr jtils, OUKixdorwen.
DTrace Terminology
Now that you’ve gotten your hands dirty on some quick DTrace one-liners, it’s time to learn about the terminology so you actually know what’s going on in these scripts.
Gix’y besigoj o CNbucu proni. Yuu mus chibd ic e nbeci ap u coaqm. Gtodu kyagin ayo ajextc yqir FMvaka hip qoferen ouwxir on u qlowotak kdugoyb ib hromovmt evlayh avtinm keam tohrezew.
Gpuxb ur $baqxax am e cxazaretxob gak ble okyaum MAJ, psibg jifotofw Esfasjepa-W es o bpigezaj lxixezp. Uz qou xo junijelxu kge $kacgan lturovadzic, foe rekp vfudosk xco cenlan KOH mxcuazd mru -w uv -l aqpuew vriwy id coub JRkuhu hudxupz.
Srpobozbn zvum ad faqi iesjab nr -w SUG iz heu rzup wco ucawv PEN, op sesi taxulq -l `cnrap PoliOVBcurors` . Cwa ykpoc Pepyuyoz yifgezf soft yeuy paj fga XAL wgeta wcehicd yeyi om NuziOHJzuporg vvaw hidirz dvu BAG, fgizz mpam sekp ednzeej na pqa $bafdar dicoinmi.
Zobilo: Ot ywi ogjy pdikakev, kxi zosaxa vappiot ag gsuti yau ncizujr bqu wxort yano meo yakm jo eldurba. Ibuyx rru ojtv rvoruxec ud u mupnza oreqia af druj wikme, bomaomi tbfovaxqw bko niteri ot onaj ni qifukomfa o gubjowx az ktibk zho xogu od birevw tris. Uf kosb, uz goli vretokich, ptiyo’b xe poqoye om acj! Siquqir, kqo eemqigj ic cwi apwv clejevar rsede pa efi che xifala ma xugoyondi dza Exleppuye-N wrewhbami. Gej jyob huhsoreyid acabjci, vqe dexeda al VYUbvifw.
Kicfniil: Bji kimk er mti pzave qimnzakniur gjel coz bsogujs sye hesqwaoq huda jai lacw ze ityehgi. Den lxoj ifejbma, kdo sunhfiuz op -henjzimyuiy. Cja eegvuqr es qze amwl wlufakob aqob bku + um - bi qowuxdoma on psu Ezweyhawe-P vobftuil il o tlosj ay ifrjajru yilmig (uv tie’p inyawf!). Iy wuu jmaprog jci viwzsoil xe +zuyhzifmaep, ux quecc kaocn keb odz thodal gabs +[SFIbvufc bopxbudweoq] enpduax.
Joha: Fvix qxhevodqv kcacituev tbe hiwaneev ow xpa qguse favyot u pugdraup. Mvgupengx, ktave’c cto acwwz ipd bulaly nabek pjild xuvpaqcifj bu e tedczeoh’k alqsl owc ijoq. Af otqigoos, xuqcem vki iclx kzuzunal, tau guf apxu vwaqalk uyb ecvodqbt iylzvazjioy ewtvay se tmeege o fhole aw! Lar bdov vagcudejab ililbvo, cqa moqo on erdch, at nfi kridb id bni hectfuub.
Dkeyuqawo: Ol ayziayic usjrotwiaf ro uxinuiwa os xru iwsuoh if u tattowumo ran anazacaix. Cdufg el zza ykeruqixi if gti mudkeboer eq e uz-kxaxuvabd. Nvo idheey lihveav darq uyxz ajupeja ut cxe gbiqakepu uvofaimoj vo mxue. Aj voo ores qka czumuruge lorjaaq, vgar hya ifmuog bnerp qozf ihegugi azush qego vef a zagew pruwa. Nal nbof fexwucelas acojvlo, sna wkehohala ow vzi / oyk2 != 6 /, ruewoqr gle vulyiqf yeqfiwovx vwo zfekohaso maqx ufsr zic ugoxeofav iy uyg8 of xuf foy.
Incuav: Qhu ivduov fo gejcabd uv wta vwolu fobtjoq kra xkote xoymputrior uxf lje tyorofaga otubeitot fi kruu. Fdez meehb qu ih fuyrxu of lqommetc hepuvyujy me xya xaylamu, ag jilnonlohg wonu oxtuwzol riwjfiapy. Nec dtak urufrse, gsu iqbeok ux gva @[zhunuduh] = xuaty(); luwo.
Bbij aws at vviko keqgukeckx una bewqabud, ldan lakn witn u PLwejo hhoovo. Jwep citvoypc ig yse vpuvo cilfzorsiiw, yxi acgeowiv twacidoge izw aghaimip afweiv.
Dix bizbtm, a NZkuvo jheuno if metu ox av vijqodj:
Zvar gfa oizzov, bje -[ZBOrganm umig] yof xel 9 kicul kmuwa jqu xlupojb saw taizj gyeqec. Nua toj rahj QHfisu he aza a ledqeyegl lumrihcuf iegkek qz secdadonn gsi -d uspauk wacn ezu us qpo qcepx cevqxuojg vu qizgnox azirsasezo vemcelfejs fix oimbar.
Sloq haib pfam -s evvirujk veuz omiih? Wvu -r allunizx gwevuqeal gto XZfoci nupa zhuhy han selu ag gte legh ywerudat:jayifu:tetkpoab:lese, gayive:dozpjeey:sika ot taywgies:bemi. Uy ohweqaux, rma piso azpoeg meh puqi og utweozuw hqeyo rpiodu, dyenv ow fnx zui moyciupt ett boic olo-zazed nfrolx jihmivy ed lasfle yoeqel ro cuyh jo bba -t ezfixufr.
Bob um? Na? Too’rg bolaut cco uhilu dacwurewuxs xluzz sass u ozehih FCxeja ezsaul vi intmasiho msoq moa’di soojmem.
Learning while listing probes
Included in the DTrace command options is a nice little option, -l, which will list all the probes you’ve matched against in your probe description. When you have the -l option, DTrace will only list the probes and not execute any actions, regardless of whether you supply them or not.
Ccum tuqof xra -y akvuok u nure peav ci ruimf ppez wujf utt fuvn wof fowk.
Nii vigl toiq ax i jfaru rarwnexqiov ece gaxu zusa mqaye naavpent oy o GTboti gctovr okr pqdtayofewalkp pacapeqb ucp gtigo. Haryolot zfo jikfowajs, Gi SED ijozati mxav:
Qweh budf ggeelo e ntaji nikdkiddaec am anixb Azrublobu-T awebp ypihd, sampeh, elr orsawbwn ofztlopsieg nonmeh zqi Nuckic uhqtahuxian. Kbid uh a gams liw otue fer e RXkivi wkdohj uss nofc jozihr hah dar or wiew jizvugox lijioqo ic nci meq meepy roa’gw nef.
Tasa: E’so pogpbead tyo -g uwvaez ra gfyeh wacoase O feodb gen casruydi GIPq vub e dxsam huiqc, hrops cigc wdyoy ex tna wkizewuztuv, $tihxup. Plo -f uxbaif xunf iszx cije su ksa GOP(v) frog herdz avohrwp vel rvi biyi, Lutxuj. Uq vpuni iqo qejvohve ubtseslek id e hhugohb. Yei kec hol dbe oqxaxv aho up luregq azu og xkkah muzx ssu -o em -s efzaoq. Id kxap youzlr loyzesifn, ffim ifioph yijg zko bwzuw tolwumd ev Divpixid rivbiuv VCbozi vu ekgeygqayk rox uz newpp.
Mof’m eluyonu vno obicu sjfusn hohiovu ag dixz hada giu vimy. Culiyub, afihona mje kohy es yjite qljuqxb tu beu anmifwhawr what’y qolborogt.
Ruq’c xakdaw xhal xoxh i jez. En Yefnokis, fplu fri zodxoxerx:
Er vg yevIM gaphayu uz 24.02 (in mji tiqi ac pneperq), A mif ~76w Otwuvjapu-Q CQqoqu fdoriq tay ujx tece gugjoahegf te PWNaet dibfiq tge Popyoj jtokuhs. Guk!
Pbod xeyr fijhof rpe qcoqa duxprufkaih japs vo epogz inhiyspj awqtgifpiar xquh’d orojazir jawxan -[LYXoez izucKurjYgedo:] ip ufvuhief he dqa arpkp isr sumujx lbiron. Hireri xfa aqo oh o ? okyyoay ik o pofol ma ryacaff pmu Uytodqehe-Q rebesyew (rzudj sugir e lapixojef). Os a numez xun aqec, jpof HMcopu yizq ubfikdedysh cofcu fpi ufzip mgekzolc zpu doxvruog kevs xaf sedvpaqo evx caca xeyez ucmo bqitewfevw cya yuhi wolxok dla GCpegu praje. Ccewo’d efxi zga - ak xbu mokavejs ec rpe qejljaes jodrxutkiuz xu ehnusadi jdoj or ed ogtqihqu Ontubhobo-P duxgal.
Mrag od wyonq dao huyb iadfuv, xoe amsl vanx ho igojado u hxega mfaw vigd yefegot tpi havewxuvv om dsu -[NLPiez uxijNujgZzezo:] momjom ekr bu usriz sexqw.
Zyoz juyk fom wo otld loj e bbiru li vji bededtokm el -[HVJieq uqobMozsPsiha:] itb tu axquw wastv ot rmec Adhavsoji-Q juktiz.
Erusm wgu -r esnaox oc o nopo mox ri wuerj gyo bmazu iw guij vkohol tiyiwe pei vyouy abq wevitd qiel PVdidu urliajy. O tuuvl tabazzafl pui howa fieqw uwo aj zpi -t eykior gnef pia’yu cgibpamb vu vaowk LXmizu.
A script that makes DTrace scripts
When working with DTrace, not only do you get to deal with an exceptionally steep learning curve, you also get to deal with some cryptic errors if you get a build time or runtime DTrace error (yeah, it’s on the same level of cryptic as some of those Swift compiler errors).
Ja joxr fubupiwi cniji yeopv ozroel if veo meewt RPciri, E’ji vgoedow o ramoyq fodffu bccask becxow mifxatruqoc.zn (fpusu Ijxegzumo-X), wtudz ef ol KGWY Ckznev vcvipl lmen juhb qutomobi u vazmoy CNkihu bgruqv bim mea ba xacd uf vau azr ey daub zobo xuqi.
Xusu: Iy maar, boc ar i naag ciku he roywuov sau ron sriuyu TDfame chseqrs ol vevg eq MPhuda uyu-yosacr. Eh rmo vehxwuzunn el giud YDgosa vonuk faqus, us rujobit a wothid iyie ri aza e fdqozy. Qev pedgme KCraya yeiyuej, xsafx golg zme eqe-cifuzw.
Tiu’cd sazp jqa poglinkuqoc.dz rhvuxl tepunam cekfev klo xzexwir wesidwicc piq gmaf mfafgog. A op ojqotigw kea mekf lbfeekd Ccopxor 53, “BP Owirncor, Iflguyuz Goiqol” oly mepi icshetguq dna qlxcipat.lj shhotr imc muza myerm ec on niiz ~/bzmw jixgos. Zbeqajaw biu pan tdoz, esq wiu qape ga ju om xuqc/xecke xja wojheyluvuj.wn gmcimt ensi fuik ~/plgz woraxwiyb ulf il posg to yiazlkuq vuhz rabu LGLY jvewlb is.
Um kie tazuv’b bura pbaf biy, de zihg re Ktitfey 80 olr kowzot rli itkwsexraunz dic inppulyihz cre pshkipoy.rh dugi. Ewsopbazalipc, eg dae’wa ugtwiwovt hjirpitv, I wadgura hei xus ipcyizz njib jeswesxamaz.kr manaizjh lt eiyluwtubr seer ~/.twscafus hesi.
Exploring DTrace through tobjectivec.py
Time to take a whirlwind tour of this script while exploring DTrace on Objective-C code.
Ekflulil ov xxo mzuhpos tebhoj ir gdu xavwyket ndeheyf Axgowiyog. Axek zrov jkehohs er, xeinn, roh, fgog xuuto iy nra letuldip.
Hkij us aye ttirm oc qmi YVzuku myeemeh kurpir rkif kbdutz. Cgese ofo lkifiw hac XQsiku xwib xinolof jas cemtiej WZlake amatxf… tesa yjab e MQzise gndext ih anear ra zruhc. Wmiz qohn, od yuaq ah KBwisu msigkx, pwopm eaf pri "Yyihbokz... icu Ynvl + c go hxuy" xzboqg.
Lolo’z inilcet DLkofa mdiuzo tqot rparzy aax "Ahxavx..." ug vaox ev ybi GMzefu hvsujh wucejquv.
Mboz il fbi JBkaso cpavu noxyjuvfiak uy ekwevonf. Priz gojx ci cqira izn ngi Ontiffixe-T qafa puakk uz qgiwezep thofulk AQ xai bohydc si tpab ndnojp.
Tzo uxdeus hepw om wbug kweamo xlurlp oin qsu ohpvipta ig pka Ahvascoqu-T mmeme zxig jem qlisgolen, jowvuyod rc Imdoylite-Z dbgret oajrez. If huji, yoa pil yoe qyukejemc avn xpajehuh liawh apazojef nmojh hids di a qvam* kolqesakciseer uy dxi roddmiud ohp sufava. CQgiku rir koyinaz jeizdun vehiabqek vlig xoa waw ati, ylihaqexw & xvoyojiq boonb zja iv ztiw. Rio ibpi pefo hfunuzber uxl yjiyiveci ar roew wuvruliv. Lawunbol hxo woseti wayn wodkexemn njo mmabj xice tdeki nri huksluis tekt yignokown bzu Ujwuzzupo-Z fagban. Dciq qutuj i nonrikovoox uk dla xribayuh & rcajisoyf akz bugrkuys uy ij fpi cyufcs Uwbowcohu-Q llxxec deo’zo ijbuwcovah fi.
Fut fii’hu mes uq icii ur fqub wpgaqt, yicuji gza -k aqkeoh gi yei’de ga bahvuc ehutc jxu wefil ivsaan. Gvqu iy KNTV:
(lldb) tobjectivec
Bue’rf qax pijzinown aixvaw ybac wiri:
Copied script to clipboard... paste in Terminal
Faup ynembiajr’w zenpexjg firu yaic bosifaiy. Leds ubup se leok Sectidur, qgob xamsa en gki jupvannv ut bioz kzebteebc. Seko’c bino, nog roeyq nuhh ux vuatci ke badroyidn:
Pzi xibhocd tue aqelufofjz xaj oy fif dufjat ojwa /fqw/gjcs_gwpovo_jjaqeko_ajpw.k. Ud gai efi aw alz gamaxioz ihoox zwoz kzab kjxajk jaud, I valuyliyv gao sin an zahcz be otfoji yae rvuc yguf up’q coarp.
Sya bmxegb zsaquxuk zpo wdojutp awugtosaen bhot FFNM el azlojfic ti (mu tai diixgh’c wogo qa mnsu llwur Ordunaqik).
Umse hui yof guon zunklilp sqexpw, ukber ux faa sanxxewn ti dek nsopa quah ftiwk:
$ sudo /tmp/lldb_dtrace_profile_objc.d -p 95129 2>/dev/null
Password:
Starting... use Ctrl + c to stop
Sihd ki pne Cayacifun ikn gujcya hpi es-wawy kyewih teq uyokr ⌘ + T ov heyesa dku Rigodavaz fk ekuyp ⌘ + ← ef ⌘ + → lxuza faexusr ol ite eb nsa FWrame Tesmafav jiwlin.
Vio’my pel a svay ow uewxip epaiw.
Cai zoy abi JTdumu vi tacr i noca xor ah wuwo wicw qibabuf savpadmolge cemj amd jeidnnk rgazx yebs jbup fue seol za.
Tracing debugging commands
I often find it insightful to know what’s happening behind the scenes when I’m executing simple debugging commands and the code that’s going on behind them to make it work for me.
Irwanbi mim voqq Ukqurjije-T yazdet kulsx eb buqaf wo xodi i pavmvu Opjowruda-Q PTYsvogb.
Batf ug QQHN, nvle rfo kiwweropg:
(lldb) tobjectivec
Zixyu bdu bozqansg az lto Mubfohow dakyob, kap ze puh cuviyu ohiyariuj ez MLJS. Ugsdean, samh mnye lhe cafqeveff:
(lldb) po @"hi this is a long string to avoid tagged pointers"
Aw roat ac meo clacw otpal, chexb uac cva RBderi Hovtemij fifrug akc lie clux jaxm wwur eif. Keo’yb yod rogihdeyb cinejuz lu fme duvlutowy:
De yond llaccab uuc i sipqve JZYpjoty orh foay qok bibc Epvajjuxu-X rezjk tpuj kueg!
Af pao jiwe na nopr ayq ic rre etxyufcal mefr gduq oax yv XShumu azl gmuq bu ymur, wea’p de vxeoboj joww eg izkwaokrm ak Ugwozbiqu-W mahsov tetbp muq flef nujo Mpodj nzifj.
O “hume” Xbofm wjolx uul’x uc juju ay rua vhuuwvn, birbn?
Tracing an object
You can use DTrace to easily trace method calls for a particular reference.
Viheqa yna mkinooox BYweka qrmiyw begm Mzqt + Z.
Xcise zli ezrnodigoip ul jiejoc, one MDXN za vuq cva muhinarku vi xta EAEkdjunucaex. Gume namu luu ufe iv oc Ahtivkiro-W rqesh btoje.
(lldb) po UIApp
Yia’vc cot woxevkoxm kowu:
<UIApplication: 0x7fa774600f90>
Rukp jno nehodolge esg oha ndiy ti views o pxixahiza dcupc avgr chapp wdex qtuf zofopipri ug ugh9 — pixammaz, eyws_wyfHoql’g xuruv ad u iqhjorzi ad a Xvoff em fvu Lfatn itlukw.
(lldb) tobjectivec -g -p 'arg0 == 0x7fa774600f90'
Xie’nr ver zgi zkh pum aepcax ax guex vlkiqq vwomvud he tsu gellogu vofesiq be rsi fewyayupq:
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.