Distinguish .shstrtab and .strtab in ELF file
From the same docs: e_shstrndx
: This member [in ElfN_Ehdr] holds the section header table index of the entry associated with the section name string table. If the file has no section name string table, this member holds the value SHN_UNDEF.
How to find `.strtab` in an ELF file?
How can I get the index of
.strtab
?
You read the Elf64_Shdr
s one by one. When you've read the 28th entry, you will have read the .strtab
, and you'll know its index.
You'll know that it's the .strtab
section by comparing its name with ".strtab"
string literal.
(You are probably intending to ask a different question, but if that's the case, you haven't expressed it well.)
Update:
Can't I do anything else rather than comparing strings
Maybe. If your real question is finding the .strtab
section, then not really.
(which is somehow hard) can I assume it will be the first STRTAB in the file for example?
There is no guarantee that that will be the case.
Note: if you are worried about the speed of strcmp()
, note that you can only do that strcmp()
when .sh_type == SHT_STRTAB
, and since there are usually at most two such sections in any given file, the concern about the speed of strcmp()
is likely misplaced. Your code would look something like:
if (shdr.sh_type == SHT_STRTAB) {
const char *sh_name = contents_of_shstrab + shdr.sh_name;
if (strcmp(sh_name, ".strtab") == 0) {
/* found .strtab; do whatever you need with it */
}
}
Update 2:
your solution is wrong, please see: http://stackoverflow.com/questions/68074508/
You can't claim that my solution is wrong, since I haven't provided a complete solution. It is also not wrong.
Here is complete code (with most error checking omitted):
#include <elf.h>
#include <fcntl.h>
#include <link.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
if (argc < 1) return 1;
int fd = open(argv[1], O_RDONLY);
if (fd == -1) return 2;
struct stat st_buf;
if (fstat(fd, &st_buf) != 0) return 3;
char *data = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (data == MAP_FAILED) return 4;
const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr) *)data;
const ElfW(Shdr) *shdr = (const ElfW(Shdr) *)(data + ehdr->e_shoff);
const char *shstrtab = data + shdr[ehdr->e_shstrndx].sh_offset;
for (int j = 0; j < ehdr->e_shnum; j++) {
printf("[%2d] %s\n", j, shstrtab + shdr[j].sh_name);
}
return 0;
}
$ gcc -g t.c -Wall
$ ./a.out ./a.out
[ 0]
[ 1] .interp
[ 2] .note.gnu.build-id
[ 3] .note.ABI-tag
[ 4] .gnu.hash
[ 5] .dynsym
[ 6] .dynstr
...
[32] .symtab
[33] .strtab
[34] .shstrtab
Reading ELF String Table on Linux from C
I was able to find out the answer myself :). Although it took a lot of time to code. Here is how it is done if someone wants to refer it for future -
Each Binary generally contains three String tables -
1. .dynstr
2. .shstrtab
3. .strtab
IN the above question we are concerned with .shstrtab which when expanded stands for - Section Header STRing TABle. Upon reading the ELF header we find the following field in ELF header - e_shstrndx. This is the index where we can find .shstrtab. Following formula can be used to calculate how it will be done -
offset = ((elfHdr.e_shstrndx)*elfHdr.e_shentsize)+elfHdr.e_shoff
Meaning of each parameter -
elfHdr.e_shstrndx = index where we can find .shstrtab
elfHdr.e_shentsize = Size of each Section Header
elfHdr.e_shoff = Offset at which section header starts.
How are strings encoded in an ELF file?
It's because the strings aren't being stored as static data.
For example if you had this:
const char* password = "a big refreshing lemonade";
Or even this:
static char password[] = "a big refreshing lemonade";
It is stored contiguously in the binary (You see "a big refreshing lemonade" next to each other) in the constants section.
If you look at the assembly output, you see this:
6:test.c **** char password[] = "a big refreshing lemonade";
23 .loc 1 6 0
24 001e 48B86120 movabsq $7309940773697495137, %rax
24 62696720
24 7265
25 0028 48BA6672 movabsq $7453010330678293094, %rdx
25 65736869
25 6E67
26 0032 488945D0 movq %rax, -48(%rbp)
27 0036 488955D8 movq %rdx, -40(%rbp)
28 003a 48B8206C movabsq $7233183901389515808, %rax
28 656D6F6E
28 6164
29 0044 488945E0 movq %rax, -32(%rbp)
30 0048 66C745E8 movw $101, -24(%rbp)
30 6500
Where you see a lot of movabsq
, which loads a 64 bit constant. So, what it does load 8 bytes at a time into password
.
You'll notice that the first constant (7309940773697495137) is the little-endian form of "a big re"
Understanding ELF TBSS and TDATA section loading
Although the size of TLS here is 0xb12a
. The alignment of 0x8
will make the TLS pointer move to 0xb130
which is the address of variable observed here.
Related Topics
Difference Between Printf and Echo in Bash
Command Not Found in Bash's If-Else Condition When Using [! -D "$Dir"]
Suppress Notice of Forked Command Being Killed
Backing Up (And Restoring) a Plone Instance
The Difference Between Initrd and Initramfs
Grep Recursively for a Specific File Type on Linux
"Couldn't Find a File Descriptor Referring to the Console" on Ubuntu Bash on Windows
Genymotion Throws Libssl_Conf.So: Cannot Open Shared Object File: No Such File or Directory
Execute Command Line and Return Command Output
Perl Fails to Set Locale Even Though It Is Installed
Emulating Slurm on Ubuntu 16.04
Copy Files from Windows to Windows Subsystem for Linux (Wsl)