发新帖我要提问
12
返回列表
打印

Crash/coredump 原理与实例

[复制链接]
楼主: keer_zu
手机看帖
扫描二维码
随时随地手机跟帖
21
keer_zu|  楼主 | 2023-2-7 17:09 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
3.4.3 可变参数函数参数个数不符合预期
#include<cstdio>
int main()
{
    printf("a:%d, b:%d\n");
    char *chs= "hello";
    int a = 0x1234;
    printf("a:%d, s:%s\n", a, chs);
    int b = 0x0188;
    __asm__("mov $0x1111, %rdx");//这里,我们手动写入rdx 寄存器的值,是为了给第三个参数一个“非法”的垃圾值
    printf("a:%d, s:%s\n", b);//crash: 因为这里会试图打印出,以0x1111为起始地址的字符串
    return 0;
}
对于可变参数函数,作为被调用方,是不会校验参数的合理性的。被调用方只会去对应的位置(寄存器 或者栈)寻找位置。因此一旦对应位置的垃圾数值不可访问,就会导致crash的发生。

使用特权

评论回复
22
keer_zu|  楼主 | 2023-2-7 17:09 | 只看该作者
3.4.4 内存越界
内存越界是一个相对比较宽泛的概念。最典型的就是数组下标越界,看一个例子。
#include<cstring>
#include<cstdio>
#include<string>
class Base {
    public:
    virtual void print() {
        printf("print\n");
    }
    void member_function () {
        printf("member\n");
    }
};

int i = 0;
Base *foop = NULL;
void CopyData(char const *szData)
{
    Base foo1;
    foop = &foo1;
    char cDest[1];
    foop->print();
    cDest[8] = 'a';
    foo1.member_function();
    foo1.print();
    foop->member_function();
    foop->print();//crash here
}
int main()
{
    CopyData("1234567890123456789012345678901234567890");
    return 0;
}
/*
print
member
print
member
[1]    2335 segmentation fault (core dumped)
*/
这里cDest[8] = 'a';是对应数组下标越界,而这里的越界会导致foo1对象的虚函数表指针被写入垃圾数值,因而会导致CopyData函数的最后一句调用失败。
由于栈上保存了很多信息,尤其是一些关键寄存器的信息:EIP和EBP等。这些缓存的寄存器被写入垃圾数值之后,可能导致函数栈回溯失败、非法指令等问题,甚至由此衍生出缓冲区溢出等攻击手段(现代操作系统已经几乎不存在)。一个常见的栈数据破坏性写入的场景是使用strcpy, strcat, sprintf, strcmp,strcasecmp等字符串操作函数,将目标字符串读/写爆.

使用特权

评论回复
23
keer_zu|  楼主 | 2023-2-7 17:10 | 只看该作者
3.5 栈破坏下crash的分析与调试方法
对于crash的分析思路,我们都知道首先使用bt命令查看crash对应的函数调用栈。但是在一些场景下,线程本身的栈结构被破坏,无法通过bt查看函数调用栈的情况。那么如何在函数调用的开始和结束执行对应的操作呢?g++/gcc正好提供了这种功能,能够让我们在函数的开始和结束嵌入对应的代码。 具体的操作方法可以参见另外一篇文章《如何处理栈被破坏的crash》

使用特权

评论回复
24
keer_zu|  楼主 | 2023-2-7 17:11 | 只看该作者
4.背景知识4.1 进程地址空间布局
进程的地址空间布局(下图为32b系统)。

这个不够直观,我们来看一个具体的程序:
//memory.cpp
#include<stdlib.h>
#include<iostream>
#include<stdio.h>
int a[100] = {0};
int b[200];
static char* global_static_inited = "static_data";
static char* global_static_uninited;
int main()
{
    int tmp[1024*1024];
    void *heap_small = malloc(10);
    void *heap_start = malloc(4*1024*1024 + 30);
    void *heap_second = malloc(4*1024*1024);
    printf("a:%p, \nb:%p, \nstatic_data:%p, \nglobal_static_uninited:%p, \ntmp:%p, \nhead_small:%p, \nheap_start:%p, \nheap_second:%p\n",\
            a,    b,    global_static_inited,    &global_static_uninited,   tmp,     heap_small,      heap_start,    heap_second);
    while(1);
    return 0;
}
/*
a:0x601080,
b:0x601220,
static_data:0x4008e0,
global_static_uninited:0x601548,
tmp:0x7fffb3267ef0,
head_small:0x1e64040,
heap_start:0x7f65e8ab2010,
heap_second:0x7f65e86b1010
*/
启动程序,运行pmap -d $thread_id
Address           Kbytes Mode  Offset           Device    Mapping
0000000000400000       4 r-x-- 0000000000000000 0fd:00017 a.out
0000000000600000       4 r---- 0000000000000000 0fd:00017 a.out
0000000000601000       4 rw--- 0000000000001000 0fd:00017 a.out
0000000001e64000     132 rw--- 0000000000000000 000:00000   [ anon ]
00007f65e86b1000    8200 rw--- 0000000000000000 000:00000   [ anon ]
00007f65e8eb3000      88 r-x-- 0000000000000000 0fd:00017 libpthread-2.17.so
00007f65e8ec9000    2048 ----- 0000000000016000 0fd:00017 libpthread-2.17.so
00007f65e90c9000       4 r---- 0000000000016000 0fd:00017 libpthread-2.17.so
00007f65e90ca000       4 rw--- 0000000000017000 0fd:00017 libpthread-2.17.so
00007f65e90cb000      16 rw--- 0000000000000000 000:00000   [ anon ]
00007f65e90cf000      12 r-x-- 0000000000000000 0fd:00017 libdl-2.17.so
00007f65e90d2000    2044 ----- 0000000000003000 0fd:00017 libdl-2.17.so
00007f65e92d1000       4 r---- 0000000000002000 0fd:00017 libdl-2.17.so
00007f65e92d2000       4 rw--- 0000000000003000 0fd:00017 libdl-2.17.so
00007f65e92d3000    1752 r-x-- 0000000000000000 0fd:00017 libc-2.17.so
00007f65e9489000    2048 ----- 00000000001b6000 0fd:00017 libc-2.17.so
00007f65e9689000      16 r---- 00000000001b6000 0fd:00017 libc-2.17.so
00007f65e968d000       8 rw--- 00000000001ba000 0fd:00017 libc-2.17.so
00007f65e968f000      20 rw--- 0000000000000000 000:00000   [ anon ]
00007f65e9694000      84 r-x-- 0000000000000000 0fd:00017 libgcc_s-4.8.5-20150702.so.1
00007f65e96a9000    2044 ----- 0000000000015000 0fd:00017 libgcc_s-4.8.5-20150702.so.1
00007f65e98a8000       4 r---- 0000000000014000 0fd:00017 libgcc_s-4.8.5-20150702.so.1
00007f65e98a9000       4 rw--- 0000000000015000 0fd:00017 libgcc_s-4.8.5-20150702.so.1
00007f65e98aa000    1028 r-x-- 0000000000000000 0fd:00017 libm-2.17.so
00007f65e99ab000    2044 ----- 0000000000101000 0fd:00017 libm-2.17.so
00007f65e9baa000       4 r---- 0000000000100000 0fd:00017 libm-2.17.so
00007f65e9bab000       4 rw--- 0000000000101000 0fd:00017 libm-2.17.so
00007f65e9bac000     932 r-x-- 0000000000000000 0fd:00017 libstdc++.so.6.0.19
00007f65e9c95000    2048 ----- 00000000000e9000 0fd:00017 libstdc++.so.6.0.19
00007f65e9e95000      32 r---- 00000000000e9000 0fd:00017 libstdc++.so.6.0.19
00007f65e9e9d000       8 rw--- 00000000000f1000 0fd:00017 libstdc++.so.6.0.19
00007f65e9e9f000      84 rw--- 0000000000000000 000:00000   [ anon ]
00007f65e9eb4000      24 r-x-- 0000000000000000 0fd:00017 gundam_preload.so
00007f65e9eba000    2044 ----- 0000000000006000 0fd:00017 gundam_preload.so
00007f65ea0b9000       4 r---- 0000000000005000 0fd:00017 gundam_preload.so
00007f65ea0ba000       4 rw--- 0000000000006000 0fd:00017 gundam_preload.so
00007f65ea0bb000     132 r-x-- 0000000000000000 0fd:00017 ld-2.17.so
00007f65ea2b3000      28 rw--- 0000000000000000 000:00000   [ anon ]
00007f65ea2da000       8 rw--- 0000000000000000 000:00000   [ anon ]
00007f65ea2dc000       4 r---- 0000000000021000 0fd:00017 ld-2.17.so
00007f65ea2dd000       4 rw--- 0000000000022000 0fd:00017 ld-2.17.so
00007f65ea2de000       4 rw--- 0000000000000000 000:00000   [ anon ]
00007fffb3267000    4104 rw--- 0000000000000000 000:00000   [ stack ]
00007fffb372f000       8 r-x-- 0000000000000000 000:00000   [ anon ]
ffffffffff600000       4 r-x-- 0000000000000000 000:00000   [ anon ]
mapped: 31104K    writeable/private: 12640K    shared: 0K
我们逐一解释:
  • 代码段
上文中0000000000400000是段的开始地址,并不是代码的开始地址。这个位置本身是不可访问的。代码段本身的权限是r + x. 需要注意的是static_data 这个字符串本身,是在代码段中。

(gdb) x/100i 0x000000000400000
   0x400000:    Cannot access memory at address 0x400000
(gdb) disassemble main
Dump of assembler code for function main():
   0x0000000000400730 <+0>:     push   %rbp
   0x0000000000400731 <+1>:     mov    %rsp,%rbp
   0x0000000000400734 <+4>:     sub    $0x400010,%rsp
   0x000000000040073b <+11>:    mov    $0x40001e,%edi
   0x0000000000400740 <+16>:    callq  0x400600 <malloc@plt>
   0x0000000000400745 <+21>:    mov    %rax,-0x8(%rbp)
   0x0000000000400749 <+25>:    mov    $0x400000,%edi
   0x000000000040074e <+30>:    callq  0x400600 <malloc@plt>
   0x0000000000400753 <+35>:    mov    %rax,-0x8(%rbp)
   0x0000000000400757 <+39>:    jmp    0x400757 <main()+39>
End of assembler dump.
(gdb) x/20i 0x0000000000400730
   0x400730 <main()>:   push   %rbp
   0x400731 <main()+1>: mov    %rsp,%rbp
   0x400734 <main()+4>: sub    $0x400010,%rsp
   0x40073b <main()+11>:        mov    $0x40001e,%edi
   0x400740 <main()+16>:        callq  0x400600 <malloc@plt>
   0x400745 <main()+21>:        mov    %rax,-0x8(%rbp)
   0x400749 <main()+25>:        mov    $0x400000,%edi
   0x40074e <main()+30>:        callq  0x400600 <malloc@plt>
   0x400753 <main()+35>:        mov    %rax,-0x8(%rbp)
   0x400757 <main()+39>:        jmp    0x400757 <main()+39>


使用特权

评论回复
25
keer_zu|  楼主 | 2023-2-7 17:12 | 只看该作者
  • 数据段
存放全局变量,包括静态和非静态,可以看到初始化和为初始化的数据,在同一个段上。这个段中的变量包括:a、b、global_static_uninited。
  • 函数局部变量
对应tmp,对应stack区域, 权限是rw
  • 堆空间
广义上,我们把mmap对应的区间也算作堆空间。这部分对应heap_start和heap_second. 狭义的堆空间,是heap_small对应的空间,起始段地址远小于heap_start对应的空间。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则