鱼C论坛

 找回密码
 立即注册
查看: 3922|回复: 4

汇编指令级混淆器

[复制链接]
发表于 2018-1-28 23:55:58 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 错过会难过 于 2018-1-28 23:55 编辑

汇编指令级混淆器

之前在脱壳的时候遇到不少的花指令,指令膨胀,虚拟机之类的壳, 然后想要尝试一下也弄一个这样的壳, 于是便有了写一个指令混淆器的想法, 起初是想写一个直接对opcode进行混淆膨胀的混淆器的, 难度不是一般地小, 这其中包括了膨胀之后call指令和jmp等以偏移作为操作数的指令的操作数的偏移量会被破坏. 虽然能写,但非常麻烦, 需要重组整个代码段, 后来就没有直接写, 写了一个汇编指令级别的混淆器尝试尝试. 这种汇编指令级别的混淆器之所以写得比较容易, 是因为汇编指令可以使用标识符来表示偏移量,而这些标识符在汇编器开始编译汇编代码时会自行计算, 因此, 在汇编指令之间插入指令完全是可行的, 如果想要将指令拆分, 只需将指令的opcode求出,然后拆分重组直接将opcode作为数据定义在源文件中交给编译器是完全没有问题的.

下面便是汇编指令混淆器的实现思路

实现思路

1. db伪指令不仅仅可以在数据段中定义数据, 也可以在.code 段中定义数据, 而这些数据如果被eip指向就会被当成代码执行, 如果eip永不指向它, 它虽在代码段中,但也不会被执行.  那么我们完全可以这样做:
  1.        .code
  2.                push ebp
  3.                mov ebp , esp
  4.                jmp _START
  5.                db 'this is data, this is code too'
  6.        _START:
  7.                mov eax , 1
  8.                mov esp , ebp
  9.                pop ebp
  10.                ret
复制代码

   这段小程序执行起来之后, 在执行了前两句之后,会接着jmp到_START标签之后, 而那段我们在代码中定义的数据将永远不会被使用到. 但有时候这种小伎俩很容易被识破 , 我们再观察另外的情况:
  1.        .rdata
  2.        g_str db 'hello' , 0
  3.       
  4.        .code
  5.        push offset g_str
  6.        call ctr_cprintf  ; printf("hello")
  7.        add esp , 4
复制代码

   上面这段代码比较正常, 调用printf函数打印hello字符串嘛. 但再看以下这段:
  1.        .code
  2.                call _PUSHSTR
  3.                db 'hello'
  4.        _PUSHSTR:
  5.                call ctr_cprintf
  6.                add esp , 4  
复制代码

   这段代码仍然还是打印字符串hello, 但它的执行流程就没有上面的清晰了, 例如, 它运行之后, 先call到了标签_PUSHSTR处, 因为这是一条call条指令,执行之后是会将返回地址入栈的, 而入栈的地址好巧不巧正是字符串hello在代码段中的地址. 而调用printf函数时, 栈中已经保存了一个字符串的地址. 因此,最后输出的正式字符串hello. 而由于字符串被保存在了代码段中, 当这个程序被OD反编译时,将会被当成opcode解析出来.,在分析时自然就不是很好看了.
2. 一些指令执行之后是不会产生任何作用, 例如 :
  1.                or eax,080000000h
  2.                js J_H_Z_L_XXXXX
  3.                db        "hello i am a string"
  4.        J_H_Z_L_XXXXX:
  5.                and eax,0xFFFFFFFF
  6.                JCC  J_H_Z_L_XXXXX  
复制代码

   这段指令看似会有分支执行 ,但实际不会, 因为or eax,080000000h执行之后, SF符号标志位必定被置1. js指令也必定会被执行. 后续的代码也一样.

混淆器的设计

整个混淆器的工作流程是这样的:

1. 从.asm文件中读取出汇编指令.
2. 将该汇编指令输入给一个混淆器对象,这个混淆器对象输出包含有这条指令的混淆指令数组.(一条变多条)
3. 将混淆指令数组写到另一个文件中.
4. 完成.



因此, 它看起来大概是这样的:

  1.             char line[200];
  2.             vector<Instruction> vecIns;
  3.            
  4.             // 获取每一行汇编源文件的代码
  5.             while( iFile.getline(line,200) ) {
  6.    
  7.                     // 将这行汇编指令交给混淆器对象出来, 混淆器将多行混淆后的指令输出到vector中.
  8.                      if( mixer.mix( line , &vecIns ) ) {
  9.                             // 混淆成功,则将混淆后的内容输出到文件
  10.                             for( auto &i : vecIns ) {
  11.                                     oFile << i << endl;
  12.                             }
  13.                     }
  14.                     else {
  15.                             // 混淆失败则将原指令输出到文件。
  16.                             oFile << line << endl;
  17.                     }
  18.             }
复制代码


至于混淆器对象 , 它是这样做的:

  1.     virtual bool mix( const Instruction& pInsObj , vector<Instruction>* vecMixer ) = 0;
复制代码


没错,这是个纯虚函数, 因为我把指令分成了不同种类,有数据传输的,有算术运算的,有位运算的, 不同的指令有不同的混淆, 而我不想将所有的代码都放在此函数中实现, 因此, 我派生了几个混淆不同种类指令的混淆器类来,它们分别有:

  • 1. MixEngine_tran  : 数据传输指令
  • 2. MixEngine_bit  : 位运算指令
  • 3. MixEngine_jcc : 条件转移指令
  • 4. MixEngine_call  : 调用指令

例如, 对数据传输指令的操作是这样的:

  1.   // 对数据传输指令进行简单的混淆
  2.     bool MixEngine_tran::mix(const Instruction& pInsObj, vector<Instruction>* vecMixer)
  3.     {
  4.             static int ___ = srand(time(nullptr));
  5.    
  6.             if (pInsObj.type() != e_tran)
  7.             {
  8.                     return false;
  9.             }
  10.    
  11.             if (vecMixer == nullptr)
  12.                     return false;
  13.    
  14.             vecMixer->clear();
  15.    
  16.             /**
  17.             * 混淆方式:
  18.             * 将预定义的指令加入到原指令的周围.
  19.             */
  20.             char* ins[10] =
  21.             {
  22.                     "add esp,2;add esp,2;sub esp,4",
  23.                     "ADD EAX,ECX; NEG ECX; ADD ECX,EAX;SUB EAX,ECX;XCHG EAX,ECX",
  24.             };
  25.    
  26.    
  27.             int count = m_hardness > _countof(ins) ? _countof(ins) : m_hardness;
  28.    
  29.             int pos = rand() % count;
  30.             for (int i = 0; i<count; ++i)
  31.             {
  32.                     InstructionGroup insGrp(ins[i]);
  33.                     for (auto&item : insGrp)
  34.                     {
  35.                             if( i == pos)
  36.                                     vecMixer->push_back(item);
  37.                     }
  38.             }
  39.             vecMixer->push_back(pInsObj);
  40.             return true;
  41.     }
复制代码


这其中, 涉及到了一个叫做Instruction的类, 这个类没什么逻辑, 它主要提供了操作一条婚变指令的功能.

   
  1.         const char* mnemonic( )const; // 得到指令的助记符
  2.             const char* operator1()const; // 得到指令的操作数1
  3.             const char* operator2( )const;// 得到指令的操作数2
  4.             const char* operator3( )const;// 得到指令的操作数3
  5.    
  6.             void                setMnemonic( const char* mnemonic ); // 设置指令的助记符
  7.             void                setOperator1(const char* pOperator ); // 设置指令的操作数1
  8.             void                setOperator2( const char* pOperator );// 设置指令的操作数2
  9.             void                setOperator3( const char* pOperator );// 设置指令的操作数3
复制代码


这个类一般接收一条字符串,例如:mov eax , 1 , 然后通过这个指令的几个成员函数, 就可以得到一条汇编指令的操作数,或者替换指令的操作数了.

还有一个InstructionGroup类, 它负责保存一组指令, 实际上就是一个vector<Instruction>
这毕竟只是花了一个下午写出来的, 因此, 只能当汇编中的高级知识来学学啦, 真心没有啥用.
代码:
游客,如果您要查看本帖隐藏内容请回复


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-1-31 15:48:50 From FishC Mobile | 显示全部楼层
不明觉厉(⊙o⊙)!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-27 06:39:31 | 显示全部楼层
呵呵,这个可以有!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-9-28 21:45:08 | 显示全部楼层

不明觉厉(⊙o⊙)!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-10-12 14:01:23 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-17 06:54

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表