Recall from Chapter 2, The ELF Binary Format, that the dynamic segment can be found in the program header table and is of type PT_DYNAMIC. There is also a .dynamic section that also points to the dynamic segment.
The dynamic segment is an array of ElfN_Dyn structs that contains d_tag and a corresponding value that exists in a union:
typedef struct {
ElfN_Sxword d_tag;
union {
ElfN_Xword d_val;
ElfN_Addr d_ptr;
} d_un;
} ElfN_Dyn;Using readelf we can easily view the dynamic segment of a file.
Following is an example of a legitimate dynamic segment:
$ readelf -d ./test
Dynamic section at offset 0xe28 contains 24 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x4004c8
0x000000000000000d (FINI) 0x400754
0x0000000000000019 (INIT_ARRAY) 0x600e10
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x600e18
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x400298
0x0000000000000005 (STRTAB) 0x400380
0x0000000000000006 (SYMTAB) 0x4002c0
0x000000000000000a (STRSZ) 87 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x601000
0x0000000000000002 (PLTRELSZ) 144 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x400438
0x0000000000000007 (RELA) 0x400408
0x0000000000000008 (RELASZ) 48 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x4003e8
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x4003d8
0x0000000000000000 (NULL) 0x0There are many important tag types here that are necessary for the dynamic linker to navigate the binary at runtime so that it can resolve relocations and load libraries. Notice that the tag type called NEEDED is highlighted in the preceding code. This is the dynamic entry that tells the dynamic linker which shared libraries it needs to load into memory. The dynamic linker will search for the named shared library in the paths specified by the $LD_LIBRARY_PATH environment variable.
It is clearly conceivable for an attacker to add a NEEDED entry into the binary that is specifying a shared library to load. This is not a very common technique in my experience, but it is a technique that can be used tell the dynamic linker to load whichever library you want. The problem for analysts is that this technique is difficult to detect if it is done correctly, which is to say that the inserted NEEDED entry is inserted directly after the last legitimate NEEDED entry. This can be difficult because you have to move all of the other dynamic entries forward to make room for your insertion.
In many cases, the attacker may do this the inexperienced way where the NEEDED entry is at the very end of all other entries, which the object linker would never do, so if you see a dynamic segment that looks like the following, you know something is up.
The following is an example of an infected dynamic segment:
$ readelf -d ./test Dynamic section at offset 0xe28 contains 24 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000000c (INIT) 0x4004c8 0x000000000000000d (FINI) 0x400754 0x0000000000000019 (INIT_ARRAY) 0x600e10 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) 0x000000000000001a (FINI_ARRAY) 0x600e18 0x000000000000001c (FINI_ARRAYSZ) 8 (bytes) 0x000000006ffffef5 (GNU_HASH) 0x400298 0x0000000000000005 (STRTAB) 0x400380 0x0000000000000006 (SYMTAB) 0x4002c0 0x000000000000000a (STRSZ) 87 (bytes) 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000015 (DEBUG) 0x0 0x0000000000000003 (PLTGOT) 0x601000 0x0000000000000002 (PLTRELSZ) 144 (bytes) 0x0000000000000014 (PLTREL) RELA 0x0000000000000017 (JMPREL) 0x400438 0x0000000000000007 (RELA) 0x400408 0x0000000000000008 (RELASZ) 48 (bytes) 0x0000000000000009 (RELAENT) 24 (bytes) 0x000000006ffffffe (VERNEED) 0x4003e8 0x000000006fffffff (VERNEEDNUM) 1 0x000000006ffffff0 (VERSYM) 0x4003d8 0x0000000000000001 (NEEDED) Shared library: [evil.so] 0x0000000000000000 (NULL) 0x0