侧边栏壁纸
博主头像
胜星的博客博主等级

行动起来,活在当下

  • 累计撰写 23 篇文章
  • 累计创建 38 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

逆向基础——不同语言程序的入口特征

胜星
2021-03-09 / 0 评论 / 0 点赞 / 348 阅读 / 8258 字

一、不同语言程序的特征

0. 如何确定目标程序的语言?
  • 入口点的特征(二进制特征)
  • 链接器版本
  • 区段的名称
1. BC++ 程序
  • 入口点的特征

    image20191108081035856

  • BC++ 编写的程序,调用IAT函数会使用到 FF25 ?? ?? ?? ??

    image20191108081428569

  • 链接器版本是: 5.0

    image20191108081534927

  • 二进制特征,后面会有 GetModuleHandle 函数的调用,由于大多数查壳工具使用的都是特征码匹配,例如 PEID 使用了 userdb.txt 中的特征,只要伪造二进制特征就可以让大多数的查壳工具失效。

    EB 10 66 62 3A 43 2B 2B 48 4F 4F 4B 90
    
  • 区段的特征:不同功能对应的数据放置在了相应的区段中

    image20191108082900273

2. Delphi 程序
  • 入口特征

    image20191108082329264

    image20191108082350253

  • 由于 Delphi 和 BC++ 程序都是宝蓝公司的,所以 IAT 调用特征相同

    image20191108082459573

  • 链接器版本:2.25

    image20191108083251386

  • 二进制特征: B8 和 E8 后面都是不同的,未知的可以使用 ?? 代替

    55 8B EC 83 C4 F0 B8 ?? ?? ?? ?? E8 ?? ?? ?? ??
    
  • 区段特征:代码段(CODE)和数据段(DATA)以及未初始化的数据(BSS)

    image20191108083011539

3. 汇编程序
  • 特征,小,入口点直接就是逻辑代码

    image20191108083528967

  • 链接器版本:5.12

    image20191108083458408

4. VC6.0\易语言
  • 入口点特征:

    image20191108083853941

  • 链接器版本

    image20191108083942566

  • 区段特征

    image20191108084051174

  • 二进制特征:

    55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00
    
5. VS 程序的连接器版本对应的VS版本
  • VS 版本的不同会导致编写出的程序特征(链接器、入口点、区段)
  • debug 下编译的程序区段的数量相对于 Release 多一些
  • release 的入口存在 call ???????? jmp ????????,debug可能是两个call
VS 版本链接器版本
VC 6.06.0
VC20037.0 / 7.1
VS20058.0
VS20089.0
VS201010.0
VS201211.0
VS201312.0
VS201514.0
VS201714.1
VS201914.2

二、VS数据的分析

1. 基本常量类型
  • 大多数的常量是作为 OPCODE 的一部分被直接存储在代码区
    • 字符串:常量字符串保存在常量区,赋值使用的实际是所在的地址
    • 浮点数:被保存在常量区,初始化时需要通过 xmm 寄存器
#define SIZE  100      

enum class eData
{
	enum_TYPE_1 = 1,
	enum_TYPE_2 = 2,
	enum_TYPE_3 = 3
};

struct sData
{
	int n;
	float fNum;
	char chA;
};


int main()
{
	const bool bRet = true;						// 布尔常量
	// mov         byte ptr[ebp - 5], 1

	const int nCount = SIZE;					// const常量
	// mov         dword ptr[ebp - 14h], 64h

	const char* szHello = "Hello 15PB";			// 字符串常量
	// mov         dword ptr[ebp - 20h], 217BCCh(字符串地址)

	const eData data = eData::enum_TYPE_1;      // 枚举常量
	// mov         dword ptr[ebp - 2Ch], 1

	const float  fNum = 1.5;					// 浮点常量
	// movss       xmm0, dword ptr ds : [00217BD8h]
	// movss       dword ptr[ebp - 38h], xmm0
	// mov         dword ptr[ebp - 4Ch], 1

	const sData stc = { 1,2.0,'1' };			// 结构体常量
	// movss       xmm0, dword ptr ds : [00217BDCh]
	// movss       dword ptr[ebp - 48h], xmm0
	// mov         byte ptr[ebp - 44h], 31h

	return 0;
}
  • 通过解析头文件(Ctrl+F9)的方式添加头文件,头文件不能解析高标准的语法
  • 可以直接在常量上按下'M'将常量解释为 枚举类型
2. 字符串的初始化
  • // 字符串数组,数据量较小,使用的是 mov
    char szStr[100] = { "szStr[100] Hello 15PB" };
    

    image20191108094859916

  • // 宽字符串数组 ,数据量较大,使用的时串操作
    wchar_t szWchar[100] = L"szWchar Hello 15PB";
    

    image20191108095311606

  • // 普通的字符数组,相比于第一个,数组的大小由字符串长度决定,不需要调用 memset 
    char szHello[] = "szHello[] Hello 15PB";
    

    image20191108095506092

3. 指针和引用
int main()
{
	int number = 10;

	int* pnumber = &number;
	/*
        lea         eax,[number]  
        mov         dword ptr [pnumber],eax   
	*/

	int& rnumber = number;
	/*
        lea         eax,[number]  
        mov         dword ptr [rnumber],eax 
	*/
	return 0;
}

三、C++ 对象分析

1. 构造函数

image20191108105356448

  • 构造函数使用 ecx 传递对象的地址,在其中进行初始化
  • 初始化当前对象的虚函数表指针
  • 会在执行具体的逻辑代码前,调用父类的构造函数
  • 会将返回值设置为当前的 this 指针
2. 析构函数

image20191108105649693

  • 构造函数使用 ecx 传递对象的地址,在其中进行初始化
  • 会在执行具体的逻辑代码前,调用父类的构造函数
  • 返回值不具备任何的意义
3. 普通成员函数
  • 使用 ecx 传递 this 指针,其余的参数使用栈传递,函数内平衡堆栈
  • 数据成员的寻址依赖的是this指针+数据相对于对象首地址偏移
4. 虚函数

image20191108111524934

  • 只有同时使用虚函数和指针或引用调用才能实现动态联编
5. 友元函数 \ 静态成员函数
  • 友元函数和静态成员函数与普通函数之间没有区别
0

评论区