知识积累(1)-reverse

关于reverse过程中的一些细节知识/经验的积累。

基础

ARM

  • 连接寄存器LR(Link Register)——在ARM体系结构中LR的特殊用途有两种:一是用来保存子程序返回地址,二是当异常发生时,LR中保存的值等于异常发生时PC的值减4(或者减2);因此在各种异常模式下可以根据LR的值返回到异常发生前的相应位置继续执行;可以使用如下两条指令之一实现子程序(调用函数)返回。
MOV PC, LR
BX LR

VM

  • 关于VM:通俗的讲 vm就是自己设计一套指令集 和一套解析这个虚拟指令集的引擎 把原本的386代码翻译成你自己的虚拟指令 然后调用你的虚拟引擎来执行这些虚拟指令;
  • 通过逆向判断是VM:参考题目如cyvm,思路如下图。

经验

  • 判断代码在编译时是否经过了优化(比如编译时是否添加了Maximize speed)——从汇编代码起始处可以看出

若经过了优化——push ecx(直接给局部变量分配空间);
若无优化——push ebp,mov ebp,esp;

  • 对于c++类中的this指针:一般存放在ecx寄存器中。
  • 对于double、float等浮点数的操作,汇编代码中就会用到xmm0等寄存器和浮点数指令,此时应该优先考虑在ida中f5查看伪代码,会容易理解一些;

如图所示代码其实就是下图红圈所示伪代码的意思。

  • 二进制文件中的一些常量值,形如qword_C08等,都存在.data段或者.rodata段中,可以在ida中IDA View-A中查看如图;

  • 在ida中对F5之后的C++伪码的理解——参考题目:c plus plus;
  • ida对字符串的识别出错;

在ida中静态分析时若发现很长的连续赋值操作如下图

并且f5之后的关键语句不是很容易明白,如下图

这种情况考虑是ida对字符串的识别出了问题;
于是分别查看两个连续赋值的地址块的大小(3E-E和6F-3F)均为0x30,即48个字符;
于是右键上图中的V5和v54,选择“set lvar type”,并将其类型改为char v5[48]和char v45[48];
此时ida就会正常识别出其中的字符串,关键代码逻辑也会变得通俗易懂;
http://www.cnblogs.com/WangAoBo/p/7706719.html#_label3

  • 在linux下善用man和cat命令理解指令的含义;

遇到不懂的指令可以在终端中输入 man 指令名 查看具体的指令解释;

像这种函数的参数是几种不同的字符串的,实际在ida中解析看到的会是一些具体的数值而不是字符串;
而他们之间的对应关系我们可以通过查看指令解释(man的输出)中的定义的头文件查找——通过 cat 头文件路径 命令;

  • 在IDA中识别各类型的变量;

https://www.cnblogs.com/17bdw/p/6629643.html
https://www.jianshu.com/p/7a0133eb9da6#422-%E8%AF%86%E5%88%AB%E7%BB%93%E6%9E%84%E4%BD%93
这里以结构体为例进行简要描述;
在ida中识别标记结构体变量(熟记结构体中所有变量都共享一片内存的特性,在反汇编中识别出结构体则在于多个变量一起传入了堆栈。逆向过程中更主要是靠猜,不对的话再改回来。而且改之前一定要有想法,知道自己要做什么);
如果在汇编代码中发现对某处内存附近进行连续读写且读写指令相距较近,则该处可能为结构体实例一部分。存在于堆空间的结构体大小一般可以从动态分配空间大小推断出来;存在于栈空间的结构体识别,则需要结合两种分析方式。第一种方式是采用累积法,如果发现内存连续赋值且这种行为在多处反汇编代码中出现就将该偏移处元素其加入结构体。第二种方式是反推法,对于栈结构体,分析当前整个函数栈大小和所有其他栈变量边界范围,反推出该结构体范围。如果从API调用参数或者从其他分析过的有关联的函数中已经得知该结构体类型,则可以简化分析。

  • ida中的8uLL或者010uLL代表此时的10个字节的数是无符号数,如图;如果某个变量是无符号数,则ida会在该变量前加上unsigned标志。