笔记:逆向005.zip
练习:MFC逆向练习-杜绝暴力破解.zip

一、全局对象的分析

1. 全局对象的构造

  • 通过调用堆栈查看调用过程
    image-20191221081048522.png
  • initterm 函数的源码
    image-20191221081417735.png
  • initterm 函数的汇编
    image-20191221083040014.png
  • initterm 函数的调用位置(源码)
    image-20191221081844837.png
  • initterm 函数的调用位置(汇编)
    image-20191221082140244.png
  • 提取 initterm 中调用初始化函数位置的特征

    1. 8B 4D FC 8B 11 89 55 F8 8B 4D F8 FF 15 ?? ?? ?? ?? FF 55 F8 EB CF
  • C:\Program Files (x86)\Windows Kits\10\Source\SDK版本\ucrt\startup 下可以查看源码

2. 全局对象的析构

  • 通过栈回溯查看调用过程
    image-20191221084109052.png
  • 析构函数调用的源头
    image-20191221084324317.png
  • 调用释放函数的汇编
    image-20191221084637598.png
  • 特征码
    1. 89 45 C4 8B 4D EC 8B 55 D4 89 11 8B 45 C4 89 45 D0 8B 4D D0 FF 15 ?? ?? ?? ?? FF 55 D0

3. 全局对象的操作

  • 无论是构造还是析构,对于全局变量,操作的指令通常都是 mov ecx, 0x????????
  • 如果是局部变量,操作方式通常是 lea ecx, [ebp - 0x??],需要进行区分

二、数据结构分析

1. 字符串分析

  • CString 对象,占用了 4 字节的大小,使用之前需要先初始化空间再调用构造函数
    image-20191221092039293.png
  • string 对象: 大小是 1C
    1. struct my_string
    2. {
    3. my_string* self; // 指向自己的指针
    4. union {
    5. char str[0x10]; // 当字符个数少于 16
    6. char* point; // 当字符个数大于 15
    7. };
    8. int length; // 当前的字符个数
    9. int size; // 缓冲区的大小-1(空字符)
    10. };

2. vector分析

  • vector 的调用过程
    image-20191221095034718.png
  • 对应的数据结构,大小是 0x10
    1. template<class T>
    2. struct my_vector
    3. {
    4. my_vector* self; // 指向自己的指针
    5. T* fisrt; // 指向数据的首地址
    6. T* last; // 最后一个元素的下一个位置
    7. T* end; // 指向堆空间的结尾(end 迭代器的指向)
    8. };

3. list 分析

  • list 的调用过程
    image-20191221102423036.png
  • list 的数据结构: 大小是 0x0c ```cpp template struct my_list_node { my_list_node next; // 下一个节点 my_list_node prev; // 上一个节点 T data; // 数据域 };

template struct my_list { my_list self; // 指向自己的指针 my_list_node header; // 指向头节点,头节点不存储数据 int size; // 元素个数 };

  1. <a name="ivysR"></a>
  2. ## 4. map 分析
  3. - 不要纠结
  4. ```cpp
  5. // map 的实现是一个红黑树
  6. struct _Tree_node
  7. {
  8. _Tree_node* _Left; // left subtree, or smallest element if head
  9. _Tree_node* _Parent; // parent, or root of tree if head
  10. _Tree_node* _Right; // right subtree, or largest element if head
  11. char _Color; // _Red or _Black, _Black if head
  12. char _Isnil; // true only if head (also nil) node; TRANSITION, should be bool
  13. // value_type _Myval; // 键值对,通常是一个结构体,大小 = sizeof(键) + sizeof(值)
  14. };

5. 迭代器分析

  • 如何获取一个迭代器:初始化迭代器 + 将迭代器作为参数调用 begin 之类的函数image-20191221103444302.png
  • 执行 beign++ 操作
    image-20191221103738069.png
  • 迭代器的数据结构:大小是 0x0C ```cpp template struct point { T target; // 目标容器的指针 my_iterator self; // 自己的地址 };

template struct my_iterator { point p; // 一个指针 my_iterator prev; // 上一个迭代器,如果是首元素就为 0 T data; // 指向的是数据, iter 就是从这里获取数据 };

  1. <a name="PELpN"></a>
  2. # 三、MFC程序的分析
  3. - 直接的获取到特征码: 不同版本的 VS 对应的特征码不同,所以需要自己分析,不同的事件对应的特征码也是不同。<br />![image-20191221105610177.png](https://cdn.nlark.com/yuque/0/2019/png/599030/1576922380529-3be5bb7e-4261-4b59-a574-f318d3847af8.png#align=left&display=inline&height=1051&name=image-20191221105610177.png&originHeight=1051&originWidth=1920&size=281563&status=done&style=none&width=1920)
  4. - 特征码:

VS19-按钮: 8B 4D 08 FF 55 B8 3B F4 0091852B 8B 4D 08 mov ecx,dword ptr [pTarget]
0091852E FF 55 B8 call dword ptr [ebp-48h]
00918531 3B F4 cmp esi,esp

Debug 动态、静态编译 CALL DWORD PTR SS:[EBP-8]

Release 动态编译 CALL DWORD PTR SS:[EBP+0C]

Release 静态编译 CALL DWORD PTR SS:[EBP+14] ```

  • MFC002 程序中的一部分逻辑
    image-20191221113207642.png