Searching for Bytes

The radare2 search engine is based on work done by esteve, plus multiple features implemented on top of it. It supports multiple keyword searches, binary masks, and hexadecimal values. It automatically creates flags for search hit locations ease future referencing.

Search is initiated by / command.

[0x00000000]> /?

|Usage: /[!bf] [arg]Search stuff (see 'e??search' for options)

|Use io.va for searching in non virtual addressing spaces

| / foo\x00 search for string 'foo\0'

| /j foo\x00 search for string 'foo\0' (json output)

| /! ff search for first occurrence not matching, command modifier

| /!x 00 inverse hexa search (find first byte != 0x00)

| /+ /bin/sh construct the string with chunks

| // repeat last search

| /a jmp eax assemble opcode and search its bytes

| /A jmp find analyzed instructions of this type (/A? for help)

| /b search backwards, command modifier, followed by other command

| /B search recognized RBin headers

| /c jmp [esp] search for asm code matching the given string

| /ce rsp,rbp search for esil expressions matching

| /C[ar] search for crypto materials

| /d 101112 search for a deltified sequence of bytes

| /e /E.F/i match regular expression

| /E esil-expr offset matching given esil expressions %%= here

| /f search forwards, command modifier, followed by other command

| /F file [off] [sz] search contents of file with offset and size

| /g[g] [from] find all graph paths A to B (/gg follow jumps, see search.count and

anal.depth)

| /h[t] [hash] [len] find block matching this hash. See ph

| /i foo search for string 'foo' ignoring case

| /m magicfile search for matching magic file (use blocksize)

| /M search for known filesystems and mount them automatically

| /o [n] show offset of n instructions backward

| /O [n] same as /o, but with a different fallback if anal cannot be used

| /p patternsize search for pattern of given size

| /P patternsize search similar blocks

| /r[erwx][?] sym.printf analyze opcode reference an offset (/re for esil)

| /R [grepopcode] search for matching ROP gadgets, semicolon-separated

| /s search for all syscalls in a region (EXPERIMENTAL)

| /v[1248] value look for an `cfg.bigendian` 32bit value

| /V[1248] min max look for an `cfg.bigendian` 32bit value in range

| /w foo search for wide string 'f\0o\0o\0'

| /wi foo search for wide string ignoring case 'f\0o\0o\0'

| /x ff..33 search for hex string ignoring some nibbles

| /x ff0033 search for hex string

| /x ff43:ffd0 search for hexpair with mask

| /z min max search for strings of given size

Because everything is treated as a file in radare2, it does not matter whether you search in a socket, a remote device, in process memory, or a file.

note that '/' starts multiline comment. It's not for searching. type '/' to end comment.

Basic Search

A basic search for a plain text string in a file would be something like:

$ r2 -q -c "/ lib" /bin/ls

Searching 3 bytes from 0x00400000 to 0x0041ae08: 6c 69 62

hits: 9

0x00400239 hit0_0 "lib64/ld-linux-x86-64.so.2"

0x00400f19 hit0_1 "libselinux.so.1"

0x00400fae hit0_2 "librt.so.1"

0x00400fc7 hit0_3 "libacl.so.1"

0x00401004 hit0_4 "libc.so.6"

0x004013ce hit0_5 "libc_start_main"

0x00416542 hit0_6 "libs/"

0x00417160 hit0_7 "lib/xstrtol.c"

0x00417578 hit0_8 "lib"

As can be seen from the output above, radare2 generates a "hit" flag for every entry found. You can then use the ps command to see the strings stored at the offsets marked by the flags in this group, and they will have names of the form hit0_:

[0x00404888]> / ls

...

[0x00404888]> ps @ hit0_0

lseek

You can search for wide-char strings (e.g., unicode letters) using the /w command:

[0x00000000]> /w Hello

0 results found.

To perform a case-insensitive search for strings use /i:

[0x0040488f]> /i Stallman

Searching 8 bytes from 0x00400238 to 0x0040488f: 53 74 61 6c 6c 6d 61 6e

[# ]hits: 004138 < 0x0040488f hits = 0

It is possible to specify hexadecimal escape sequences in the search string by prepending them with "\x":

[0x00000000]> / \x7FELF

if, instead, you are searching for a string of hexadecimal values, you're probably better of using the /x command:

[0x00000000]> /x 7F454C46

Once the search is done, the results are stored in the searches flag space.

[0x00000000]> fs

0 0 . strings

1 0 . symbols

2 6 . searches


[0x00000000]> f

0x00000135 512 hit0_0

0x00000b71 512 hit0_1

0x00000bad 512 hit0_2

0x00000bdd 512 hit0_3

0x00000bfb 512 hit0_4

0x00000f2a 512 hit0_5

To remove "hit" flags after you do not need them anymore, use the f- hit* command.

Often, during long search sessions, you will need to launch the latest search more than once. You can use the // command to repeat the last search.

[0x00000f2a]> // ; repeat last search

Configuring Search Options

The radare2 search engine can be configured through several configuration variables, modifiable with the e command.

e cmd.hit = x ; radare2 command to execute on every search hit

e search.distance = 0 ; search string distance

e search.in = [foo] ; pecify search boundarie. Supported values are listed under e search.in=??

e search.align = 4 ; only show search results aligned by specified boundary.

e search.from = 0 ; start address

e search.to = 0 ; end address

e search.asmstr = 0 ; search for string instead of assembly

e search.flags = true ; if enabled, create flags on hits

The search.align variable is used to limit valid search hits to certain alignment. For example, with e search.align=4 you will see only hits found at 4-bytes aligned offsets.

The search.flags boolean variable instructs the search engine to flag hits so that they can be referenced later. If a currently running search is interrupted with Ctrl-C keyboard sequence, current search position is flagged with search_stop.

Pattern Matching Search

The /p command allows you to apply repeated pattern searches on IO backend storage. It is possible to identify repeated byte sequences without explicitly specifying them. The only command's parameter sets minimum detectable pattern length. Here is an example:

[0x00000000]> /p 10

This command output will show different patterns found and how many times each of them is encountered.

Search Automation

The cmd.hit configuration variable is used to define a radare2 command to be executed when a matching entry is found by the search engine. If you want to run several commands, separate them with ;. Alternatively, you can arrange them in a separate script, and then invoke it as a whole with . script-file-name command. For example:

[0x00404888]> e cmd.hit = p8 8

[0x00404888]> / lib

Searching 3 bytes from 0x00400000 to 0x0041ae08: 6c 69 62

hits: 9

0x00400239 hit4_0 "lib64/ld-linux-x86-64.so.2"

31ed4989d15e4889

0x00400f19 hit4_1 "libselinux.so.1"

31ed4989d15e4889

0x00400fae hit4_2 "librt.so.1"

31ed4989d15e4889

0x00400fc7 hit4_3 "libacl.so.1"

31ed4989d15e4889

0x00401004 hit4_4 "libc.so.6"

31ed4989d15e4889

0x004013ce hit4_5 "libc_start_main"

31ed4989d15e4889

0x00416542 hit4_6 "libs/"

31ed4989d15e4889

0x00417160 hit4_7 "lib/xstrtol.c"

31ed4989d15e4889

0x00417578 hit4_8 "lib"

31ed4989d15e4889

Searching Backwards

Sometimes you want to find a keyword backwards. This is, before the current offset, to do this you can seek back and search forward by adding some search.from/to restrictions, or use the /b command.

[0x100001200]> / nop

0x100004b15 hit0_0 .STUWabcdefghiklmnopqrstuvwxbin/ls.

0x100004f50 hit0_1 .STUWabcdefghiklmnopqrstuwx1] [file .

[0x100001200]> /b nop

[0x100001200]> s 0x100004f50p

[0x100004f50]> /b nop

0x100004b15 hit2_0 .STUWabcdefghiklmnopqrstuvwxbin/ls.

[0x100004f50]>

Note that /b is doing the same as /, but backward, so what if we want to use /x backward? We can use /bx, and the same goes for other search subcommands:

[0x100001200]> /x 90

0x100001a23 hit1_0 90

0x10000248f hit1_1 90

0x1000027b2 hit1_2 90

0x100002b2e hit1_3 90

0x1000032b8 hit1_4 90

0x100003454 hit1_5 90

0x100003468 hit1_6 90

0x10000355b hit1_7 90

0x100003647 hit1_8 90

0x1000037ac hit1_9 90

0x10000389c hit1_10 90

0x100003c5c hit1_11 90


[0x100001200]> /bx 90

[0x100001200]> s 0x10000355b

[0x10000355b]> /bx 90

0x100003468 hit3_0 90

0x100003454 hit3_1 90

0x1000032b8 hit3_2 90

0x100002b2e hit3_3 90

0x1000027b2 hit3_4 90

0x10000248f hit3_5 90

0x100001a23 hit3_6 90

[0x10000355b]>

Assembler Search

If you want to search for a certain assembler opcodes, you can use /a commands.

The command /ad/ jmp [esp] searches for the specified category of assembly mnemonic:

[0x00404888]> /ad/ jmp qword [rdx]

f hit_0 @ 0x0040e50d # 2: jmp qword [rdx]

f hit_1 @ 0x00418dbb # 2: jmp qword [rdx]

f hit_2 @ 0x00418fcb # 3: jmp qword [rdx]

f hit_3 @ 0x004196ab # 6: jmp qword [rdx]

f hit_4 @ 0x00419bf3 # 3: jmp qword [rdx]

f hit_5 @ 0x00419c1b # 3: jmp qword [rdx]

f hit_6 @ 0x00419c43 # 3: jmp qword [rdx]

The command /a jmp eax assembles a string to machine code, and then searches for the resulting bytes:

[0x00404888]> /a jmp eax

hits: 1

0x004048e7 hit3_0 ffe00f1f8000000000b8

Searching for AES Keys

Thanks to Victor Muñoz, radare2 now has support of the algorithm he developed, capable of finding expanded AES keys with /Ca command. It searches from current seek position up to the search.distance limit, or until end of file is reached. You can interrupt current search by pressing Ctrl-C. For example, to look for AES keys in physical memory of your system:

$ sudo r2 /dev/mem

[0x00000000]> /ca

0 AES keys found

If you are simply looking for plaintext AES keys in your binary, /Ca will not find them, but you might want to search with is~AES instead if the programmer left those hints for you:

[0x00000000]> /Ca

Searching 0 byte in [0x100000-0x1f0000]

hits: 0

Searching 0 byte in [0x196e4-0x1b91c]

hits: 0

Searching 0 byte in [0x194b4-0x196e4]

hits: 0

Searching 0 byte in [0x8000-0x114b4]

hits: 0

[0x00000000]> is~AES

010 0x000096d4 0x000196d4 GLOBAL OBJ 16 AES_KEY

Other than that, AES keys might show up in different ways in the binary: encrypted, hidden by another encrypting routine, so there's no absolute way other than understanding the binary being analized. For instance, p=e might give some hints if high(er) entropy sections are found trying to cover up a hardcoded secret. As an example on entropy searching, since radare 3.2.0, there's the possibility to delimit entropy sections for later use like so:

[0x00000000]> b

0x100

[0x00000000]> b 4096

[0x00000000]> /s

0x00100000 - 0x00101000 ~ 5.556094

0x014e2c88 - 0x014e3c88 ~ 0.000000

0x01434374 - 0x01435374 ~ 6.332087

0x01435374 - 0x0144c374 ~ 3.664636

0x0144c374 - 0x0144d374 ~ 1.664368

0x0144d374 - 0x0144f374 ~ 4.229199

0x0144f374 - 0x01451374 ~ 2.000000

(...)

[0x00000000]> /s*

f entropy_section_0 0x00001000 0x00100000

f entropy_section_1 0x00001000 0x014e2c88

f entropy_section_2 0x00001000 0x01434374

f entropy_section_3 0x00017000 0x01435374

f entropy_section_4 0x00001000 0x0144c374

f entropy_section_5 0x00002000 0x0144d374

f entropy_section_6 0x00002000 0x0144f374

The blocksize is increased to 4096 bytes from the default 100 bytes so that the entropy search /s can work on reasonably sized chunks for entropy analysis. The sections flags can be applied with the dot operator, ./s* and then looped through px 32 @@ entropy*.

Moreover AES keys might be referenced from strings or pointed from the imports, for instance, so the / and other search-related commands can come in handy in this regard.

Загрузка...