如何找出定义了哪些部分变量和字符串?

逆向工程 C 雷达2 小精灵 部分
2021-06-28 03:31:15

给定一个像这样的简单程序,

void main (int argc, char * argv[] ) {
    char * arr[] = {"foo", "bar", "baz"};
    *(arr[0]) = 'F';
    printf( "%s", arr[0] );
}

如何找出部分字符串foobar以及baz在界定?例如,它们是否在.text或 部分.rodata,并检查以确保这些部分是ro, 或rw

1个回答

在下面的答案中,我将向您展示实现您想要的几种方法。我将使用不同的方法来使用 radre2 来做到这一点。

首先,让我们用更长的字符串创建一个程序:

$ cat helloworld.c 

#include <stdio.h>

void main (int argc, char * argv[] ) {
    char * arr[] = {"Hello", "World", "Byebye"};
    arr[0] = "F";
    printf( "%s\n", arr[0] );
}

$ gcc helloworld.c -o helloworld

并在radare2中打开它:

$ r2 helloworld

现在我们有了一个很小的二进制文件,我们可以开始了。


方法一:数据段中的字符串

使用该iz命令可以列出数据部分中的字符串。对于每个字符串,您可以看到它所属的部分:

[0x000005b0]> iz
000 0x000007b4 0x000007b4   5   6 (.rodata) ascii Hello
001 0x000007ba 0x000007ba   5   6 (.rodata) ascii World
002 0x000007c0 0x000007c0   6   7 (.rodata) ascii Byeby

当然,您始终可以使用radare 的内部grep ( ~) 仅获取相关列:

[0x000005b0]> iz~[5,7]
(.rodata) Hello
(.rodata) World
(.rodata) Byebye

方法2:整个二进制中的字符串

与 不同iz,该命令izz将在整个二进制文件中搜索字符串。此命令将向您显示更多的字符串,iz但它也会在其他部分中搜索字符串。

[0x000005b0]> izz
000 0x00000034 0x00000034   4  10 (LOAD0) utf16le @8\t@
001 0x00000238 0x00000238  27  28 (.interp) ascii /lib64/ld-linux-x86-64.so.2
002 0x00000379 0x00000379   9  10 (.dynstr) ascii libc.so.6
003 0x00000383 0x00000383   4   5 (.dynstr) ascii puts
004 0x00000388 0x00000388  16  17 (.dynstr) ascii __stack_chk_fail
005 0x00000399 0x00000399  14  15 (.dynstr) ascii __cxa_finalize
006 0x000003a8 0x000003a8  17  18 (.dynstr) ascii __libc_start_main
007 0x000003ba 0x000003ba   9  10 (.dynstr) ascii GLIBC_2.4
008 0x000003c4 0x000003c4  11  12 (.dynstr) ascii GLIBC_2.2.5
009 0x000003d0 0x000003d0  27  28 (.dynstr) ascii _ITM_deregisterTMCloneTable
010 0x000003ec 0x000003ec  14  15 (.dynstr) ascii __gmon_start__
011 0x000003fb 0x000003fb  25  26 (.dynstr) ascii _ITM_registerTMCloneTable
...
019 0x000007b4 0x000007b4   5   6 (.rodata) ascii Hello
020 0x000007ba 0x000007ba   5   6 (.rodata) ascii World
021 0x000007c0 0x000007c0   6   7 (.rodata) ascii Byebye
022 0x00000810 0x00000810   4   5 (.eh_frame) ascii \e\f\a\b
023 0x00000840 0x00000840   4   5 (.eh_frame) ascii \e\f\a\b
024 0x00000867 0x00000867   5   6 (.eh_frame) ascii ;*3$"
025 0x0000088a 0x0000088a   4   5 (.eh_frame) ascii h\f\a\b
026 0x00001038 0x00000000  16  17 (.comment) ascii GCC: (GNU) 7.2.0
027 0x00001669 0x00000001   6   7 (.strtab) ascii init.c
028 0x00001670 0x00000008  10  11 (.strtab) ascii crtstuff.c
...

同样,您可以看到radare2 向您显示每个字符串的部分名称。如果您正在搜索特定的字符串,grep 是您的朋友:

[0x000005b0]> izz~Hello, World, Byebye
019 0x000007b4 0x000007b4   5   6 (.rodata) ascii Hello
020 0x000007ba 0x000007ba   5   6 (.rodata) ascii World
021 0x000007c0 0x000007c0   6   7 (.rodata) ascii Byebye

[0x000005b0]> izz~Hello, World, Byebye[5,7]
(.rodata) Hello
(.rodata) World
(.rodata) Byebye

方法 3:特定地址的部分

在这种方法中,您已经知道字符串的地址,并且您想知道它属于哪个部分。让我们以“你好”为例。我们看到“你好”地址是0x000007b4让我们使用验证psp RINT小号特林):

[0x000005b0]> ps @ 0x000007b4
Hello

如您所见,我们打印了一个以零结尾的字符串0x07b4(“@”是radare 的临时搜索)。现在我们确定这是“Hello”的地址,我们可以使用iS.来显示当前的Section名称:

[0x000005b0]> iS. @ 0x07b4
Current section
00 0x000007b0    25 0x000007b0    25 -r-- .rodata

正如预期的那样,该地址属于该.rodata部分。就像我们之前看到的那样。


显示部分的属性

最后,您想检查节的属性是只读还是读写。使用iS您可以列出所有部分,包括它们的属性:

[0x000005b0]> iS
[Sections]
00 0x00000000     0 0x00000000     0 ---- 
01 0x00000238    28 0x00000238    28 -r-- .interp
02 0x00000254    32 0x00000254    32 -r-- .note.ABI_tag
03 0x00000274    36 0x00000274    36 -r-- .note.gnu.build_id
04 0x00000298    28 0x00000298    28 -r-- .gnu.hash
05 0x000002b8   192 0x000002b8   192 -r-- .dynsym
06 0x00000378   157 0x00000378   157 -r-- .dynstr
07 0x00000416    16 0x00000416    16 -r-- .gnu.version
08 0x00000428    48 0x00000428    48 -r-- .gnu.version_r
09 0x00000458   216 0x00000458   216 -r-- .rela.dyn
10 0x00000530    48 0x00000530    48 -r-- .rela.plt
11 0x00000560    23 0x00000560    23 -r-x .init
12 0x00000580    48 0x00000580    48 -r-x .plt
13 0x000005b0   498 0x000005b0   498 -r-x .text
14 0x000007a4     9 0x000007a4     9 -r-x .fini
15 0x000007b0    25 0x000007b0    25 -r-- .rodata
16 0x000007cc    52 0x000007cc    52 -r-- .eh_frame_hdr
17 0x00000800   240 0x00000800   240 -r-- .eh_frame
18 0x00000de0     8 0x00200de0     8 -rw- .init_array
19 0x00000de8     8 0x00200de8     8 -rw- .fini_array
20 0x00000df0   480 0x00200df0   480 -rw- .dynamic
21 0x00000fd0    48 0x00200fd0    48 -rw- .got
22 0x00001000    40 0x00201000    40 -rw- .got.plt
23 0x00001028    16 0x00201028    16 -rw- .data
24 0x00001038     0 0x00201038     8 -rw- .bss
25 0x00001038    17 0x00000000    17 ---- .comment
26 0x00001050  1560 0x00000000  1560 ---- .symtab
27 0x00001668   555 0x00000000   555 ---- .strtab
28 0x00001893   259 0x00000000   259 ---- .shstrtab
29 0x00000040   504 0x00000040   504 -r-x PHDR
30 0x00000238    28 0x00000238    28 -r-- INTERP
31 0x00000000  2288 0x00000000  2288 -r-x LOAD0
32 0x00000de0   600 0x00200de0   608 -rw- LOAD1
33 0x00000df0   480 0x00200df0   480 -rw- DYNAMIC
34 0x00000254    68 0x00000254    68 -r-- NOTE
35 0x000007cc    52 0x000007cc    52 -r-- GNU_EH_FRAME
36 0x00000000     0 0x00000000     0 -rw- GNU_STACK
37 0x00000de0   544 0x00200de0   544 -r-- GNU_RELRO
38 0x00000000    64 0x00000000    64 -rw- ehdr

或者,用于iSq显示更简洁的输出(q表示quiet),您还可以 grep 用于读写部分:

[0x000005b0]> iS~rw
18 0x00000de0     8 0x00200de0     8 -rw- .init_array
19 0x00000de8     8 0x00200de8     8 -rw- .fini_array
20 0x00000df0   480 0x00200df0   480 -rw- .dynamic
21 0x00000fd0    48 0x00200fd0    48 -rw- .got
22 0x00001000    40 0x00201000    40 -rw- .got.plt
23 0x00001028    16 0x00201028    16 -rw- .data
24 0x00001038     0 0x00201038     8 -rw- .bss
32 0x00000de0   600 0x00200de0   608 -rw- LOAD1
33 0x00000df0   480 0x00200df0   480 -rw- DYNAMIC
36 0x00000000     0 0x00000000     0 -rw- GNU_STACK
38 0x00000000    64 0x00000000    64 -rw- ehdr

如果您想查看只读部分,请像这样使用 grep iS~r--