pwntools icon indicating copy to clipboard operation
pwntools copied to clipboard

Parse __libc_ifunc_impl_list data to provide more symbols for libc

Open ZetaTwo opened this issue 5 years ago • 2 comments

Libc has a bunch of optimized implementations of many of its functions such as __strlen_avx2, etc. These are not exported as symbols but instead there is a function called __libc_ifunc_impl_list that can give you this information at runtime. If we can parse the info from that function, we can provide more entries in the symbols dict.

This is useful in cases where you leak the address of one of these functions and want to calculate the libc base without hardcoding the offset.

I intend to look at possible solutions but I'm starting by opening an issue here to get input and document my findings.

The function follows a format like this:

 else if ( !strcmp(name, "memmove") )
  {
    array[7].usable = 1;
    array[8].usable = 1;
    array->name = "__memmove_avx_unaligned";
    array->fn = (__int64)&loc_18EA70;
    v16 = *((_DWORD *)&rtld_global_ro + 45);
    array[1].name = "__memmove_avx_unaligned_erms";
    array[1].fn = (__int64)&loc_18EAD0;
    v17 = v16;
    array[2].name = "__memmove_avx512_no_vzeroupper";
    LOBYTE(v16) = (v16 >> 12) & 1;
    array[2].fn = (__int64)&loc_192460;
    array[2].usable = v16;
    array[3].usable = v16;
    array[4].usable = v16;
    v18 = *((_DWORD *)&rtld_global_ro + 30);
    array[3].name = "__memmove_avx512_unaligned";
    array[3].fn = (__int64)&loc_192E50;
    array[5].name = "__memmove_ssse3_back";
    v19 = (v17 >> 6) & 1;
    v20 = (v18 >> 9) & 1;
    array[5].fn = (__int64)&loc_174790;
    array[5].usable = v20;
    array[6].usable = v20;
    array[6].name = "__memmove_ssse3";
    array->usable = v19;
    array[7].name = "__memmove_erms";
    array[1].usable = v19;
    array[4].name = "__memmove_avx512_unaligned_erms";
    array[4].fn = (__int64)&loc_192EC0;
    array[7].fn = (__int64)&loc_BB4C0;
    array[6].fn = (__int64)&loc_16F120;
    array[8].name = "__memmove_sse2_unaligned";
    array[8].fn = (__int64)memcpy_0;
    array[9].name = "__memmove_sse2_unaligned_erms";
    array[9].fn = (__int64)&loc_BB520;
    array[9].usable = 1;
    result = 10LL;
  }
  else if ( !strcmp(name, "memrchr") ) {
  ...

The "usable" flag is not that interesting but the name-function mapping is.

ZetaTwo avatar Oct 17 '19 12:10 ZetaTwo

The proper term for these are apparently "indirect functions"

ZetaTwo avatar Oct 17 '19 21:10 ZetaTwo

I tried to implement this in pwntools by emulating the function using Unicorn but it quickly became pretty messy. Instead, I ended up writing this small tool to dump the offsets separately: https://github.com/ZetaTwo/ifunc-dumper I have no idea if there is a better way to do it but at least this is something.

ZetaTwo avatar Oct 17 '19 23:10 ZetaTwo