联合、数据对齐和缓冲区溢出攻击

阅读经典——《深入理解计算机系统》05

本文讲述三个比较冷门的话题:联合、数据对齐和缓冲区溢出攻击。

  1. 联合体
  2. 数据对齐
  3. 栈帧为什么必须16字节对齐?
  4. 缓冲区溢出攻击

联合体

在C语言中有这么一个不常用的数据类型union,往往被人们遗忘。它就是联合体。

与结构体类似,都是用来封装多种数据类型,但含义不同。结构体会将各个字段按顺序分配各自独立的内存空间。而联合体则是只申请一块内存空间,由所有字段共用。听起来有些不可思议,共用一块内存空间的字段岂不是只能有一个值,那那些字段还怎么区分?下面给出一个使用联合体的经典案例。

我们想要实现一个二叉树结构,所有的内部结点具有左孩子和右孩子,但没有数据;所有的叶子结点既没有左孩子也没有右孩子,但有数据。很容易想到可以用如下的结构体来实现:

struct NODE_S {
    struct NODE_S *left;
    struct NODE_S *right;
    double data;
};

这样的话每个结点需要16字节,是不是有点浪费?因为总是有一半的空间处于无用状态,当作为内部结点时,data字段为空,当作为叶子结点时,leftright结点都为空。

这时候就可以用联合体来节约空间,原型如下:

union NODE_U {
    struct {
        union NODE_U *left;
        union NODE_U *right;
    } internal;
    double data;
};

这样的话每个结点只需要8个字节了,因为internal大小为8个字节,double大小也是8个字节,取最大值还是8个字节。对于该联合体类型的指针n,我们可以用n->internal.left来访问内部结点的左孩子,也可以用n->data来访问叶子结点。

可是,这个结果仍然不够令人满意,因为我们无法分辨出当前结点是内部结点还是叶子结点。那么我们可以增加一个枚举字段来表示结点类型:

typedef enum { N_LEAF, N_INTERNAL } nodetype_t;

struct NODE_T {
    nodetype_t type;
    union {
        struct {
            struct NODE_T *left;
            struct NODE_T *right;
        } internal;
        double data;
    } info;
};

这样一来每个结点需要12个字节了,type字段占用4个字节,info字段占用8个字节。当internaldata占用空间非常大时,该方案可以极大地降低内存消耗。

数据对齐

IA32并不要求数据对齐,但不同的平台有着额外的要求。Linux要求2字节数据类型(例如short)必须2字节对齐(意思是该数据的地址必须是2的整数倍),大于2字节的数据类型必须4字节对齐。而Windows要求K字节数据类型必须K字节对齐,除了long double要求4字节对齐。

对齐的数据有利于提高CPU的存取效率,更详细的说明见参考资料。

值得一提的是,为了对齐数据,结构体中往往会采取增加间隙的措施。例如对于如下结构体:

struct S1 {
    int i;
    char c;
    int j;
};

如果以完全紧密放置的方式保存的话,内存空间分配如下:

未对齐的数据

这导致j不满足4字节对齐的要求。因此编译器会在c后面插入一个3字节的间隙,如下所示:

对齐的数据

此时所有数据都满足了对齐要求。

栈帧为什么必须16字节对齐?

现在我们来解释上一篇文章《函数调用栈》中提出的问题,栈帧为什么必须16字节对齐。

Intel从Pentium III处理器开始推出的SSE指令集(Streaming SIMD Extensions,单指令多数据流扩展)要求操作对象为16字节对齐的数据。因此,栈帧为了支持该指令集,必须使自己16字节对齐,从而栈帧内部的数据才可能16字节对齐。否则即使数据相对于栈顶对齐,地址也不是16的整数倍。

缓冲区溢出攻击

缓冲区溢出的含义是为缓冲区提供了多于其存储容量的数据,就像往杯子里倒入了过量的水一样。通常情况下,缓冲区溢出的数据只会破坏程序数据,造成意外终止。但是如果有人精心构造溢出数据的内容,那么就有可能获得系统的控制权!例如,对于如下的简单程序:

void echo()
{
    char buf[8];
    gets(buf);
    puts(buf);
}

该函数的功能是读取输入的字符串,并输出。对应的栈帧结构如下:

echo函数的栈帧结构

如果gets函数中给buf赋予了长度超过8的字符串,可以想象,这个字符串将覆盖buf上方的内容。随着字符串长度的增大,echo栈帧中的“保存的%ebx”、“保存的%ebp”,以及调用者的栈帧中的“返回地址”将被依次覆盖。大部分情况下,覆盖会使程序紊乱并出错,从而导致程序终止,但如果有人巧妙地设计覆盖的内容,就实现了所谓的缓冲区溢出攻击。

简单来讲,黑客可以把恶意代码通过buf传入内存,并恰好使返回地址指向恶意代码的起始位置。这样的话,一旦echo函数返回,程序将立即跳转到恶意代码段,如果程序具有管理员权限,恶意代码就有了任意操作整个计算机的能力,后果不堪设想。

当然,时至今日,缓冲器溢出攻击已经不能通过这种简单的方式实现了。人们在编译器、处理器中切断了缓冲区溢出攻击的必经之路。但是,道高一尺魔高一丈,黑客们总能找到系统的漏洞,让系统安全人员防不胜防。正应了那句话:没有绝对安全的系统。在参考资料提到的另一篇博文中,详细讲述了缓冲区溢出攻击的细节,并给出了简单的实现代码,感兴趣的读者可以前往阅读。

参考资料

数据对齐详解 bakari
缓冲区溢出攻击 范志东

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容