Mach-O is the file format used for a compiled program running on any of your Apple operating systems. Knowledge of the format is important for both debugging and reverse engineering, since the layout Mach-O defines is applicable to how the executable is stored on disk as well as how the executable is loaded into memory.
Knowing which area of memory an instruction is referencing is useful on the reverse engineering side, but there are a number of useful hidden treasures on the debugging front when exploring Mach-O. For example:
You can introspect an external function call at runtime.
You can quickly find the reference to a singleton’s memory address without having to trip a breakpoint.
You can inspect and modify variables in your own app or other frameworks
You can perform security audits and make sure no internal, secret messages are being sent out into production in the form of strings or methods.
This chapter introduces the concepts of Mach-O, while the next chapter, Mach-O Fun will show the amusing things that are possible with this knowledge. Make sure you have that caffeine on board for this chapter since the theory comes first, followed by the fun in the following chapter.
Terminology
Before diving into the weeds with all the different C structs you’re about to view, it would be best to take a high level view of the Mach-O layout.
This is the layout of every compiled executable; every main program, every framework, every kernel extension, everything that’s compiled on an Apple platform.
At the start of every compiled Apple program is the Mach-O header that gives information about the CPU this program can run on, the type of executable it is (A framework? A standalone program?) as well as how many load commands immediately follow it.
Load commands are instructions on how to load the program and are made up of C structs, which vary in size depending on the type of load command.
Some of the load commands provide instructions about how to load segments. Think of segments as areas of memory that have a specific type of memory protection. For example, executable code should only have read and execute permissions; it doesn’t need write permissions.
Other parts of the program, such as global variables or singletons, need read and write permissions, but not executable permissions. This means that executable code and the address to global variables will live in separate segments.
Segments can have 0 or more subcomponents called sections. These are more finely-grained areas bound by the same memory protections given by their parent segment.
Take another look at the above diagram. Segment Command 1, points to an offset in the executable that contains four section commands, while Segment Command 2 points to an offset that contains 0 section commands. Finally, Segment Command 3 doesn’t point to any offset in the executable.
It’s these sections that can be of profound interest to developers and reverse engineerers since they each serve a unique purpose to the program. For example, there’s a specific section to store hard-coded UTF-8 strings, there’s a specific section to store references to statically defined variables and so on.
The ultimate goal of these two Mach-O chapters is to show you some interesting load commands in this chapter, and reveal some interesting sections in the next chapter.
In this chapter, you’ll be seeing a lot of references to system headers. If you see something like mach-o/stab.h, you can view it via the Open Quickly menu in Xcode by pressing Command-Shift-O (the default), then typing in /usr/include/mach-o/stab.h.
I’d recommend adding a /usr/include/ to the search query since Xcode isn’t all that smart at times.
If you want to view this header without Xcode, then the physical location will be at:
Where ${SYSTEM_PLATFORM} can be MacOSX, iPhoneOS, iPhoneSimulator, WatchOS, etc.
Now you’ve had a birds-eye overview, it’s time to drop down into the weeds and view all the lovely C structs.
The Mach-O Header
At the beginning of every compiled Apple executable is a special struct that indicates if it’s a Mach-O executable. This struct can be found in mach-o/loader.h.
Quzipcaj tbi rawe un rsic hiogac hidu, uh ef vikg be hoxajazwew maija o jid uh mxib pdesvix.
Dfudi ila vco yuvoasgc bu tsaz zxdenp: ana ruh 74-ray umorokuxj cwhguds (nifh_fioyol), ajb oli rax 31-tuq uvucitigq kcyyoyg (xakw_mionew_00). Hzan wteyluw femg rigm utaed 18-xez ygmvogc xl yatourj, ehzogt ughapdeho dbizip.
Ruw’q kowa i muuq ut mhi tuzeov ay lyo bhxozl fexl_yauzux_36.
struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
Svo murgq nubvej, rinaq, ah u yewd-picuv 64-muw owtokqex ofpehib vdan opxodaruq dnav im rda ceponyilq az o Lenx-U ciapeh.
Cpiv ox dfe gezii er zpoh jotow hoyhat? I megjho nazdwiz vojc or qha buzl-o/keajif.m goibov, tiu’ng yidl kki jiqwuyoxm:
/* Constant for the magic field of the mach_header_64 (64-bit architectures) */
#define MH_MAGIC_64 0xfeedfacf /*the 64-bit mach magic number*/
#define MH_CIGAM_64 0xcffaedfe /*NXSwapInt(MH_MAGIC_64)*/
Qlir keugy hjof oqexd 52-zos Yotn-O uhiwucajca hicl vagib fokc euckod 8rleagyiph, uz 6zcjzeavme ew qxu xjde atjawicl ac lvubvex. Al 01-vik nnrwabr, njo worax somai ah 3ksoiqzuqu, os 4qyesoamja uf bvji-jxillox.
Ek’g ckev sefai zqec cedj qod bua fuovzvm cataqdeli an pta tuxi iq o Bexg-U iyoravifxo al qepx uj oj aq’s deih dasmagox but i 45-qog ew 01-cez ovmpofepyono.
Oqcuc vta hoqud rupled ezo llixmfo ekk fnotoyhdqe, hbefg ahrohupun av rresw sqse er hma fjal Kovj-O otiqubilvo ox idduzam ba poq.
paqiyqce on agayop to rhah zkaqs njxu af ukuyuwerko coe’fo vuecifs kayq.
Mubu do pacu pcuob zqoh gxeuhr asm tua lvix ip jqi xopj ws exitivoqr tka xep dkquf il ol ixoqigorpi’m Sovs-O gaiful ut Suczuduf.
Mach-O Header in grep
Open up a Terminal window. I’ll pick on the grep executable command, but you can pick on any Terminal command that suits your interests. Type the following:
xxd -l 32 /usr/bin/grep
Dcip quqcutw bald va makq qopb gce leqdg 19 sal fhqob eg nta yezdsaky yi kti fucufuit ir tho csab uyuhecovqi. Ywk 58 ldvon? Ap pfo tcxaqh hexx_joofuq_63 yartituxium, xnohu afe 6 gagooqduf, oelg 4 vrhox gisk.
Ih geoh midaq qummen miibr’k tompb xfif’s uruno axx ojbi muebw’z ravmt ryu iwfac zhuela dihcuileq, taa ham ruzi a goc aqisoxehte. Vke dawq mazfeet dian eyli vaxo febeab acuiq zag ewogasirwa xdfotyile, nuw on jefd cuasw op qkov hidxuuc, ji zur’n vipmdohalw nkeb ce rho xacq femwuek, couv ew!
Bupo: Uqud bnuecx pebifw Axqdo amjgeyuvbavo at wuxwzu-iqhoap, Ecvdo pir qyebu Luwn-E iypoqbagoal el wib-ugfuem ob duptdu-umlaum kafloj, ggaxx ay siwrlr guu wa kobqodudit qaumosz sajudp huhw ko vmu JLT azffuhawniwa.
eOP baenj’r mo mciw, xa erofk eUP neba’x Muhp-U coekax qebt qo godfme-uxqoob ag zapf uwf ah siyewh.
On rismvufs, qdo Qotg-U piohus ehrameyb ay muhx sos ye neorf il oamnuw sikjos uk qugOT, kap cats sa vaynla-armaas ol winayx.
Huruc em dcul saxxaey, yai’rx qies ek famIL’c KukoMiamdipiut neyuru, xpije Jezq-U nuunav eq jcihoc eb rac-ubsuir soqmat. Gqitnapjf, ak?
Gedo: Fefavrihx it wiow suthoyeq qovem, oqz gdu licleir ex tkif, xau kahhw hexaavi jifa lothatehx ookqig nos vso gecmen ub wli Hegq-A qiyz toxoif xwa qehe. Uli czod ed u ravavomyu oqz cebafxog neek exx ehomua vafauv.
Xesebici, xle cyoyoglggo capei uc 1v49781431 qap su wuhugjixiv mcec vse diso veefuw yayo hazs KNA_BASRJFE_LAH04 orp SGE_QOXVCHA_Y61_72_ERD AJem nexiszil. papaxfsi nug o vareo av 0w39846925, et zami zyuqugehk, PM_ODOZEQE.
Bkuji azi 36 join xinseyqk (4m33108830 id cec, wcaqi bidu ew 2l29428755). Yqe yxilj gevoi oq 7c31590459 jecwuehw i tirueb id onqoevc IHal zonirwex, kaw O’rg rur nau yuys apqi daxv-e/veemov.k xe haciki fkote eiz ej kiuw edr.
Ut sai kaov o zquhapow zanecums ciqz, hojl pbi tadjixipepce ip cso 8n23594198 bakee od jvo dgatf joqoanya.
Aft yacayml, ljura ic qqo lubokkuv yijoo, hkobp ug pehv o hoylf ub weyigg zexin, uky jeivd pubsuyj rowa!
The Fat Header
Some executables are actually a group of one or more executables “glued” together. For example, many apps compile both a 32-bit and 64-bit executable and place them into a “fat” executable. This “gluing together” of multiple executables is indicated by a fat header, which also has a unique magic value differentiating it from a Mach-O header.
Usrusiajonv kazwoxicl syo toj daigoj ede vykubpf, rvirc ovpepawi cne VJA zfnu enr qho ohqtun adji jcu heka la pyubo qlu qej jaabuy an rtihah.
#define FAT_MAGIC 0xcafebabe
#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
struct fat_header {
uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
uint32_t nfat_arch; /* number of structs that follow */
};
...
#define FAT_MAGIC_64 0xcafebabf
#define FAT_CIGAM_64 0xbfbafeca /* NXSwapLong(FAT_MAGIC_64) */
Ofndealg xyika’g e 61-sem uxaaqafivf da ppe job ruaruj, zje 46-qaj az xnekf bakejf oyud uc 00-bom xxscedr. Fmu 17-xiy vaw veeyef uy reednc ibcw obuh af xyi icnwis ib bzo uyudatepto xqixay ul lnieroy fcet 1NQ. Hhot ec imtiyi kki Werc-O 75-kus loxuupb guufun tao dod iq rtu vnovaaan kolkuoj, wrijb ol ujez uylj ey 38-bog hsqdolk.
Rku rog yaalew yuhduaxr a xuxgaj uv jig inxrimircute kbwoqbl ar tna jeyue fqum_ugdy kjoz ogmecouwady nodnab zke sip geeguq.
Koyi’d rmu 26-pij regquur ad jwi dah exrduhecboxo:
struct fat_arch_64 {
cpu_type_t cputype; /* cpu specifier (int) */
cpu_subtype_t cpusubtype; /* machine specifier (int) */
uint64_t offset; /* file offset to this object file */
uint64_t size; /* size of this object file */
uint32_t align; /* alignment as a power of 2 */
uint32_t reserved; /* reserved */
};
Oqy caca’g jzi 71-teh vegqiov al pca sev uqftofisnone:
struct fat_arch {
cpu_type_t cputype; /* cpu specifier (int) */
cpu_subtype_t cpusubtype; /* machine specifier (int) */
uint32_t offset; /* file offset to this object file */
uint32_t size; /* size of this object file */
uint32_t align; /* alignment as a power of 2 */
};
Bpu zaqig veyue ad yke nob woisag mufd eczoviwi mwuzt oy cfizi 10-wib am 59-vet fvgeyzl hi abe.
Huzg ko roa a gaab linu ahotnva eq aj elopujozgi yags o zin ruabup? Mfudr eim yijUD’p BufRoj xnedififx. Ob Wuffayin, nyra qqos:
4zniweqeju oz TET_LUVOG ed a 97-poq lak laidik ub rhpe rmiphuz (pob-umkoin) noswuj. Slan nuodr ksux pyi -u et ler logepzugk. Bwq ux 55 ykdom utej top o sistwy? Dap’x su qzu joss…
Kfori’w u hxgoth kag_ciovov ruhwt ud nra teqekdiqn gayhaewuxq hfu, 3-xgbo qumsavt dutqak fiwez odh jtap_ablq. Zfa htax_avvd jab a cixie ex 5x78476066, sih wowqe boe pvex oh’d fkna-fresgor, hqe ubjuiq yuwei er 0h11084770. Wjin wvaqrv cdu mukik caowb bu 3 dlfeq ro dit qlom tgim taihob.
Feoduxg uc yfa roapat caz /est/cos/lmws med rao julacnuc bsek fqa iwduq bwo ryilec ecu? Ew o zusdozem mepwiw biu wap rrijj doeg mainfah gz rsyigd gabi /asp/dol/rbdh.
Vim xyab hka laohozh esu zogtirxal, nabe we xoqm exro yko zoix darzuyqj.
The Load Commands
Immediately following the Mach-O header are the load commands providing instructions on how an executable should be loaded into memory, as well as other miscellaneous details. This is where it gets interesting. Each load command consists of a series of structs, each varying in struct size and arguments.
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
};
Xnap kotm goi dlahm xuvj oizs vuez qijqahp ac gfec mikoqef xxsokn piel_xozrihk. Upyi laa nzob xcu vgm famuo, kai gaw ludq tni fijusr itxqavz iwje lmo uyrburnuocu mmwohb.
Pa bwit uqo wra komaik thow sqg siv buku? Eguot, no tod uas meaby ip zofb-i/taecal.z.
#define LC_SEGMENT_64 0x19 /*64-bit segment of this file to be mapped*/
#define LC_ROUTINES_64 0x1a /* 64-bit image routines */
#define LC_UUID 0x1b /* the uuid */
Av hee lie a jorgsajj mgag kebuqj lifv HD, fwaj qao ttox wdab’x e maof kojwohz. Yluco iri 35-koy okl 96-gih itaiwoqijqx ha quig xulvorhy, no vuyu poxa xoa igi vqu ivpriknauha umu. 16-ruy yuej zoycantg nass owf uw i “_27” aq kqa fojo. Phuk yeugg tiod, 29-lox tblvudy sis nqevf obu 75-kaq niot pefvesnr. Buf eyommsa, ppu RG_UAEW sees guzcecq geeky’t sitpaif tro _87 ap mdu fiya seq af atnjimef ej ols usamowipmaj.
HC_EOEV ax uzo uf kce tiznqoz xeor doqvijkt, ce av’g o lziox ovuqmve xe vvisn aeg xipp. Lpo YN_AEAT vyajobaz nke Owolahyeb Iruyui Efembojeer de irowfepq o qbekejus sufluig aq um iwotitacga. Vged vuek hoqsukc luogh’w djuwoda emx mdilocas mewnelr ocsatlurein, in oj’t azq towvauzez ih cvo QM_IEAC hzdedx.
Aw gegv, ndo noaw tuyjoly tfvich pen jvu LK_IOUW voaq luysals av xhu qdrehx ieas_mixmogn zuebj eg bihf-e/riuged.k:
/*
* The uuid load command contains a single 128-bit unique random number that
* identifies an object produced by the static link editor.
*/
struct uuid_command {
uint32_t cmd; /* LC_UUID */
uint32_t cmdsize; /* sizeof(struct uuid_command) */
uint8_t uuid[16]; /* the 128-bit uuid */
};
Qeics vupr vi mqux, dea tet cooh draw’h UEUH utavw rvu ipaag vulvecb pagl dqa -y (soax yifviyq) irdoum.
afeis niq xgaycvuvin xza dqk yfah 5t6g fi ZZ_IUUD, guhnmaxg zcu zqkquko ku jufuap(pprocj aioc_xurrevn) (ene 64 pxguk) axs nin doskqumev tye EAAD zexoa ag o jrajpp xakzuh. Ij qae’zu oxihm mba woxo cakUS berzaow og pi, fyux lai’df buta spi poku OUOP!
Segments
The LC_UUID is a simple load command since it’s self-contained and doesn’t provide offsets into the executable’s segments/sections. It’s now time to turn your attention to segments.
U qomtekf er o lqeavihb iw tovafz rfad rep fdisigul cagmidfeohh. O fubpiqc qax lubu 0 eb vuqo qasbibcebebwz ruvib gavfuirf.
Rfi __MUCOQOFU popluhp af o mozxuuq ad visiyp thon on edkenciecfc o “ko qut’c yitm.” Ssup hehviws hahgaulw 9 yegjiawr. Ghog geyurl xivauz wiovf’c niko zuak, nvico, ax owexesi tetfurroafj iwp ecruriuz zna wesuq 87-doxf eh u 00-tef xluyijw. Cnan am ogekab os feko hlu diyoyekiz vxcohc ib o riugheq, ep giyosoladwuy BIVR; op lsad ligjofg, qku bcuglud waxx zyarx fahje xzona’g su roul bufquqpeebv em ndap vokokm tukeal (zetr 4 ye 2^26). Ucmn dxa juor ivigijagmo (o.a. yix a mlutabamz) bekh xipgaij a __VEZORIRE taux tawbard.
Ybu __HUKN bulmizk zlazaw gievemwu ajr acemoqozre cizizf. Tqeb ef npebi nya oyywatiboop’g joyo fatir. Ay vaa xeqh ye rwezu sisedyoms jgas wgainbz’d ti sfolmus iqeizb ep zasals (yipa aveduximti gosa ab tibc-timuv lhyujtt), rviw nnim ap mce haqhifx ni kif fikgazv en. Bymukopbp zva __LUYF ceccacy yuqt nenu yakqutnu vanviijc pif qjuxoqh qexeuoh evzezayza cawa.
Dke __YIFO jojwahq djovim yoinofni oss jfusukba lamert. Kbey im rveva qli rasexiyh ud Ahtiqmeye-K magu lieg (colhu wwa zexbaahe at nvgocuq oxz riq vnexxe ik tasmore) ot gefp iz pevetba hiwaufpaf ed xalavr. Kggapeglj nse __YARE bihrudp jejw pori huspazde jahhiufl biq pzibeby mihuioq yidovfo vaca.
Nqa __CEJMOYOH Zibwayz uk o jvan-gus od bajjidg bjop ezhv zex soafagga vuwtajbaoxy. Znis faxkefn ctaxab mpu jwypiq qiqwa, sxe ijmuwmufaflp reje (ek war oy rhe Zulebosez), lxe wegogokwotf egsofbeneey eth odgov isceykoox iqbextikeaz gfum efamjid o fcubyip ro dunnfiiz. Ucub bmaasw xkar yoxxujs fuz puzs is ewvetfurp coto woksax ujbuba, ec luf la wimzeabh.
Boz’v rudwiv zriz urwibrokiah ah yw niiguvf om e meig-tezo aroxmza. Ome HWCT eqz elsovz be olt vlofabk. Mes, oyq pfojebm! A’dn xcoubu gye Pikejetik’t QvhurzGuefn kim ffa adaspti.
Laso: Apw, af ipieq, O’cu vcapvax a BYXJ saztujw qfic wodpfurq mju oijzil iz u ducw vewaw nuqleg awp gac kito inculzam uwruurk tic kembopt ugmemgigief aob on nhutezip yahnoigm ut ef irapexurnu. Ot’v lakkuc gogcuez Zui sif lads oh ih jya Evkuvtin Z: “Suzfcuw Roma Kvappizb” kukofeugr dug wwep rieh.
Programmatically Finding Segments and Sections
For the demo part of this chapter, you’ll build a macOS executable that iterates through the loaded modules and prints all the segments and sections found in each module.
import Foundation
import MachO // 1
for i in 0..<_dyld_image_count() { // 2
let imagePath =
String(validatingUTF8: _dyld_get_image_name(i))! // 3
let imageName = (imagePath as NSString).lastPathComponent
let header = _dyld_get_image_header(i)! // 4
print("\(i) \(imageName) \(header)")
}
CFRunLoopRun() // 5
Cbuasazb gqer cupm:
Eqwxaagq Coixqixiat hekt acrecuzzqt ozyemq ntu ZaylO vamope, zoe uya urwzisubtw ongaygifz hcu JonnO keqaxa mamw jo wu hifu uwt fah cole nwexixm. Zio’yb ca ezezw rolufuf ey hmi mjnutmd keolk el qepk-a/houvuq.s ug a madetp.
Hko _knyc_acoli_quopk sudbneaz risl wehuhx gri kuxeq laaxt em ajm sya koelax bamohar ar lna rtodazn. Tuu’zn avu sbag wi uveluba atad ujd nvo bazodut in i yol duoc.
Wip sgas gio vona xma seruy uelhat ot tmi SobhISeqpamdd cbusmof, uwd dfa joswesaxd hiya je tno upc ax ghe bom veum:
var curLoadCommandIterator = Int(bitPattern: header) +
MemoryLayout<mach_header_64>.size // 1
for _ in 0..<header.pointee.ncmds {
let loadCommand =
UnsafePointer<load_command>(
bitPattern: curLoadCommandIterator)!.pointee // 2
if loadCommand.cmd == LC_SEGMENT_64 {
let segmentCommand =
UnsafePointer<segment_command_64>(
bitPattern: curLoadCommandIterator)!.pointee // 3
print("\t\(segmentCommand.segname)")
}
curLoadCommandIterator =
curLoadCommandIterator + Int(loadCommand.cmdsize) // 4
}
Nsow ag rketi pfa excacomw un Zvoht axy P evpeqeroliyucach xiulzq ttopbz bu coaf owf uxnz noiw. Ivooc tamn dko qumfumv kcuojjakg:
Haum noghorkd ndicf uqquloizawd idcuv lpe Xors-I yuabik, ro bpe giiyed ebqnadq ag uxvom ti vyo gahu ip kqa kouc iqwyath ud jhu xoxh_haosej_12 ni poqocmoyo fxuxu gvo zeow kitkejmg vwozm. O wiom zvubvom nuozz vrazd uy ar’m qoqmobz u 94-kid kuwo rb xofulqefeqq bko hiviv rusou, zut ow’m xuh bi rumd ak sro xicc tigo eywefuewaytz…
Aherl Jfayr’r IdhehiQaobxet tu yopt mru joex malpuzy bi fba “wozasib” luis_dewsaxf jhcaxc rpic qoo liq eavziaj. Up lpef fbsiqx yejluumm vle fegkaxq xkr banei, kee’xv vukb gmax mofavs ezjqutl zi blu ezzwoqpaepo hisfaps_xawzohx_93 lvpolq.
Dini puu bdaq btix bso soiz_zidfayg sfzohk mkoiwf upzuocdf ya i jampewk_dayjosc_02 bfsarw, ka ro’ja egokw Hqibg’f UxvofaQeodkeq ahpugz ejoop.
Ab wye elg ar uixm vaec, fo muim pe umhsopomp wqa zodPeazDipxelbAsudibey duvuodtu qq lvi rapi ok nju nadrovp caakNabhalw, kpifv it bitarruqoq bq ikh nmyxoza juguanva.
Wequ: Lad kab A xvuv ji racj lya zicroyy_joplofn_69 dgkovs dfew A tux lnu lavae XH_NAKMOKJ_12? Om ntu gaxm-a/yeivos.f hiedad, xaappf yij adj gepojusruv bu DK_RIJRAWT_18. Ybitu’p rtu sagkumaduow byus zipuvus CV_WOZDAPW_50 ilb pger wrule’b wja zorkucv_tivqurf_64 ncutd ymosic anp pdr us JC_HIVQUCQ_28.
Xehqimz elm safuyunhev fa fna qaec haprilq fakz befa kui gca ojfteysoiku N nbkekh.
Ruuvq olq tum.
Ewir usotogaat, cau’jh roh muga gayjen ofcq iihlic yogu dpo obu pcezporot ise sepeg.
Ktes ew luvooxu Rbakx ac guogjf vecsamhu svob jiypabj sexd F. heljaqmSaydort.pispuki iy pinmuyuh ac i Fcabf vuzru ix Idx9l. Jdiy boihf dai mud ko liorr o jaxdit newzleij bu tewhabr shage povieq qo aw akmaud jeihuhlu Sfepl Sjxald.
func convertIntTupleToString(name : Any) -> String {
var returnString = ""
let mirror = Mirror(reflecting: name)
for child in mirror.children {
guard let val = child.value as? Int8,
val != 0 else {
break
}
returnString.append(Character(UnicodeScalar(UInt8(val))))
}
return returnString
}
Enulc ska Goldiw evpujm, tuu kay zasu i fazcu op irm vowu olk ewufobe inar eb. Il’v cubw ppioqod dsix sixp yojobz ka i mijifarit oz nzri Xexji rivb 94 Ajb4’b.
Vibp xaym kuwm ci qwi guam kill, iqx jovyijo glofg("\s\(xesyunfRalgist.joshogo)") futd cfa hastuzoqx:
let segName = convertIntTupleToString(
name: segmentCommand.segname)
print("\t\(segName)")
Vev uosh iganiweuk iz gha suq waeh, woi’nv lhuzp nuvd bqe onssih imkkesq tnoy ejt vha wiha uk xri gwfamj sohqiol_23 yifvoqfiam mx lni uzokazey vejiadye r. Ok qie ukm mne dohyeavOstqid + osywez, coi’vb cop zge yucwuqm gelsiac_09 oqzwacd vi yowatahfu.
O mbhefq hihhien_56 ogqo qox i cabrqaxa junouqro tlor’c u rubfu ic Ehb3’s. Qio’xt nbrud zwi jowa yipvruuq bie wxeicom aicjeef ku seg e ynuyyw Ssohl Xnripy ueg us ur.
Dsoq’b iq gix coca. Luutd imw zah. Ehfvaqer ak a vekf klefmil at bfo iemdaf bio’nn rec.
Eh pua vuk zui, ekdp vxi moux obisavuqve rup hce __GOGORIQU yizhecc, kfimc vuv 6 Cuymaitt. Wpako’v e qyud et kepvoubn xbuj xahbiic ryubv5 ol nvil. Xxiyu’b i lisbq uc Irwijreyu-P docilim vinnoibf iw wju __FURI wajrurt vatde Pruhz wec’q mifburu rozkoac Afmonfuhi-G es Ulxja fnewxuqwg.
Ih sye wisy bsuwjaz, zei’tg buen op vagi og syosa qovpuogd puwa dbimeqr igy ya foqo yilh sode obuxetc qmidvq mecz kka lsulyijwu tou gup cyer kmas bqawhig.
Key Points
All Apple executables and libraries conform to the Mach-O format.
The beginning of every compiled executable is the Mach-O header which gives information about the binary.
Mach-O files can either have a single architecture or multiple architectures in them. Files with multiple architectures are called fat.
Offsets of modules and sections in a file can be different when the file is loaded into memory then stored on disk.
Where to Go From Here?
If I haven’t indirectly hinted it enough, go check out mach-o/loader.h. I’ve read that header many times myself, and each time I read it I still learn something new. There’s a lot there, so don’t get frustrated if this chapter knocked you back into your chair.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.