Hello, this is Dr. Miller and this
is Episode fifteen point five of
Assembly.
Today, we're going to talk about
static linking and dynamic
linking, and that'll include the got
and the T.
So static linking.
Static linking provides the ability
for us to reuse code, and
when we do that, all of that code
gets placed inside of the binary
that we are building.
And so, for example, if you want to
use open SSL,
then you can include all
of the open SSL code inside of
your binary.
Now, what this does is this is going
to use more space and
then if multiple programs are going
to use that library.
So like open SSL, then
that library is going to get loaded
multiple times.
Another issue is that if you update
the library, then you have to
rebuild your entire code
to add that library in there
so we can contrast that with dynamic
linking.
So in dynamic linking, the
code is set at runtime
and this provides the ability for us
to have shared code.
And one of the things that we are
going to have with security is
address space, layout randomization.
So Asla and what
this does is every time a
library runs, it's going to
run at a different address.
And so the actual address
where that that library gets loaded
is changed by the OS.
So it's different every single time.
And this makes hacking and attacking
exploits more difficult because
the addresses aren't known
beforehand.
So this is one technique that was
used a lot, was to hard code
addresses for specific
binaries and then use those in order
to leverage when
you're doing an attack.
Now on Linux, these dynamic
libraries are called Shared Objects
or O's, and then on
Windows, they're called dynamically
linked libraries or DLs.
And then we also have a
notion of what's called absolute
code, so that is a
piece of code is loaded at a
specific address, and then
the linker or loader will actually
remap that code to a bunch of
new addresses.
And so a lot of times with old
binaries, we would see that they
actually get created all at the same
address. And then whatever binary
is loaded, first the linker, the
loader will remap it
to the new addresses so that that
code can run.
But one of the notions that we have
in Lennix is this notion of
position, independent code or pick.
And so in this, the code
doesn't actually reference an
absolute address.
And this is usually made possible
by the fact that on 64 bit
operating systems, we have the
ability to do addresses
based on the program counter.
And so then you can have things
relative to each other
in a way that makes it so it's
easy to create position, independent
code.
So the global offset table or got
so this is a table
of addresses that
points to dynamic addresses
and this will be the either the
address of a variable.
So if you create a static variable
or a function and so these
are the things that are shared
library is going to provide, it will
provide variables
are constants and will provide
functions that the programmer
can use.
And then the way this is set up is
that initially each
one of these pointers points to
the dynamic linker.
And so the first time it gets used,
the dynamic linker is going to
actually update that offset.
And then after that, it's
going to use the new updated
address instead of pointing to the
linker. So the pointer gets changed
so that every time after the first
time, it'll go faster.
And this is generally called Lezley
initialization or lazy
resolution.
We also have the procedure linking
table or plot,
and what this does is it provides a
mechanism to resolve
dynamic memory addresses.
So if I need to get the memory
address of a function,
the party has the ability
in order to do that.
And so it has those addresses of
where those
libraries are located
and so allows us to create pecan
pie code or position, independent
code or position, independent,
executable.
So one example is the Linux
dynamic loader or LDA,
and it's in LDA Esso,
and this provides us the ability
to look up different libraries.
So a couple of places that it
typically looks in is slash
lab or slash you just lib
and it uses those
absolute pass or it can use the
old library path, environment
variable.
And so if you're going to build a
binary and you don't want to put
it in usr lib or in lib
and you want to test it in your own
space, you can use the old library
path variable for that.
So here's an example.
So the first time that we call the
Put's function. So I put a couple
different examples of using
Put's, so it called it two
different times and so we can see
inside of here it's going to jump
at the puts at PLT.
And so when we do this call,
it's going to jump into the put's at
the inside
of the code and we can see that
again we're going to use RIP or
the R IP
for that.
And so we're using addresses based
on the instruction pointer
and not absolute addresses.
So we can see here that
the Put's is going to jump into
here, which then is going to jump
into a
location in memory,
and what this is, if you look inside
of here. So I just did a trace as
I was stepping through this program.
We can see that this is running the
DL runtime resolve
function inside of there.
So, again, the first time we call
it, it ends up trying to resolve
what that address is
for the function called Put's, which
is a shared library.
But then when we call it a second
time, we see again, we call puts
that TLT, it's going to do
a jump into the
location at this address.
And now we are actually in
the Put's library.
So the first time it ends up getting
to the library, I didn't put that in
the screenshot, but here
we reduce that step.
And so this is how the dynamic
linker and we'll resolve
the address of whatever function it
is that you're trying to get.
So today, we talked about static
linking and then dynamic linking
using the got and the T.
In a future lecture, we'll talk
about creating an example dynamic
library, if you have questions,
you can email me Miller at you and
Edu and you can find me on Twitter
at Milhouse 30.