逆向基础05

全局对象的分析

全局对象的构造

通过调用堆栈查看调用过程

image-20191221081048522

_initterm 函数的源码

image-20191221081417735

_initterm 函数的汇编

image-20191221083040014

_initterm 函数的调用位置(源码)

image-20191221081844837

_initterm 函数的调用位置(汇编)

image-20191221082140244

提取 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 下可以查看源码

全局对象的析构

通过栈回溯查看调用过程

image-20191221084109052

析构函数调用的源头

image-20191221084324317

调用释放函数的汇编

image-20191221084637598

特征码

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

全局对象的操作

无论是构造还是析构,对于全局变量,操作的指令通常都是 mov ecx, 0x????????

如果是局部变量,操作方式通常是 lea ecx, [ebp - 0x??],需要进行区分

数据结构分析

字符串分析

CString 对象,占用了 4 字节的大小,使用之前需要先初始化空间再调用构造函数

image-20191221092039293

string 对象: 大小是 1C

1
2
3
4
5
6
7
8
9
10
struct my_string
{
my_string* self; // 指向自己的指针
union {
char str[0x10]; // 当字符个数少于 16
char* point; // 当字符个数大于 15
};
int length; // 当前的字符个数
int size; // 缓冲区的大小-1(空字符)
};

vector分析

vector 的调用过程

image-20191221095034718

对应的数据结构,大小是 0x10

1
2
3
4
5
6
7
8
template<class T>
struct my_vector
{
my_vector* self; // 指向自己的指针
T* fisrt; // 指向数据的首地址
T* last; // 最后一个元素的下一个位置
T* end; // 指向堆空间的结尾(end 迭代器的指向)
};

list 分析

list 的调用过程

image-20191221102423036

list 的数据结构: 大小是 0x0c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <class T>
struct my_list_node
{
my_list_node* next; // 下一个节点
my_list_node* prev; // 上一个节点
T data; // 数据域
};

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

map 分析

不要纠结

1
2
3
4
5
6
7
8
9
10
11
12
// map 的实现是一个红黑树
struct _Tree_node
{
_Tree_node* _Left; // left subtree, or smallest element if head
_Tree_node* _Parent; // parent, or root of tree if head
_Tree_node* _Right; // right subtree, or largest element if head

char _Color; // _Red or _Black, _Black if head
char _Isnil; // true only if head (also nil) node; TRANSITION, should be bool

// value_type _Myval; // 键值对,通常是一个结构体,大小 = sizeof(键) + sizeof(值)
};

迭代器分析

如何获取一个迭代器:初始化迭代器 + 将迭代器作为参数调用 begin 之类的函数

image-20191221103444302

执行 beign++ 操作

image-20191221103738069

迭代器的数据结构:大小是 0x0C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <class T>
struct point
{
T* target; // 目标容器的指针
my_iterator* self; // 自己的地址
};

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

MFC程序的分析

直接的获取到特征码: 不同版本的 VS 对应的特征码不同,所以需要自己分析,不同的事件对应的特征码也是不同。

image-20191221105610177

特征码:

1
2
3
4
5
6
7
8
9
10
11
12
13
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