hu1y40's blog

hu1y40'blog
天堂的穹空遍布地狱之火的颜色,但也是天堂。
  1. 首页
  2. 书籍阅读
  3. 正文

加密与解密 第4章实验

2023年10月7日 1421点热度 0人点赞 0条评论

0x01 函数的识别

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 OD

实验过程

fig:

如图所示,call指令将call指令的下一条指令地址压入栈中并且jmp到了00401010

fig:

随后retn会将执行结果同pop eip

0x02 函数的参数

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 IDA

实验过程

fig:

如图所示,call指令将call指令的下一条指令地址压入栈中并且jmp到了00401010

fig:

随后retn会将执行结果同pop eip

fig:

fastcall调用约定,最左边的两个参数分别用ecx,edx传递了

fig:

thiscall调用约定,用ecx传递了this指针。

0x03 局部变量

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 IDA

实验过程

fig:

较为容易看明白,首先将一个静态or全局变量(单看汇编无从辨认,都是固定地址)赋值给edi,esp+eax+4很明显是一个基址+偏移的形式但是这个基址准确的指向数组的时候是eax>=4的时候,所以add eax,4在其前面,随后就是一个循环三次。其赋值给的新数组分别存了原数组的第一个数,第一第二个数之和,第1-3个数之和。

fig:

0x02 函数的参数

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 IDA

实验过程

fig:

如图所示,call指令将call指令的下一条指令地址压入栈中并且jmp到了00401010

fig:

随后retn会将执行结果同pop eip

fig:

fastcall调用约定,最左边的两个参数分别用ecx,edx传递了

fig:

thiscall调用约定,用ecx传递了this指针。

0x04 虚表1

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 IDA

实验过程

C代码

#include "stdafx.h"

class CVirtual {
public:
CVirtual() {
m_nMember1 = 1;
m_nMember2 = 2;
printf("CVirtual()\r\n");
}
virtual ~CVirtual() {
printf("~CVirtual()\r\n");
}
virtual void fun1() {
printf("fun1()\r\n");
}
virtual void fun2() {
printf("fun2()\r\n");
}
private:
int m_nMember1;
int m_nMember2;
};

int main(int argc, char* argv[]) {
CVirtual object;
object.fun1();
object.fun2();
return 0;
}

fig:

rcx=this随后进入构造函数。

fig:

构造函数内部。

fig:

虚表指向的地方的三个虚函数。

fig:

地址对上了。

fig:

这里有两个析构函数,并且我们调用的析构函数同样lea reg,this;mov [reg],reg初始化了虚表,返回值为this指针。

区分析构函数和构造函数可以看先后顺序。虚表中的函数时按照函数声明的顺序依次放入到,有时候不一定相同(虚函数重载)。虚表的每一项都是8字节,存储的成员函数地址。虚表的最后一项不一定以0结尾,虚表项的个数会根据其他信息决定。

虚表里的析构函数对比我们调用的析构函数多了一个delete操作。所以我们调用的时出作用域时调用的析构函数,虚表的时delete的时候调用的。delete对象的时候,先调用析构函数,在释放堆空间。

fig:

0x05 虚表2

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 IDA

实验过程

C代码

#include "stdafx.h"

class CBase {
public:
CBase() {
m_nMember = 1;
printf("CBase()\r\n");
}
virtual ~CBase() {
printf("~CBase()\r\n");
}
virtual void fun1() {
printf("CBase::fun1()\r\n");
}
private:
int m_nMember;
};

class CDerived :public CBase {
public:
CDerived() {
m_nMember = 2;
printf("CDerived()\r\n");
}
~CDerived() {
printf("~CDerived()\r\n");
}
virtual void fun1() {
printf("CDerived::fun1()\r\n");
}
virtual void fun2() {
printf("CDerived::fun2()\r\n");
}
private:
int m_nMember;
};

int _tmain(int argc, _TCHAR* argv[]) {
CBase *pBase = new CDerived();
pBase->fun1();
delete pBase;
return 0;
}

fig:

fig:

这里new申请的空间为24字节是因为虚表需要8字节空间,而变量需要8字节对齐。

构造函数先调用CBase的构造函数会初始化一次虚表CBase的虚表,后续又会初始化一次CDrived的虚表。构造函数中CBase给成员变量赋值1,CDrived赋值2。所以最后的值为2。

fig:

fig:

随后调用析构函数,这里传入1,表示析构函数要delete,进入虚表的虚构函数发现delete那里检测了这个传入的1,不是1就不delete。

虚表中的析构函数

fig:

先调用CDerived析构函数,CDerived析构函数内部结束的时候会调用CBase的析构函数。

0x05 虚表3

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 IDA

实验过程

C代码

#include "stdafx.h"

class CBase1 {
public:
CBase1() {
m_nMember = 1;
printf("CBase1()\r\n");
}
~CBase1() {
printf("~CBase1()\r\n");
}
virtual void fun1() {
printf("CBase1::fun1()\r\n");
}
private:
int m_nMember;
};
class CBase2 {
public:
CBase2() {
m_nMember = 2;
printf("CBase2()\r\n");
}
~CBase2() {
printf("~CBase2()\r\n");
}
virtual void fun2() {
printf("CBase2::fun1()\r\n");
}
private:
int m_nMember;
};

class CDerived :public CBase1, public CBase2 {
public:
CDerived() {
m_nMember = 2;
printf("CDerived()\r\n");
}
~CDerived() {
printf("~CDerived()\r\n");
}
virtual void fun1() {
printf("CDerived::fun1()\r\n");
}
virtual void fun3() {
printf("CDerived::fun3()\r\n");
}
private:
int m_nMember;
};

int _tmain(int argc, _TCHAR* argv[]) {
CDerived derievd;
return 0;
}

fig:

构造函数最先调用的CBase1构造函数

fig:

调用完CBase1后 this+10h进行第二个构造函数CBase2调用

随后分别将两个虚表放在了首地址,首地址+10h处。

fig:

fun1 fun3派生类实现了虚函数,所以覆盖,fun2没实现,照搬。

fig:

0x06 虚表4

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 IDA

实验过程

C代码

#include "stdafx.h"

class A {
public:
A() {
m_nMember = 1;
printf("A()\r\n");
}
~A() {
printf("~A()\r\n");
}
virtual void fun1() {
printf("A::fun1()\r\n");
}
private:
int m_nMember;
};

class B :virtual public A{
public:
B() {
m_nMember = 2;
printf("B()\r\n");
}
~B() {
printf("~B()\r\n");
}
virtual void fun2() {
printf("B::fun2()\r\n");
}
private:
int m_nMember;
};

class C :virtual public A{
public:
C() {
m_nMember = 3;
printf("C()\r\n");
}
~C() {
printf("~C()\r\n");
}
virtual void fun3() {
printf("C::fun3()\r\n");
}
private:
int m_nMember;
};

class BC :public B, public C {
public:
BC() {
m_nMember = 4;
printf("BC()\r\n");
}
~BC() {
printf("~BC()\r\n");
}
virtual void fun3() {
printf("BC::fun3()\r\n");
}
virtual void fun4() {
printf("BC::fun4()\r\n");
}
private:
int m_nMember;
};

int _tmain(int argc, _TCHAR* argv[]) {
BC theBC;
return 0;
}

fig:

多了一个参数表示是否调用基类构造函数

fig:

设置了b和c的虚基类偏移表指针,随后调用A的构造函数

fig:

调用完A的构造函数调用b的

fig:

C的过程和B差不多。

fig:

最后调用BC的构造函数

fig:

虚表

fig:

这里main首先调用了BC的构造函数,但是其要调用B和C的构造函数,都会调用A的构造函数,所以多传递一个参数,用来表示是否进行虚基类的构造,这里在开头传递1先构造了虚基类A。

初始化虚基类偏移表的操作时为了定位虚基类在对象内存中的位置,虚基类偏移表也在全局数据区。虚基类偏移表8字节,后四字节用于表示虚基类在当前虚基类偏移表中的偏移。

fig:

0x07 虚表5

实验环境

推荐使用的环境 备注
操作系统 Windows 10
编译器
编译选项
build版本
调试器 IDA

实验过程

C代码

class IBase {
public:
IBase() {
m_nMember = 1;
printf("IBase()\r\n");
}
virtual void fun1() = 0;
virtual void fun2() = 0;
private:
int m_nMember;
};

class CDerived :public IBase
{
public:
CDerived()
{
printf("CDerived()\r\n");
}
virtual void fun1(){};
virtual void fun2() {};
};

int _tmain(int argc, _TCHAR* argv[]) {
IBase *pBase = new CDerived();
delete pBase;
return 0;
}

抽象类与单重继承没什么区别,抽象类的虚表为两个purecall

fig:

purecall的功能是显示一个错误信息并退出程序。

标签: 实验 总结
最后更新:2023年10月7日

hu1y40

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复
文章目录
  • 0x01 函数的识别
    • 实验环境
    • 实验过程
  • 0x02 函数的参数
    • 实验环境
    • 实验过程
  • 0x03 局部变量
    • 实验环境
    • 实验过程
  • 0x02 函数的参数
    • 实验环境
    • 实验过程
  • 0x04 虚表1
    • 实验环境
    • 实验过程
  • 0x05 虚表2
    • 实验环境
    • 实验过程
  • 0x05 虚表3
    • 实验环境
    • 实验过程
  • 0x06 虚表4
    • 实验环境
    • 实验过程
  • 0x07 虚表5
    • 实验环境
    • 实验过程

分类目录

  • 0day安全
  • Bypass
  • C++Prime
  • CTF
  • DoS
  • DoS
  • FUZZ
  • iot
  • JSONP
  • MISC
  • MISC
  • PHP伪协议
  • Python
  • REVERSE
  • sqli-labs
  • SQL注入
  • Trick
  • UAF
  • WEB
  • WEB
  • XXE
  • 书籍阅读
  • 二进制
  • 代码阅读
  • 信息搜集
  • 信息泄露
  • 加密与解密
  • 双重释放漏洞
  • 反序列化
  • 命令执行
  • 命令执行
  • 堆溢出
  • 密码学
  • 弱加密
  • 提权漏洞
  • 整数溢出
  • 文件上传
  • 未分类
  • 栈溢出
  • 格式化字符串漏洞
  • 模型
  • 汇编语言
  • 渗透测试
  • 漏洞分析
  • 漏洞利用
  • 漏洞战争
  • 漏洞挖掘
  • 病毒分析
  • 越界读取
  • 路径遍历
  • 逻辑漏洞
  • 配置不当
  • 钓鱼
  • 靶场
最新 热点 随机
最新 热点 随机
加密算法 2023年度总结 RTSPServer StackOverflow Vulnerability FUZZ 总览篇 MP4Box 无限循环漏洞 CVE-2023-40477 Winrar RCE漏洞分析
Fuzzing101 8 Trinity 源码阅读 bugku 白哥的鸽子 CVE-2013-0077 Firefox字符串替换整数溢出漏洞 加密与解密 第11章实验 栅栏加解密

COPYRIGHT © 2023 hu1y40's blog. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

鄂ICP备2021009673号-1