软件安全逆向——软件漏洞
软件漏洞可了解攻击虚函数虚函数指针保存在对象的内存空间中,紧接着的是其他成员变量。虚函数表保存在静态数据区,其入口地址(虚函数指针)被统一存放在虚函数表中。其代码存在代码区。 虚函数表与类对应,相同类的不同对象的虚函数指针指向相同的虚函数表 对象使用虚函数时先通过虚函数表指针找到虚函数表,然后从虚函数表中取出虚函数指针,之后利用指针去调用代码 若虚函数表里存储的虚函数指针被篡改,程序调用虚函数的时候就会执行篡改后指定地址的恶意代码,即虚函数攻击 权限类漏洞(权限提升)分为水平越权和垂直越权 水平越权:相同级别的用户或同一角色的不同用户之间可以越权访问、修改或删除的非法操作; 垂直越权分为向上越权和向下越权;向上越权即低权限用户或无权限用户可做与高权限用户相同的事情;向下越权即高级别用户可以访问一个低级别的用户信息 需掌握整数溢出漏洞一般用于绕过目标程序的条件检测以实现其他攻击,当malloc计算size时若发生整数溢出则会分配大小为0的内存块,使得后续执行会发生堆溢出。 存储溢出:使用另外的数据类型来存储整型数 运算溢出:对整型变量进行运算时没有考虑边界范围,造成运算后数值...
软件安全逆向——溢出漏洞
溢出漏洞可了解漏洞也称为脆弱性【Vulnerability】 缓冲区:一块连续的内存区域,用于存放程序运行时加载到内存的运行代码和数据 缓冲区溢出:程序运行时,向固定大小的缓冲区写入超过其容量的数据,多余的数据会越过缓冲区的边界覆盖相邻内存空间从而造成溢出 造成缓冲区溢出的根本原因:缺乏类型安全功能的程序设计语言(C\C++等)处于效率的考虑,部分函数不对数组边界条件和函数指针引用等进行边界检查。(未对缓冲区边界进行检查) 对于单字节溢出,必须利用其函数中首个变量 堆溢出漏洞C语言中,堆通过malloc命令申请堆空间 123456char bufchar[100];//20 字节本身不满足 16/32/64 字节对齐,向上取整为 32;同时malloc本身带16字节char* buf1 = (char*)malloc(20); char* buf2 = (char*)malloc(20);/*因为有效区起始地址要满足32地址对齐,因此buf2会从下一个32字节块开始分配,这也就导致两个buf起始地址会相差64字节*/diff = (long long)buf2-(long lo...
软件安全逆向——调试分析
调试分析可理解 PE:win32平台下的可执行文件数据格式(.exe,.dll) 加壳全称为可执行程序资源压缩 加壳工具:分为压缩类和加密类 附加在原程序上的解压程序的作用过程:通过Windows加载器载入内存后,先于原始程序执行,得到控制权;执行过程中对原始程序进行解密,还原,还原完成后再把控制权交还给原始程序,执行原来的代码程序。 Windows系统是哟个的处理器存取模式及对应的内存层面:用户模式(虚拟内存地址)和内核模式(物理内存地址)。 程序从虚地址到实地址(物理内存地址)的转换过程称为程序的再定位 存放差异PE文件中的数据按照磁盘数据标准存放,当一个数据节不足0x200时,空位会被0x00填充,超出时会将下一个0x200分配给这个节使用,因此文件中的数据节大小永远是0x200的1整数倍; PE文件中的数据按照内存数据标准存放,以0x1000字节为基本单位组织,空位以0x00补全,超出把下一节分配给它,文件中的数据总是0x1000的整数倍; x64dbg快捷键: F2 设断点 F8单步步过(不进入) F7单步步过(会步入子程序) F9 运行 F4运行到选...
C筑基——函数利用
函数利用 一个程序即由一个main函数和若干其他用户自定义函数(完成特定功能的程序模块)组成; 通过定义函数创建可被重复使用的代码以简化程序 分类:库函数(系统提供)+自定义函数(用户按需定义) 定义函数的一般形式1)无参函数版([]表示可省略)执行时无需从主调函数调用数据进来 123456/*这都是例子哈哈哈哈哈*/int Luxsie([void]) //如果主调函数不需要这个函数返回值,则直接写成void Luxsie()【不带return语句】{ int x=727; //声明部分 cout<<x<<endl; //执行部分} 2)有参数版执行时需接收来自主调函数传来的数据,实参与形参的类型必须相同或者是相容的; 相容的意思就是float b可以直接转成int x,然后b顺利送到形参x; 字符型与整型可以互相通用。 12345678910111213141516171819/*实参:须有确定值,以能有东西赋给形参形参: 定义时必须在首部的括号内指明类型实参与形参的传递是单向的,调...
C筑基——循环结构
循环结构 结构化程序设计的基本构成单元:顺序结构 选择结构 选择结构 C++中提供了三种类型循环即while语句、do~while语句和for语句 while语句(先判断表达式后执行)1234while(i<10){ cout<<i<<endl; i++;} do~while语句(先执行再判断,为真继续执行,为假退出)【即循环体至少会被执行一次】,因此对于循环条件要格外注意 1234do{ sum = sum+i; i++;}while(i<=100); //注意这里要有分号 for语句12345for(表达式1;表达式2;表达式3) //表达式1:对循环变量赋初值 表达式2:循环条件 表达式3:增量条件{ 语句1; ...} 分号都不能省略; 表达式1可省略,但要在for语句之前给循环变量设置初值,但分号不省略; 表达式2要是省略,内部必须有if语句来跳出,否则会陷入死循环; 1if (i<10) ...
C筑基——选择结构
选择结构 用于解决判断型问题,即根据不同的条件选择不同的操作,也称为分支结构 1234567891011121314/*这里补充一下之前的知识点*/#include <iostream>using namespace std;int main() { int a = 10; a += 2; // 累加赋值运算符,a = 10+2 = 12 a -= 5; // a = 12-5 = 7 a *= 3; // a = 7*3 = 21 a /= 4; // a = 21/4 = 5(整数除法,舍去小数) a %= 2; // a = 5%2 = 1 cout << a << endl; // 输出1 return 0;} if语句单分支结构【if(表达式)语句】语句可为单条语句,也可以是复合语句(需用{}括起来) 双分支结构【if(表达式)语句1 else 语句2】else条件范围内有多条语句也需要用{}扩起来 多分支结构【i...
软件安全逆向——寻址方式
寻址方式 [!IMPORTANT] 对于汇编主要指令的复习要会判断指令的合法性和判断基本运算(主要考察选择题) 立即数:直接嵌入在汇编指令中的常数 可理解 寻址方式就是处理器根据指令中给出的地址信息来寻找有效地址的方式,是确定本条指令的数据地址(操作数寻址)以及下一条要执行的指令地址(指令寻址)的方法。 指令寻址 顺序寻址:由于指令地址在内存中按顺序安排,当执行一段程序时,通常是一条一条指令地顺序进行。 跳跃寻址:当程序执行转移指令时,指令的寻址就采取跳跃寻址方式。所谓跳跃,就是指下条指令的地址由本条转移指令给出。 操作数寻址(会判别)形成操作数的有效地址的方法称为操作数的寻址方式。【汇编中表示例如:MOV 目的操作数,源操作数】 立即寻址:指令给出操作数本身 【MOV CL,05H(表示将数值存到CL存储器中)】 寄存器寻址:操作数存在寄存器中【MOV CL,AL】 直接寻址:指令中直接给出操作数的有效地址【MOV AL,[2100H]】(地址默认来自DS存储器,也可以指定ES:[2100H]) 寄存器间接寻址:操作数的有效地址是寄存器的值【MOV AX,...
软件安全逆向——汇编语言
汇编语言可理解堆结构堆块 堆块是堆的基本组织单位,包括块首和块身;一般位于整个堆区的开始位置,用于索引堆区中所有堆块的重要信息;堆块共分为占有态(系统管理)和空闲态(程序员管理),对于空闲态堆块而言,块首会额外存储两个4字节指针:Flink(前向)指针和Blink(后向)指针。 当我们使用函数申请的地址指针/句柄,会指向堆块块身的首地址(直接越过8字节的块首);堆块的大小包括块首,当申请16字节时,实际会分配24字节(自动加首部);堆块的单位是8字节,因此不足会按8字节进行分配。 堆表 在windouws系统中占有态的堆块被使用程序索引,空闲态的对快被堆表索引;其中最重要的堆表有:空闲双向链表(空表,freelist)和快速单向链表(快表,lookaside,加速堆块分配);空表包含空表索引(也叫空表表头,大小为128的数组(free[]),数组的每一项包含两个指针用于标识一条空表)和空闲链块两部分。 空表索引的free[1]用于白哦是堆中所有大小为8字节的空闲堆块,之后每个索引项指引的空闲堆块递增8字节。free[...

