点饭的百度空间
银牌会员
     
积分 2315
发帖 2236
注册 2007-11-30
|
#1 [syscoder] 杀软行为分析1-4
syscoder:参加了百度的笔试 2009-10-18 23:20
我想说的是百度的题真是很难,很变态,我也写的乱七八糟,我真是好头晕啊,好头晕啊。。。。 不过这么多人去应聘,出的复杂点也是理所应当滴
杀软行为分析一:判断文件是否为PE文件结构
操作系统以及杀毒软件是怎么判断一个文件是否是PE文件的呢?先来看看操作系统是怎么识别的。学过PE文件的同学知道,PE文件结构中有两个标志在PE文件头中,一个是MZ标志,如果是PE文件的话,在文件的开头就是该标志,还有一个是PE文件标志,在PE文件头的开始出现(即:IMAGE_NT_HEADERS的开始出)。
很多软件都靠上面两个标志合起来判断是否是PE文件结构,那么一个软件的运行到底需要这两个标志的哪一个呢?或许一个就够了呢?带着这些疑问,我们来测试一下,随便打开一个exe文件,用winhex修改文件开头的那个MZ(ACSII码为:4d 5A)修改成:00 00,然后保存,运行,结果发现程序无法运行了,出来一个Dos窗口,开来操作系统判断其不是PE文件结构,而是判断成了dos时代的程序,呵呵。开来MZ标志在判断PE文件结构中是不可缺少的,再来看一下PE标志是否是必须的呢?和上面操作一样,抹掉PE标志,然后运行会发现,程序无法运行了,与上面一样,弹出来一个dos窗口,看来MZ和PE都是判断PE文件不可缺少的标志。
如果一个软件想要运行的话,那么就必须具有MZ和PE两个标志,你可以把一个病毒的MZ或PE标志去掉,会发现杀软不再杀了,当然这时文件也无法运行。
杀软行为分析二:对文件末尾多出字节的判断
有些木马在配置客户端地址时会把客户端地址写到服务端的末尾,然后服务端读取末尾的字符得到客户端地址,然后开始连接,这样添加后文件还是可以运行的,不信的人可以试试,那么杀毒软件对此有什么反应呢?我们可以分析PE文件结构,得到最后一个节的文件偏移,然后加上该节经过文件对齐的大小,就是该PE文件实际的文件大小,如果后面还有数据,那么就可能就是木马的配置信息了,不过到底是不是,也不能这么确定啊,呵呵。。。
那么有哪些杀毒软件会对这个很在意呢?小红伞就是其中一位,而且比较严重的一位,当小红伞发现一个文件的后面多出的字节超过大约4kb时,就开始报毒了,都不带查特征码的,这个大小是我实际测试中获得的,如果某个正常文件末尾有超过4kb的字节时,可要小心了,呵呵,说不定就被小红伞KO了,这样容易造成误杀,不过有那个正常的程序会在程序后面多加几个无用字节呢?碰到这个情况,可以选择把该文件截尾,即把后面的去掉,那么要是木马配置信息的话,木马也就被KO一半了,同时也不容易造成误杀。。
杀软行为分析三:对入口代码的判断
PE文件的各个节在磁盘上是按照安装文件对齐的方式存放的,那么也就是说两个节之间可能存在空隙,实际情况中这些空隙往往都是存在的,只不过有大有小而已,病毒可以使用这些空隙来插入恶意代码,然后修改PE文件中的入口代码到插入代码的开始出,当文件开始执行时,则首先执行病毒代码,然后由病毒代码跳到原来的文件入口执行正常的代码,也就是说这些空隙可以被利用。。。
杀毒软件是怎么处理的呢?要分两种情况,当病毒插入了代码,但病毒作者忘了更新节的IMAGE_SECTION_HEADER中的VirualSize字段。该字段就是该节没有对齐前的大小,那么杀毒软件只要对比一下该值就可以发现,入口代码竟然在节的空隙中,那么该文件就可能为病毒了。。
第二种情况就复杂了,就是病毒更新了VirualSize字段,新添加的代码就输入该节的一部分了,而且是合法的部分,杀毒软件只判断VirualSize是无法发现异常的,不过这时入口代码就可能在该节的最后面,那么这是不是引发了一个问题呢?我们只要判断入口代码是不是在该节的最后面,若在最后面就是病毒了,否则则不是,那么要解决这个问题,要研究一下,一个正常PE文件的入口代码是不是总在该节的首位呢?写个程序判断一下,程序遍历一个system32文件夹下的所有PE文件,查看其入口是不是总在该节入口出呢?
// GetEntryCodeOffset.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "windows.h"
char * Dir="c:\\windows\\system32\\*.exe";
bool _MapViewFile(char * FileName,HANDLE* FileHwnd,HANDLE* MapHwnd,PVOID* MapMem);
int _IsEntryCodeInBeginSeciton(HANDLE FileHwnd,PVOID MapMem);
WIN32_FIND_DATAA FileInfo;
ULONG CountB=0,CountN=0,CountF=0;
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE Hwnd,FileHwnd,MapHwnd;PVOID MapMem;
SetCurrentDirectoryA("c:\\windows\\system32\\");
Hwnd=FindFirstFileA(Dir,&FileInfo);
if(Hwnd!=INVALID_HANDLE_VALUE)
{
do
{
printf("Find One File :%s\n",FileInfo.cFileName);
if(_MapViewFile(FileInfo.cFileName,&FileHwnd,&MapHwnd,&MapMem))
{
int Type=_IsEntryCodeInBeginSeciton(FileHwnd,MapMem);
switch (Type)
{
case 0:
{
CountF++;
break;
}
case 1:
{
CountB++;
break;
}
case 2:
{
CountN++;
break;
}
}
UnmapViewOfFile(MapMem);
CloseHandle(FileHwnd);
CloseHandle(MapHwnd);
}
} while(FindNextFileA(Hwnd,&FileInfo));
}
printf("入口代码在节的开始数量:%d\n",CountB);
printf("入口代码不在节的开始数量:%d\n",CountN);
printf("失败个数:%d\n",CountF);
return 0;
}
bool _MapViewFile(char * FileName,HANDLE* FileHwnd,HANDLE* MapHwnd,PVOID* MapMem)
{
HANDLE THwnd,TMapHwnd;PVOID TMapMem;
THwnd=CreateFileA(FileInfo.cFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(THwnd!=INVALID_HANDLE_VALUE)
{
TMapHwnd=CreateFileMappingA(THwnd,NULL,PAGE_READONLY,0,0,NULL);
if(TMapHwnd!=NULL)
{
TMapMem=MapViewOfFile(TMapHwnd,FILE_MAP_READ,0,0,0);
if(TMapMem!=NULL)
{
*FileHwnd=THwnd;
*MapHwnd =TMapHwnd;
*MapMem =TMapMem;
return true;
}
CloseHandle(TMapHwnd);
}
CloseHandle(THwnd);
}
return false;
}
int _IsEntryCodeInBeginSeciton(HANDLE FileHwnd,PVOID MapMem)
{
ULONG SizeL,SizeH,NumSection,EntryAddr,SectionEnd;
PIMAGE_DOS_HEADER pDos;
PIMAGE_NT_HEADERS pNt;
PIMAGE_SECTION_HEADER pSection;
SizeL=GetFileSize(FileHwnd,&SizeH);
if(SizeL>sizeof(IMAGE_DOS_HEADER))
pDos =(PIMAGE_DOS_HEADER)MapMem;
else
return 0;
if(pDos->e_magic!=IMAGE_DOS_SIGNATURE)
return 0;
if(SizeL>(pDos->e_lfanew+sizeof(IMAGE_NT_HEADERS)))
pNt =(PIMAGE_NT_HEADERS)((ULONG)MapMem+pDos->e_lfanew);
else
return 0;
if(pNt->Signature!=IMAGE_NT_SIGNATURE)
return 0;
pSection =(PIMAGE_SECTION_HEADER)((ULONG)pNt+sizeof(IMAGE_NT_HEADERS));
NumSection =pNt->FileHeader.NumberOfSections;
EntryAddr =pNt->OptionalHeader.AddressOfEntryPoint;
while(NumSection>0)
{
SectionEnd=pSection->VirtualAddress+pSection->SizeOfRawData;
if((SectionEnd>EntryAddr)&&(EntryAddr>pSection->VirtualAddress))
{ printf("在节的偏移:%d处\n",EntryAddr-pSection->VirtualAddress);
if(pSection->VirtualAddress==EntryAddr)
return 1;
return 2;
}
pSection++;
NumSection--;
}
return 0;
}
程序运行结果如图:

看来基本上没有PE文件的入口正好在该节的入口处,那么上面的只是判断是否在后面将不再适用。。。那么难道没有方法来检测了么?呵呵,方法是有的,你可以判断一下,是不是程序一下从后面一个JMP跳了十万八千里跳到了大前面,不过会造成误杀的,如果某位作者写程序就爱一个Jmp跳的好远,那也说不定。。。。
|
※ ※ ※ 本文纯属【点饭的百度空间】个人意见,与【 微点交流论坛 】立场无关※ ※ ※
|
 你的微笑 is 微点的骄傲!
http://hi.baidu.com/new/micropoint |
 |
|
2010-1-14 18:45 |
|
点饭的百度空间
银牌会员
     
积分 2315
发帖 2236
注册 2007-11-30
|
#2
杀软行为分析四:对添加节感染的处理
杀软行为分析三提到了,病毒可以在PE文件的节空隙添加代码来感染,不过当节的空隙不够时,即空隙的大小不足以存放代码的大小时,这个方法就不好使了,病毒就会尝试添加一个节,然会在添加的节中写入代码,这样无论如何都有足够的大小来存放病毒代码了,为了首先执行,一定会修改入口代码到新增加的节的代码处,然会执行完后跳到原来的节入口去执行,这种方法要比在空隙中添加代码复制的多,要修复PE文件中很多位,不过有足够的空间加代码已经很好了。。。
杀毒软件怎么检测这种病毒呢?杀毒软件还是一般查一下特征码,没有病毒就拉倒了,我在这只是扩展一下该方面的查杀,纯属个人见解,呵呵,当添加了一节后,那么该节就一定要修改属性为可执行的,就是添加IMAGE_SCN_MEM_EXECUTE标志,这样才可以执行代码,但是文件本来就有一个可执行的代码段,现在又多了一个,那么其可以成为一个可以点,可以根据此来判断一个PE是否被感染。。。那么到底是否可行呢?看来有必要看一下,正常的PE文件到底有几个可执行节。。。。写个代码测试下,代码只是对杀软行为分析三中的代码修改了一下。。代码如下:
// GetEntryCodeOffset.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "windows.h"
char * Dir="c:\\windows\\system32\\*.exe";
bool _MapViewFile(char * FileName,HANDLE* FileHwnd,HANDLE* MapHwnd,PVOID* MapMem);
int _IsJustOneExecutionSeciton(HANDLE FileHwnd,PVOID MapMem);
WIN32_FIND_DATAA FileInfo;
ULONG CountOne=0,CountMore=0,CountF;
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE Hwnd,FileHwnd,MapHwnd;PVOID MapMem;
SetCurrentDirectoryA("c:\\windows\\system32\\");
Hwnd=FindFirstFileA(Dir,&FileInfo);
if(Hwnd!=INVALID_HANDLE_VALUE)
{
do
{
printf("Find One File :%s\n",FileInfo.cFileName);
if(_MapViewFile(FileInfo.cFileName,&FileHwnd,&MapHwnd,&MapMem))
{
int Type=_IsJustOneExecutionSeciton(FileHwnd,MapMem);
switch (Type)
{
case 0:
{
CountF++;
break;
}
case 1:
{
CountOne++;
break;
}
default:
{ printf("该文件有:%d个\n",Type);
CountMore++;
break;
}
}
UnmapViewOfFile(MapMem);
CloseHandle(FileHwnd);
CloseHandle(MapHwnd);
}
} while(FindNextFileA(Hwnd,&FileInfo));
}
printf("只有一个执行节的个数:%d\n",CountOne);
printf("有多个执行节的个数:%d\n",CountMore);
return 0;
}
bool _MapViewFile(char * FileName,HANDLE* FileHwnd,HANDLE* MapHwnd,PVOID* MapMem)
{
HANDLE THwnd,TMapHwnd;PVOID TMapMem;
THwnd=CreateFileA(FileInfo.cFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(THwnd!=INVALID_HANDLE_VALUE)
{
TMapHwnd=CreateFileMappingA(THwnd,NULL,PAGE_READONLY,0,0,NULL);
if(TMapHwnd!=NULL)
{
TMapMem=MapViewOfFile(TMapHwnd,FILE_MAP_READ,0,0,0);
if(TMapMem!=NULL)
{
*FileHwnd=THwnd;
*MapHwnd =TMapHwnd;
*MapMem =TMapMem;
return true;
}
CloseHandle(TMapHwnd);
}
CloseHandle(THwnd);
}
return false;
}
int _IsJustOneExecutionSeciton(HANDLE FileHwnd,PVOID MapMem)
{
ULONG SizeL,SizeH,NumSection,EntryAddr,SectionEnd,NumExe=0;
PIMAGE_DOS_HEADER pDos;
PIMAGE_NT_HEADERS pNt;
PIMAGE_SECTION_HEADER pSection;
SizeL=GetFileSize(FileHwnd,&SizeH);
if(SizeL>sizeof(IMAGE_DOS_HEADER))
pDos =(PIMAGE_DOS_HEADER)MapMem;
else
return 0;
if(pDos->e_magic!=IMAGE_DOS_SIGNATURE)
return 0;
if(SizeL>(pDos->e_lfanew+sizeof(IMAGE_NT_HEADERS)))
pNt =(PIMAGE_NT_HEADERS)((ULONG)MapMem+pDos->e_lfanew);
else
return 0;
if(pNt->Signature!=IMAGE_NT_SIGNATURE)
return 0;
pSection =(PIMAGE_SECTION_HEADER)((ULONG)pNt+sizeof(IMAGE_NT_HEADERS));
NumSection =pNt->FileHeader.NumberOfSections;
while(NumSection>0)
{
if((pSection->Characteristics & IMAGE_SCN_MEM_EXECUTE))
{
NumExe++;
}
pSection++;
NumSection--;
}
return NumExe;
}
执行情况如图:

虽然大部分都是一个执行节,结果发现有两个文件竟然大于了1个可执行节,这两个文件是什么呢?
就是这两位:

竟然有12个可执行节,不过学过驱动的同学可能到不惊讶,因为这两个文件是系统内核核心文件,这两个文件是运行Ring0下的。。不过,总体来说,在判断时这两个文件可以排除在外,这两个文件要坏了,你可能就要重装系统了。。呵呵。。。得出结论:判断是否多于1个执行节是可行的方法。。。
下一篇:
杀软行为分析五:微点对网络通信的拦截
|
※ ※ ※ 本文纯属【点饭的百度空间】个人意见,与【 微点交流论坛 】立场无关※ ※ ※
|
 你的微笑 is 微点的骄傲!
http://hi.baidu.com/new/micropoint |
 |
|
2010-1-14 18:45 |
|
zzz@zzz
注册用户
 
积分 111
发帖 111
注册 2010-1-4
|
#3
这位同学理解的还算精湛,如果超微考虑一下壳的概念和工作流程,这篇比较鲜明的对比又会变得模糊了。。。
|
※ ※ ※ 本文纯属【zzz@zzz】个人意见,与【 微点交流论坛 】立场无关※ ※ ※
|
 |
|
2010-1-14 22:19 |
|
点饭的百度空间
银牌会员
     
积分 2315
发帖 2236
注册 2007-11-30
|
|
2010-1-15 18:02 |
|
Legend
超级版主
        超级版主
积分 77171
发帖 70170
注册 2005-10-29
|
#5
请楼上让您同事将微点杀毒软件升级到最新版本测试,如果还有问题,麻烦他协助我们生成个蓝屏文件发给我们具体分析,谢谢。
具体的设置和操作如下:
1)设置生产蓝屏文件:
我的电脑(或计算机)-〉右键属性-〉高级-〉启动和故障恢复 -〉将"写入调试信息"改为“完全内存转储”,并取消勾选"系统失败"中的“自动重新启动” 。
2)在出现蓝屏时请等待蓝屏文件写入100%完成后重启,然后将c:\windows\MEMORY.DMP压缩发给我们,以便我们具体分析。
|
※文章所有权归【Legend】与【东方微点论坛】共同所有,转载请注明出处!※
|
 微点官方认证新浪微博:欢迎进入 微点新浪微博
微点技术支持邮箱: support@micropoint.com.cn
给Legend发短消息 |
 |
|
2010-1-15 18:19 |
|
点饭的百度空间
银牌会员
     
积分 2315
发帖 2236
注册 2007-11-30
|
|
2010-1-15 18:43 |
|
Legend
超级版主
        超级版主
积分 77171
发帖 70170
注册 2005-10-29
|
|
2010-1-15 19:39 |
|
|