m4b / goblin

An impish, cross-platform binary parsing crate, written in Rust
MIT License
1.2k stars 160 forks source link

`is_import` is wrong on MIPS ELF #419

Open trou opened 3 months ago

trou commented 3 months ago

Hello, thank you very much for goblin, it is awesome. I've developed a tool called findso, in my rsbkb project, using your crate, using !is_import to identify if a given symbol is exported or not. It looks for which .so implements a given function. For example:

$ findso -p /usr/arm-linux-gnueabi/lib/ -a memcpy
/usr/arm-linux-gnueabi/lib/libc.so.6

However, on mips I have the following result:

$ findso -p /usr/mips-linux-gnu/lib/ -a memcpy
/usr/mips-linux-gnu/lib/libatomic.so.1
/usr/mips-linux-gnu/lib/libatomic.so.1.2.0
/usr/mips-linux-gnu/lib/libc.so.6
...

readelf gives the following:

$ mips-linux-gnu-readelf -D -a /usr/mips-linux-gnu/lib/libnss_compat.so.2 | grep memcpy
    47: 00007d90     0 FUNC    GLOBAL DEFAULT  UND memcpy@GLIBC_2.0 (4)
  00020188 -32600(gp) 00007d90 00007d90 FUNC    UND memcpy
$ mips-linux-gnu-readelf -D -a /usr/mips-linux-gnu/lib/libc.so.6 | grep memcpy
   862: 000a75b0   984 FUNC    GLOBAL DEFAULT   13 memcpy@@GLIBC_2.0

I think there's some MIPS weirdness (as usual), where UND symbols have a global value?

I don't know if there's a simple and reliable way of checking if a symbol is actually defined or not.

Any idea?

Some sample files can be found in the following Debian package: https://packages.debian.org/bookworm/all/libc6-mips-cross/filelist

Code from rsbkb:

                let strtab = elf_file.dynstrtab;

                let found = elf_file
                    .dynsyms
                    .iter()
                    .any(|s| !s.is_import() && strtab.get_at(s.st_name) == Some(fun));
                if found {
                    println!("{}", f.display());
                }
trou commented 2 months ago

Exactly the same bug in LIEF: https://github.com/lief-project/LIEF/issues/796

philipc commented 2 months ago

It's probably better to check for st_shndx == SHN_UNDEF instead of st_value == 0.