首页
社区
课程
招聘
[Anti Virus专题]长度反汇编引擎的打造
发表于: 2009-5-5 02:00 17182

[Anti Virus专题]长度反汇编引擎的打造

2009-5-5 02:00
17182

长度反汇编引擎(Length-Disassembler Engine)的打造

        忙,好忙。利用晚上下班的时间给大家赶出篇文章来。貌似好长时间没有睡过好觉了。这个星期还要回趟家乡去.... **** 总是时间太少........

        这个星期先给大家来一篇Virus编写中经常要用到的长度反汇编引擎Length-Disassembler Engine的编写思路文章。因为它在Virus编写中也是十分重要。我们病毒变形、感染很多时候都要用到它。

        长度反汇编引擎(Length-Disassembler Engine)是用于获取目标地址所在代码的长度。举个例子push ebp | mov ebp, esp 。我想大家对这两句代码并不陌生了,一般被用于我们的子程序中建

立堆栈框架。那么这两句指令的长度是不同的,有时候我们要替换某内存地址中的指令的话,如果我们茫然的替换,只能把稳定性给大大的抛弃了。所以这个时候就需要我们的长度反汇编引擎来获取我

们要替换地址所在指令的长度,如果小于或者等于替换指令的长度,我们则可以进行替换。假设我们通过Length-Disassembler Engine获取push ebp所在的地址的代码长度,那么返回的长度肯定是1。
那么目前我所见到过非常短小精炼的长度反汇编引擎就是rgblde,300 bytes+  啊?有点扯远了我们继续主题。

比如把

Oep:
push ebp        ;1 bytes  $55
mov ebp, esp         ;2 bytes  $8B, $EC

换成
Oep:
push ebp        ;1 bytes  $55
push esi        ;1 bytes  $56
mov  ebp, esp        ;2 bytes  $8B, $EC

假如我们在替换指令的时候, 我们的程序按照之前的替换方式。从mov ebp, esp地址处开始替换。因为此时这个地址是我们的指令push esi,(假设替换指令是 jmp shor Oep(2 bytes) - $EB $FD)。那

么替换后形成
Oep:
push ebp        ;1 bytes  $55
jmp  short Oep        ;2 bytes  $EB $FD
                ;1 bytes  $EC

那么此时如果替换后的话,并执行的话肯定会出现异常的。还有平常我们的inline Hook 例如那常用的5字节 替换(jmp long xxxx),如果我们不通过Length-Disassembler Engine长度取下要替换目标地

址的指令长度是否等于5字节就茫然替换的话这个程序的稳定性就太欠缺了。以上就是我们Length-Disassembler Engine的用处。它在病毒中也常常要用,例如用到EPO,例如搜索代码段的5字节指令进行

替换,或者用到变形等。

OK。了解了用处我们就来实现吧。

首先要编写长度反汇编引擎
       

                     intel指令格式

+-------------+--------+----------+---------+--------------+------------+
; instruction ; opcode ;  ModR/M  ;   SIB   ; Displacement ; Immediate  ;
;   prefixe   ;        ;          ;         ;              ;            ;
+-------------+--------+----------+---------+--------------+------------+
    前缀(可选)   操作码  (可选)    (可选)  地址偏移(可选) 立即数(可选)

这里opcode成员是必需的,其他5个成员是可选的。但是千万切记它们的顺序是不能颠倒的。sib我们可以认为是mod/rm的扩展。只要有sib成员那么mod/rm也是必需的。

在这里我不想太多的去介绍Intel指令格式,因为要介绍它我估计得另立一个专题的讲。幸好论坛也有朋友做过此类的系列课程。所以与其我给大家简要讲解,大家还不如去先学习下这些相关的专题。

如我们论坛

egogg 的打造自己的反汇编引擎——Intel指令编码学习报告专题。

我这里主要将部分的重点内容给大家标记下。

前缀:
   1. 前缀是唯一的一个可能出现在Code之前的域

   2. 所有的Prefixes都只有一个字节

   3. 在一个opcode中可能会有多个Prefixes

   4. 如果Prefixes不能对随它之后的opcode起作用,那么处理器将忽略它。

   5. 一条指令可能只有一个CODE域,一个mod r/m域,或者一个 offset域等,但是可以有多个Prefixes.  

Prefixes被分为:
1.  切换默认操作数大小(66h)

2.  切换默认地址大小(67h)

3.  重复(Rep)(F3h,F2h)

4.  切换默认段(2eh,36h,3eh,26h,64h,65h)

5.  总线锁定(Buslock)(F0)

ModR/M
涉及内存操作数的指令都有一个紧挨着主操作码的寻址格式说明字节也就是ModR/M。你应该知道ModR/m什么时候该用,什么时候不该用了吧。

SIB
ModR/M字节编码需要第二寻址字节(SIB).基址+索引或者比例+索引形式的32位寻址则需要SIB字节成员。

Displacement  Immediate
这两个成员我就不说了吧。

OK。了解了结构,我们来说说如何编写。

不知道大家是否用过opcode表。
我们每一个汇编助记符就相当于opcode表的索引。举个例子
pushad - 060h

那么我们假设我们将如pushad, dec reg等单字节指令自己定义一个数值,例如1 来表示它是一个单字节指令。

  那么我们的反汇编引擎读取目标地址的机器码后,通过opcode表偏移地址+机器码来索引我们机器码在表中的对应成员,例如我们的pushad如果取出的对应成员值是1的话,我们则知道我们的指令是一

个单字节指令。那么我们就可以直接将size +1,然后返回过程,这样我们的长度反汇编过程返回的就是1.

  这就是我们长度反汇编引擎的过程。

  当然如果都是单字节指令的话我们也就不用去学上面的intel格式了。

  其实清楚了上面的pushad的长度反汇编引擎的工作原理,那么接下来的解码工作也是很简单。

  例如通过opcode表偏移地址+机器码来索引我们机器码在表中的对应成员,然后通过对成员进行判断。如果是前缀的话,则跳转到我们的前缀处理过程处去执行。如果是存在ModR/m的指令则跳转到我们

的ModR/m过程去执行,其他的亦然。由于我们的指令成员字节数是可以确定,所以只要通过对指令结构成员进行解码确定我们的目标地址代码到底存在哪些成员,就可以确定目标地址代码的长度。

其实说到底还是要求你对intel指令格式的掌握。所以看不懂的朋友还是尽量先把基础补补。

我这里主要说说引擎的大小优化。

其实之前看到很多作者在设计表的时候居然用dword类型来初始化,这大大增加我们opcode表的字节大小。后期有的人采用了byte 来初始化。NONO,这都不是我们想要的。我们可以采用4bit位的方式来
定义,这样大大简化我们的opcode表字节大小。恩,没错。这个方式最早被29a的sars所使用。我们今天也是学习的29a - sars的Catchy32代码思路。那么我们在通过4bit位来定义成员,我们还是要讲究

点技巧,这样后面为我们提供方便。

1h 2h 4h 8h我们通过每次*2的形式来定义(还是否记得逻辑左移指令)。没错也就是每次shl 1位。为什么要这样?
我们这样定义的话,我们就省略了cmp判断了。直接通过btr来测试我们二进制位并影响CF标志位,然后通过jc分支跳转 来完成我们的判断,是不是很GOOD。

完成后的Opcode表如下。
;--------------------Opcode Table--------------------       

;++
;Description:
;Size of table element is 4 bits.
;0h-one byte instruction
;1h-ModRM byte
;2h-imm8,rel8 etc
;4h-ptr16 etc
;8h-imm16/32,rel16/32 etc
;0Fh-prefix
;0Eh-unsupported opcodes
;--

pref66h equ 1
pref67h equ 2
Table:
;    01  23    45   67   89   AB   CD   EF
db 011h,011h,028h,000h,011h,011h,028h,000h;0Fh
db 011h,011h,028h,000h,011h,011h,028h,000h;1Fh
db 011h,011h,028h,0F0h,011h,011h,028h,0F0h;2Fh
db 011h,011h,028h,0F0h,011h,011h,028h,0F0h;3Fh
db 000h,000h,000h,000h,000h,000h,000h,000h;4Fh
db 000h,000h,000h,000h,000h,000h,000h,000h;5Fh
db 000h,011h,0FFh,0FFh,089h,023h,000h,000h;6Fh
db 022h,022h,022h,022h,022h,022h,022h,022h;7Fh
db 039h,033h,011h,011h,011h,011h,011h,011h;8Fh
db 000h,000h,000h,000h,000h,0C0h,000h,000h;9Fh
db 088h,088h,000h,000h,028h,000h,000h,000h;AFh
db 022h,022h,022h,022h,088h,088h,088h,088h;BFh
db 033h,040h,011h,039h,060h,040h,002h,000h;CFh
db 011h,011h,022h,000h,011h,011h,011h,011h;DFh
db 022h,022h,022h,022h,088h,0C2h,000h,000h;EFh
db 0F0h,0FFh,000h,011h,000h,000h,000h,011h;FFh
;==============================================
Lentable equ $-Table
;===============EXTENDED OPCODES===============
TableExt:
;    01  23    45   67   89   AB   CD   EF
db 011h,011h,0E0h,000h,000h,0EEh,0E1h,003h;0Fh
db 011h,011h,011h,011h,01Eh,0EEh,0EEh,0EEh;1Fh
db 011h,011h,01Eh,01Eh,011h,011h,011h,011h;2Fh
db 000h,000h,000h,0EEh,0EEh,0EEh,0EEh,0EEh;3Fh
db 011h,011h,011h,011h,011h,011h,011h,011h;4Fh
db 011h,011h,011h,011h,011h,011h,011h,011h;5Fh
db 011h,011h,011h,011h,011h,011h,011h,011h;6Fh
db 033h,033h,011h,010h,011h,011h,011h,011h;7Fh
db 088h,088h,088h,088h,088h,088h,088h,088h;8Fh
db 011h,011h,011h,011h,011h,011h,011h,011h;9Fh
db 000h,001h,031h,011h,000h,001h,031h,011h;AFh
db 011h,011h,011h,011h,0EEh,031h,011h,011h;BFh
db 011h,031h,033h,031h,000h,000h,000h,000h;CFh
db 0E1h,011h,011h,011h,011h,011h,011h,011h;DFh
db 011h,011h,011h,011h,011h,011h,011h,011h;EFh
db 0E1h,011h,011h,011h,011h,011h,011h,01Eh;FFh
;==============================================

OK,这里给大家贴一段我参考29a - sars的Catchy32代码思路写的一段长度反汇编引擎,我去掉了些不必要的代码, 并且以上我已经说了这个符号表以及这个引擎的判断方式,相信理解了以上,你看代码应该没有问题了。。它处理完重定位 大概应该在500 byte  - 600 byte之间。抱歉原谅我不喜欢静态库的方式来移植到高级语言编译器中,我还是喜欢shellcode方式。。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (19)
雪    币: 193
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不懂,先去看基础!
2009-5-5 08:41
0
雪    币: 115
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
先顶 再学习
2009-5-5 09:23
0
雪    币: 91
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
我能接受的只有运行"lde32.exe", 啥也没看见.. 飘过了...
2009-5-5 09:25
0
雪    币: 370
活跃值: (52)
能力值: ( LV13,RANK:350 )
在线值:
发帖
回帖
粉丝
5
小鱼姐,谢谢。要注意身体了,嘿嘿
2009-5-5 10:43
0
雪    币: 393
活跃值: (100)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
6
小鱼姐,谢谢。要注意身体了,嘿嘿
2009-5-5 12:17
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
先顶,再细看!
2009-5-5 14:02
0
雪    币: 59
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
不好,哎,都是一味地看别人的东西,写成自己,什么时候有好的东西出现,指令集里有些特殊指令,比如3dnow指令,ia64位指令,这些都不兼容
2009-5-5 14:08
0
雪    币: 358
活跃值: (118)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
对多态变形病毒或木马生成器产生的指令来说,很少有3dnow/IA64的。这个模块对静态反多态变形病毒和批量生成的木马区分垃圾数据和指令很有意义。很期待你接下来的帖子,顶起。
2009-5-5 18:20
0
雪    币: 247
活跃值: (141)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
学习中!十分感谢,楼主辛苦了…
2009-5-5 20:21
0
雪    币: 315
活跃值: (23)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
11
.....
任何东西我们都是先学习别人的东东,然后改进。
因为我们就是在一个未知领域进行探讨,关键还是在于自己去理解学习。这篇文章重要的是引擎的优化。

  另外你说的3DNOW指令关键在于表的建立,这个表支持3DNOW的。并且SSE,SSE2、MMX等指令也支持。64位当然就不说了,因为我们毕竟还是在win32环境下。
2009-5-5 20:35
0
雪    币: 445
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
顶了!学习!
2009-5-5 21:44
0
雪    币: 97
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
进来学习
2009-5-6 02:38
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
哇,太深刻了,先顶了
2009-5-8 18:38
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
非常强悍,非常想学
2009-5-9 16:09
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
16
LED,挺汗的,病毒里貌似只用于OEP混淆,所以只支持常用函数开头的指令就够了我觉得
2009-5-9 17:27
0
雪    币: 101
活跃值: (88)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
17
顶了也不看~~~~~~
2009-5-9 19:03
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
看不懂啊 要多加点注释哦 最近一直在看一个病毒自带的32位长度的反汇编引擎 虽然代码不长 但是看了很久也没看懂 不过结构上看 差不多的 就是搞不明白其中的意思
2009-5-26 16:40
0
雪    币: 171
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
太感人拉   继续顶
2009-8-17 15:09
0
雪    币: 377
活跃值: (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
20
这里面还有女的??
2009-9-12 15:28
0
游客
登录 | 注册 方可回帖
返回
//