Hello, my name is Ivan.
And in this lecture, let's shift our focus to the fascinating world of the program header table, which
offers a segment view of the binary in contrast to the section header table which we discussed earlier,
which that provides a section view primarily for static linking purposes.
The program header table, which you will learn in this lecture, serves a different purpose.
So it is utilized by the operating system and dynamic linker during the loading process of an Elf binary
into a process for execution.
The program header table enables them to locate the relevant code and make informed decisions about
what to load into the virtual memory.
And in an Elf binary, a segment encapsulates a zero or more sections.
So let's go back to the Kali machine here and.
Here we have.
Let's open the include elf dot header file.
And here, as you can see here, a segment encapsulates zero or more sections, essentially bundling
them together into a cohesive unit.
So the segments provide an execution view, making them essential for Elf for executable files, but
not executable files like Relocatable objects do not require them.
So to represent this segment, view the program header tables instruct employs program headers of type
the Elf 64 here.
As you can see here, F 64 and specifically F 64, the error.
Here.
So these are the as you can see here, this header file also has the header of the also comments to
that says that this is a program header program, segment header.
And here which this each containing various fields that provide essential information.
And here as you can see, the segment types flags, file offsets, virtual addresses, physical address,
size and file size and memory and segment alignment.
So understanding the program header table is crucial as it grants us insights into how the operating
system and dynamic linker organize and load binaries into a memory.
By examining the program headers, we can decipher the layout and composition of the binary, enabling
us to comprehend the crucial components that contribute to the binaries functionality.
In the upcoming sections, we will delve deeper into the inner workings of program headers and their
role in the loading and execution of Elf binaries.
And as we continue our exploration of the Elf format, we gain a comprehensive understanding of its
intricate structure.
This knowledge equips us with the necessary tools to dissect and analyze binaries effectively, or reverse
engineer malware and unraveling their secrets and uncovering the fascinating world of binary analysis.
Now let's.
Analyze this, files this information more deeply here.
So and I will describe each of these fields in the next.
Uh, times, uh, some of them in this lecture, some of them in next lecture.
And now we will.
Again.
Use the red elf here.
We can actually.
No, let's actually open the new tab and let's go to desktop where our Hello World program exists.
And here we have that A.out.
Let's actually run this.
And you will see that we have Hello comma world.
So here we will again use the clear red, white and segments, segments and a dot out.
And this is our compiled application.
Just a regular Hello world application.
And here we have this.
Output here.
You can see that we have the program headers section to segment mapping and.
Which in this section we are interested in this field.
So also keep you in mind that section to segment mapping at here of the rate of output, which clearly
illustrates that segments are simply a bunch of sections bundled together.
As you can see here.
And this specific section to segment mapping is typical for most Elf binaries, but you will encounter
and in.
This.
The rest of the section, we will learn the program header fields.
As you can see here, specifically the P type which we will start P type.
And we will also learn the P flags and.
So on.
So here we let's go back to the header file.
He type P flags.
We have this segments, right?
So P type P flex P offset p v adder, which is segment virtual address segment, physical address,
segment size and file, segment size in memory and segment alignment.
So let's start with the segment type here and we will also need that.
The here and perfect.
We also have this marker, which is not great, but.
Susceptible, I think.
And here let's also increase the font size a little bit so you can see better.
And this P type field, as you can see, we have two of these.
Which one is for the Elf 64 and one is for Elf 32.
As you can see here, this has several additional methods, variables.
And as you can see here, we have in 64.
After the word here.
As you can see, Elf64 error.
And here in L32 we have the just the regular word.
And here in Elf64, we have the word.
So their names may be varied depending on the structure, but.
If you look at this here, they all have the same functionality here and some description.
And this P type, which is segment type field, identifies the type of the segment and important values
for this fields include the load dynamic and p t interpreter.
And as you can see here, Interp, we have offset virtual.
Address.
Yes.
Virtual address, physical address, file size, mem size, flags and so on.
And the segments of this type load, as the name implies, are intended to be loaded into memory when
setting up the process and the size of the loadable chunk and the address to load it at are described
in the rest of the program header.
As you can see in this output, there are usually less load here and here.
Let's actually.
We have the entire peer dynamic.
And we have the Lords, the Lord of Lords here, dynamic node, node, node, renew property and so
on, which you will learn here.
And we also.
Have the flags field second field so this flags field.
Hit the flags.
The flags.
So the flags specify the runtime access permission for the segment.
And three important types of flags is the exist is t, f, x, p, f, w and the p f read or are here.
T f x flag.
Let's actually write it down here.
He.
Underscore X means that it indicates that the segment is executable and set for the code.
Segments like Rudolph displays it as an E rather than X in the flag column here.
It's actually.
You can see here HDR flag in.
Sometimes here we have R, W and E here.
So you can read this as X, so.
They are the same in reality, but rather wants to write it as E because it's actually the first word,
the first character of the executable.
So it makes the sense.
But X was as as acceptable here and finally here, which the and also the R here means the readable
and.
We have W, which is the means that segment is writable and it's normally set only for writable data
segments and never for the code segments.
And we have this R here obviously.
This means that readable segment here, as in normally the case for both code and data segments.
And the later we have this.
After flax we have PE offset pe vector.
PE pe.
After pe files SC and he mem SC here.
These fields are analogous to the C-H offset here which you saw previously.
We have this here section file offset section size in bytes and so on.
So.
You need to go back to p files here.
Yes.
So they specify the file offset at which the segment starts and the virtual address at which it is to
be loaded and the file size.
Of the segments respectively for loadable segments.
P.
V Adder here.
P.
Adder.
And R must be equal to P offset, which is typically 4096 bytes.
And on some systems it's possible to use the p addr field to specify at which address in physical memory
to load the segment.
On modern operating systems such as Linux, this field is unused and set to zero since they execute
all binaries in virtual memory.
So at first glance it may not be obvious that why there are distinct fields for the file size of the
segment.
Like if.
He files SEC and the size and memory memes.
Um, to understand this, let's recall the subsections only indicate the need to allocate some bytes
in memory, but don't actually occupy these bytes in the binary file.
So for instance, the BSS section.
Which you can't see on the shelf here, contains zero initialized data.
Since all data in this section is known to be zero anyway.
And there are no need to actually include all these zeros in the binary.
Right.
So, however, when loading the segment containing the BSS into virtual memory, all the bytes in BSS
should be allocated.
So this is possible for mem mem sec to be larger than the PE file sec.
When this happens, the loader adds the extra bytes at the end of the segment when loading the binary
and initializes them to zero.
And lastly before ending this.
Section here.
This field.
Here we have just one field left to explained.
So the p align field is analogous to the error a align filled in the section header.
It indicates the required memory alignment in bytes for the segments, just as with the Kwadril line,
an alignment value of 0 or 1 indicates that no particular alignment is required and if p align is set
to 0 or 1 then its value must be power of two and p of adder must be equal to p offset modulo p align.
And in this lecture you learned all the intricacies of the elf format.
And we have covered the format of executable header.
The section header and program header tables and contents of sections.
So that was quite an endeavor and it was worth it because now that you are familiar with the innards
of Elf binaries, you have a great foundation for learning more about binary analysis and reverse engineering.
And stay tuned for more exciting insights into format and reverse engineering and its impact on binary
analysis.
I'm waiting you in the next lecture.