c++反汇编与逆向分析技术揭秘 crackme怎么无法运行

作者&投稿:徒虏 (若有异议请与网页底部的电邮联系)
这本书好不好 C++反汇编与逆向分析技术揭秘~

我看过这本书,不太好,不是写的不好,而是说你没有逆向基础的话,不太看得懂,你有基础的话,这本书也没必要看,一句话,可读性不好。----个人看法
建议你看《加密与解密》和《逆向:逆向工程揭秘》这两本。

一、单类继承

在父类中声明为私有的成员,子类对象无法直接访问,但是在子类对象的内存结构中,父类私有的成员数据依然存在。C++语法规定的访问限制仅限于编译层面,在编译过程中进行语法检查,因此访问控制不会影响对象的内存结构。
子类未提供构造函数或析构函数,而父类却需要构造函数与析构函数时,编译器会为子类提供默认的构造函数与析构函数。但是子类有构造函数,而父类不存在构造函数,且没有虚函数,则编译器不会为父类提供默认的构造函数。

1. 内存结构:

①先安排父类的数据

②后安排子类新定义的数据

说明:基于上述的内存排列方法,即父类数据成员被安排前面。不管是父类的对象,还是子类的对象,父类的数据成员在内存中相对于对象的首地址的偏移值都是一样的。而且成员数据访问都是基于this指针间接寻址的。所以,对于子类对象而言,使用父类指针或者子类指针都可以正确访问其父类数据。

2. 虚表:

虚表的排列顺序是按虚函数在类继承层次中首次声明的顺序依次排列的。只要继承了父类,其派生类的虚函数表中的父类部分的排列就与父类一样。子类新定义的虚函数会按照声明顺序紧跟其后。

3. 构造函数:

①先调用父类构造函数

②然后按照声明顺序调用成员数据变量的构造函数和初始化列表中指定的成员

③最后再执行子类构造函数的函数体。

说明:

①父类构造函数,虚表指针修改为指向父类的虚表,所以在父类构造函数内调用虚函数,调用的是父类的虚函数。

②子类构造函数,虚表指针修改为指向子类的虚表

4. 析构函数:

①先调用子类析造函数

②然后成员对象的析构函数,按照声明的顺序以倒序方式依次调用成员对象的析构函数。

③再执行父类构造函数

说明:

析构函数执行会首先设置虚表指针为自身虚表,再调用自身的析构函数。防止父类析构函数内调用子类对象的虚函数。
类有派生与继承关系,需要声明析构函数为虚函数。若析构函数不是虚函数时,当使用父类指针指向堆中的子类对象,并使用delete释放对象空间时,编译器会按照指针类型调用父类的析构函数,从而引发错误。

识别类之间的关系:

先定位构造函数,根据构造先后顺序得到与之相关的其他类。

再根据虚表,利用IDA中使用引用参考功能可得到所有的构造和析构函数。

二、多重继承

1. 内存排列:

数据成员的排列顺序由继承父类的先后顺序所决定,从左向右依次排列。
子类虚表指针的个数取决于所继承的父类的个数,有几个父类便对应几个虚表指针(虚基类除外)。
将一个子类对象赋值给某个父类指针时,该父类指针便指向该父类所对应的虚表指针。

三、单类继承与多重继承比较:

单继承类
在类对象占用的内存空间中,只保存一份虚表指针
只有一个虚表指针,对应的也只有一个虚表
虚表中各项保存了类中各虚函数的首地址
构造时先构造父类,再构造自身,并且只调用一次父类构造函数
析构时限析构自身,再析构父类,并且只调用一次父类析构函数

多重继承类
在类中所占用的内存空间中,根据继承父类的个数保存对应的虚表指针
根据所保存的虚表指针的个数,对应产生相应个数的虚表。
转换父类指针时,需要跳转到对象的首地址。
构造时需要按照继承顺序调用多个父类构造函数。
析构时先析构自身,然后以与构造函数相反的顺序调用所有父类的析构函数
当对象作为成员时,整个类对象的内存结构和多重继承相似。当类中无虚函数时,整个类对象内存结构和多重继承完全一样,可酌情还原;当父类或成员对象存在虚函数时,通过过观察虚表指针的位置和构造函数、析构函数中填写虚表指针的数目及目标地址,来还原继承或成员关系。

四、 示例

1. 单类继承:

C++源码

1 #include <iostream>
2 using namespace std;
3
4 class Base {
5 public:
6 Base(){ nBase= 1;printf("CBase"); }
7 ~Base(){ printf("~CBase"); }
8 virtual void f() { printf("Base:f()");}
9 virtual void g() { printf("Base:g()");}
10 private:
11 int nBase;
12
13 };
14
15
16 class Derive : public Base {
17 public:
18 Derive(){ nDerive=2;printf("Derive"); }
19 ~Derive(){ printf("~Derive"); }
20 virtual void g(){ printf("Dervie:g()");}
21 virtual void h(){ printf("Dervie:h()");}
22 private:
23 int nDerive;
24 };
25
26
27
28 int main()
29 {
30 Derive d;
31 Base *b = &d;
32 b->g();
33 return 0;

34 }

汇编代码(VS2010编译)

1. 内存分布

1 类Derive对象
2 0019FD30 0139583C =>.rdata:const Derive::`vftable'
3 0019FD34 00000001 =>Base.nBase
4 0019FD38 00000002 =>Derive.nDerive
5
6 虚函数表
7 0139583C 01391163 Base::f(void)
8 01395840 0139110E Derive::g(void)
9 01395844 013911AE Derive::h(void)

2. 构造函数

1 pop ecx ;=>this指针出栈
2 mov [ebp+this], ecx ;=>保存this指针
3 mov ecx, [ebp+this]
4 call j_??0Base@@QAE@XZ ;=>调用基类构造函数Base::Base(void)
5 mov eax, [ebp+this] ;=>eax=this指针
6 mov dword ptr [eax], offset ??_7Derive@@6B@ ;=>初始化虚表指针为const Derive::`vftable'

3. 析构函数

1 pop ecx ;=>this指针出栈
2 mov [ebp+this], ecx ;=>保存this指针
3 mov eax, [ebp+this]
4 mov dword ptr [eax], offset ??_7Derive@@6B@ ;=>重置虚表指针为const Derive::`vftable'
5 mov esi, esp
6 push offset aDerive ; "~Derive"
7 call ds:__imp__printf
8 add esp, 4
9 cmp esi, esp
10 call j___RTC_CheckEsp
11 mov ecx, [ebp+this] ;=>ecx传参this指针
12 call j_??1Base@@QAE@XZ ; =>调用基类析构函数 Base::~Base(void)

2. 多重继承:

C++源码

1 #include <iostream>
2 using namespace std;
3
4 class Base1 {
5 public:
6 virtual void f() { cout << "Base1::f" << endl; }
7 virtual void g() { cout << "Base1::g" << endl; }
8 Base1(){b1 = 1; printf("Base1"); }
9 ~Base1(){ printf("~Base1"); }
10 private:
11 int b1;
12
13 };
14
15 class Base2 {
16 public:
17 virtual void f() { cout << "Base2::f" << endl; }
18 virtual void g() { cout << "Base2::g" << endl; }
19 Base2(){b2 = 2; printf("Base2"); }
20 ~Base2(){ printf("~Base2"); }
21 private:
22 int b2;
23 };
24
25 class Derive : public Base1, public Base2{
26 public:
27 virtual void f() { cout << "Derive::f" << endl; }
28 virtual void g1() { cout << "Derive::g1" << endl; }
29 Derive(){ d1 = 3; printf("Derive"); }
30 ~Derive(){ printf("~Derive"); }
31 private:
32 int d1;
33
34 };
35
36 typedef void(*Fun)(void);
37
38 int main()
39 {
40
41 Derive d;
42 Base1 *b1 = &d;
43 b1->f();
44 b1->g();
45 Base2 *b2 = &d;
46 b2->f();
47 b2->g();
48 return 0;
49 }

汇编代码(VS2010编译)

1.内存分布

;内存布局
0019FA0C 008F584C ;=>.rdata:const Derive::`vftable'{for `Base1'} 第一个虚表
0019FA10 00000001 ;=>Base1.b1
0019FA14 008F583C ;=>.rdata:const Derive::`vftable'{for `Base2'} 第二个虚表
0019FA18 00000002 ;=>Base2.b2
0019FA1C 00000003 ;=>Derive.d1

;虚函数表Derive::`vftable'{for `Base1'}
00FB584C 00FB1041 ;=>Derive::f(void)
00FB5850 00FB1118 ;=>Base1::g(void)
00FB5854 00FB111D ;=>Derive::g1(void)

;虚函数表Derive::`vftable'{for `Base2'}
00FB583C 00FB1113 ;=>Base2::g(void)
00FB5840 00FB1028 ;=>[thunk]:Derive::f`adjustor{8}' (void)

;追踪地址:00FB1028
00FB1028 jmp ?f@Derive@@W7AEXXZ ;=>[thunk]:Derive::f`adjustor{8}' (void)

;追踪函数:?f@Derive@@W7AEXXZ
00FB1F30 ?f@Derive@@W7AEXXZ proc near
00FB1F30 sub ecx, 8 ;=>调整this指针 this = this+8,则this=>Derive::`vftable'{for `Base2'}
00FB1F33 jmp j_?f@Derive@@UAEXXZ ;=>Derive::f(void)

2.构造函数

1 00FB14D9 mov [ebp-4], ecx ;=>this指针保存在esp-4处
2 00FB14DC mov ecx, [ebp-4]   ;=>ecx获得this指针
3 00FB14DF call j_??0Base1@@QAE@XZ ;=>调用构造函数 Base1::Base1(void)
4 00FB14E4 mov ecx, [ebp-4]   ;=>ecx获得this指针
5 00FB14E7 add ecx, 8    ;=>ecx获得this+8
6 00FB14EA call j_??0Base2@@QAE@XZ ;=>调用构造函数 Base2::Base2(void)
7 00FB14EF mov eax, [ebp-4] ;=>eax获得this指针
8 00FB14F2 mov dword ptr [eax], offset ??_7Derive@@6BBase1@@@ ;=>初始化第一个虚表指针为const Derive::`vftable'{for `Base1'}
9 00FB14F8 mov eax, [ebp-4] ;=>eax获得this指针
10 00FB14FB mov dword ptr [eax+8], offset ??_7Derive@@6BBase2@@@ ;=>初始化第二个虚表指针const Derive::`vftable'{for `Base2'}
11 00FB1502 mov eax, [ebp-4] ;=>eax获得this指针
12 00FB1505 mov dword ptr [eax+10h], 3
13 00FB150C push offset Format ; "Derive"
14 00FB1511 call ds:__imp__printf
15 00FB1517 add esp, 4

3.析构函数

00FB17C9 mov [ebp-4], ecx ;=>this指针保存在esp-4处
00FB17CC mov eax, [ebp-4] ;=>ecx获得this指针
00FB17CF mov dword ptr [eax], offset ??_7Derive@@6BBase1@@@ ;=>重置第一个虚表指针为const Derive::`vftable'{for `Base1'}
00FB17D5 mov eax, [ebp-4]
00FB17D8 mov dword ptr [eax+8], offset ??_7Derive@@6BBase2@@@ ;=>重置第二个虚表指针为const Derive::`vftable'{for `Base2'}
00FB17DF push offset aDerive ; "~Derive"
00FB17E4 call ds:__imp__printf
00FB17EA add esp, 4
00FB17ED mov ecx, [ebp-4] ;=>ecx获得this指针
00FB17F0 add ecx, 8 ;=>ec;得this+8
00FB17F3 call j_??1Base2@@QAE@XZ ;=>调用虚构函数Base2::~Base2(void)
00FB17F8 mov ecx, [ebp-4] ;=>ecx获得this指针
00FB17FB call j_??1Base1@@QAE@XZ ;=>调用虚构函数Base1::~Base1(void)

4.虚函数调用

;Base1 *b1 = &d;
00FB1431 lea eax, [ebp-14h] ;=>eax获得this指针
00FB1434 mov [ebp-18h], eax ;=>局部变量b1赋值为this指针

;b1->f();
00FB1437 mov eax, [ebp-18h] ;=>eax获得b1值
00FB143A mov edx, [eax] ;=>edx指向第一个虚表
00FB143C mov ecx, [ebp-18h] ;=>ecx传递this指针
00FB143F mov eax, [edx] ;=>eax获得成员函数Derive::f(void)的地址
00FB1441 call eax ;=>调用成员函数Derive::f(void)

;b1->g();
00FB1443 mov eax, [ebp-18h] ;=>eax获得b1值
00FB1446 mov edx, [eax] ;=>edx指向第一个虚表
00FB1448 mov ecx, [ebp-18h] ;=>ecx传递this指针
00FB144B mov eax, [edx+4] ;=>eax获得成员函数Derive::g(void)的地址
00FB144E call eax ;=>调用成员函数Derive::g(void)

;Base2 *b2 = &d;
00FB1457 lea ecx, [ebp-14h] ;=>ecx获得this指针
00FB145A add ecx, 8 ;=>ecx=this+8指向第二个虚表
00FB145D mov [ebp-64h] ;=>保存ecx到临时变量中
00FB1460 jmp short loc_FB1469 ;--|
; |
00FB1469 mov edx, [ebp-64h];<----|
00FB146C mov [ebp-1Ch], edx ;=>局部变量b2赋值为this+8

;b2->f();
00FB146F mov eax, [ebp-1Ch] ;=>eax获得b2值
00FB1472 mov edx, [eax] ;=>edx获得指向第二个虚表
00FB1474 mov ecx, [ebp-1Ch] ;=>ecx传递this+8
00FB1477 mov eax, [edx+4] ;=>eax为第二个虚表的第二个元素=>[thunk]:Derive::f`adjustor{8}' (void),间接调用Derive::f(void)
00FB147A call eax

;b2->g();
00FB147C mov eax, [ebp+b2] ; =>eax获得b2值
00FB147F mov edx, [eax] ;=>edx获得指向第二个虚表
00FB1481 mov ecx, [ebp+b2] ;=>ecx传递this+8
00FB1484 mov eax, [edx] ;=>eax为第二个虚表的第一个元素=>Base2::g(void)
00FB1486 call eax ;=>调用Base2::g(void)


逆向工程,反汇编工作有前途吗?
各行各业都有前途,找到自己喜欢做的工作就可以了

汇编语言书上说用Debug进行反汇编查看,反汇编是什么意思?
从而解出它的注册码或者编写注册机)、外挂技术、病毒分析、逆向工程、软件汉化等领域。学习和理解反汇编语言对软件调试、漏洞分析、OS的内核原理及理解高级语言代码都有相当大的帮助,在此过程中我们可以领悟到软件作者的编程思想。总之一句话:软件一切神秘的运行机制全在反汇编代码里面。

关于逆向反汇编的编程语言的问题
别人看不懂你的代码,你看C代码也很吃力,如果你只是业余做做编程或者玩玩破解的话用delphi一点问题也没有,当然破解主要还是汇编的功底,有其他语言编程基础更好,如果你想专业搞逆向,进安全公司分析病毒之类的工作,那就得学C和C++了.看你自己想在这行做到什么程度了 ...

什么是正向工程?逆向工程又是什么?
逆向工程是指通过分析已有的软件系统来获取其内部设计和实现的过程。逆向工程的目的是理解已有的软件系统的结构、功能和工作方式,以帮助开发人员进行修改、扩展或者重新设计。逆向工程通常包括反编译、反汇编、静态分析、动态分析等技术手段,以便还原出软件的设计、算法和代码逻辑呢。正向工程和逆向工程在软件...

反汇编和二进制分析工具清单
探索二进制世界的神器清单 在这个数字时代,反汇编和二进制分析工具犹如探索代码世界的秘密武器。让我们一起深入了解一系列强大而多样的工具,它们在破解、调试和理解复杂代码中扮演着关键角色。IDA Pro: 作为重量级选手,IDA Pro以其强大的反汇编能力而闻名,但其价格高昂,适合专业开发者和逆向工程专家。然...

反编译技术与软件逆向分析的图书目录
3.2 指令解码1.3.3 语义映射1.3.4 相关图构造1.3.5 过程分析1.3.6 类型分析1.3.7 结果输出1.4 逆向分析框架1.4.1 静态分析框架1.4.2 动态分析框架1.4.3 动静结合的分析框架第2章 指令系统2.1 指令系统概述2.2 机器指令与汇编指令2.2.1 机器指令2.2.2 汇编...

一般学汇编要多久,反汇编呢?加上逆向工程?多久
汇编技术在大学里是一学期的课程,前提是你已经读到计算机专业的大学三年级;逆向工程是一个经验+实践的东西,每天都要更新知识,因为软件技术在发展。顺便说,自学不了在网上找人带似乎没什么实际意义,网上的人最多能给你点拨一下,主要还得靠自己。

net逆向是什么意思?
Net逆向是指将.net程序进行反编译、破解等行为的过程。参与此类活动的人员一般都是熟悉.net框架和C#语言以及反汇编工具,他们通过对程序的深入分析和修改,使程序破解以达到绕过验证、解密等目的。这种行为可能会侵犯版权,并且有可能导致程序出现不稳定或错误行为。因此,进行此类行为需要特别谨慎。虽然进行....

什么是逆向工程?有哪些应用?
和国外相比,目前我国企业对于技术引进基础上的逆向工程重视还不够,多数企业把技术设备的引进仅仅看作是提高产品技术含量或者增加产品种类的方式,而没有考虑到技术引进与逆向工程的结合对企业技术水平的提升,没有从更高的战略角度来考虑技术引进问题。逆向工程是制造业实现快速产品创新设计的重要途径,实物...

什么是逆向工程?
软件升级或更新。出于功能、合规、安全等需求更改,逆向工程被用来了解现有或遗留软件系统,以评估更新或移植系统所需的工作。制造没有许可\/未授权的副本。学术\/学习目的。去除复制保护和伪装的登录权限。文件丢失:采取逆向工程的情况往往是在某一个特殊设备的文件已经丢失了(或者根本就没有),同时又找不到...

太和县13588772797: 请反汇编高手给我指条明路 -
第印艾唯: 条条大道通罗马.你先学C,然后C++ 编写这些的时候顺便看它生成的反汇编代码 你学反汇编的目的就是为了逆向吧?所以你得先了解语言,然后看看它被编译器汇编成什么样子.写的多了看的多了就知道了 《C++反汇编与逆向分析技术揭秘》

太和县13588772797: 逆向分析书籍介绍 -
第印艾唯: 对立志成为信息安全领域的专家,特别是逆向分析高手推荐的必读书籍.1、在学习汇编前,掌握一门高级程序设计语言 C语言程序设计 (The C Programming Language (2nd Edition), Brian W.Kernighan & Dennis M.Ritchie著) C++语言程序设...

太和县13588772797: 求解释简单c++的反汇编代码 -
第印艾唯: 高级语言与机器语言不是一一对应的,所以将EXE文件反编译成C++语言,或其它任何的高级语言,原则上都是不可能的.反汇编成汇编语言是可能的,不过现在的程序都这么复杂而庞大,即使你懂汇编语言,也不可能看懂全部的程序.查看特定的代码是可以的.

太和县13588772797: 想学逆向和反汇编,请问该看什么书入门 -
第印艾唯: 那就说个大概吧. C->汇编->数据结构->《Windows程序设计》/ 《Windows环境下32位汇编程序语言设计》-> 《加密与解密(第三版) 》->《Windows核心编程》 以后可以看情况再选读 《IDA Pro权威指南》 《C++反汇编与逆向分析技术揭秘》 《Windows PE...

太和县13588772797: 当黑客应该从哪里学习 -
第印艾唯: 推荐你一些书吧,虽然不是最新出版的,但是内容非常基础,打好基础很重要啊.作为入门可能难了些,但是可以下载电子版的看看,有利于开阔眼界,这是真正的技术:“0day安全:软件漏洞分析技术”:讲如何挖掘0day漏洞;“Windows PE权威指南”:解析Windows系统可执行文件PE格式,可用于可执行程序分解、捆绑;“加密与解密 第三版”:虽然它讲的是程序破解、软件保护,但病毒分析必学它;“C++反汇编与逆向分析技术揭秘”:软件逆向分析的深入学习,里面还有熊猫烧香的逆向分析.

太和县13588772797: 以后想学C和汇编,做免杀和逆向这些,是不是需要很强大的数学底子啊?
第印艾唯: 我个人是从13年的7月份开始接触逆向的,目前菜鸟水平,刚刚算是入门.就我个人经验来看,做逆向对数学没啥大要求.这句话的前提是你搞破解用爆破,不要去碰加密算法.加密算法么,既然叫算法,肯定跟数学扯不清.想从汇编角度写出...

太和县13588772797: 我想学渗透和和反汇编,现在只有c语言和python的基础,想请教老师们给个学习计划学习书单,要考虑 -
第印艾唯: 学汇编语言.一、处理器指令原理.主要涉及编程角度的工作原理,而这些指令就是汇编语言的基本语句.二、高级语言如何转换成汇编语言.主要涉及高级语言中各种语言特征如何转换成汇编语言,例如if语句、switch语句如何用汇编语言.《C++反汇编与逆向分析技术揭秘》

太和县13588772797: 30RMB求解答这个C语言反汇编的问题 -
第印艾唯: 1、对30块没兴趣2、免加qq3、这个优化几年前就看到过,原理是x / 7可以转化成x * (1 / 7),这个1 / 7可以使用小数点后一定精度的值表示(实际上有32位精度就够了),我们看到的24924925就是这么的来的,而且你代码贴错了,我用vc产生了...

太和县13588772797: 想往逆向C++,病毒分析方向发展 (win32是肯定要学的,不在讨论范围内)该先学C++还是C 求指点 -
第印艾唯: 你好:C++相对于C主要是引入了类(就是面向对象思想里面的东西),类和逆向思想要联系起来实际上是有点困难的.或者说,C和汇编一样都是面向过程,你要用面向过程的汇编去理解面向对象的C++是很难的.逆向高手是可以在C代码和汇编代码之间快速转换的,比如看到一个函数能马上想到对应的汇编代码是什么,但你看到C++的代码就不一定了,这个函数可能被包含在一个类里作为成员函数,转换成汇编代码可能就有点繁琐了.所以建议楼主学C是必须的,C++可选,即使你用C++做开发,其实也很少会用到面向对象思想,除非是MFC之类的.其他问题欢迎咨询电脑管家企业平台!

太和县13588772797: 反汇编逆向难学吗,入门难吗? -
第印艾唯: 反汇编是工具来做的,比如IDA,OD,你说的这个应该是逆向和破解技术. 逆向其实是有它的难度在里面的,要跟汇编打交道,很多时候破解要涉及加密算法,驱动保护还有壳.可以这么说,逆向技术本身不算太难,但是难的是逆向防御技术....

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网