二进制基础

2022-01-12 09:09:41 浏览数 (1)

做 pwn 或者 reverse 的一些基础

程序的编译与链接

编译:由 C 语言代码生成汇编代码

汇编:由汇编代码生成机器码

链接:将多个机器码的目标文件链接成一个可执行文件

Linux 下的可执行文件格式 ELF

可执行文件:.out

动态链接库:.so

静态链接库:.a

Windows 下的可执行文件格式 PE

可执行文件:.exe

动态链接库:.dll

静态链接库:.lib

ELF 文件结构

节视图 (磁盘中划分程序)、段视图 (内存中)

32 位系统虚拟内存大小为 4GB (2 的 32 次方)

并且内核空间 (kernal) 共享,下面的用户空间为 3GB,上面的内核空间为 1GB

操作系统 (arch 为例):1. linux 内核 (不同发行版都一样)。 2. 软件是由 GUN 开发的 (ls, cd 等) 3. arch 提供软件源 4. 桌面环境也是一个用户态程序 (也是一个软件)

内核是用于管理硬件的,所以内核只要在内存中装载一份,复用的思想

glic 动态链接库在内存中也只有一份

64 位操作系统 256TB, 内核 128TB, 用户 128TB

内存从低位向高位写

进程虚拟地址空间

代码语言:javascript复制
用户空间中分为(从上往下地址由高到低)
    内核空间
    栈空间(Stack):动态存储区, 控制程序流
    Memory Mapping Region:映射一个虚拟空间(glic)
    堆空间(heap):动态存储区, 满足用户动态内存申请(malloc)
    data段:静态存储区
    code段:静态存储区
    
堆空间从低地址向高地址增长
栈空间从高地址向低地址增长


段和节:

·代码段包含了代码和只读数据
    .test节(用户的代码实现)
    .rodata节
    .hash节
    .dynsym节
    .dynstr节
    .plt节
    .rel.got节
    ......
·数据段包含了可读可写数据
    .data节(一般性数据)
    .dynamic节(动态链接所需要的结构)
    .got节
    .got.plt节
    .bss节(全局偏移量的地址)
    ......
·栈段

·一个段包含多个节(意思是从磁盘到内存,一个段会变为多个节)
·段视图用于进程的内存区域的rwx权限划分
·节视图用于ELF文件 编译链接时 与 在磁盘上存储时 的文件结构的组织

程序的装载与进程的执行

磁盘上的可执行文件要先到内存,才能被 CPU 执行

从程序变为虚拟内存中

代码语言:javascript复制
int glb;
char* str = "Hello world";

int sum(int x, int y)
{
    int t = x   y;
}

int main
{
    sum(1, 2); (调用函数消耗的内存空间在栈中)
    void* ptr = malloc(0x100);
    read(0, ptr, 0x100);    // input "deadbeef"
    return 0;
}

编译链接执行 载入内存

代码语言:javascript复制
Kernel: 
Stack: t、ptr (程序进程执行栈)
Shared libraries: 
Heap: "deadbeef" (存放堆分配的空间)
Bss: glb (存放未初始化的全局变量)(不占用磁盘空间但是占用内存空间)
Data: str (保存只读、不可写、不可执行的数据)
Text: main、sum、"Hello world!" (以机器码的形式存放函数)
Unused: 

型参x、y的:
    amd64: CPU寄存器中
    x86: Stack中
代码语言:javascript复制
大端序和小端序

小端序(LSB):
    ·低地址存放数据低位、高地址存放数据高位(高"ABC"低, 内存中低到高: CBA)
    ·主要关注
大端序(MSB):
    ·低地址存放数据高位、高地址存放数据低位(高"ABC"低, 内存中低到高: ABC)
代码语言:javascript复制
amd64寄存器结构
    rax: 8Bytes (rax表示64bits(8Bytes)长的寄存器) 64位
    eax: 4Bytes (eax表示32bits(4Bytes)长的寄存器, 取rax的低四字节来操作)    32位
    ax: 2Bytes  (rx的低二字节)   16位
    ah: 1Bytes  (ax中的高一位字节)
    al: 1Bytes  (ax中的第一位字节)

部分寄存器的功能
    RIP: PC, 存放下一条指令的偏移地址
    RSP: 存放当前栈帧的栈顶偏移地址
    RBP: 存放当前栈帧的栈底偏移地址
    RAX: 通用寄存器或存放函数返回值
代码语言:javascript复制
静态链接的程序的执行过程

user mode
    $ ./binary
    frok()
    execve("./binary", *argv[], *envp[])
    
kernel mode
    -----------------------------------
    sys_execve()
    do_execve()
    search_binary_handler()
    load_elf_binary()
    -----------------------------------
    
user mode
    _start
    main()
    
代码语言:javascript复制
动态链接的程序的执行过程

user mode
    $ ./binary
    frok()
    execve("./binary", *argv[], *envp[])
    
kernel mode
    -----------------------------------
    sys_execve()
    do_execve()
    search_binary_handler()
    load_elf_binary()
    -----------------------------------
    
user mode
    ld.so   //库函数偏移地址
    _start
    __libc_start_main()
    _init
    main()
    

x86&amd64 汇编基础简述

函数状态涉及到: esp, ebp, eip esp 存储函数调用栈的栈顶地址 ebp 存储当前函数状态的基地址 eip 存储下一条执行的指令的地址

指令格式 | Base | Index | Scale | | ——————— | —– | —– | | 0 | 2 | 4 | | 偏移地址: 0 2*4 = 8 | | |

假设位移为: 0x10

则地址为: 0 2*4 0x10 = 24

代码语言:javascript复制
·MOV: 
    MOV DEST SRC 把源操作数传给目标(源操作数和被操作数不能同时是内存)
    
·LEA: 把源操作数的有效地址送给指定的寄存器
    LEA EBX ASC: 取ASC的地址存放至EBX寄存器中
    
·ADD/SUB: 目的操作数  /- 源操作数 -> 目的操作数地址

·PUSH: 将一个寄存器中的数据入栈,然后RSP减一个字节
    例如:   push $2
    分解为: sub 长度 %rsp
            mov $2 (%rsp)
            
·POP: 出栈用一个寄存器接受数据, 然后RSP减一个字节
    例如:   pop 目的地址
    分解为: mov (%rsp) 目的地址
            add 长度 %rsp
            
·CMP
    目的操作数减去源操作数
    
·JMP
    
·J[Condition]:
    
·CALL: 将目标地址压栈, 然后JMP
    例如:   call    reg
    分解为: push    RIP
            JMP     reg
            
·LEAVE: 函数返回时, 回复父函数栈帧的指令
    MOV ESP, EBP
    POP EBP
    
·RET: 在函数返回时, 控制程序执行流返回父函数的指令
    POP RIP(实际不存在的)

两种汇编格式

intel

AT&T

mov eax, 8

movl $8, �x

mov ebx, 0ffffh

movl $0xffff, �x

int 80h

int $0x80

mov eax, [ecx]

movl (�x), �x

[ ]: 取目的地址中的数值

intel

操作符重载

intel 汇编格式

代码语言:javascript复制
[base index*scale]Disp

byte ptr
mov qword ptr [rsp], 0xfffff
代码语言:javascript复制
sum: 
    push ebp
    mov ebp, esp
    mov eax, [ebp 12]
    add eax, [ebp 8]
    pop ebp
    retn

AT&T

在操作符后面会加上操作数的大小描述

AT&T 汇编格式

代码语言:javascript复制
Disp(base, index, scale)

movq $0xffff, (%rsp)

C 语言

数据类型

汇编代码后缀

char

字节

b byte

short

w word

int

双字

l

long int

双字

l

long long int

char*

双字

l

float

单精度

s

double

双精度

l

long double

扩展精度

t

代码语言:javascript复制
sum:
    pushl �p
    movl %esp, �p
    movl 12(�p), �x
    addl 8(�p), �x
    popl �p
    ret

0 人点赞