Hacking Your ELF For Fun And Profit
10 May 2013
Have you ever wondered how the Linux kernel
subsys_initcall) macros work? Even after a quick
glance at their definition things might not be exactly clear:
The key to understanding what’s going on here is understanding that
__attribute__((__section__(...))) business. Normally, variables are
placed in sections like
bss. But with gcc, you can use the
to manually specify which section of the ELF (assuming you’re
compiling to ELF) you’d like that variable to live in.
Custom ELF Sections
Using custom ELF sections, you can essentially build dynamic arrays of arbitrary data at compile time. No need to modify the calling code or register your function at runtime.
We’ll walk through the Linux kernel example a little later, but first let’s look at a simple example of how this works in plain-ol’ C.
Simple Plugin Architecture
Imagine that you’re building a C program that you would like others to be able to easily extend. One way you could accomplish this is by providing a plugin system based on custom ELF sections. Maybe you want other developers to be able to add functions to permute and print out some text without having to modify your main program source code. The following types and macros should do the trick:
__attribute((__section__("my_formatters"))). That’s the
key. With this, the
REGISTER_FORMATTER macro will put functions
inside an ELF section called
my_formatters. The macro can then be
used like so:
You can then iterate over all of the functions in the
ELF section (all those that were registered with
in your main program, like so:
Note the usage of the special variables
ld, rather) includes these variables
for extra ELF sections as long as the section name will result in a
valid C variable name (e.g. it can’t start with a “.” (which is one
way to prevent these variables from being generated
automatically)). In general, the variables will be named
__stop_SECTION. I couldn’t find any formal
documentation for this feature, only a few obscure mailing list
references. If you know where the docs are, drop a comment!
In the end, the main code for your program might look something like this:
And someone could provide a plugin file like this:
Compile with this:
And you’ll get the following output when you run your program:
Linux Kernel Init Calls
Back to our original example of the Linux kernel init calls. The idea
here is to collect a bunch of different functions that correspond to
the various stages of boot into separate ELF sections so that they can
be executed in sequence, without having to modify the code that
actually calls them. At boot time, for each section, the kernel
simply takes the address of the section and starts iterating over the
functions it finds there, calling them in sequence. The code that does
that is the following three functions:
do_one_initcall, shown here:
This simply iterates over each section, and for each function found within a section, simply calls the function. It’s really pretty simple and quite elegant if you ask me.
Note that rather than relying on
gcc to emit those magical
__stop_SECTION variables, the Linux kernel
actually sets up its custom ELF sections by hand in a linker script:
If you’re curious, the call path from
start_kernel (the entry point
to the Linux kernel) to
do_initcalls is as follows:
start_kernel | `--> rest_init | `--> kernel_init | `--> do_basic_setup | `--> do_initcalls
Custom ELF sections can be useful for accumulating similar data
(function pointers, for example) at compile time. With
variables or custom linker scripts you can access the start and end of
those sections at runtime.
Now go hack some ELFs!
blog comments powered by Disqus
- GitHub Profile
- Stack Overflow Careers Profile
- Stack Overflow Profile
- G+ Profile
- PGP Public Key
- Rafty -- Ripper and Friggin Transcoder, Y'all
- Make Readme Markdown
- Diffview Mode
- Indent Hints Mode
- Track That Thing
- Co-Founder & CEO of Directangular, LLC.
- Previously: Linux Kernel development for QuIC. Some of my work (a little stale) is available on the Code Aurora Forum, here, here, here, and here.
- My nerd hobby: Creating and contributing to a variety of Open Source projects. See my GitHub profile.