编译技术什么是程序的入口语句

编译技术什么是程序的入口语句,第1张

编译技术什么是程序的入口语句?我们刚开始学习C语言的时候,总会以一个hello world程序开始了解,并会被告知main是程序的入口函数。

那么是否有怀疑过,既然main是函数的入口,那么全局函数是如何初始化的?

实际上main并不是一个程序的入口地址。

以linux为例,一个可执行程序是ELF格式(Executable and Linkable Format)。在ELF的文件头里老档记录了当程序入口地址,该入口地址是内核加载该文件后的第一条指令执行的地方。

可以写个hello world,生成可执行文件,然后通过readelf -h a.out查看文件头:

ELF 头: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 类别: ELF64 数据: 2 补码,小端序 (little endian) 版本: 1 (current) OS/ABI: UNIX - System V ABI 版本: 0 类型: DYN (共享目标文件) 系统架构: Advanced Micro Devices X86-64 版本: 0x1 入口点地址: 0x1040 程序头起点: 64 (bytes into file) Start of section headers: 14688 (bytes into file) 标志: 0x0 本头的大小: 64 (字节) 程序头大小: 56 (字节) Number of program headers: 11 节头大小: 64 (字节) 节头数量: 29 字符串表索引键含帆节头: 28

这里入口地址是0x1040。

让我们反编译看看:

0000000000001040 <_start>: 1040: f3 0f 1e fa endbr64 1044: 31 ed xor %ebp,%ebp 1046: 49 89 d1 mov %rdx,%r9 1049: 5e pop %rsi 104a: 48 89 e2 mov %rsp,%rdx 104d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 1051: 50 push %rax 1052: 54 push %rsp 1053: 4c 8d 05 76 01 00 00 lea 0x176(%rip),%r8 # 11d0 <__libc_csu_fini>105a: 48 8d 0d ff 00 00 00 lea 0xff(%rip),%rcx # 1160 <__libc_csu_init>1061: 48 8d 3d d1 00 00 00 lea 0xd1(%rip),%rdi # 1139 <main>1068: ff 15 72 2f 00 00 callq *0x2f72(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5>106e: f4 hlt 106f: 90 nop

0x1040对应的是_start函数,_start调用了glibc中的__libc_strat_main.__libc_strat_main最终会调用main函数。(_start和__libc_start_main的分析见《程序员的自我修改——链接、装载与库》11.1)

既然知道main不是程序的真正入口,那么是否稿雹有办法在main之前或之后执行代码呢?

gcc提供了一组“进入”、“退出”函数可以首先这个功能:

前言:在逆向工作流程中,我们会接触到so文件,并且在某种情况下会对so文件进行处理。 在文件的角度而言,so隶属于 ELF 文件。 站在ELF文件角度来分析一下so文件。

ELF 文件大致分为3个主要部分

1、ELF HEAD --ELF文件头部分

2、 Program Header Table --程序头表

3、Section Header Table --节头表

这个部分称为“头”,里面大闷蚂致描述在这个文件里面的组织。如:文件魔术、目标架构体系(如ARM、X86...)、版本信息、各个部分的大小、衡芦各个部分的偏移起始地址等等。

下面描述的位置都是固定的,且位置都是紧接着下一部分的位置。(有误欢迎指出)

这里我用的是IDA的android_server文件做演示,来简单看一部分内容。

文件的标识信息(e_ident):前16字节 (包括魔术部分:前4字节 如.ELF)

文件类型(e_type ):2字节

目标架构(e_machine ):2字节

版本(e_version):4字节

程序入口虚拟地址(e_entry ):4字节

程序头部表偏移地址(e_phoff ):4字节

节区头部表偏移地址(e_shoff ):4字节

保存与文件相关的,特定于处理器的标志(e_flags ):4字节

ELF头的大小(e_ehsize ):2字节

每个程序头部表的大小(e_phentsize ):2字节蚂拦埋

程序头部表的数量(e_phnum ):2字节

每个节区头部表的大小(e_shentsize):2字节

节区头部表的数量(e_shnum ):2字节

节区字符串表位置(e_shstrndx):2字节

......

程序头表描述的是程序里面各个段的信息。

这里来举例看一下

比如程序头,第一部分, 这个部分描述程序头的信息,比如类型、大小、偏移等等;这个部分描述的就是程序头的信息。

一个程序中到底有多少节信息,取决于这一部分,节头表。

比较经典的,就是这里的导出函数信息。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8236524.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-14
下一篇 2023-04-14

发表评论

登录后才能评论

评论列表(0条)

保存