freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

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

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

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

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

这个主要是我学习二进制分析实战的笔记,今天来到第一章节,简单的介绍一下二进制分析。本章节主要涉及编译相关的简要知识。如下是一个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
可试读前30%内容
¥ 19.9 全文查看
9.9元开通FVIP会员
畅读付费文章
最低0.3元/天
# 漏洞 # 网络安全 # 系统安全 # 漏洞分析
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 HKAlong 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
二进制分析实战
HKAlong LV.2
这家伙太懒了,还未填写个人描述!
  • 4 文章数
  • 1 关注者
二进制分析实战笔记(三)---pwntool介绍
2025-03-27
二进制分析实战笔记(二)
2025-03-27
供应链投毒(恶意NPM包内嵌木马分析)
2024-11-25
文章目录