前言 C++ 是面向对象语言,C++ 的面向对象机制在多个维度增加了由 C++ 编写的程序的逆向难度。对于逆向工程人员来说,掌握 C++ 的核心概念的底层表示形式非常重要。
C++ 严格来说是 C 的超集,向下兼容 C 很多地方和 C 是相同的。
进行 C++ 的逆向,是必须了解 C++ 的基本语法的。
严格来说C++逆向是一个很大也很难的东西,但是也是比赛中非常多的一个考点。
这里默认你已经了解了。
1 2 3 4 5 6 7 8 9 10 #include <string> #include <iostream> using namespace std;class Animal { int age; double weight; }
类内存布局 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> class MyClass {public : MyClass (){ var1=1 ; var2=2 ; var3=3 ; }; int get_var1 () {return var1;}private :int var1;int var2;int var3; }; int main () { MyClass my; return 0 ; }
MSVC利用RCX
传递this
指针
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 # License: MSVC Proprietary # The use of this compiler is only permitted for internal evaluation purposes and is otherwise governed by the MSVC License Agreement. # See https:this $ = 8 MyClass::MyClass (void ) PROC ; MyClass::MyClass, COMDAT mov QWORD PTR [rsp+8 ], rcx mov rax, QWORD PTR this $[rsp] mov DWORD PTR [rax], 1 mov rax, QWORD PTR this $[rsp] mov DWORD PTR [rax+4 ], 2 mov rax, QWORD PTR this $[rsp] mov DWORD PTR [rax+8 ], 3 mov rax, QWORD PTR this $[rsp] ret 0 MyClass::MyClass (void ) ENDP ; MyClass::MyClass my$ = 32 main PROC $LN3: sub rsp, 56 ; 0000003 8H lea rcx, QWORD PTR my$[rsp] call MyClass::MyClass (void ) ; MyClass::MyClass xor eax, eax add rsp, 56 ; 0000003 8H ret 0 main ENDP
含有虚函数的内存布局
1 2 3 4 5 6 class MyClassVirtual { int var1;public : virtual int get_num (int x,int y) ; virtual void reset_values () {var1=7 ;} };
内部布局
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 # License: MSVC Proprietary # The use of this compiler is only permitted for internal evaluation purposes and is otherwise governed by the MSVC License Agreement. # See https: MyClassVirtual::`RTTI Base Class Descriptor at (0 ,-1 ,0 ,64 ) ' DD imagerel MyClassVirtual `RTTI Type Descriptor' ; MyClassVirtual::`RTTI Base Class Descriptor at (0 ,-1 ,0 ,64 ) ' DD 00H DD 00H DD 0ffffffffH DD 00H DD 040H DD imagerel MyClassVirtual::`RTTI Class Hierarchy Descriptor' MyClassVirtual::`RTTI Base Class Array' DD imagerel MyClassVirtual::`RTTI Base Class Descriptor at (0 ,-1 ,0 ,64 ) ' ; MyClassVirtual::`RTTI Base Class Array' ORG $+3 MyClassVirtual::`RTTI Class Hierarchy Descriptor' DD 00H ; MyClassVirtual::`RTTI Class Hierarchy Descriptor' DD 00 H DD 01 H DD imagerel MyClassVirtual::`RTTI Base Class Array' MyClassVirtual `RTTI Type Descriptor' DQ FLAT:const type_info::`vftable' ; MyClassVirtual `RTTI Type Descriptor' DQ 0000000000000000 H DB '. ?? AVMyClassVirtual' , 00 Hconst MyClassVirtual::`RTTI Complete Object Locator' DD 01H ; MyClassVirtual::`RTTI Complete Object Locator' DD 00 H DD 00 H DD imagerel MyClassVirtual `RTTI Type Descriptor' DD imagerel MyClassVirtual::`RTTI Class Hierarchy Descriptor' DD imagerel const MyClassVirtual::`RTTI Complete Object Locator'const MyClassVirtual::`vftable' DQ FLAT:const MyClassVirtual::`RTTI Complete Object Locator' ; MyClassVirtual::`vftable' DQ FLAT:virtual int MyClassVirtual::get_num (int ,int ) DQ FLAT:virtual void MyClassVirtual::reset_values(void) this$ = 8 virtual void MyClassVirtual::reset_values (void ) PROC ; MyClassVirtual::reset_values, COMDAT mov QWORD PTR [rsp+8 ], rcx mov rax, QWORD PTR this $[rsp] mov DWORD PTR [rax+8 ], 7 ret 0 virtual void MyClassVirtual::reset_values (void ) ENDP ; MyClassVirtual::reset_values
vtable ptr 指向虚表,虚是一个函数地址 表,虚表指针在构造函数中初始化
1 2 3 const MyClassVirtual::`vftable' DQ FLAT:const MyClassVirtual::`RTTI Complete Object Locator' ; MyClassVirtual::`vftable' DQ FLAT:virtual int MyClassVirtual::get_num (int ,int ) DQ FLAT:virtual void MyClassVirtual::reset_values(void)
单继承内存布局
1 2 3 4 5 6 7 8 9 10 11 12 class MyClassVirtual { int val;public : virtual int get_num (int x,int y) ; virtual void reset_values () {var1=7 ;} };class MyClassVirtual2 :public MyClassVirtual{ int var1;public : int get_values () {return var1;} };
调用父类构造函数
1 2 3 4 5 6 7 8 9 main PROC $LN3: sub rsp, 56 ; 0000003 8H lea rcx, QWORD PTR v$[rsp] call MyClassVirtual::MyClassVirtual (void ) xor eax, eax add rsp, 56 ; 0000003 8H ret 0 main ENDP
多继承内存布局
STL函数识别 C++异常处理机制 C++异常处理是通过try...catch
来实现的,语法结构:
1 2 3 4 5 6 7 8 9 10 try { 语句组 }catch (异常类型){ 异常处理代码 } ...catch (异常类型){ 异常处理代码 }
C++的异常处理try catch
执行过程
执行try
块中的语句,如果执行的过程中没有异常抛出,那么执行完后就执行最后一个catch
块后面的语句,所以catch
块中的语句都不会被执行。
如果try
块执行的过程中抛出了异常,那么抛出异常后立即跳转到第一个 “异常类型” 和抛出的异常类型匹配的catch
块中执行(称作异常被该catch
块 “捕获”),执行完后再跳转到最后一个catch
块后面继续执行
C++异常的再抛出:如果一个函数在执行过程中抛出的异常在本函数内就被catch
块捕获并处理,那么该异常就不会抛给这个函数的调用者,如果异常在本函数中没有被处理,则它会被抛给上一层的函数
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 #include <string> #include <stdio.h> #include <iostream> void catched_by_self (int i) { try { } catch (char ){ } catch (int ) }void catched_by_before1 (int i) { throw std::string ("Fuck You\n" ); printf ("被抛到上层之后,函数后面的语句就不会被执行\n" ); }void catched_by_before2 () { thrwo 666 ; printf ("被抛到上层之后,函数后面的语句就不会被执行\n" ); }int mainf () { int testnum=0x123 ; try { } catch }
例题
2024YLCTF
2024DASCTF ezcpp
2024Moectf
2024Newstar