首页
论坛
专栏
课程

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

2009-5-5 02:00 14371

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

2009-5-5 02:00
14371
长度反汇编引擎(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方式。。



	format PE GUI 4.0
	include 'win32ax.inc'
	
.text
	
 entry	$
 
 	mov	esi, Lde32
 	push	esi
 	call	Lde32
 	add	esi, eax
 	jmp	$-13
 	ret
	
	

 ;++
 ;
 ; Int
 ;   Lde32(
 ;   IN byte *pDestAddress   
 ;   )
 ;
 ; Routine Description:
 ;
 ;    获取目标地址代码的长度
 ;
 ; Thanks sars .
 ;
 ; Arguments:
 ;
 ;    (esp)          	- return address
 ;
 ;    Data  (esp+4*8+4) - pDestAddress
 ;
 ; Return Value:
 ;
 ;    eax = TRUE, initialization succeeds . = OpCode Length
 ;    eax = -1,   Faild
 ;--
 
 include 'optable.inc'
 Lde32:
	pushad
	xor	ecx, ecx
	mov	esi, [esp+4*8+4]
	
 Lde_ExtFlags:
 	xor	eax, eax
 	xor	ebx, ebx
 	cdq
	lodsb
	mov	cl, al
	cmp	al, 0fh
	je	Lde_ExtdTable
 	jmp	Lde_NormTable
 	
 Lde_ExtdTable:				;Load flags from extended table
	lodsb
	inc 	ah			;EAX=al+100h (100h/2 - lenght first table)

 Lde_NormTable:				;Load flags from normal table
	shr	eax, 1			;Div 2
	mov	al, byte [Table+eax]
	
	jc	Lde_CheckC1		;如果是奇数则取低4位
	shr	eax, 4			;Get Hight high 4-bits

 Lde_CheckC1:				
 	and	eax, 0Fh		;...low
 	xchg	eax, ebx
 	
 ;--------------Opcode type checking---------------
 Lde_CheckFlags:
 	cmp	bl, 0Eh			;unsupported opcodes
 	je	Lde_Error
 	cmp	bl, 0Fh			;test prefix
 	je	Lde_Prefix
 	or	ebx, ebx		;Test One byte command   
 	jz	Lde_GetLen
 	btr	ebx, 0			;Test ModRM byte
 	jc	Lde_ModRM		
 	btr	ebx, 1			;Test imm8,rel8 etc
 	jc	Lde_incr1
 	btr	ebx, 2			;Test ptr16 etc
 	jc	Lde_incr2
 ;-----imm16/32,rel16/32, etc types processing-----
 Lde_16_32:
 	and 	bl, 11110111b    	;Reset 16/32 sign 
 	
 	cmp 	cl, 0A0h		;Processing group 0A0h-0A3h
	jb	Lde_Check66h
	cmp	cl, 0A3h
	ja	Lde_Check66h
	test	ch, pref67h		
	jnz	Lde_incr2
	jmp	Lde_incr4
		
 Lde_Check66h:				;Processing other groups
	test 	ch, pref66h  		;pref66h                    
	jz 	Lde_incr4                            
	jmp 	Lde_incr2                            
 
 ;---------------Prefixes processing---------------
 Lde_Prefix:
 	cmp	cl, 66h
 	je	Lde_SetFlag66h
 	cmp	cl, 67h
 	jne	Lde_ExtFlags
 	
  Lde_SetFlag67h:
  	or	ch, pref67h  
  	jmp	Lde_ExtFlags
  	
  Lde_SetFlag66h:
 	or	ch, pref66h
 	jmp	Lde_ExtFlags
 	
 ;--------------ModR/M byte processing-------------
 Lde_ModRM:
 	lodsb
 	
 	cmp	cl, 0F7h
 	je	Lde_GroupF6F7
 	cmp	cl, 0F6h
 	jnz	Lde_Modxx
 	
 Lde_GroupF6F7:
 	test 	al, 00111000b	
	jnz 	Lde_Modxx
 	test 	cl, 00000001b
	jz	Lde_incbt1			
	test	ch, pref66h
	jnz	Lde_incbt2	
	inc 	esi
	inc 	esi
 Lde_incbt2:	inc 	esi
 Lde_incbt1:	inc 	esi
 	
 Lde_Modxx:
 	mov 	edx, eax
	and 	al, 00000111b		;al <- only R/M bits
	test	dl, 11000000b		;Check MOD bits
	jz  	Lde_Mod00
	jp  	Lde_CheckFlags		;Or Lde_Mod11
	js  	Lde_Mod10
 
 Lde_Mod01:
	test 	ch, pref67h
	jnz 	Lde_incr1 		;16-bit addressing
	cmp 	al, 4			;Check SIB
	je 	Lde_incr2
	jmp 	Lde_incr1

 Lde_Mod00:
	test 	ch, pref67h		;pref67h
	jz 	Lde_Mod00_32		;32-bit addressing
	cmp 	al, 6
	je 	Lde_incr2
	jmp 	Lde_CheckFlags	
 Lde_Mod00_32:
	cmp 	al, 4			;Check SIB
	jne 	Lde_disp32

 Lde_SIB:				;Processing SIB byte
	lodsb
	and 	al, 00000111b
	cmp 	al, 5
	je 	Lde_incr4
	jmp 	Lde_CheckFlags	

 Lde_disp32:	
	cmp 	al, 5
	je 	Lde_incr4
	jmp 	Lde_CheckFlags 

 Lde_Mod10:
	test 	ch, pref67h
	jnz 	Lde_incr2		;16-bit addressing
	cmp 	al, 4			;Check SIB
	je 	Lde_incr5
	jmp 	Lde_incr4

 Lde_incr5:	inc 	esi
 Lde_incr4:	inc 	esi
	inc 	esi
 Lde_incr2:	inc 	esi
 Lde_incr1:	inc 	esi
	jmp 	Lde_CheckFlags	
 
 ;-----------Command length calculation------------	
 Lde_GetLen:
 	sub	esi, [esp+4*8+4]
 	mov	[esp+pushad_eax], esi
 	jmp	Lde_Ret
 	
 	
 ;-----------Setting the error-----------------------
 Lde_Error:
 	xor	eax, eax
 	dec	eax
 	mov	[esp+pushad_eax], eax
 	 
 Lde_Ret:
 	popad
 	retn 4*1



[公告]看雪20周年会 | 感恩有你,一路同行

上传的附件:
最新回复 (19)
cham 2009-5-5 08:41
2
0
不懂,先去看基础!
hust白客 2009-5-5 09:23
3
0
先顶 再学习
xygwf 2009-5-5 09:25
4
0
我能接受的只有运行"lde32.exe", 啥也没看见.. 飘过了...
moonife 8 2009-5-5 10:43
5
0
小鱼姐,谢谢。要注意身体了,嘿嘿
iiii 1 2009-5-5 12:17
6
0
小鱼姐,谢谢。要注意身体了,嘿嘿
壹无所有 2009-5-5 14:02
7
0
先顶,再细看!
圣新冰心 2009-5-5 14:08
8
0
不好,哎,都是一味地看别人的东西,写成自己,什么时候有好的东西出现,指令集里有些特殊指令,比如3dnow指令,ia64位指令,这些都不兼容
renbaishi 2009-5-5 18:20
9
0
对多态变形病毒或木马生成器产生的指令来说,很少有3dnow/IA64的。这个模块对静态反多态变形病毒和批量生成的木马区分垃圾数据和指令很有意义。很期待你接下来的帖子,顶起。
tianci 2009-5-5 20:21
10
0
学习中!十分感谢,楼主辛苦了…
xfish 5 2009-5-5 20:35
11
0
.....
任何东西我们都是先学习别人的东东,然后改进。
因为我们就是在一个未知领域进行探讨,关键还是在于自己去理解学习。这篇文章重要的是引擎的优化。

  另外你说的3DNOW指令关键在于表的建立,这个表支持3DNOW的。并且SSE,SSE2、MMX等指令也支持。64位当然就不说了,因为我们毕竟还是在win32环境下。
kuifatang 2009-5-5 21:44
12
0
顶了!学习!
清清爽爽 2009-5-6 02:38
13
0
进来学习
dezhou 2009-5-8 18:38
14
0
哇,太深刻了,先顶了
ychhy 2009-5-9 16:09
15
0
非常强悍,非常想学
nbw 24 2009-5-9 17:27
16
0
LED,挺汗的,病毒里貌似只用于OEP混淆,所以只支持常用函数开头的指令就够了我觉得
nkspark 3 2009-5-9 19:03
17
0
顶了也不看~~~~~~
gulunhua 2009-5-26 16:40
18
0
看不懂啊 要多加点注释哦 最近一直在看一个病毒自带的32位长度的反汇编引擎 虽然代码不长 但是看了很久也没看懂 不过结构上看 差不多的 就是搞不明白其中的意思
daheshan 2009-8-17 15:09
19
0
太感人拉   继续顶
宙斯 4 2009-9-12 15:28
20
0
这里面还有女的??
游客
登录 | 注册 方可回帖
返回