参考教程:https://www.wangan.com/docs/551
http://blog.nsfocus.net/linux-overflow-vulnerability-exploitation/

IDA F5不能正确反编译的情况:
https://bbs.pediy.com/thread-212429.htm
原因在于IDA用F5是通过;判断eax作为函数返回值
笔记:逆向003.zip
伪代码查看交叉引用是x,汇编代码ctrl+x和x一样

一、使用IDA分析程序

  • IDA 的快速启动界面(打开一个可执行文件)image-20191218083159935.png
  • 打开一个新的应用程序时,IDA的自动识别功能image-20191218083418367.png
  • 关闭IDA的时候,会自动的提示是否需要保存当前的数据文件(.idb),文件中存储了分析的过程中存在的函数名称等数据,以及 EXE 程序的本体,以后再次进行分析就不需要源文件。

image-20191218084225743.png

二、 认是IDA的界面

  • 主界面的默认布局如下,其中保存了多个不同的窗口,如果不小心关闭了窗口,可以通过菜单中的 VIEW -> OPEN Subview 再次打开指定的窗口,每一个窗口都可以同时存在多个image-20191218091339936.png
  • IDA 代码显示界面image-20191218091926595.png
  • IDA 的内存窗口使用,可以通过右键修改内存的显示方式image-20191218092906818.png
  • IDA 导出窗口,查看导出函数,找到 OEPimage-20191218093159151.png
  • IDA 导入窗口,查看导入函数image-20191218093351847.png
  • IDA 名称窗口,可以通过 F1 查看具体的类型image-20191218093732115.png
  • IDA 的函数窗口,可以查看函数的信息image-20191218094253260.png
  • IDA 字符串窗口,配合交叉引用有很大的作用image-20191218094629768.png
  • IDA 区段窗口:使用的比较少,主要是查看区段属性image-20191218094748186.png
  • IDA 签名窗口(Shift + F5 ),合理的使用签名可以让 IDA识别更多的函数,尽量打开一个程序的第一件事情就是加载签名,主要会识别一些库函数,防止不小心分析系统模块image-20191218095156793.png

vc32mfc、vc32rtf是常用的载入符号

  • IDA 的类型窗口,可以添加内置类型image-20191218095355001.png
  • 本地类型窗口,当前已经可以使用的一些内置结构体

image-20191218095444018.png

三、如何查找 main 函数

image-20191218101816256.png

image-20191218101905909.png

image-20191218102039613.png

  • 使用 OD 查找 main 函数: 1 + 2 + 3(三个间隔的函数中间一个) + 4

image-20191218102350963.png

image-20191218102439791.png

image-20191218102528138.png

image-20191218102627002.png

image-20191218102803453.png

image-20191218102937009.png

image-20191218103057238.png

image-20191218103124110.png

四、使用IDA分析程序

一、局部变量

  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3. // 局部变量
  4. int nNum = 1;
  5. float fNum = 2.5;
  6. char ch = 'A';
  7. printf("int %d, float %f, char %c", nNum, fNum, ch);
  8. return 0;
  9. }

使用快捷键 n

可以给函数或者变量或者代码修改名称

  • 如果不能确定一个函数的实际名称,尽量不要使用内置的名称
  • 对于 IDA 来说,所有的操作都是不可逆的,可以使用 ESC 返回上一层,使用 ctrl+enter 进入函数

    IDA中可以使用冒号(:)和分号(;)

    对代码进行注释,合理的注释可以更方便的分析image-20191218104404469.png

    可以使用 y

    或者菜单项修改变量的类型image-20191218110133693.png

二、全局变量

  1. // 全局变量,静态变量
  2. int g_nNum = 1;
  3. static int g_nCount = 2;
  4. float g_fNum = 2.5;
  5. char g_ch = 'A';
  6. int _tmain(int argc, _TCHAR* argv[])
  7. {
  8. printf("int %d, float %f, char %c",
  9. g_nNum, g_fNum, g_ch);
  10. return 0;
  11. }

交叉引用:

  • 函数的引用: 查找一个函数被哪一些地方调用
  • 数据的引用: 查找一个数据被哪一些地方使用image-20191218111329371.png

    对于已经初始化的数据,

    实际没有代码进行赋值,初始化操作是编译器完成的
    image-20191218111504596.png

    三、数组类型

  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3. int nArr[5] = { 1, 2, 3, 4, 5 };
  4. int n = 2;
  5. nArr[n] = 20;
  6. return 0;
  7. }

函数的模拟栈帧image-20191218112120979.png

将类型转换成数组的操作image-20191218112548932.png

如果不小心修改了代码,

并且无法还原,可以执行下面的操作

  • u: 表示取消这个函数的定义,取消后就是字节
  • c: 将目标看作是一段代码进行解释
  • p: 将目标看作是一个函数解释,解释函数的过程中会重新构建模拟栈帧

四、 结构体类型

  1. struct MyStruct{
  2. int nNum;
  3. float fNum;
  4. char chA;
  5. };
  6. void Print(MyStruct stc)
  7. {
  8. printf("int %d, y %f, z %c", stc.nNum, stc.fNum, stc.chA);
  9. }
  10. int _tmain(int argc, _TCHAR* argv[])
  11. {
  12. MyStruct stc = { 1, 2.2, 'A' };
  13. stc.fNum = 5.5;
  14. Print(stc);
  15. return 0;
  16. }

添加一个新的结构体image-20191218113959148.png

为结构体添加字段image-20191218114135872.png

应用结构体image-20191218114259750.png

五、一些内置函数的特征

CheckEsp 函数:

用于检查堆栈是否平衡,通常在函数调用后使用

  1. cmp xxx, esp
  2. call j___RTC_CheckEsp

CheckStackVars 函数:

用于检查数组是否越界,原理是判断数组后的 cc 有没有被覆盖

  1. lea edx, dword_411420(全局变量)
  2. call CheckStackVars