zoukankan      html  css  js  c++  java
  • CC++反汇编中几个比较重要的知识点

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

    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
    ");
            break;
        case 102:
            printf("102
    ");
            break;
        case 103:
            printf("103
    ");
            break;
        case 104:
            printf("104
    ");
            break;
        default:
            printf("error
    ");
            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

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

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

      

       反汇编代码

       

  • 相关阅读:
    爬取卡通图片
    python 列表生成式
    python 装饰器
    python 协程 and 进程
    ssh登录缓慢问题
    解决 input 元素点击有蓝色边框的问题
    JavaScript面试题总结系列(九)
    JavaScript面试题总结系列(八)
    JavaScript面试题总结系列(七)
    JavaScript面试题总结系列(六)
  • 原文地址:https://www.cnblogs.com/onetrainee/p/12576764.html
Copyright © 2011-2022 走看看