0x7Fancy

8086架构花指令入门

Time: 2019.02.19
Tags: 逆向分析

0x00 前言

在逆向工程的工作中,往往会遇到花指令以抵抗逆向分析,增加逆向分析的难度。近期在分析的一个恶意软件中,使用了非常多、非常复杂的花指令,借此机会对花指令进行一个整理,便于以后方便的使用。

本文针对 80x86 汇编,对该指令集下的常用花指令进行了分类示例,不涉及编程以及自动加花/去花。

  1. junk code简介
  2. 无效指令list
  3. 跳转指令控制流程list
  4. 总结

0x01 junk code简介

junk code
花指令(Junk Code)又称为垃圾代码,程序开发者在完成开发后,在程序中插入大量的花指令,以抵抗逆向分析;这些花指令不会修改到程序的逻辑,但是可以扰乱逆向工具的自动化分析,比如导致反汇编引擎无法正确解析指令、IDA Hex-rays 无法正常工作等。

分类
花指令可以分为两个大类:1.无效指令(or组合),2.跳转指令控制执行流程。

1.无效指令(or组合)

无效指令:加入的花指令虽被执行,但不会修改程序的的逻辑。

example:

单条指令:
[1]add edi, 0		83 C7 00
[2]jg $+2			7F 00

也有组合形式的:
[3]push eax			50
   pop eax			58

无效的花指令,会增加逆向分析者的工作量,扰乱其分析思维;其次还会导致 IDA Hex-rays 无法正常工作。

2.跳转指令控制执行流程

跳转指令控制执行流程:花指令由跳转指令和垃圾数据构成,可以任意打乱原指令在文件中的顺序,由跳转指令进行串联,仍然不会修改程序的逻辑。

example:

(ds:dword_1001BE5C = 0)
[1]83 3D 5C BE 01 10 00	cmp     ds:dword_1001BE5C, 0
[2]74 05				jz      short loc_10042F25
[3]E9 06 46 00 00		jmp     loc_1004752B
loc_10042F25:
[4][....] 其中 `dword_1001BE5C = 0`,`jz` 指令将永远都会进行跳转,那么第三条指令 `jmp` 就是一条垃圾数据,永远不会被执行到。所以第三条指令的 5 个字节可以任意修改,如果精心填充数据,则可以影响反汇编引擎的工作。

这类形式的花指令,如果精心构造垃圾数据,即可导致反汇编引擎发送错误,从而无法显示正确的汇编指令,或直接显示原始数据;增加逆向难度。

0x02 无效指令list

对于无效指令,按照指令的类型进行以下分类汇总(以 eax 为主要例子)。

1.无效跳转
使用近跳转,跳转至该行指令的下一句指令,那么无论该行指令是否执行,都将执行下一句指令。

[1]eb 00        jmp $+2

[2]67 e3 00     jcxz $+3 
[3]e3 00        jecxz $+2

[4]74 00        je $+2
[5]75 00        jne $+2
[6]78 00        js $+2
[7]79 00        jns $+2
[8]70 00        jo $+2
[9]71 00        jno $+2
[10]77 00       ja $+2
[11]76 00       jbe $+2
[12]73 00       jae $+2
[13]72 00       jb $+2
[14]7f 00       jg $+2
[15]7e 00       jle $+2
[16]7d 00       jge $+2
[17]7c 00       jl $+2
[18]7a 00       jp $+2
[19]7b 00       jnp $+2
......

2.无效算数指令
执行运算指令但没有修改值。

[1]83 c0 00     add eax, 0
[2]83 e8 00     sub eax, 0
[3]f6 e3        mul bl
[4]f6 f3        div bl

[5]c1 e0 00     shl eax, 0
[6]c1 f8 00     sar eax, 0
[7]c1 e8 00     shr eax, 0
[8]c1 c0 00     rol eax, 0
[9]c1 c8 00     ror eax, 0
[10]c1 d0 00    rcl eax, 0
[11]c1 d8 00    rcr eax, 0

[12]c1 c0 20    rol eax, 0x20
......

3.无效算数指令(组合)
由多条算术语句组成,运行完该组合的所有指令后,没有发生值的改变。除此之外,还可以在组合指令之间添加其他花指令

[1]83 c0 01     add eax, 1
   83 e8 01     sub eax, 1
   
[2]83 f0 11     xor eax, 0x11
   83 f0 11     xor eax, 0x11
   
[3]40           inc eax
   48           dec eax
   
[4]c1 c0 02     rol eax, 2
   c1 c8 02     ror eax, 2
  
[5]83 c0 08     add eax, 8
   83 e8 04     sub eax, 4
   83 e8 04     sub eax, 4
......

4.无效指令
和「算术无效指令」一样,执行运算指令但没有修改值。

[1]90          nop

[2]89 c0       mov eax, eax
   8b 24 24    mov esp, [esp]

[3]85 c0       test eax, eax
......

5.无效指令(组合)
和「算术指令组合」一样,运行完该组合的所有指令后,没有发生值的改变。并且同样可以在组合之间添加其他的花指令。

[1]50      push eax
   58      pop eax

[2]66 9c   pushfw 
   66 9d   popfw  

[3]93      xchg eax, ebx
   93      xchg eax, ebx
......

0x03 跳转指令控制流程list

反汇编引擎有两种工作方式,线性扫描算法(以OD为代表)和递归下降算法(以IDA为代表)。

线性扫描算法逐个解析数据并翻译为指令,由于不能解析程序执行流而很容易将垃圾数据翻译为指令,并且后续的工作都将发生错误。

递归下降算法为了解决线性扫描算法的这个问题,参考 CPU 执行指令的原理,解析其中部分的程序流控制指令(如跳转),并进行跳转翻译。

递归下降算法没有进行所有指令的模拟执行,所以无论是那种算法都没有完全解决花指令的问题;递归下降算法表现得稍好一些。

就如「1.junk code简介」中的示例,这里同样也给个示例,并演示反汇编引擎解析错误的效果。

在语句中插入跳转花指令和垃圾数据:

[...]
mov eax, 0x0a
test eax, 0
jnz A
db 0xeb
db 0x12
db 0x34
A:
mov eax, 0x10
[...]

使用 IDA 查看反汇编的结果:

.text:08000000 _text           segment para public 'CODE' use32
.text:08000000                 assume cs:_text
.text:08000000                 ;org 8000000h
.text:08000000                 assume es:nothing, ss:nothing, ds:_text, fs:nothing, gs:nothing
.text:08000000                 dd 0AB8h, 0A900h, 3750000h
.text:0800000C                 db 0EBh, 12h, 34h
.text:0800000F ; ---------------------------------------------------------------------------
.text:0800000F
.text:0800000F A:
.text:0800000F                 mov     eax, 10h
.text:0800000F _text           ends

如此的语句,可以自由的进行构造,精心设计垃圾数据,就可以使得反汇编引擎发生很多错误,这里不过多举例了。

0x04 anti花指令

目前在 OD 中有辅助插件可以处理简单的花指令,但在实际运用中并不是很理想;花指令的构造方式非常随性,组合无穷,目前没有统一的自动化处理工具。

solving
在遇到花指令时,大多情况都需要对花指令进行详细的分析,在摸清楚规律后,自行编写脚本进行去花。

在花指令较少的情况下,也可以直接手工去花,借助反汇编引擎进行分析,对无效指令进行 nop,并按需修改跳转指令,最后保存到文件即可。

0x05 总结

本文大致举例介绍了常用的花指令,在以后逆向分析过程中,可以按照如此的方式,对程序中出现的花指令进行分类总结,以便于编写自动化处理脚本。初次之外,在某些需要花指令的场合,也可以按照本文的示例,进行扩展,形成花指令库,插入程序中以抵抗逆向分析。