程序的机器级表示
隐藏的东西 in higher
程序计数器PC,寄存器(整数寄存器,浮点数寄存器,条件码寄存器)。寄存器可以操作不储存不同字节大小的数据。
阅读汇编代码
反汇编得到汇编代码
了解各个指令的具体含义,sub、movb、movzbw、leaq等等。学会阅读不同的操作数格式。
控制语句
根据条件码寄存器跳转到指定位置,以达到循环语句和判断语句的效果。
switch使用跳转表,根据对应值按照跳转表进行跳转,跳转表对应数值较大时可以进行相应加减运算处理。跳转表范围较大且表项比较稀疏的时候,可以构建二叉树 二分查找。
过程
全局变量在data区域,代码在text区域,局部变量在stack区域,new、malloc的变量在heap区域。
Stack
被调用的函数调用结束时,对栈指针进行操作,之后ret弹出返回地址,返回调用函数。
栈帧管理(每一个函数有自己对应的栈帧),函数在stack上的储存空间 成为过程的栈帧(stack fram),栈帧会保留需要保留的寄存器 以便在函数调用结束后恢复寄存器原有的值(有的寄存器由caller保存 有的由callee保存)。
寄存器不足够存放本地数据、对局部变量进行&运算、局部变量为数组或者结构,此时局部变量必须存放在内存中。
Array Union Struct
数组地址顺序排列。结构体地址顺序排列。
Union所占地址空间大小为其中最大的数据所占地址空间,相当于对同一地址空间的不同部分赋予不同的别名,在使用时按照别名进行类型转换。
1 | union u{ |
则 i 为 f底层float表示方法的 十进制数值。
sizeof(u0)=4
size0f(u0.i)=sizeof(u0.f)=sizeof(u0)=4
数据对齐
任何K字节的基本对象的地址必须是K的倍数
1 | struct test{ |
则 sizeof(t1)=12
i占四字节,j占一字节但是j后面三字节为空以达到数据对齐目的,K占四字节 所以共十二字节。
同一类型对象尽量放在一起,节省空间。
内存越界引用和缓冲区溢出
attack lab就是基于缓冲区溢出后 修改返回地址 达到攻击的效果。
C对于数组引用不进行边界检查,局部变量和状态信息都保存在stack 越界引用数组容易修改状态信息(返回地址等)进行破坏。
gets读函数对读入数据大小不进行检查,数据溢出缓冲区会导致stack中信息被破坏。
防范手段
写更加strong的代码,进行数据大小检查。
对stack进行破坏检测,存储canary(金丝雀)值(通常该值 末尾以 0 结尾,即使字符数组溢出1位也不影响,因为字符以0结尾,不会修改canary数值,贴心)
stack地址随机化
限制可执行代码区域,