首页 > 其他分享 >聊一聊 .NET高级调试 中必知的符号表

聊一聊 .NET高级调试 中必知的符号表

时间:2023-12-12 16:58:03浏览次数:24  
标签:中必知 符号表 0000000000000000 聊一聊 func var main data

一:背景

1. 讲故事

在高级调试的旅行中,发现有不少人对符号表不是很清楚,其实简而言之符号表中记录着一些程序的生物特征,比如哪个地址是函数(签名信息),哪个地址是全局变量,静态变量,行号是多少,数据类型是什么 等等,目的就是辅助我们可视化的调试,如果没有这些辅助我们看到的都是一些无意义的汇编代码,逆向起来会非常困难,这一篇我们就来系统的聊一聊。

二:程序编译的四个阶段

1. 案例代码

要想理解符号表,首先需要理解 代码文件 是如何变成 可执行文件 的,即如下的四个阶段。

  • 预处理阶段
  • 编译阶段
  • 汇编阶段
  • 链接阶段

为了能够看到每一个阶段,用 gcc 的相关命令手工推进,并用 chatgpt 写一段测试代码,包含全局变量,静态变量,函数等信息。


#include <stdio.h>
#define PI 3.1415926

int global_var = 10;

void func() {

    static int static_var = 5;

    printf("global_var = %d, static_var = %d PI=%f\n", global_var, static_var,PI);

    global_var++;
    static_var++;
}

int main() {
    func();
    func();

    return 0;
}

接下来用 gcc --help 命令查看下需要使用的命令列表。


[root@localhost data]# gcc --help
Usage: gcc [options] file...
Options:
  -E                       Preprocess only; do not compile, assemble or link
  -S                       Compile only; do not assemble or link
  -c                       Compile and assemble, but do not link
  -o <file>                Place the output into <file>
  ...

2. 预编译阶段

预处理主要做的就是代码整合,比如将 #include 文件导入,将 #define 宏替换等等,接下来使用 gcc -E 进行预处理。


[root@localhost data]# gcc main.c -E -o main.i
[root@localhost data]# ls
main.c  main.i

可以看到这个 main.c 文件已经膨胀到了 858 行了。

3. 编译阶段

前面阶段是把代码预处理好,接下来就是将C代码编译成汇编代码了,使用 gcc -S 即可。


[root@localhost data]# gcc main.c -S -o main.s -masm=intel
[root@localhost data]# ls
main.c  main.i  main.s

从图中可以看到汇编代码中也有很多辅助信息,比如 global_var 是一个 @object 变量,类型为 int,在 .rodata 只读数据段中,目的就是给汇编阶段打辅助。

4. 汇编阶段

有了汇编代码之后,接下来就是将 汇编代码 转成 机器代码,这个阶段会产生二进制文件,并且会构建 section 信息以及符号表信息,可以使用 gcc -c 即可。


[root@localhost data]# gcc main.c -c -o main.o -masm=intel
[root@localhost data]# ls
main.c  main.i  main.o  main.s

二进制文件模式默认是不能可视化打开的,可以借助于 objdump 工具。


[root@localhost data]# objdump
  -h, --[section-]headers  Display the contents of the section headers
  -t, --syms               Display the contents of the symbol table(s)

[root@localhost data]# objdump -t main.o

main.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*	0000000000000000 main.c
0000000000000000 l    d  .text	0000000000000000 .text
0000000000000000 l    d  .data	0000000000000000 .data
0000000000000000 l    d  .bss	0000000000000000 .bss
0000000000000000 l    d  .rodata	0000000000000000 .rodata
0000000000000004 l     O .data	0000000000000004 static_var.2179
0000000000000000 l    d  .note.GNU-stack	0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame	0000000000000000 .eh_frame
0000000000000000 l    d  .comment	0000000000000000 .comment
0000000000000000 g     O .data	0000000000000004 global_var
0000000000000000 g     F .text	0000000000000058 func
0000000000000000         *UND*	0000000000000000 printf
0000000000000058 g     F .text	000000000000001f main

在上面的符号表中看到了 func函数以及 static_varglobal_var 以及所属的 section。

5. 链接阶段

这个阶段主要是将多个二进制代码文件进一步整合变成可在操作系统上运行的可执行文件,可以使用 gcc -o


[root@localhost data]# gcc main.c -o main
[root@localhost data]# ls
main  main.c  main.i  main.o  main.s
[root@localhost data]# ./main
global_var = 10, static_var = 5 PI=3.141593
global_var = 11, static_var = 6 PI=3.141593
[root@localhost data]# objdump -t main

main:     file format elf64-x86-64

SYMBOL TABLE:
...
0000000000601034 g     O .data	0000000000000004              global_var
0000000000601034 g     O .data	0000000000000004              global_var
...
000000000040052d g     F .text	0000000000000058              func
...

相比汇编阶段,这个阶段的 符号表 中的第一列都是有地址值的,是相对模块的偏移值,比如说: module+0x000000000040052d 标记的是 func 函数。

上面是 linux 上的可执行文件的符号表信息,有些朋友说我是 windows 平台上的,怎么看符号表信息呢?

三:Windows 上的 pdb 解析

1. 观察 pdb 文件

上一节我们看到的是 linux 上 elf格式 的可执行文件,这一节看下 windows 平台上的PE文件 的符号表信息是什么样的呢?有了前面四阶段编译的理论基础,再聊就比较简单了。

在 windows 平台上 符号表信息 是藏在 pdb 文件中的,这种拆开的方式是有很大好处的,如果需要调试代码,windbg 会自动加载 pdb 文件,无调试的情况下就不需要加载 pdb 了,减少了可执行文件的大小,也提升了性能。

接下来用 SymView.exe 这种工具去打开 pdb 文件,截图如下:

从图中可以看到,符号表信息高达 10968 个,并且 func 函数的入口地址是在 module +0x11870 处,相当于做了一个标记,接下来我们拿这个func做一个测试。

2. 有 pdb 的 func 函数

首先说一下为什么通过 exe 可以找到 pdb,这是因为 PE 头的 DIRECTORY_ENTRY_DEBUG 节中记录了 pdb 的地址。

只要这个路径有 pdb 就可以在 windbg 运行中按需加载了,然后通过 u MySample.exe+0x11870 观察,截图如下:

图中显示的非常清楚,地址 00fd1870 就是 func 的入口地址,让一个无意义的地址马上有意义起来了,哈哈~~~

3. 无 pdb 的 func 函数

这一小节是提供给好奇的朋友的,如果没有 pdb,那汇编上又是一个什么模样,为了找到 func 的入口地址,我们内嵌一个 int 3 ,然后把 pdb 给删掉,代码如下:


int main() {

	__asm {
		int 3;
	}
	func();
	func();

	return 0;
}

从图中可以看到,func 标记已经没有了,取而代之的都是 module+0xxx,这就会给我们逆向调试带来巨大的障碍。

三: 总结

总而言之,符号表就是对茫茫内存进行标记,就像百度地图一样,让我们知道某个经纬度上有什么建筑,让无情的地理坐标更加有温度,让世界更美好。

图片名称

标签:中必知,符号表,0000000000000000,聊一聊,func,var,main,data
From: https://www.cnblogs.com/huangxincheng/p/17897278.html

相关文章

  • 【Cpp 语言基础】简单聊一聊to_string
    头文件:#include<string>功能:将数字常量转换为字符串参数:value返回值:转换好的字符串重载版本:std::stringto_string(intvalue);(1)(C++11起) std::stringto_string(longvalue);(2)(C++11起) std::stringto_string(longlongvalue);(3)(C++11起) std::stringto......
  • 聊一聊 .NET高级调试 中的一些内存术语
    一:背景1.讲故事在高级调试的旅程中,经常会有一些朋友问我什么是工作集(内存),什么是提交大小,什么是VirtualSize,什么是WorkingSet。。。截图如下:既然有很多朋友问,这些用口头也不怎么好描述,刚好上午有时间就系统的聊一下吧。二:内存术语解读1.VirtualSize是什么可......
  • 聊一聊市面上电子签章产品的区别
    关于电子签名技术衍生的产品厂商有很多,产品定义大致有这几种叫法:电子签章平台、电子合同平台、电子签约平台、电子印章平台等等。无论如何定义产品,在普通用户看来大同小异,但是我认为各有千秋,这可能与创始团队要打造的产品理念不同,也许想从名称上定义自己的产品理念。目前市场上主......
  • 聊一聊市面上电子签章产品的区别
    关于电子签名技术衍生的产品厂商有很多,产品定义大致有这几种叫法:电子签章平台、电子合同平台、电子签约平台、电子印章平台等等。无论如何定义产品,在普通用户看来大同小异,但是我认为各有千秋,这可能与创始团队要打造的产品理念不同,也许想从名称上定义自己的产品理念。目前市场上主流......
  • 聊一聊大模型
    事情还得从ChatGPT说起。2022年12月OpenAI发布了自然语言生成模型ChatGPT,一个可以基于用户输入文本自动生成回答的人工智能体。它有着赶超人类的自然对话程度以及逆天的学识。一时间引爆了整个人工智能界,各大巨头也纷纷跟进发布了自家的大模型,如:百度-文心一言、科大讯飞-星火大模......
  • 简单地聊一聊Spring Boot的构架
    本文由葡萄城技术团队发布。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。前言本文小编将详细解析SpringBoot框架,并通过代码举例说明每个层的作用。我们将深入探讨SpringBoot的整体架构,包括展示层、业务逻辑层和数据访问层。通过......
  • 【主流技术】聊一聊 Redis 的基本结构和简单应用(一)
    目录前言一、String类型二、List类型三、Hash类型四、Set结构五、SortSet(Zset)结构六、文章小结前言Redis是目前互联网后端的热门中间件之一,在许多方面都有深度的应用,作为后端开发熟练掌握该技术是十分有必要的。Redis的五种数据类型是:1、String(字符串);2、Hash(哈希);3、L......
  • 聊一聊 tcp/ip 在.NET故障分析的重要性
    一:背景1.讲故事这段时间分析了几个和网络故障有关的.NET程序之后,真的越来越体会到计算机基础课的重要,比如计算机网络课,如果没有对tcpip协议的深刻理解,解决这些问题真的很难,因为你只能在高层做黑盒测试,你无法看到tcp层面的握手和psh通讯。这篇我们通过两个小例子来理解一......
  • nm 方便的查看对象文件的符号表信息工具
    很多时候我们需要知道对应一些以来库提供的方法,nm就是一个方便的工具,可以方便的查看对象文件的一些符号信息参考使用命令nm<objectfile>效果 其中T代表代码(实际上就是文本段)说明参考链接中有完整的输出信息说明可以参考参考资料https://ma......
  • 聊一聊质量度量之bug收敛
    之前有个做测试的同事给我吐槽,他们开发问他,为什么提测了,刚开始bug不多,到后面bug越来越多,bug到后期改都改不完了。她解释道,是因为刚开始拿到系统还有个熟悉的过程,慢慢测这才深入了,当然后面才多了。我相信很多测试或者开发同事都遇到过这种问题,开发说测试怎么回事,bug怎么越来越多,测......