首页 > 编程语言 > 详细

C\C++反汇编中几个比较重要的知识点

时间:2020-03-26 20:30:54      阅读:59      评论:0      收藏:0      [点我收藏+]

C\C++反汇编中几个比较重要的知识点

1. C++的虚函数表

2. C++中的引用

3. C中针对switch的优化

 

1. C++的虚函数表

#include <Windows.h>
#include <iostream>
#include <stdio.h>

using namespace std;

class animal{
    virtual void speak()=0;
    virtual void name()=0;
};

class cat: public animal {
public:
    void speak() {
        cout << "miaomiaomaio~" << endl;
    }
    void name() {
        cout << "I am a cat" << endl;
    }
};

int main() {
    cat c;
    c.speak();
}

  如上代码,其对于cat类,存在两个虚函数。

  虚函数存储在虚函数表中,因此该成员的第一位是一个表的地址,里面存储了其对应的虚函数地址。

  技术分享图片

  我们在IDA中查看其虚函数表所在位置

  技术分享图片

 

 

2. C++中的引用

#include <Windows.h>
#include <iostream>
#include <stdio.h>

using namespace std;

void func(int& x) {
    cout << x << endl;
}

int main() {
    int x = 2;
    func(x);
}

  引用的本质是指针,但是又对指针做了限制,无法对指针本身指向内容进行修改。

  查看下面的反汇编代码就很好理解。

  我们查看其反汇编代码:

  func(x);
  005E20B9  lea         eax,[ebp-0Ch]   // 传入变量x的地址
  005E20BC  push        eax  
  005E20BD  call        005E145B

  cout << x << endl;

  005E1941  mov         eax,dword ptr [ebp+8]  
  005E1944  mov         ecx,dword ptr [eax]  
  005E1946  push        ecx          // 从指针中取出值来进行操作

 

3. C中针对switch的优化

1)常规形式

  switch被翻译成 if..else..结构

2)大表索引

#include <stdio.h>

int main(int argc, char* argv[])
{
    int s = 5;
    switch (s) {
    case 101:
        printf("101\n");
        break;
    case 102:
        printf("102\n");
        break;
    case 103:
        printf("103\n");
        break;
    case 104:
        printf("104\n");
        break;
    default:
        printf("error\n");
        break;
    }
    return 0;
}

  我们查看其反汇编代码:

   switch (s) {
  00AF183F  mov         eax,dword ptr [ebp-8]  
  00AF1842  mov         dword ptr [ebp+FFFFFF30h],eax  
  00AF1848  mov         ecx,dword ptr [ebp+FFFFFF30h]  
  00AF184E  sub         ecx,65h  
  00AF1851  mov         dword ptr [ebp+FFFFFF30h],ecx  
  00AF1857  cmp         dword ptr [ebp+FFFFFF30h],3  
  00AF185E  ja          00AF18A9  
  00AF1860  mov         edx,dword ptr [ebp+FFFFFF30h]  
  00AF1866  jmp         dword ptr [edx*4+00AF18CCh] 

  其将变量S-101h,获取索引(0,1,2,3),然后判断如果大于3,直接跳到default域中,否则根据索引去 00AF18CCh 这张表中获取跳转地址。

  我们查看这张表中的内容:

  技术分享图片

  因此这样可以极大的加快查找效率

3)大表+小表索引

  上面大表索引有一个缺点,就是当出现断层时,中间很大一块要使用default的地址填补,比如 1,2,3,4,101,102,103,104;

  此时就是采用大表+小表的索引形式,构建两张大表。

  我们按例子中的思路再来构建 1,2,3,4,101,102,103,104 这种情况

    switch (s) {
  0088504F  mov         eax,dword ptr [ebp-8]  
  00885052  mov         dword ptr [ebp+FFFFFF30h],eax  
  00885058  mov         ecx,dword ptr [ebp+FFFFFF30h]  
  0088505E  sub         ecx,1  
  00885061  mov         dword ptr [ebp+FFFFFF30h],ecx  
  00885067  cmp         dword ptr [ebp+FFFFFF30h],67h  
  0088506E  ja          008850FE  
  00885074  mov         edx,dword ptr [ebp+FFFFFF30h]  
  0088507A  movzx       eax,byte ptr [edx+00885138h]  
  00885081  jmp         dword ptr [eax*4+00885114h]

  可以看到索引值从00885138h这张表中获取,一个字节,拿到该索引值后又从00885114h这张表中获取。

  技术分享图片    技术分享图片

   这样本来需要四个字节存储的空白只需要一个字节就够了。

4)放弃大表+小表,重新回归大表。

  上面那种仍然有很多空白,我们继续设想,如果更加极端的情况呢?

  现在我们假设 1,2,3,4,101,102,103,104,10001,10002,10003,10004

  在这种情况下,我们继续观察,发现其放弃采用两张表的形式,又回归到一张表中了。

  其根据大小按索引重新排序,回归到一张表中。

  技术分享图片

   反汇编代码

  技术分享图片 

C\C++反汇编中几个比较重要的知识点

原文:https://www.cnblogs.com/onetrainee/p/12576764.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!