序
话不多说,看效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | bool __fastcall cocos2d::LuaStack::setCai(cocos2d::LuaStack *this, const char *a2, const char *a3, const char *a4){ _BOOL8 result; // x0 size_t v8; // w26 size_t v9; // w24 size_t v10; // w22 void *v11; // x0 void *v12; // x0 void *v13; // x0 (*(void (__fastcall **)(cocos2d::LuaStack *))(*(_QWORD *)this + 240LL))(this); result = a4 != 0LL; if ( a3 != 0LL && result && a2 ) { v8 = strlen(a2); v9 = strlen(a3); v10 = strlen(a4); v11 = malloc(v8); *((_QWORD *)this + 6) = v11; memcpy(v11, a2, v8); *((_DWORD *)this + 14) = v8; v12 = malloc(v9); *((_QWORD *)this + 8) = v12; memcpy(v12, a3, v9); *((_DWORD *)this + 18) = v9; v13 = malloc(v10); *((_QWORD *)this + 10) = v13; memcpy(v13, a4, v10); *((_DWORD *)this + 22) = v10; result = 1LL; *((_BYTE *)this + 44) = 1; } else { *((_BYTE *)this + 44) = 0; } return result;} |
修复后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | bool __fastcall cocos2d::LuaStack::setCai( cocos2d::LuaStack *this, const char *xxteaKey, const char *xxteaSign, const char *xorKey){ _BOOL8 result; // x0 size_t v8; // w26 size_t v9; // w24 size_t v10; // w22 char *v11; // x0 char *v12; // x0 char *v13; // x0 this->cleanupXXTEAKeyAndSign(this); result = xorKey != 0LL; if ( xxteaSign != 0LL && result && xxteaKey ) { v8 = strlen(xxteaKey); v9 = strlen(xxteaSign); v10 = strlen(xorKey); v11 = (char *)malloc(v8); this->_xxteaKey = v11; memcpy(v11, xxteaKey, v8); this->_xxteaKeyLen = v8; v12 = (char *)malloc(v9); this->_xxteaSign = v12; memcpy(v12, xxteaSign, v9); this->_xxteaSignLen = v9; v13 = (char *)malloc(v10); this->_xorKey = v13; memcpy(v13, xorKey, v10); this->_xorKeyLen = v10; result = 1LL; this->_xxteaEnabled = 1; } else { this->_xxteaEnabled = 0; } return result;} |
破
开始之前,让我们先做套小学二年级自测题(此处非游戏代码,仅用于回忆知识):
考试环境:Debian GNU/Linux 12 (bookworm),g++ (Debian 12.2.0-14) 12.2.0,x86_64。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <iostream>using namespace std;struct Base{ Base(int a, long b) : m_a(a), m_b(b) {} int m_a; virtual void print() { cout << "m_a = " << m_a << ", m_b = " << m_b << endl; } long m_b; virtual ~Base() { cout << "~Base() called" << endl; }};struct Derived : public Base{ Derived(int a, long b, int c) : Base(a, b), m_c(c) {} virtual ~Derived() { cout << "~Derived() called" << endl; } void print() { cout << "m_a = " << m_a << ", m_b = " << m_b << ", m_c = " << m_c << endl; } int m_c;};int main(){ Derived d(1, 2, 3); Base *pb = &d; cout << sizeof(d) << endl; cout << *(int *)((long *)pb + 3) << endl; void (Base::*func)() = &Base::print; (pb->*func)(); ((void (*)())*(long *)*(long *)&d)(); pb = new Derived(4, 5, 6); cout << (*(long *)&d == *(long *)pb) << endl; delete pb; cout << "---- 楚河汉界 ----" << endl;} |
问题是:请给出输出结果。
做完了吗,揭晓答案:
1 2 3 4 5 6 7 8 9 10 | 323m_a = 1, m_b = 2, m_c = 3m_a = 0, m_b = 0, m_c = 01~Derived() called~Base() called---- 楚河汉界 ----~Derived() called~Base() called |
如果您都做对了,那您可以直接跳到下个章节了,否则,您需要恶补以下知识点:
- 内存对齐
- 类对象的大小(内存布局)
- 虚函数表指针
- 虚函数表
限于篇幅,这里就不展开写了。
对本文而言,核心就是要弄懂如何通过指针访问数据成员及调用虚函数。
Q
通过上一章的回顾,您可能已经自信满满了,但是先别高兴太早,您和编译器的理解方式未必就是 IDA 的理解方式。
让我们处理下前面的测试题,保存成一个头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | struct Base{ Base(int a, long b); int m_a; virtual void print(); long m_b; virtual ~Base();};struct Derived : public Base{ Derived(int a, long b, int c); virtual ~Derived(); void print(); int m_c;}; |
导入IDA中,然后插入Base_vtbl和Derived_vtbl两张虚函数表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 00000000 ; ---------------------------------------------------------------------------0000000000000000 Base_vtbl struc ; (sizeof=0x18, align=0x8, copyof_110)00000000 print dq ? ; offset00000008 Base_dtor_8 dq ? ; offset00000010 Base_dtor_10 dq ? ; offset00000018 Base_vtbl ends0000001800000000 ; ---------------------------------------------------------------------------0000000000000000 Derived_vtbl struc ; (sizeof=0x18, align=0x8, copyof_111)00000000 print dq ? ; offset00000008 Derived_dtor_8 dq ? ; offset00000010 Derived_dtor_10 dq ? ; offset00000018 Derived_vtbl ends00000018 |
注意看虚函数表的大小,是不是比预想的多了一个四字?
不难发现,虚析构函数指针多了一个。查验可知,虚析构函数确实都多了一个:
所以,我们在构造虚函数表的时候,一定要留意虚析构函数指针,必须构造两个。
终
有空再写~~