radareorg / radare2-r2pipe

Access radare2 via pipe from any programming language!
389 stars 99 forks source link

R2pipe truncates R2 output that contains multiple \x00 characters #156

Closed sidra-asa closed 1 year ago

sidra-asa commented 1 year ago

Environment

$ date; r2 -v; uname -ms; python -c 'import r2pipe;print(r2pipe.version())'
Wed Jun 14 21:28:20 CST 2023
radare2 5.8.8 30900 @ darwin-x86-64
birth: git.5.8.8 2023-06-09__10:00:18
commit: ea7f0356519884715cf1d5fba16042bac72b2df5
options: gpl -O2 cs:5 cl:2 make
Darwin x86_64
1.8.0

Description

Take a Python script r2_wrapper.py, which analyzes the APK(SHA1: 42b25b60aa7d6d9f0b388c10a45e8a8f8c1fc718), as an example. I print the raw bytes with the pr command, then try to disassemble the function and print some other bytes. But the pr command output is incomplete, and the follow-up command outputs are wrong.

$ cat r2_wrapper.py

import os
import r2pipe

sample = "14d9f1a92dd984d6040cc41ed06e273e.apk"

r2 = r2pipe.open(f"apk://{sample}")
r2.cmd("aa")
result = r2.cmd("pr @ 280203")
print(f"result: {result}")

result = r2.cmd("pdfj @ 112712")
print(f"result: {result}")

result = r2.cmd("pr @ 280203")
print(f"result: {result}")

$ python r2_wrapper.py
INFO: Analyze all flags starting with sym. and entry0 (aa)
WARN: set your favourite calling convention in `e anal.cc=?`
INFO: Analyze all functions arguments/locals (afva@@@F)

result: tener.java
result: rotocolCommandSupport.java
result: Proxy

The following are the expected results of r2_wrapper.py.

python r2_wrapper.py
INFO: Analyze all flags starting with sym. and entry0 (aa)
WARN: set your favourite calling convention in `e anal.cc=?`
INFO: Analyze all functions arguments/locals (afva@@@F)

result: b'tener.java\x00\x1bProtocolCommandSupport.java\x00\x05Proxy\x00\x1bProxy-Authorization: Basic \x00\x04QUIT\x00\x11QUOTE_OF_DAY_PORT\x000Queue is full! Cannot process another character.\x00\x01R\x00\x06R.java\x00\x03RCP\x00\x04RCPT\x00\x08RCPT TO:\x00\x04RCTE\x00\x13RCommandClient.java\x00\x0fREAD_PERMISSION\x00\x0cREAD_REQUEST\x00\x10RECEIVED_COMMA\x00'
result: b'{"name":"method.public.Lcom_google_progress_AndroidClientService.Lcom_google_progress_AndroidClientService.method.beginRecord_Ljava_lang_String__Z","size":280,"addr":112712,"ops":[ ...
result: b'tener.java\x00\x1bProtocolCommandSupport.java\x00\x05Proxy\x00\x1bProxy-Authorization: Basic \x00\x04QUIT\x00\x11QUOTE_OF_DAY_PORT\x000Queue is full! Cannot process another character.\x00\x01R\x00\x06R.java\x00\x03RCP\x00\x04RCPT\x00\x08RCPT TO:\x00\x04RCTE\x00\x13RCommandClient.java\x00\x0fREAD_PERMISSION\x00\x0cREAD_REQUEST\x00\x10RECEIVED_COMMA\x00'

From my understanding, the root cause is the function _cmd_process which is defined in open_sync.py. If the command result contains more than one \x00 hexadecimal character, the function will return the substring before the first \x00 character and hold the remaining substring in self.pending until the next invoke. In this case, the next command will output the wrong result that is the remaining substring from self.pending.

Please let me know if anything is unclear.

trufae commented 1 year ago

Yes thats how r2pipe works. You may not run commands that print null bytes. And i think pr is the only one that does this. You can encode any raw data as base64 or hexa easily. Or even escape that null byte. But internally in r2pipe this is not handled

sidra-asa commented 1 year ago

Thank you for the kind reply and the detailed explanation. These are helpful. I'm going to close this issue and try to use some other commands that encodes raw data as base64 or hex string.