【RE】花指令

一、什么是花指令

1)定义

花指令又名垃圾代码、脏字节,英文名是junk code。花指令就是在不影响程序运行的情况下,往真实代码中插入一些垃圾代码,从而影响反汇编器的正常运行;或是起到干扰逆向分析人员的静态分析,增加分析难度和分析时间。

2)分类

花指令分为不可执行花指令、可执行花指令

可执行花指令 顾名思义,可以执行的花指令,这部分垃圾代码会在程序运行的时候执行,但是执行这些指令没有任何意义,并不会改变寄存器的值,同时反汇编器也可以正常的反汇编这些指令。目的是为了增加静态分析的难度,加大逆向分析人员的工作量。

不可执行花指令 不可以执行的花指令,这类花指令会使反编译器在反编译的时候出错,反汇编器可能错误的反汇编这些指令。根据反汇编的工作原理,只有花指令同正常指令的前几个字节被反汇编器识别成一组无用字节时,才能破坏反汇编的结果。因此,插入的花指令应当是一些不完整的指令,被插入的不完整指令可以是随机选择的。

为了能够有效迷惑反汇编器,同时又确保代码的正确运行,花指令必须满足两个基本特征,即:

  • 垃圾数据必须是某个合法指令的一部分。
  • 程序运行时,花指令必须位于实际不可执行的代码路径。
3)原理:反汇编算法的设计缺陷

常用的两类反汇编算法:

1.线性扫描算法:逐行反汇编(无法将数据和内容进行区分)

2.递归行进算法:按照代码可能的执行顺序进行反汇编程序。

通过构造必然条件或者互补条件,使得反汇编出错。

简单的花指令 0xe8是跳转指令,可以对线性扫描算法进行干扰,但是递归扫描算法可以正常分析。

两个跳转一个指向无效数据,一个指向正常数据来干扰递归扫描算法。

二、花指令实现

1.简单jmp

这是最简单的花指令。

这种jmp单次跳转只能骗过线性扫描算法,会被IDA识别(递归下降)。

__asm{
    jmp label1
    db junkcode
label1:    
}

2.多层跳转

本质上和简单跳转是一样的,只是加了几层跳转。显然无法干扰ida

start://花指令开始
    jmp label1
    DB junkcode
label1:
     jmp label2
     DB junkcode
label2:
    jmp label3
    DB junkcode
label3   

和单次跳转一样,这种也会被IDA识别。

为了骗过IDA,我们将上面的花指令改写一下,

__asm {
       _emit 0xE8
       _emit 0xFF
            //_emit 立即数:代表在这个位置插入一个数据,这里插入的是0xe8
      }

查看反汇编后的结果

可以看到IDA错误的识别loc_411877处的代码,成功的实现了花指令的目的。那么我们知道了如何构造,自然也就明白了如何去除,只需要将插入的立即数nop掉即可,点击0xe8和0xff,点击右键,选择patching->change byte

也可以使用一个idapython脚本添加一个快捷键,

from idaapi import *
from idc import *
def nopIt():
	start = get_screen_ea()
	patch_byte(start,0x90)
	refresh_idaview_anyway()

add_hotkey("ctrl-N",nopIt)

这个快捷键可以将选中的地方直接nop掉。

3.jnx和jx条件跳转

利用jz和jnz的互补条件跳转指令来代替jmp。骗过OD

_asm{
    jz label1
    jnz label1
    db junkcode
label1:    
}

 __asm {
        jz Label;
		jnz Label;
		_emit 0xC7;
Label:

这种混淆去除方式也很简单,特征也很明显,因为是近跳转,所以ida分析的时候会分析出jz或者jnz会跳转几个字节,这个时候我们就可得到垃圾数据的长度,将该长度字节的数据全部nop掉即可解混淆。

4.永真条件跳转

通过设置永真或者永假的,导致程序一定会执行,由于ida反汇编会优先反汇编接下去的部分(false分支)。也可以调用某些函数会返回确定值,来达到构造永真或永假条件。ida和OD都被骗过去了

__asm{
    push ebx
    xor ebx,ebx
    test ebx,ebx
    jnz label1
    jz label2
label1:
    _emit junkcode
label2:
   pop ebx//需要恢复ebx寄存器    
}

__asm{
	clc
	jnz label1:
	_emit junkcode
label1:
}

确保一个支路永远跳转

在另一个不跳转的支路填充垃圾代码

 __asm {
         push ebx;
         xor ebx, ebx;
         test ebx, ebx;
         jnz LABEL7;
         jz    LABEL8;
     LABEL7:
         _emit 0xC7;
     LABEL8:
         pop ebx;
     }

先对ebx进行xor之后,再进行test比较,zf标志位肯定为1,就肯定执行jz LABEL8,也就是说中间0xC7永远不会执行。

解混淆的时候也需要稍加注意,需要分析一下哪里是哪里是真正会跳到的位置,然后将垃圾数据nop掉,本质上和前面几种没什么不同。

5.call&ret构造花指令

这里利用call和ret,在函数中修改返回地址,达到跳过thunkcode到正常流程的目的。可以干扰ida的正常识别

__asm{
    call label1
    _emit junkcode
label1:
    add dword ptr ss:[esp],8//具体增加多少根据调试来
    ret
    _emit junkcode
}

call指令:将下一条指令地址压入栈,再跳转执行
ret指令:将保存的地址取出,跳转执行

6.汇编指令共用opcode

jmp的条指令是inc eax的第一个字节,inc eax和dec eax抵消影响。这种共用opcode确实比较麻烦

三、清除花指令

手动清除

找到所有的花指令,重新设置数据和代码地址。或者将花指令设置为nop(0x90)

在0x401051设置为数据类型(快捷键D),在0x401052设置为代码类型(快捷键C)

这里用一个ida python脚本添加ALT+N快捷键来将指令的第一个字节设置为NOP

from idaapi import *
from idc import *

def nopIt():
	start = get_screen_ea()
	patch_byte(start,0x90)
	refresh_idaview_anyway()

add_hotkey("alt-N",nopIt)

参考文章

CTF逆向Reverse 花指令介绍 and NSSCTF靶场入门题目复现_ctf 花指令-CSDN博客

【逆向学习】花指令的去除_去除花指令-CSDN博客

VMP常见花指令学习笔记1 - 哔哩哔哩 (bilibili.com)

逆向分析基础 --- 花指令实现及清除_jmp花指令逆向-CSDN博客

  • 17
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值