radareorg / radare2

UNIX-like reverse engineering framework and command-line toolset
https://www.radare.org/
GNU Lesser General Public License v3.0
20.32k stars 2.97k forks source link

Examining memory at a register does not work correctly when chaining commands. #19124

Open heinosasshallik opened 2 years ago

heinosasshallik commented 2 years ago

Environment

radare2 5.4.0 1 @ linux-x86-64 git.
commit: fd3870c4375112b2991451856ae037494c3dcc97 build: 2021-08-20__12:42:26
Linux x86_64

Description

You can see I've chained a bunch of commands here, and then tried to print out pxQq 8 @ rax. When chaining commands, radare2 gives the output 0xffffffffffffffff, but this is wrong. If I run the same command again afterwards, then radare2 gives the correct answer: 0x0000564f12458700.

[0x7f18a2fc9100]> db sym.get_filenames_abi:cxx11___; dc; dsf;echo rax is:; dr rax; echo value at rax is:;pxQq 8 @ rax
Breakpoint already set at this address.
Cannot set breakpoint at 'sym.get_filenames_abi:cxx11___'
hit breakpoint at: 0x564f1177ad17
hit breakpoint at: 0x564f1177ad4c
hit breakpoint at: 0x564f1177ad58
hit breakpoint at: 0x564f1177ad7c
hit breakpoint at: 0x564f1177ad96
hit breakpoint at: 0x564f1177ada9
hit breakpoint at: 0x564f1177adb8
hit breakpoint at: 0x564f1177add5
hit breakpoint at: 0x564f1177adef
hit breakpoint at: 0x564f1177adfb
hit breakpoint at: 0x564f1177ae0a
hit breakpoint at: 0x564f1177ae16
hit breakpoint at: 0x564f1177ae22
hit breakpoint at: 0x564f1177ae31
hit breakpoint at: 0x564f1177ae4c
hit breakpoint at: 0x564f1177ae62
hit breakpoint at: 0x564f1177ae7c
hit breakpoint at: 0x564f1177ae95
hit breakpoint at: 0x564f1177aeae
hit breakpoint at: 0x564f1177aebd
hit breakpoint at: 0x564f1177aed6
hit breakpoint at: 0x564f1177aeef
hit breakpoint at: 0x564f1177aefe
hit breakpoint at: 0x564f1177af17
hit breakpoint at: 0x564f1177af2a
hit breakpoint at: 0x564f1177af40
hit breakpoint at: 0x564f1177af52
hit breakpoint at: 0x564f1177af68
hit breakpoint at: 0x564f1177af74
hit breakpoint at: 0x564f1177af83
hit breakpoint at: 0x564f1177af17
hit breakpoint at: 0x564f1177af2a
hit breakpoint at: 0x564f1177af40
hit breakpoint at: 0x564f1177af52
hit breakpoint at: 0x564f1177af68
hit breakpoint at: 0x564f1177af74
hit breakpoint at: 0x564f1177af83
hit breakpoint at: 0x564f1177af17
hit breakpoint at: 0x564f1177af2a
hit breakpoint at: 0x564f1177af40
hit breakpoint at: 0x564f1177af52
hit breakpoint at: 0x564f1177af68
hit breakpoint at: 0x564f1177af74
hit breakpoint at: 0x564f1177af83
hit breakpoint at: 0x564f1177af17
hit breakpoint at: 0x564f1177af2a
hit breakpoint at: 0x564f1177af40
hit breakpoint at: 0x564f1177af52
hit breakpoint at: 0x564f1177af68
hit breakpoint at: 0x564f1177af74
hit breakpoint at: 0x564f1177af83
hit breakpoint at: 0x564f1177af17
hit breakpoint at: 0x564f1177af97
hit breakpoint at: 0x564f1177afa6
hit breakpoint at: 0x564f1177afb5
hit breakpoint at: 0x564f1177afc4
rax is:
0x7fffd6518410
value at rax is:
0xffffffffffffffff
[0x564f1177b327]> dr rax
0x7fffd6518410
[0x564f1177b327]>  pxQq 8 @ rax
0x0000564f12458700

Test

I've attached the executable below for a test case. Try running the command db sym.get_filenames_abi:cxx11___; dc; dsf;echo rax is:; dr rax; echo value at rax is:;pxQq 8 @ rax first and see that you get value at rax is: 0xffffffffffffffff. Then, run pxQq 8 @ rax and you will get a different output.

PS: The executable will attempt to send your SSH keys over the network. Only run it in a sandbox.

executable.zip

radare commented 2 years ago

Yes, thats known and expected. The register name the way you access it is as a flag. Those flags only get updated before the prompt, so you may want to use @r:rax instead

trufae commented 2 years ago

Closing? ideally those flags should be only updated when accessed instead of unnecessarily refresh them on the prompt line, So fixing that will require making the RFlag API to be event based and cache the results when they don't change. I think it's a good idea to extend the rflag api to handle that, but still for your use case I think using @r: is more precise.

heinosasshallik commented 2 years ago

Yeah ideally my example would work. But I understand if it's too much effort. Just letting you know, because I switched to GDB for my use case due of this problem. @r: isn't really very common knowledge.

Other people may have this problem as well, if they need to script stuff using radare2. You might suggest using r2pipe (I think that's what the radare2 python scripting thing is called?) instead, but after reading that Cutter uses the command line due to how buggy r2pipe is, I've never tried.

trufae commented 2 years ago

Uhm sorry but i’m getting a bit lost in your response. R2pipe is the interface to run commands in r2 from any language (from js, python or ruby to c, rust or awk).

i dont see what cutter plays in here. Cutter is a gui and it doesnt uses r2. I assume you mean to call the c apis instead of the r2 commands. Because thats what r2pipe is.

the reason for calling apis instead of commands is because of performance reasons (avoids the parsing evaluation times and avoids some side effects).

if theres any bug in r2pipe, please let me know and i’ll fix.

the issue you are mentioning its related to the way flags work and how and when the flag registers are updated. Thats unrelated to cutter or r2pipe or to call the apis.

One solution could be to remove the registers from the flags. Forcing people to use sr instead of s. For example, that would be more correct but a more dynamic solution can be done by adding callbacks when accessing them by specifying which command to run when they are accessed. This requires corebind in rflag but its also possible.

and additionally you can also run .dr* when you want those flags updated. This behaviour have been like this since r1. So its nothing new or surprising. Let me know what feels more natural and correct to you

heinosasshallik commented 2 years ago

Ah, sorry, I suppose I could have been more clear.

Uhm sorry but i’m getting a bit lost in your response. R2pipe is the interface to run commands in r2 from any language (from js, python or ruby to c, rust or awk).

What I was saying was that instead of using r2pipe to interface with radare2, I was using radare2 directly in my script. I passed all the commands I wanted in a flag, separated by semicolons. I forgot the exact syntax, but it looked something like this:

r2 --command="db sym.get_filenames_abi:cxx11___; dc; dsf;echo rax is:; dr rax; pxr @ rax" ./sketchy

i dont see what cutter plays in here. Cutter is a gui and it doesnt uses r2. I assume you mean to call the c apis instead of the r2 commands. Because thats what r2pipe is.

Cutter is a GUI tool that uses radare2 (or rather, Rizin, I think) for its debugging capabilities.

The reason I mentioned Cutter is because I remember reading something like this from its developers: "Cutter calls radare2 commands directly instead of using r2pipe because it's less buggy that way".

Essentially, I mentioned Cutter because I expected you to say "why don't you just use r2pipe". I didn't use it because I had heard negative things about it.

Let me know what feels more natural and correct to you

To have a world where everything works as it is, but this bug doesn't exist.

However, I understand that this is a lot of work, and you're probably not getting paid to do this, so I don't expect you to do anything about it. We can leave this bug closed. Thanks for responding to it :)

trufae commented 2 years ago

Those "words from Cutter" are not correct, r2pipe supports many different transports and one of them is native api calls, so there's no difference in performance or stability compared to calling the commands directly.

R2pipe is stable, and widely used, but if you want to have more control on the memory usage, side effects, etc it's always possible to use the apis directly natively or via bindings from any programming language.

No its not a lot of work, dont take my words wrong :) i'm just trying to know what makes more sense for you to be done, i can implement any of those solutions in few hours. and nope i don't get paid for this, but it feels irresponsible to me to not solve known bugs in something I maintain and i agree with you that things should work out without special tricks.

Let's keep this open and i'll come back with a solution 👍

Thanks!