Shared library injection into a Linux process (bonus)

Shared library injection into a Linux process (bonus)

Introduction

This bonus article describes a second easy method to retrieve a symbol address into a process. The first method was exposed here. As explained previously, the injected lib is loaded into the victim process (yeah, that’s the goal) but also into the injector in order to compute an offset. This last loading can cause several drawbacks:

  • Load a library just to compute an offset may be overkill.
  • If the library contains some constructors, these ones will be run into the injector process. They can potentially failed (segmentation faults, etc.).
  • etc.

So, in this short article, we are going to approach a method to retrieve a symbol address without library loading into the injector.

Parse the ELF

The ELF format (man page) provides a lot of information and we can use them to compute the symbol address. Let’s see how to get the address of __libc_dlopen_mode by using the ELF format.

Step 1: get the __libc_dlopen_mode offset

The readelf command (man page) allows to display some information about a ELF file. Its argument -s lists all the entries of the symbols table:

$ readelf -s /usr/lib64/libc-2.30.so | grep __libc_dlopen_mode
  2271: 000000000013ba20   128 FUNC    GLOBAL DEFAULT   15 __libc_dlopen_mode@@GLIBC_PRIVATE
 23052: 000000000013ba20   128 FUNC    LOCAL  DEFAULT   15 __GI___libc_dlopen_mode
 26673: 000000000013ba20   128 FUNC    GLOBAL DEFAULT   15 __libc_dlopen_mode

So, the __libc_dlopen_mode offset into the libc is: offset = 0x13ba20.

Step 2: get the virtual address of the libc executable segment

By parsing the elf

The readelf argument -l displays all the segments of the ELF file. In the excerpt below, I just keep the interesting executable segment:

$ readelf -l /usr/lib64/libc-2.30.so 

Elf file type is DYN (Shared object file)
Entry point 0x272b0
There are 14 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
# [...]
  LOAD           0x0000000000025000 0x0000000000025000 0x0000000000025000
                 0x000000000014e9bc 0x000000000014e9bc  R E    0x1000
# [...]

Thus, the virtual address of the executable segment is: vaddr = 0x25000.

By parsing the proc maps file

This value can also be computed with the maps file of the victim process (in our case, the victim is vlc) by subtracting the address of the executable mapping from the address of the first mapping:

$ cat /proc/$(pidof vlc)/maps | grep 'libc-2.30.so'
7f668e288000-7f668e2ad000 r--p 00000000 fd:00 12981143                   /usr/lib64/libc-2.30.so
7f668e2ad000-7f668e3fc000 r-xp 00025000 fd:00 12981143                   /usr/lib64/libc-2.30.so
[...]

Here is the calculation:

vaddr = 0x7f668e2ad000 - 0x7f668e288000 = 0x25000

Step 3: get the libc executable mapping address into the victim process

Again, just use the victim proc maps file:

$ cat /proc/$(pidof vlc)/maps | grep 'libc-2.30.so' | grep x
7f668e2ad000-7f668e3fc000 r-xp 00025000 fd:00 12981143                   /usr/lib64/libc-2.30.so

In this case, the base address is: mapping = 0x7f668e2ad000.

Step 4: compute!

The address of __libc_dlopen_mode into our victim process (vlc) is:

offset + (mapping - vaddr)
= 0x13ba20 + (0x7f668e2ad000 - 0x25000)
= 0x7f668e3c3a20

A little check with gdb:

$ gdb -p $(pidof vlc)
# [...]
gdb-peda$ info sym 0x7f668e3c3a20
__libc_dlopen_mode in section .text of /lib64/libc.so.6

Done!

Implementation into my Python proc lib

As I write this article, this strategy is not yet implemented into my proc library. I would like to limit Python dependencies but I’m too lazy to implement an ELF parser… Maybe the first implementation will slackly relies on the readelf output parsing…

Related articles

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.