GLOBAL 符号和 NONE 之间有什么区别?

逆向工程 雷达2 符号
2021-06-14 22:54:05

我正在玩 pe32 文件。随着is,我的一些符号说GLOBAL其他人说NONE

006 0x00027514 0x100428114 GLOBAL   FUNC    0 k.exe_asdf
....
002 0x0002a808 0x10042c008   NONE   FUNC    0 imp.foo.dll_bar

只有两个选项GLOBALNONE? 在哪里可以找到此屏幕的输出定义。如果我在objdump -t下面运行相同的可执行文件只显示

./k.exe:     file format pei-x86-64

SYMBOL TABLE:
no symbols

nm也没有显示符号。我猜虽然这radare2只是更好地处理 pe32+ 文件?

3个回答

PE绑定

“GLOBAL”和“NONE”是radare2符号表中“Bind”列的值。正如@blabb 正确描述的那样,每当您通过radare2 查看“导出”时,您都会看到"GLOBAL"分配给的值ptr->bind并且您会看到"NONE"分配给每个导入的值。问题是,这仅与 PE 文件相关,我将很快对其进行更深入的解释。现在,让我们看一下radare2 中的实现代码。

@blabb 提到你可以很容易地在代码中发现这一点,这是真的。以下bind是 PE出口的实现方式

if ((symbols = PE_(r_bin_pe_get_exports)(bf->o->bin_obj))) {
        for (i = 0; !symbols[i].last; i++) {
            if (!(ptr = R_NEW0 (RBinSymbol))) {
                break;
            }
            ptr->name = strdup ((char *)symbols[i].name);
            ...
            ptr->bind = r_str_const ("GLOBAL");
            ptr->type = r_str_const ("FUNC");
            ptr->size = 0;
            ...
            ...

您可以看到ptr->bind无条件分配为“GLOBAL”。

这就是bindPE导入的实现方式

if ((imports = PE_(r_bin_pe_get_imports)(bf->o->bin_obj))) {
        for (i = 0; !imports[i].last; i++) {
            if (!(ptr = R_NEW0 (RBinSymbol))) {
                break;
            }
            ...
            ptr->name = r_str_newf ("imp.%s", imports[i].name);
            ptr->bind = r_str_const ("NONE");
            ptr->type = r_str_const ("FUNC");
            ptr->size = 0;
            ...
            ...

同样,它被无条件地分配给“NONE”。


符号绑定

符号绑定是@SYS_V 在这个令人难以置信的好答案中已经彻底回答的主题

引用他的回答:

链接编辑器 (ld) 必须有一种方法可以在链接时确定符号的范围。换句话说,符号绑定允许链接编辑器区分仅在被链接的特定文件中可见的符号(本地范围)与可以从位于其他文件中的函数中引用的符号(全局范围)。

对于 ELF 文件,GLOBAL 绑定意味着符号在文件外部可见。LOCAL 绑定仅在文件中可见。WEAK 就像全局一样,符号可以被覆盖。

如您在此表中所见,ELF 有更多绑定值

+------------+-------+
|    Name    | Value |
+------------+-------+
| STB_LOCAL  |     0 |
| STB_GLOBAL |     1 |
| STB_WEAK   |     2 |
| STB_LOOS   |    10 |
| STB_HIOS   |    12 |
| STB_LOPROC |    13 |
| STB_HIPROC |    15 |
+------------+-------+

并且radare2也在以下方面实现了它fill_symbol_bind_and_type

switch (ELF_ST_BIND(sym->st_info)) {
case STB_LOCAL:  s_bind ("LOCAL"); break;
case STB_GLOBAL: s_bind ("GLOBAL"); break;
case STB_WEAK:   s_bind ("WEAK"); break;
case STB_NUM:    s_bind ("NUM"); break;
case STB_LOOS:   s_bind ("LOOS"); break;
case STB_HIOS:   s_bind ("HIOS"); break;
case STB_LOPROC: s_bind ("LOPROC"); break;
case STB_HIPROC: s_bind ("HIPROC"); break;
default:         s_bind ("UNKNOWN");
}

进一步阅读

我强烈推荐@SYS_V 的答案以获取更多信息。您还可以在此处阅读有关符号解析的更多信息,并且可以在此链接中找到有关符号可见性的更多信息

二进制中的导出函数用 GLOBAL 表示二进制中的导入函数用 NONE 表示

:\>rabin2  -i ..\..\miscinfo\Debug\tzinfo.dll | grep -i Mod
003 0x10016008 NONE FUNC KERNEL32.dll_GetModuleFileNameA
011 0x10016028 NONE FUNC KERNEL32.dll_GetModuleHandleW
009 0x10016088 NONE FUNC VCRUNTIME140D.dll___vcrt_GetModuleFileNameW
010 0x1001608c NONE FUNC VCRUNTIME140D.dll___vcrt_GetModuleHandleW

:\>rabin2  -E ..\..\miscinfo\Debug\tzinfo.dll
[Exports]
000 0x0000bb80 0x1000c780 GLOBAL   FUNC    0 tzinfo.dll_DebugExtensionInitialize
001 0x0000bc10 0x1000c810 GLOBAL   FUNC    0 tzinfo.dll_DebugExtensionNotify
002 0x0000bbb0 0x1000c7b0 GLOBAL   FUNC    0 tzinfo.dll_DebugExtensionUninitialize
003 0x0000bad0 0x1000c6d0 GLOBAL   FUNC    0 tzinfo.dll_help
004 0x00000670 0x10001270 GLOBAL   FUNC    0 tzinfo.dll_tzinfo

顺便说一句,您可以通过 src 获取radare 和grep 的来源以找到大部分答案

>grep -r "\"GLOBAL\"" *
libr/bin/format/elf/elf.c:      case STB_GLOBAL: s_bind ("GLOBAL"); break;
libr/bin/p/bin_mach0.c:                 "LOCAL":"GLOBAL");
libr/bin/p/bin_pe.c:                ptr->bind = r_str_const ("GLOBAL");
libr/core/bin.c:        return (strcmp (s->bind, "GLOBAL") == 0);
shlr/java/class.c:                      sym->bind = r_str_const ("GLOBAL");
shlr/java/class.c:                      sym->bind = r_str_const ("GLOBAL");

和实际的srccode

>grep -r -B 10 -A 5 "\"GLOBAL\""  .\libr\bin\p\bin_pe.c
        if (!(ret = r_list_new ()))
                return NULL;
        ret->free = free;
        if ((symbols = PE_(r_bin_pe_get_exports)(arch->o->bin_obj))) {
                for (i = 0; !symbols[i].last; i++) {
                    if (!(ptr = R_NEW0 (RBinSymbol)))
                        break;
                    ptr->name = strdup ((char *)symbols[i].name);
                    ptr->forwarder = r_str_const ((char *)symbols[i].forwarder);
                    //strncpy (ptr->bind, "NONE", R_BIN_SIZEOF_STRINGS);
                    ptr->bind = r_str_const ("GLOBAL");
                    ptr->type = r_str_const ("FUNC");
                    ptr->size = 0;
                    ptr->vaddr = symbols[i].vaddr;
                    ptr->paddr = symbols[i].paddr;
                    ptr->ordinal = symbols[i].ordinal;

虽然我不确定,但我认为NONE意味着IMPORTEDNONE 的符号列表可以用rabin -iwhere-i表示导入的符号复制

2 0x10042c008    NONE    FUNC NETAPI32.dll_NetUserModalsSet