2020.03.16-2020.03.22
32位软件逆向技术
数据结构
计算机存储、组织数据的方式。确定数据结构后,算法就很容易得到,有时候也根据特定算法来判断数据结构
局部变量
局部变量分配空间时通常会使用栈和寄存器
利用栈存放局部变量
变量分配与清除的形式:
1 | sub esp,n |
1 | add esp,-n |
- (省空间)
1 | push reg ;(相当于sub esp,4) |
局部变量的起始值是随机的,是其他函数执行后留在栈中的垃圾数据,因此需要进行初始化,一种方法是通过mov指令,另一种是用push,如:“push 5”
利用寄存器存放局部变量
除了栈占用2个寄存器,编译器会利用其他6个通用寄存器尽可能的存放局部变量,如果寄存器不够用会存到栈中
全局变量
全集变量通常位于.data区块的一个固定地址处,访问时一般会用一个固定的硬编码地址直接对内存进行寻址(←使用这种方式比较容易识别出这是一个全局变量。)
一般编译器会将全局变量放到可读写的区块里,如果放到只读区块里就是一个常量
数组
访问一般时通过基址加变址寻址实现的(基址可以是常量也可以是寄存器)
虚函数
虚函数是在程序运行时定义的函数。(c++)
虚函数的地址不能在编译时确定,只能在调用即将进行时确定。所有对虚函数的引用通常放在一个专用数组-虚函数表(virtual table)中,数组中的元素存放的就是类中数表的地址。
虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
基类:当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。
继承:代表了 is a 关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。(runoob.com)
程序通过两次寻址得到虚函数的地址然后执行
控制语句
if-else
通常为:
1 | cmp a,b |
整数用cmp指令比较,浮点值用fcom、fcomp等指令比较
许多情况下,编译器用test或or之类的较短的逻辑指令来替换cmp指令
switch-case
编译器会编译出一组由不同关系运算组成的语句
如果编译时设置优化选项为“Maximize Speed”,编译器会用"dec eax"代替cmp指令。如:
1 | push ecx |
转移指令机器码的计算
短转移:无条件和有条件的机器码均为2字节,范围为-128~127(2^8)
长转移:无条件的机器码为5字节,条件转移为6字节。因为无条件用一个字节(jmp)表示转移类型;条件转移用2个字节(如je、jns),用其他四个字节表示偏移量
子程序调用指令:调用的参数不涉及寄存器、栈等值的类似于长转移;涉及的例如“call dword ptr [eax+2]” 比较复杂,不表(…)
条件转移指令的范围是16位遗留下的。
cpu开发人员只给目的地址分配了1字节(8位),将跳转的长度限制在225字节之内
无条件短转移的机器码形式为:“EBxx”。B00H~EB4F是向后转移,EB80~EBFFH是向前转移
转移指令的机器码形式为:
位移量=目的地址-起始地址-跳转指令本身长度
转移指令机器码=转移类别机器码(如前文中的EB)+位移量
python爬虫学习
记录的有点乱,还没整理好
学习的原因是 看了某个论坛上一个学了几周爬虫 后用其爬的结果回答的答主 遂感牛逼,再加上有时候想学点别的作为调节(🤦)
https://brubbish.github.io/710f8e5f.html