Dear viewer, these subtitles were generated by a machine via the service YouTube and therefore are (very) buggy. If you are capable, please help us to create good quality subtitles: https://c3subtitles.de/talk/2563 Thanks!
[Music]
good morning welcome back on the milway
stage for the second talk on day
three and uh we welcome here our speaker
garan and he will talk about
demystifying
M uh please give him a warm welcome and
enjoy the
talk howdy everyone can hear me cool so
let's start with just who I am I am Gary
again I work on an iOS cyber security
framework over in States and uh yeah I'm
not this isn't too important though uh
let's talk about what we're going to
talk about so first going to look at
what is Mao and why you should maybe
look at it if you want to then we're
going to go into the deep dive into the
file format and like the specification
for it and then end with a little code
example about how you could parse a MAO
file to get some information from it so
first Mao is the executable file format
for Darwin systems thanks iOS Mac OS
tvos all of those systems um it's very
similar to eelf if you've ever used that
for Linux but it's a bit different it's
an architecture independent file format
and essentially any IOS app or Macos app
uh that you create or want to reverse
engineer or look at will end up as this
file format uh generally speaking on the
device or on your uh on your machine so
there's a few reasons why you might want
want to look at these files first is if
you want to read executables at runtime
such as doing meta programming on your
own code or if you want to do Integrity
checks on your own code uh or maybe you
want to do something like Freda and
install trampolines on other people's
code and that requires you know being
able to parse through these kind of
files Uh custom build tooling so if you
want to uh you know inject data into
your executables in specific parts of
the uh and parts of the um of the
segment so that you can have like the
loader automatically map data really
quickly for you
or you could have special hashes for
integrity checks inside your executable
files uh any disassembly or reverse
engineering you're going to have to look
at these things like for example you
want to see what Apple code looks like a
really good way to do that is to load
one of these files by linking the dialab
into memory and then just dumping the
this executable file and disassembling
it yourself so you can see what what's
under the hood uh for these types of
system libraries that Apple usually
hides pretty well um so yeah those are
various reasons why you might want to
look at these files and how you would
get to them
so uh it's a binary format so as we go
through we're going to fill in just this
block of bytes to show what the
structure of the file looks like and how
you might get to various parts of it um
so first we have to talk about what are
called fat binaries so fat binaries are
essentially a way to contain multiple
executables of different architectures
in the same file so essentially you have
like a program and you want it to have
x86 and r64 instructions on it so you
can run it or maybe 32bit and 64 bit
applications on the same space uh you
can just put them right next to each
other uh and once it's loaded it only
actually loads the architecture for the
current machine so the loader will know
not to pick up the entire file but only
the one for the current machine you're
on um and you can have a fat binary that
is only one architecture but uh you know
the existence of the fat header is very
optional you know it's not required but
it is possible for it to be uh there
even if there's only one architecture uh
it is important to note that these are
kind of going away fat binaries were
used for a very long time you still use
them on uh applications you find on the
internet for Mac but most iOS
applications do not use fat binaries
anymore because there was a conflict in
the iOS 16 arm 64 simulator uh that made
it so that they couldn't essentially
there was a naming conflict so they had
to reintroduce XC Frameworks which are
essentially a better version of this but
yeah this is a way that you can have one
file repr multiple architectures and not
have to worry about like giving people
uh the x86 or the arm 64 version um so a
fat binary starts with a fat header uh
you can Define these definitions I'll
list the headers as we go along they're
all in the system headers for iOS and
Mac OS and all that uh if the file is a
fat binary you'll start with a fat
header and you check that by looking at
the magic number there uh it gives you
both fat magic and fat saam so you can
determine the Indian
of the data that you're about to look at
that's very important for the fat header
because it may be produced on a machine
completely different like for example
you could be reading this on iOS but it
was produced on an x86 64 uh Intel
machine like a Mac and so you use that
to determine Indi so you can actually
read the header correctly uh it then
tells you the type of the uh the header
tells you how many AR architectures
there are each architecture tells you
the CPU type and subtype that it belongs
to as well as the offset into the file
that architecture belongs and then it
also tells you the size and the
alignment uh the size will always be an
integer multiple of the underlying page
size of that architecture right so I
think for arm 64 that's 512 bytes or
yeah I think so um yeah and then of
course it's a 64-bit variant uh the
there's also apis you can use in
machine. to determine which CPU type
belongs on either your machine or if you
want to try and like grade it's the same
thing that operating system uses to
choose which architecture to load but
it'll grade slices and then determine
which one to load you can they have
those uh available in machine. so if
you're like opening a framework up um on
disk and you want to check which one to
use you can use those uh to make sure
you're loading the correct one or at
least looking at the correct
one um you can use lipo and O tool these
are two little command line utilities
that come uh in the box and you can use
them to kind of see fat
headers and also lipo lets you inject or
remove various slices into a universal
or fat binary um you can see here we can
see the header and all the type of stuff
within
it so yeah so this is the structure at
this point we have a fat header two fat
architectures you know let's say this is
32-bit 64-bit and then we have two Mach
o objects which Define executables uh at
the same time theoretically these are
two programs just different architect
same program two
architectures so a MAO object is then
kind of the way that if you are familiar
with how like segmentation originally
worked in memory for operating systems
it's kind of this influences how this
works here uh the object is split into
segments which are effectively memory
ranges that will exist in virtual memory
when your program is running uh each of
those have their own memory protections
and a space that the loader will then
map into your process's virtual memory
space um they all begin with the header
and they are followed by a list of load
commands load commands Define everything
else about the file so once you read
through the load commands you know where
everything is um the SE each segment can
have you know sections inside of it so
that you can have a little more
information on where things are and uh
we'll go through the definition of a lot
of these uh going through we're not
going to look at every segment in every
section because uh technically there's
like you can make your own segments in
your own sections there's also just a
lot of them so uh you can use oool to
like look through these on a various
files that you already have um and yeah
so if we look at some common segments so
you these probably should be familiar uh
page
zero is a n pointer trap on Mac uh I
know different operator the different
os's handle a little differently but on
Darwin they actually don't map page zero
they just claim it to have no
protections at all which that gives you
your nice behavior where if you you know
try to do reference an old pointer it
crashes instead of just doing whatever
uh and so there might be a change to
this I remember reading somewhere that
they were looking at actually mapping it
not like allocating memory for it just
mapping it because apparently there's a
null pointer exploit uh because of the
fact that it's not actually mapped um
and for 64-bit applications uh um this
doesn't just map the first page of the
the process space it also maps all of
32-bit application space so on 64bit
apps on Darwin you cannot dreference a
32-bit pointer uh it also means you
can't load a 32-bit applica uh Library
into 64-bit space so that's a neat
little thing they did there um the teex
segment is usually the first segment uh
it is the first segment and it always
contains the mock header the reason it
does that is so that when you're code
signing your stuff it the code sign only
looks at the Tex segment uh so whenever
you have like signed executables from
the IOS app store or whatever it's just
looking at that first Tex segment that's
the only thing in the executable that
gets code signed that also means that if
you have um data that you want to be
code signed and like have integrity
protection on it from like apple systems
you can put it in the tech segment you
know you can uh either via a C string or
you can actually just explicitly tell
the compiler hey put this in the uh Tech
segment uh watch out the so uh it means
it'll also be executable so I don't know
take your risk there um data that's
where like all your common data mutable
mutable state will be uh data
const um is a bit uh interesting uh so
yeah the way these protections work is
uh left is the initial protection so you
can see on text it's read execute and
then right is Max protections so that's
what you can theoretically upgrade the
segment to so like on Mac you can make
your Tex segment writable uh data const
is a bit weird so data const it was a
section that was added because
originally there was no ConEd data on
Darwin or any Mac system like that they
just had like a section in data that was
assumed const uh for like the global
offset table that isn't great because
you can just go in and like for example
an attacker can go in and change the
global offset table and then suddenly
all your calls to any system functions
are can be easily detoured um they kind
of fix this by adding data const which
is also not const but instead what
happens is it starts out as read write
then dld after it's done Dynamic linking
will make it read only but you can
always just go back and make it writable
again because it has that Max
protections and D is in user space so
it's not const but it's con it's by
default though const however there is a
change Happening Here in iOS 17 they are
releasing which I should be releasing in
like a month or two they added this SG
read only flag so this flag when added
to a Mac a mock header will have the uh
it will have the kernel if make it
actually read only after d is done um if
you don't want that behavior for your
executable you can remove the flag but
that's something you notice so if you're
or maybe if you're trying to hook
another executable uh look for that flag
cuz it might break all your hooks um but
that that it will actually be ConEd or
closer to con and iOS
17 um and then there you have things
like you know uh your Global off step
table your objectiv see class list and
con data that kind of stuff and then
link edit is at the end of most
executables and it's just Linker data uh
it's where dold will get its uh
operation codes uh because dld has its
own special op codes that are used to
Define how to update the uh various
Dynamic linking in the
file so yeah so let's look at what an
actual mock header looks like uh first
you have the magic number to make sure
you know it is correct uh like similarly
it has an indianess check in it so you
can check if it's MH magic or
mham uh and it again contains the
architecture info the file type we'll
look at those in just a second um it
also contains the number of load
commands and the size of the
entire list of commands and that's
because uh load commands are variable
size which we'll get into in a bit uh
that has some annoying implications but
yeah uh and then it also has some flags
on it that's where that SG read only
thing this is where this would be uh
there's a lot of flags and they're
mostly used by the Linker but you know
here are some ones that you'll probably
see if you look poke around no unds
means that it's fully linked and doesn't
need to be dynamically linked um Pi
every executable should have Pi that
means position independent don't write
position dependent executables that's
really not great um a has Objective C
just means it has objective c dld means
use dld and two Lev is a feature where
dld will create name spaces for the
libraries that you link against so that
there's not naming collisions between
symbols um I think that's on by default
but I don't quote
me uh here are the various file types
that are known um presumably Apple might
have some more that they just don't
publicly Define uh object that's that's
like when you compile a C file it's an
intermediate object representation of
machine code uh execute is just an
executable fvm lib is an obsolete uh VM
file uh for like in the old days uh core
is for when you get core dumps so if you
ever want to investigate core dumps
those are also Moco files and that's how
like apple gets those crash reports on
them uh preload is also an obsolete one
dib dib is how you you know determine a
dynamic library that wants to be loaded
uh these have to be loaded so like think
um I don't know object lib objective c.
diib or whatever those are all dib files
dib executables they can only be loaded
via load commands inside another
executable or through an explicit call
to DL open inside a running process um
dial Linker is a special executable file
that is a dynamic Linker you can make
your own and have uh executable programs
point to a unique Dynamic Linker if you
don't want to use dld for whatever
reason um MH bundle that one is for
resource bundles those actually can only
be opened via bundle apis in code uh you
can't open them the via the loader
directly uh dsim is for dsim files and
uh dilip stub that one's an old one it's
not really used anymore essentially
Apple doesn't want to give out its
source code and xcode so the way they do
that they used to do that was we to
create empty executable files that just
had symbol tables so you could say like
oh yes link me to this diib and then on
Mac on your development machine it would
have no code but it would link correctly
and then on the phone it would work
they've replaced that with this new text
Bas definition file which you won't get
into so you probably won't see that
around uh if you wanted if you wanted to
try and poke around xcode to see what
API are available you'll see a lot of
these text based definition files and
some of these dib stubs which are just
essentially just empty files and lists
of names
um and yeah and then kex bundles for Mac
OS kernel
extensions uh so yes this is kind of
what we're looking at now each
individual object has these load
commands and we know that there's
segments somewhere spread about but we
don't know where they are yet we don't
know how big they are and we don't know
what kind of memory protections they
have uh but we can figure that out by
looking at but we do know where these
load commands are and that's where we're
going to find out all this extra
information so a load command defines
the various segments and sections and
also other various things such as OS
version and name and all types of stuff
there's a lot of load commands um there
is uh there they are a variable size you
can see the base load command is just a
type and a size um that also means that
you can't index into load commands you
have to go one by one and look at each
individual load command as you go
through so whenever you're parsing one
of these things try and make it to where
you only have to do it once so you don't
have to do an ins squared algorithm of
going over and over again um and we're
going to look at a few load commands
just but they're all very different uh
there are uh about 47 I think load
commands currently supported or at least
publicly supported by Apple uh on Darwin
systems however you could make your own
uh and you could also presumably make if
you make your own Dynamic Linker you
could also use them
somehow um so we'll look at a few one a
few common ones but if you want an
exhaustive list I think loader .h has a
most of them and um you could also look
at Jonathan Levan has a good list that's
pretty exhaustive of which ones are
actually used um so first look at
probably one of the more important ones
which is the segment command there's
64-bit versions of a lot of these
commands which is underscore
64 uh you'll see this pattern a lot when
looking at load commands where it's
basically just C style inheritance where
you have uh it's the same as the load
command in the first two fields and then
just adds a bunch of stuff so first it
starts with the segment name which is a
16 byte uh string uh that's where you
get things like text Data data cont so
that's where you'll be looking for those
things if you're looking for a specific
segment then you get the address and
size in memory note that if you're
reading from file these are zero or at
least I wouldn't trust the values if you
find them here uh these are are Lo are
provided by the loader as it loads it
into process space so if you're reading
it off a file this will probably be zero
or maybe some other garbage value and if
you're rting out file you're going to
want to use file offset and file size
that tell you where in the file and how
big it is um I also think there might be
a potential difference between file size
and VM size as I think VM size will
always be page aligned well I don't know
if file size is guaranteed to be
that uh then you have your maximum and
initial memory protections uh and then
of course you have something called
sections so each segment is allowed to
Define sections within itself uh the
sections are more logical than
necessarily physical but they uh are
there to help Define and separate the
segment into logical uh sections uh if
the insect flag is greater than zero
then that's how you know there will be
that many sections immediately after
this segment command so there could be
it's immediately after the command it's
not located somewhere else it's just
right after it um and that's where you
get these section commands uh a section
has a 16 byte name as well uh for and
also you can see it has this the address
that it's currently located at the size
of bytes in the section as well as the
offset similarly address may not be
filled if you're reading it from disk
use offset uh the alignment uh uh the
relocation entries all that like kind of
symbol stuff uh the flags are pretty uh
interesting but essentially the eight uh
LSB uh determines the type so for
example you could have a section of C
string literals this is very helpful
when you're trying to parse because it
tells you how to actually interpret the
section so like a C string literal
section is literally a list of null
terminated C strings so when you know
where that section is you can just build
an array of strings pretty easily off of
it there's a very there's a various
types you can find them in
loader. uh the other bits are used to
for various attributes such as you could
say it's a debug section which means it
has debug symbols included inside it uh
and also sections are naive in that
there is no checking to make sure
sections uh make sense you can have SE
the bounds of a section are not in uh
guaranteed to overlap or not overlap
with any other section they're not
guaranteed to actually be ordered uh
there's no checking it just it's B it's
just off of good faith so there might be
an exploit there I don't know maybe
y'all can think of it but there is like
there is no checking there you can
probably come up with some things that
[ __ ] with sections or at least [ __ ] with
your disassembler disassem assembler um
you can also create custom sections
inside a segment by using incode you can
just say this attribute like you know
put this section in this segment this is
also how if you wanted to put data in
your text segment you could create a
custom section uh put the data in there
and then it'll get code signed and then
you can also uh create a section via a
file by using this Linker command to
LD um yeah another load command would be
LC main this literally just tells us
where the main function is so if you're
ever interested in where the entry point
finding entry points can be kind kind of
hard in code luckily for executables
just look at this guy tell you exactly
where it is um yeah uh another one is di
Linker this actually specifies the
dynamic Linker that the operating system
should use when uh fixing up the
executable at runtime uh usually it's
dld or Dore simulator if you're working
on simulator uh but you can always make
your own uh I don't know why you would
but you can and and you can always just
uh have your uh executable or what
executable you're investigating you can
always overwrite this load command with
your Dynamic Linker and then you're able
to then capture and get the fix UPS you
know maybe you want to see what symbols
various L uh objects want to look at or
something like
that uh and then this is probably the
other more common command you'll see is
the load command this is what loads
Dynamic libraries into your process
space um it uses this dib struct uh
inside of it which is this long thing of
various um it's just like a bunch of
data structs inside of each other it's
just nested for you uh and it has a
command and command size just tells you
where it is uh there's various versions
of this one for all the types you can
way you to import a dynamic Library such
as weekly or re-exporting and all those
things um yeah so this is the basic
structure of a mac o file you have a fat
header with various architectures after
it each of those architectures as a MCO
object that has a header themselves
followed by a list of load commands
inside of the text segment and those
load commands tell you where all of
these segments lie within the object uh
and then you can use the various things
to go through and look at the sections
and look at the various load commands as
well so to give this a little more
concrete example uh we I wrote up a
little program that will extract The
Objective C Class hierarchy from any
process any memory load any any module
loaded into process space uh and we'll
just go run through that so you can see
what it looks like um we're assuming
64-bit because I don't think Apple
supports 32bits since like 2017
2018 uh and yeah and also there's some I
removed some Arrow checkings to make
sure that it's not too uh
verbose so yeah we're going to look at
all of the even all the system modules
loaded into just a basic hello world
application and we're going to take a
look at what their Objective C Class
hierarchy is by just looking at the
executable images that uh were loaded by
the system um and for reference
Objective C only has single inheritance
and the root object is NS
object so here's our main function this
first bit here is just some way so that
it didn't take forever it's just
parallelizing it so don't worry about it
uh the first important bit is that we do
want to see every mock image loaded into
our process and we do that with do
register funk for add image what this
will do is it when we first call it it
will use this call back we give it and
call it for every single image that has
been loaded as of yet into the into the
process um that includes our own our own
image as well uh then after it is done
doing that it will go to sleep and then
anytime a new image is loaded into the
process in the future it will also call
into our call back to let us know this
happen so if you ever ever want to
monitor what uh images are being loaded
in and out of your process this is a
really good way to do that maybe you're
worried about someone injecting
themselves in there or something like
that but yeah this is a good way to do
that is to use this uh dld
API so in our callback this is what the
Callback uh signature looks like it
gives us a mock header and the slide the
slide is referring to uh address layout
space randomization essentially whenever
the OS loads you into memory it chooses
a random place to just plop you so that
it's harder to determine where your code
will be so that things like uh stack
overflows and buffer overflows are less
uh
exploitable um note that the mock header
uh here is technically a 32-bit one I
don't know why they did the API like
this but it only gives you a 32-bit one
but luckily you can just cast it to
64-bit and it works fine actually you
kind of have to um yeah so next we will
just come into here we're not going to
look at the expert hierarchy code
because it's boring uh so we'll just go
straight into the actual Macho
parsing so at the beginning here we're
just doing normal Objective C initial
initialization stuff uh this is where
you can see I'm just casting it to the
64-bit mock header you just have to
remember to do that if you're doing
things in production you would probably
you know have a pre-processor Define to
make sure you're choosing the correct uh
headers here that's actually pretty
common is just redefine all of Apple's
structs to be based off of pre-processor
definitions so they always get the
64-bit or 32-bit version um here here
we're checking that file type we only
care about dibs we're not going to look
at bundles or executables or anything
like that uh note that we don't need to
actually check for indianness because
it's loaded into our process space and
so hopefully it's the same indianness as
our process um how and also we're not
looking at the fat header because it's
also loaded into our process space we
don't need to know which architecture
we're looking at once again to reiterate
if you are load looking at fth headers
you do need to check that and if you're
looking at architectures that you're
unsure of you really should check it so
that you can swap uh yeah and then we go
to parse the binary so this is kind of
the basic iteration Loop of parsing the
binary uh first we grab the load command
which is right after the mock header so
we just take the next element after that
and cast it um then as we iterate uh we
just you know double check that our
current command as a bite location is
less than our size of
commands
um and then starting at the beginning of
the first load command uh and then to
iterate at the bottom we just you know
add the command size from each
particular command uh yeah and then you
know at the end we return nil if uh we
return true if we parsed it correctly
and all that stuff so here's that inside
of the loop uh you see this you'll
almost definitely use a switch structure
just because it's convenient because
you're going to be checking IDs of load
commands so it makes sense um so in this
first case we're going to see if it's a
dib and if it is a dib we're just going
to Gra grab its
name uh or this grabs the name of the
dib that was
loaded uh so this lets us you know keep
track of which uh processes which images
are which uh here we're grabbing the
segments of that image and trying to see
which one uh if it's a data cont section
then we move on because that's where the
Objective C class list is uh we then
iterate through all the sections so this
is a very similar structure as through
the load commands uh where we just move
past each uh section until we find The
Objective C class list uh in which case
we can then parse that uh which we can
see here uh then when we're inside The
Objective C class list this is like a
literal array of Objective C Class
objects that the runtime has already
populated with the correct data since
we're loaded into memory so because of
that uh we can actually just use the
objective c runtime functions on these
uh pointer bite values that we found in
this list uh there's a million ways you
could have done this you could have
parsed the object see class object you
could have done a lot of things I
thought this was the simplest so we just
use class get name and class get super
class to get all of the names of the
various classes we're trying to look at
um then we just you know return it uh
and yeah and that's basically the entire
parsing uh here's a here's a little test
framework I made to verify that this
worked you know and you can see from
this you can actually get a decent
amount of structural information but
this is a very simple case um here is
the shared with you
framework uh this is how they do uh this
is the framework that is used for like
uh screen sharing or uh the the activity
controller where you do like the little
shared communication stuff uh it's not
too complicated it looks like it just
has you know a little bit of radial
thing here not too many uh like clusters
as you would normally see in an
Objective C stuff um here is cloudkit it
was a bit too big but but if we zoom in
a little bit we can see uh right here
that's where all the database operations
are um you know so you can check this
out there and I wanted to do core data
but it got really it got really gnarly
let's see if I can get this video
working yeah it was it was just there
was too many things in
there but you can even see there's like
a guy freaking out in the middle I think
that's NS object and
yeah but uh yeah so that was you know
the little thing there just as a example
of what you could do with it you know
I'm sure yall are more creative than me
so you can figure out other cool stuff
um yeah so uh for resources on this uh
there are the various headers I was
referring to throughout loader fat Arch
and machine uh otol and lipo are really
helpful for working these types of files
uh and as for books Jonathan Levan has
great books on all of this in fact he
probably is the person for the
definition of he's I mean he's the
documentation for apple and he doesn't
he doesn't work there so uh OS invol
star OS internals volume one has all of
this information and more so I'd highly
recommend it if you're interested in
reverse engineering Apple systems and
yeah uh any questions
or
[Applause]
yeah all have questions
hi thank you that was very interesting
um earlier in in the talk you mentioned
about uh Apple code signing some parts
of the I think the text section yeah uh
and I think maybe I misunderstood you
but you said like it only signs the
first part uh there was something like
that so the when Apple when you code
sign to be released on the app store or
so that your Mac OS app doesn't require
them to have to like click through three
menus to be loaded uh it doesn't code
sign the entire executable it only Cod
signs the text segment so that includes
the mock header and then all your code
and then any thing you want to put in
there like C strings or whatever um they
don't do the entire executable I'm not
exactly sure why but that's currently
how it works that's also what is
encrypted by the iOS store so you can
actually if you get iOS apps downloaded
from the store there's a old
iTunes uh It app for Windows that lets
you download ipas from the App Store
directly onto a Windows PC you can
actually look at their executables and
you won't see their code because it's
encrypted but that teex segment will be
code signed and encrypted but nothing
else will
yeah so if I were to rewrite some parts
of the maos sections would I need to
resign the binary then because the sign
sign wouldn't match right yeah so if you
are using build tooling to do that you
will have to Res resign it um if you're
building locally that's not a huge issue
uh you can just use the code sign tool
on command line it does get a little
more troubling if you're trying to I
don't know break into something right um
because you don't have their
certificate uh I would say the easiest
way to fix that would be to jailbreak
the phone you're on and then you don't
have to worry about it um yeah that's
probably the easiest way to do it uh or
there might be a way to do it also using
the debugger uh however I don't know the
exact way you do that I know that Freda
is able to get away with breaking code
signing using the debugger so maybe look
at the free to Tool which is also a very
great tool for this kind of stuff thank
you
yeah uh there further
questions okay that seems not to be the
case and you now all know how these
files work and uh have fun with some and
we s Gary again
[Applause]
[Music]
again