freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

二进制分析实战笔记(一)
2024-11-28 21:18:13
所属地 江苏省

这个主要是我学习二进制分析实战的笔记,今天来到第一章节,简单的介绍一下二进制分析。本章节主要涉及编译相关的简要知识。如下是一个C语言的程序源码。

#include <stdio.h>
#define FORMAT_STRING "%s"
#define MESSAGE "Hello, world!\n"
int
main(int argc, char * argv[]) {
printf(FORMAT_STRING, MESSAGE);
return 0;
}

以下的内容是围绕这段代码的进行展开,首先说一下这段代码也就是一个简单的输出。

C编译过程

上图是介绍了源代码文件通过预处理、编译、汇编、链接等过程,生成了二进制可执行文件。

1、预处理阶段

stdio.h头文件全部包含在内,其所有的类型定义、全局变量及函 数原型都被“复制”到源文件中。因为每个#include指令都会发生这种情况,所以预处理器输出可能非常冗长。预处理器还完整地扩展 了#define定义的任何宏的所有用法。在示例中,这意味着对 printf(FORMAT_STRING和MESSAGE)的两个参数进行计算,并用它们所代表的常量字符串进行替换。

使用命令:gcc -E -P test1.c 。生成的结果:

typedef long unsigned int size_t;
typedef unsigned long int __fsblkcnt_t;
struct _IO_FILE;
struct _IO_marker;
struct _IO_codecvt;
struct _IO_wide_data;
typedef void _IO_lock_t;
struct _IO_FILE
{
  int _flags;
  char *_IO_read_ptr;
  char *_IO_read_end;
  char *_IO_read_base;
  char *_IO_write_base;
  char *_IO_write_ptr;
  char *_IO_write_end;
  char *_IO_buf_base;
  char *_IO_buf_end;
  char *_IO_save_base;
  char *_IO_backup_base;
  char *_IO_save_end;
  struct _IO_marker *_markers;
  struct _IO_FILE *_chain;
  int _fileno;
  int _flags2;
  __off_t _old_offset;
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];
  _IO_lock_t *_lock;
  __off64_t _offset;
  struct _IO_codecvt *_codecvt;
  struct _IO_wide_data *_wide_data;
  struct _IO_FILE *_freeres_list;
  void *_freeres_buf;
  size_t __pad5;
  int _mode;
  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
};
extern int printf (const char *__restrict __format, ...);
extern int __overflow (FILE *, int);
..........

int
main(int argc, char * argv[]) {
 printf("%s", "Hello, world!\n");
 return 0;
}

编译阶段

使用命令:gcc -S -masm=intel test1.c ,生成了汇编文件 test1.s ,  查看汇编的内容:

.file   "test1.c"
        .intel_syntax noprefix
        .text
        .section        .rodata
.LC0:
        .string "Hello, world!"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        endbr64
        push    rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        mov     rbp, rsp
        .cfi_def_cfa_register 6
        sub     rsp, 16
        mov     DWORD PTR -4[rbp], edi
        mov     QWORD PTR -16[rbp], rsi
        lea     rdi, .LC0[rip]
        call    puts@PLT
        mov     eax, 0
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0"
        .section        .note.GNU-stack,"",@progbits
        .section        .note.gnu.property,"a"
        .align 8
        .long    1f - 0f
        .long    4f - 1f
        .long    5
0:
        .string  "GNU"
1:
        .align 8
        .long    0xc0000002
        .long    3f - 2f
2:
        .long    0x3
3:
        .align 8

汇编阶段

使用命令:gcc -c test1.c

# 生成“.o"文件,查看“test1.o"文件,可以看到已经是ELF文件了。

# file test1.o
test1.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

链接阶段

此阶段将所有对象 文件链接到一个二进制可执行文件中。在现代系统中,链接阶段有时 会包含额外的优化过程,被称为链接时优化(Link-Time Optimization,LTO)。

C++root@z:~/bin_learn/chater01# gcc test1.c
root@z:~/bin_learn/chater01# file a.out
a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ea93fdba43c44214e687d2943d2d68c1f4f56403, for GNU/Linux 3.2.0, not stripped

最后a.out文件可以直接执行。解释器/lib64/ld-linux-x86- 64.so.2的文件输出会告诉你,当可执行文件加载到内存中执行时, 哪个动态链接器将会被用来解析动态库的最终依赖关系。

符号和剥离的二进制文件

查看符号信息

” readelf --syms a.out“  输出的结果做了一些删减,各位朋友可以自己做实验的时候查看具体的输出。

Symbol table '.dynsym' contains 7 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
6: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2)

Symbol table '.symtab' contains 65 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
…………
26: 0000000000004010 0 SECTION LOCAL DEFAULT 26
27: 0000000000000000 0 SECTION LOCAL DEFAULT 27
28: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
29: 0000000000001090 0 FUNC LOCAL DEFAULT 16 deregister_tm_clones
58: 0000000000004018 0 NOTYPE GLOBAL DEFAULT 26 _end
59: 0000000000001060 47 FUNC GLOBAL DEFAULT 16 _start
60: 0000000000004010 0 NOTYPE GLOBAL DEFAULT 26 __bss_start
61: 0000000000001149 38 FUNC GLOBAL DEFAULT 16 main
62: 0000000000004010 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__
63: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
64: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2

我们可以关注索引号为61的符号:

61: 0000000000001149 38 FUNC GLOBAL DEFAULT 16 main

main函数有一个符号。你可以看到它指定了当二进制文件加载到内存时main将驻留的地址(0x00001149)。输出 还显示main的代码大小(38字节),并指出你正在处理一个函数符号 (类型为FUNC)。

剥离二进制文件

1)查看对象文件

# .rodata节代 表的是“只读数据”
root@z:~/bin_learn/chater01# objdump -sj .rodata test1.o
test1.o: file format elf64-x86-64
Contents of section .rodata:
0000 48656c6c 6f2c2077 6f726c64 2100 Hello, world!.


# 以intel的语法反汇编
root@z:~/bin_learn/chater01# objdump -M intel -d test1.o

test1.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 55 push rbp
5: 48 89 e5 mov rbp,rsp
8: 48 83 ec 10 sub rsp,0x10
c: 89 7d fc mov DWORD PTR [rbp-0x4],edi
f: 48 89 75 f0 mov QWORD PTR [rbp-0x10],rsi
13: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # 1a <main+0x1a>
1a: e8 00 00 00 00 call 1f <main+0x1f>
1f: b8 00 00 00 00 mov eax,0x0
24: c9 leave
25: c3 ret
root@z:~/bin_learn/chater01#

显示对象文件中存在的所有重定位符号

# readelf --relocs test1.o

Relocation section '.rela.text' at offset 0x260 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000016  000500000002 R_X86_64_PC32     0000000000000000 .rodata - 4、
# 000000000016重定位符号告诉链接器应该解析对字符串的引用,使其 指向在.rodata节中结束的任意位置。

00000000001b  000c00000004 R_X86_64_PLT32    0000000000000000 puts - 4
# 00000000001b 重定位符号 告诉链接器应该解析对puts的引用。

Relocation section '.rela.eh_frame' at offset 0x290 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000020  000200000002 R
# 漏洞 # 网络安全 # 系统安全 # 漏洞分析
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录