4

I have a linux binary that imports functions from an external library (shared object). The functions are lazy loaded and not available when rip is at @main or @entry. When i step into such a function (like call sym.imp.<function>) it goes into plt->got->linker->function. Doing this manually (step-into) is very time consuming and uncomfortable. None of the analysis functions (aaa) seem to register any functions (afl ~ <function>) of the lazy loaded library so there is no way to gather the function start address (until the linker fills the plt/got).

The only way i figured out so far is to break at the call, look up the mapped memory (dm) of the (now loaded) library and adding the offset of the function (gathered by directly/statically loading the library beforehand). This finally leads to the target function start address.

Even though this works i think its still too complicated for such a basic task and there might be a much easier way. I can remember that IDA/Windows allowed to prepare a static environment (load binary, libs, add comments, annotations and such) and once going into the debugger the initialization phase (linker) detected the prepared libs and asked to use/overload them in the dynamic session. There, you could easily set breakpoints on the functions and the debugger stopped successfully.

The question is: How to get into lazy loaded imported functions without going over plt/got/linker in radare2?

Edit: Here is a specific example:

r2 -d /usr/bin/rar
aaa
db sym.imp.__swprintf_chk
dc

Then you end up in the .plt (twice) and then in map.usr_lib_ld_2.27.so.r_x + 50055.

  • Can you please share your binary and point to the specific locations. This way we will be able to give you the best answer. – Megabeets Jul 17 '18 at 9:39
  • I've added an example. – Maniaxx Jul 17 '18 at 19:44
3

The sym.imp.* symbols are pointing to the plt and this is intended. In order to locate a specific function of a loaded module/library, you need to use the dmi command and its subcommands.

To follow your example, in the following steps I'll demonstrate how to reach the address of __swprintf_chk.

First, open a binary in a debug mode. I'm using the same binary as you.

$ r2 -d /usr/bin/rar

Process with PID 8617 started...
= attach 8617 8617
bin.baddr 0x00400000
Using 0x400000
asm.bits 64
 -- This computer has gone to sleep.
[0x7f1f85401090]>

__swprintf_chk is part of libc so we need the library to be loaded in the memory first. By default, radare2 breaks before libc is loaded into the memory so let's quickly continue the execution until we reach the program's entrypoint using dcu (debug continue until):

[0x7f1f85401090]> dcu entry0
Continue until 0x00403000 using 1 bpsize
hit breakpoint at: 403000

Now that we are at the program's entrypoint, we can simply execute the following command:

[0x00403000]> dmi libc __swprintf_chk
235 0x001335f0 0x7f1f845c35f0 GLOBAL   FUNC  162 __swprintf_chk

We received the address of __swprintf_chk which is 0x7f1f845c35f0. We can use radare2's internal grep (~) to take only this value:

[0x00403000]> dmi libc __swprintf_chk~[2]
0x7f1f845c35f0

We can also print it as a radare2 commands using dmi*:

[0x00403000]> dmi* libc __swprintf_chk
f sym.__swprintf_chk 162 0x7f1f845c35f0

And if you want to execute the command, simply prepend it with a dot:

[0x00403000]> .dmi* libc __swprintf_chk
[0x00403000]> f~sym.__swprintf_chk
0x7f1f845c35f0 162 sym.__swprintf_chk

As you can see, the address was added as a flag named "sym.__swprintf_chk".

For more help you can execute dmi? and dm? and read the help for these commands.
More information can be found in the "Memory Maps" chapter I wrote for r2book.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.