吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 23272|回复: 24
收起左侧

[PC样本分析] PE文件型病毒[含样本]

  [复制链接]
Cherishao 发表于 2018-2-5 21:59
使用论坛附件上传样本压缩包时必须使用压缩密码保护,压缩密码:52pojie,否则会导致论坛被杀毒软件等误报,论坛有权随时删除相关附件和帖子!
病毒分析分区附件样本、网址谨慎下载点击,可能对计算机产生破坏,仅供安全人员在法律允许范围内研究,禁止非法用途!
禁止求非法渗透测试、非法网络攻击、获取隐私等违法内容,即使对方是非法内容,也应向警方求助!
本帖最后由 Cherishao 于 2018-2-7 14:59 编辑

0x00 概述

之前分享了关于病毒的的一些小知识,有坛友对PE文件病毒比较感兴趣,于是,把之前学过的PE文件型病毒知识整理分享一下。

0x10 PE文件病毒

是Windows系统病毒之一,在安全模式下可以删除。

0x11 病毒特点

该病毒是将可执行文件的代码中程序入口地址改为病毒的程序入口,这样就会导致用户在运行的时候执行病毒文件,这是黑客比较常用的方式。

0x20 如何判定PE文件

:如何判断一个文件是否为PE文件?

1、检验文件头部第一个字的值是否等于MZ,如果是,则DOS头有效。
2、用DOS头的字段e_lfanew来定位PE头。
3、比较PE透的第一个双字的值是否等于45500000H(PE\0\0)。

0x21PE文件结构

PE文件结构图如下:
PE文件结构

0x22 判断是否为PE文件

汇编代码实现

#定义局部变量
IMAGE_DOS_HEADER  dos_header;
IMAGE_NT_HEADER  nt_header;
CFile fp;
fp.Read(&dos_header,sizeof(dos_header)); 
If(dos_header.e_magic!=0x5A4D) #用DOS头的字段e_lfanew来定位PE头。
{…..}
fp.Seek(dos_header.e_lfanew,CFile::begin);

if(nt_header.Signature!=0x00004550) #比较PE透的第一个双字的值是否等于45500000H(PE\0\0)。

0x30 PE病毒编写的关键

定位、获取API函数、搜索目标文件、感染、破坏。

0x31 病毒编写的难点

病毒是在宿主的运行环境下运行,所以无法像在自己本身的运行环境下一样访问自己的静态(全局)变量的数据和直接调用系统API。

0x32 病毒感染PE文件的基本方法

(1)判断目标文件开始的两个字节是否为“MZ”;
(2)判断PE文件标记“PE”;
(3)判断感染标记,如果已被感染过则跳过这个文件,否则继续;
(4)获得Directory(数据目录)的个数,每个数据目录信息占8个字节;
(5)得到节表起始位置:Directory的地址+数据目录占用的字节数=节表起始位置;
(6)得到目前最后节表的末尾偏移(紧接其后用于写入一个新的病毒节):
节表起始位置+节的个数×(每个节表占用的字节数28H)=目前最后节表的末尾偏移
(7)开始写入新的节表项
①写入节名(8字节);
②写入节的实际字节数(4字节);
③写入新节在内存中的开始偏移地址(4字节),同时可以计算出病毒入口位置:
上节在内存中的开始偏移地址+(上节大小/节对齐+1)×节对齐
④写入新节(即病毒节)在文件中对齐后的大小;
⑤写入新节在文件中的开始位置:
上节在文件中的开始位置+上节对齐后的大小(8) 修改映像文件头中的节表数目
(9)修改AddressOfEntryPoint(即程序入口点指向病毒入口位置),同时保存旧的AddressOfEntryPoint,以便返回HOST继续执行。
(10)更新SizeOfImage(内存中整个PE映像尺寸=原SizeOfImage+病毒节经过内存节对齐后的大小);
(11)写入感染标记(可以放在PE头中);
(12)写入病毒代码到新节指向的文件偏移中。

0x40 重定位

0x41 病毒感染重定位原因?

病毒要用到变量,在病毒感染host程序后,由于它依附到host程序中的位置各不
相同,因此病毒随着host载入内存后,病毒中的各个变量在内存中的位置会随着host程序的位置而发生变
化,因此,病毒程序要能正常使用变量。必须采用重定位技术。

0x42 重定位步骤

1.call指令跳转到下一条指令,使下一条指令感染后在内存中的实际地址进栈。
2.用pop EXX,[ESP]指令取出栈顶内容,得到感染后下一条指令内存中的实际地址Base。
3.varstart为感染前call指令的下一条指令地址,varlable为感染前变量地址,则感染后var实际地址为(Base-Offset varstart)(基
地址)+Offset varlable

0x50 API函数获取

0x51 为什么要获取API函数地址

Win32下的系统功能调用一般通过调用动态连接库中的API函数实现。
API函数调用的实质是找到函数地址,然后

call MessageBox(0,”123”,0,0);
Call 0x7c91001c;  (WIN XP SP3)`

0x60 病毒获取API函数地址

0x61 静态方式

调用时,根据函数名查引入表,就可以获取该函数的地址。

0x62 动态方式

使用函数LoadLibrary装载需要调用的函数所在的dll文件,获取模块句柄。然后调用GetProcAddress获取需要调用的函数地址。这种方式是在需要调用函数时才将函数所在的模块调入到内存中,同时也不需要编译器为函数在引入表中建立相应的项。
这里主要注意下面2个特殊的API

LoadLibrary加载一个DLL,返回DLL地址
GetProcAddress通过DLL地址和API函数名获得API函数的地址

0x63 得到模块kernel32的地址方法

由于程序入口点是被kernel32某个函数调用的,所以这个调用函数肯定在kernel32的地址空间上。那么我们只要取得这个返回地址,就得到了一个kernel32空间中的一个地址。
通过这个地址,我们可以从高地址向低地址方向进行搜索,通过PE标志的判断,搜索到kernel32模块的基地址!
大致流程如下:
取栈顶值到寄存器A(KERNEL32中的一个地址)
A =  A 与 0FFFFF000h(分配粒度是1000h,基地址必然在xxxx000h处)
循环:
      如果[A] == IMAGE_DOS_SIGNATURE(判断DOS头标志)
      {B = A;B =B+e_lfanew;  指向PE标志
      如果[B] ==IMAGE_NT_SIGNATURE (判断“PE\0\0”标志)
              { 跳出循环;(找到,退出!)}
       A =  A - 01000h;
循环结束  
代码实现:

GetKBase:
    mov edi ,[esp]        ;取栈顶值,就是KERNEL32中的一个地址
    and edi,0FFFFF0000h    ;分配粒度是10000h,基地址必然在xxxx0000h处

   .while TRUE
      .if WORD ptr [edi] == IMAGE_DOS_SIGNATURE    ;判断DOS头标志
          mov esi,edi
          add esi,DWORD ptr [esi+03Ch]              ;esi指向PE标志
         .if DWORD ptr [esi] ==IMAGE_NT_SIGNATURE   ;判断PE标志
               .break                                       ;若正确,则跳出循环
         .endif
      .endif

       sub edi, 010000h        
   .endw

mov hKernel32,edi           ;把找到的KERNEL32.DLL的基地址保存起来

在得到了Kernel32的模块地址以后,就可以搜索他的导出表得到GetProcAddress和LoadLibrary两个API函数的地址。
对这两个API函数的联合调用就可以得到WIN32 应用层上任何所需要的API函数地址了。

0x64 函数名地址查找

通过函数名称查找函数名地址,具体如下:

1、定位到PE文件头。
2、从PE文件头中的可选文件头中取出数据目录表的第一个数据目录,得到导出表的地址。
3、从导出表的NumberOfNames字段得到以命名函数的总数,并以这个数字做微循环的次数来构造一个循环。
4、从AddressOfNames字段指向的函数名称地址表的第一项开始,在循环中将每一项定义的函数名与要查找的函数名比较,如果没有任何一个函数名符合,说明文件中没有指定名称的函数。
如果某一项定义的函数名与要查找的函数名符合,那么记住这个函数名在字符串地址表中的索引值(如x),然后在AddressOfNameOrdinals指向的数组中以同样的索引值x去找数组项中的值,假如该值为y。
5、以y值作为索引值,在AddressOfFunctions字段指向的函数入口地址表中获取的RVA就是函数的入口地址,当函数被装入内存后,这个RVA值加上模块实际装入的基址(ImageBase),就得到了函数真正的入口地址。

0x65 导出表中获取API函数地址

exportD=hKernel32.OptionalHeader.DataDirectory.VirtualAddress + hKernel32;
int i,iA;
for (i=0;i<exportD.NumberOfNames;i++)
{
p=hKernel32+exportD.AddressOfNames[i]; If (!strcmp(p,name)) break;
}
WORD *pw = (WORD*)(hKernel32 + exportD.AddressOfNamesOrdinals);
iA = pw[i];
DWORD *pA = (DWORD*)(hKernel32 + exportD.AddressOfFunctions);
DWORD address = pA[iA];

0x70 目标文件搜索

PE病毒通常以PE文件格式的文件(如EXE、SCR、DLL等)作为感染目标。在对目标进行搜索时一般采用两个关键的API函数:

FindFirstFile
FindNextFile

其一般搜索“.exe”、“.scr”等文件进行感染。在算法上可以采用递归或者非递归算法对所有盘符进行搜索。

0x71 文件感染

一个被病毒感染的HOST程序通常首先执行病毒代码,然后执行HOST程序的正常代码。这既保证病毒首先获得控制权,同时也不影响HOST程序的正常执行。
另外也可能在HOST程序执行的过程中调用病毒代码,例如病毒的EPO技术中就采用这种方式。 

0x80 病毒对PE文件的修改方式

主要有这三种方式:添加节;扩展节;插入节。

0x81 添加节方式修改PE 

在文件的最后建立一个新节,在节表结构的后面建立一个节表,用以表述该节。入口地址修改为病毒所在节.

1、把病毒代码追加到文件尾部。

2、在节表中增加一个section header各项数据填写正确(VirtualSize,VirtualAddress,PointerToRawData…..)。

3、在FILEHEADER中修改节表项数目: +1。

4、重新计算SizeofHeaders,并替换原值。
5、重新计算SizeofImage,并替换原值。

6、记录未感染时的AOEP(入口地址),因为在病毒代码结束时要让宿主程序正常执行。所以要先记录AOEP,在病毒程序结束后JMP跳到宿主程序的AOEP。

7、修改OptionalHEADER中的AddressOfEntryPoint,让它指向新加节的入口代码

添加节修改PE 结构图如下
添加节修改PE

0x82 插入节方式修改PE

这种方式不增加节的个数和文件长度,病毒搜寻到一个可执行文件后,分析每个节,查询节的空白空间是否可以容纳病毒代码,若可以,则感染之。CIH病毒就是采用这种方法感染可执行文件的。
SizeOfRawData - VirtualSize

插入节方式修改PE结构图如下
插入节修改PE

0x83 扩展节修改PE

先把病毒代码追加到最后一个节的尾部。修改节表中最后一项section header并增加 SizeOfRawData 的大小和内存布局大小。

扩展节修改PE结构图如下:
扩展节修改PE 

0x90 Show me the code

最后分享2个实验,感兴趣的坛友可以动手实践下
(1)打造最小的PE文件。
(2)动态获取API函数地址及观察被PE文件型病毒感染的文件
(3)建议在吾爱虚拟机中实验。
链接:https://pan.baidu.com/s/1sna9Wdv 密码:ilgd 

压缩包提取密码:52pojie

免费评分

参与人数 6威望 +1 吾爱币 +15 热心值 +5 收起 理由
边缘人静心 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
dsb2468 + 1 + 1 总结贴,不错
dapeng2113 + 1 + 1 虽然看不懂,但是很牛逼的感觉!
so丶小静 + 1 + 1 我很赞同!
Hmily + 1 + 10 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
1296565985 + 1 + 1 收获颇丰~

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Cherishao 发表于 2018-2-6 21:19
mq5123 发表于 2018-2-6 17:24
其实大多数蠕虫病毒就是这个原理(比如srv),简而言之就是把病毒数据写入到可执行文件,通过修改程序入口 ...

是有这个,不过,蠕虫病毒的攻击方式比较多样化,大多是利用操作系统和应用程序的漏洞主动进行攻击(RPC溢出漏洞、LASS溢出漏洞)
mq5123 发表于 2018-2-6 17:24
其实大多数蠕虫病毒就是这个原理(比如srv),简而言之就是把病毒数据写入到可执行文件,通过修改程序入口(OEP)使程序先执行病毒代码后再执行原可执行程序
shaokui123 发表于 2018-2-6 01:00
gongyong728125 发表于 2018-2-6 08:11
谢谢楼主分享,学习学习!
guoxiaofei029 发表于 2018-2-6 08:20
不动编程的路过
wj158 发表于 2018-2-6 08:52
这介绍的通俗易懂,感谢分享!
dapeng2113 发表于 2018-2-6 11:08
看不懂。。。但是很牛逼的感觉。。。
壹天 发表于 2018-2-6 11:30
看了一半,然后就没有看下去的欲望了
 楼主| Cherishao 发表于 2018-2-6 13:12
dapeng2113 发表于 2018-2-6 11:08
看不懂。。。但是很牛逼的感觉。。。

感兴趣的话,可以了解清楚PE结构的东西,再来看一遍。
小黑霸天 发表于 2018-2-6 14:10
学习一下 日常防毒。。。
liujiajia123 发表于 2018-2-6 15:21
分析的可以,谢谢分享。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-25 17:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表