Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse __libc_ifunc_impl_list data to provide more symbols for libc #1353

Open
ZetaTwo opened this issue Oct 17, 2019 · 2 comments
Open

Parse __libc_ifunc_impl_list data to provide more symbols for libc #1353

ZetaTwo opened this issue Oct 17, 2019 · 2 comments

Comments

@ZetaTwo
Copy link
Contributor

ZetaTwo commented Oct 17, 2019

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
Copy link
Contributor Author

ZetaTwo commented Oct 17, 2019

The proper term for these are apparently "indirect functions"

@ZetaTwo
Copy link
Contributor Author

ZetaTwo commented Oct 17, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant