DLL注入(1): 进程创建初期添加垃圾DLL

 静态修改PE的IID增加DLL比较繁琐,而且直接操作十六进制数据容易出错。另一方面如果程序有检查是否被dll注入的机制也会报错,那么可以在创建进程初期就在内存里面,对目标的程序注入DLL,原理和在文件内操作都是一样的。

找一个64位的程序作为目标,看一下导入表结构:

然后目标是插入一个无用的DLL让程序崩溃。

打开目标文件:(不能用openfile)

HANDLE hFile = CreateFile(szImageFilePath,
      GENERIC_READ|GENERIC_WRITE,
      FILE_SHARE_READ,
      NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

增加一个IID数组:

    dwOldIIDSize = Img.m_pImpDataDir->Size ;
    dwOldIIDCnt = dwOldIIDSize / sizeof(IMAGE_IMPORT_DESCRIPTOR) ;
    dwNewIIDCnt = dwOldIIDCnt + 1;
    dwNewIIDSize = dwNewIIDCnt * sizeof(IMAGE_IMPORT_DESCRIPTOR) ;

计算新增的IID内部指针大小:

dwnewThunkDataSize = sizeof(ULONG_PTR)*4 + strlen(szDllName) + 1 + sizeof(WORD) + strlen(szDllExportFunName) + 1 ;
dwnewThunkDataSize = ALIGN_SIZE_UP(dwnewThunkDataSize,sizeof(ULONG)); //对齐

然后就是判断导入表大小能否装得下IID数组,是否需要新分配空间,以及分配新空间大小问题:

InfectImport.cpp:

#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include "Image.h"

#define INFECT_SIG ('PE')

BOOL AddSectionTest();
BOOL InfectImport(
    IN char *szImageFilePath, IN char *szDllPath, IN char *szDllExportFunName ); int main(int argc, char* argv[]) { InfectImport("S:\\HostProc64.exe","123.dll","NULL"); return 0; } BOOL InfectImport( IN char *szImageFilePath, IN char *szDllName, IN char *szDllExportFunName) { CImage Img; BOOL bResult = FALSE ; WORD i = 0 ; DWORD dwIoCnt = 0 ; char szErrMsg[1024]={0}; PIMAGE_SECTION_HEADER pImpSecHeader,pNewSecHeader = NULL,pTargetSecHeader = NULL; DWORD dwOldIIDCnt = 0 ,dwNewIIDCnt = 0 ; DWORD dwOldIIDSize = 0, dwNewIIDSize = 0 ; DWORD dwVAToStoreNewIID = 0 ; //新IID数组的存储位置 DWORD dwnewThunkDataSize = 0 ; //新IID项的ThunkData的存储位置 DWORD dwNewThunkDataVA = 0 ;//新IID项的ThunkData的存储位置 DWORD dwSizeNeed = 0 ; DWORD dwThunkDataOffsetByIID = 0 ; BOOL bUseNewSection = FALSE ; //是否使用了新节 BOOL bPlaceThunkDataToOldIID = TRUE ; //表明ThunkData存放的位置是不是在原来的IID位置,如果放不下,得找新位置  printf("[*] Path = %s\n",szImageFilePath); //以读写方式打开目标文件 HANDLE hFile = CreateFile(szImageFilePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //解析PE结构 PBYTE pNotepad = Img.LoadImage(hFile,FALSE,0,FALSE); printf("[*] pImageBase = 0x%p\n",pNotepad); if (pNotepad == NULL) { printf("[-] 加载PE文件失败! %s\n",Img.GetErrorMsg(szErrMsg,1024)); return FALSE; } //检查是否被感染过 if (Img.m_pDosHeader->e_csum == INFECT_SIG) { printf("[-] 文件已经被感染过!\n"); return FALSE; } printf("[*] 当前导入表信息 VA = 0x%p Size = 0x%X\n",Img.m_pImpDataDir->VirtualAddress,Img.m_pImpDataDir->Size); dwOldIIDSize = Img.m_pImpDataDir->Size ; dwOldIIDCnt = dwOldIIDSize / sizeof(IMAGE_IMPORT_DESCRIPTOR) ; dwNewIIDCnt = dwOldIIDCnt + 1; dwNewIIDSize = dwNewIIDCnt * sizeof(IMAGE_IMPORT_DESCRIPTOR) ; printf("[*] dwOldIIDCnt = %d Size = 0x%X\n",dwOldIIDCnt,dwOldIIDSize); printf("[*] dwNewIIDCnt = %d Size = 0x%X\n",dwNewIIDCnt,dwNewIIDSize); dwSizeNeed = dwNewIIDSize; //所需的大小是新导入表IID结构的大小  pImpSecHeader = Img.LocateSectionByRVA(Img.m_pImpDataDir->VirtualAddress); printf("[*] 导入表所在节 %s RawOffset = 0x%X Size = 0x%X\n", pImpSecHeader->Name, pImpSecHeader->PointerToRawData, pImpSecHeader->SizeOfRawData); DWORD dwPaddingSize = Img.GetSectionPhysialPaddingSize(pImpSecHeader); printf("[*] 导入表节空隙大小 = 0x%X\n",dwPaddingSize); //计算填充ThunkData需要的大小,它包括了OriginalFirstThunk、FirstThunk、IMPORT_BY_NAME,以及DllName dwnewThunkDataSize = sizeof(ULONG_PTR)*4 + strlen(szDllName) + 1 + sizeof(WORD) + strlen(szDllExportFunName) + 1 ; dwnewThunkDataSize = ALIGN_SIZE_UP(dwnewThunkDataSize,sizeof(ULONG)); //对齐 //判断原导入表位置能否写下新的ThunkData if (dwnewThunkDataSize > dwOldIIDSize) { //写不下,那么在寻找节隙时就要加上 //按ULONG_PTR对齐之后再添加ThunkData,虽然不按这个对齐也可以 dwThunkDataOffsetByIID = ALIGN_SIZE_UP(dwNewIIDSize,sizeof(ULONG_PTR)) ; dwSizeNeed = dwThunkDataOffsetByIID + dwnewThunkDataSize ; bPlaceThunkDataToOldIID = FALSE ; } printf("[*] 放置新导入表数据所需要的大小 = 0x%X\n",dwSizeNeed); //dwPaddingSize = 0 ;//测试,强制添加新节 if (dwPaddingSize >= dwSizeNeed) { printf("[*] 节空隙可以放下新的导入表,不需添加新节!\n"); dwVAToStoreNewIID = pImpSecHeader->VirtualAddress + Img.GetAlignedSize(pImpSecHeader->Misc.VirtualSize,sizeof(DWORD)); pTargetSecHeader = pImpSecHeader; } else { printf("[-] 节空隙不能放下新的导入表,需要添加新节!\n"); //根据所需的空间大小添加一个新节 pNewSecHeader = Img.AddNewSectionToFile(".Patch",dwSizeNeed); printf("[*] 新节添加完毕! VA = 0x%X RawOffset = 0x%X RawSize = 0x%X\n", pNewSecHeader->VirtualAddress,pNewSecHeader->PointerToRawData,pNewSecHeader->SizeOfRawData); dwVAToStoreNewIID = pNewSecHeader->VirtualAddress ; pTargetSecHeader = pNewSecHeader; bUseNewSection = TRUE; } //保存原导入表 PIMAGE_IMPORT_DESCRIPTOR pOldImpDesp = Img.m_pImportDesp; PIMAGE_IMPORT_DESCRIPTOR pBuildNewImpDesp = (PIMAGE_IMPORT_DESCRIPTOR)malloc(dwSizeNeed); ZeroMemory(pBuildNewImpDesp,dwSizeNeed); //保存原来的导入表部分到新的中  memcpy(pBuildNewImpDesp,pOldImpDesp,dwOldIIDSize); printf("[*] 原导入表IID结构保存完毕.\n"); //指向一个新添加的IID项,稍后填充 PIMAGE_IMPORT_DESCRIPTOR pNewImpEntry = pBuildNewImpDesp + dwOldIIDCnt - 1; //需要注意的是,ThunkData在32位和64位下的长度是不一样的,所以这里定义为自适应的ULONG_PTR PULONG_PTR pOriginalFirstThunk = NULL ; if (bPlaceThunkDataToOldIID) { //使用原IID的位置存放Thunk数据 pOriginalFirstThunk = (PULONG_PTR)(Img.m_hModule + Img.m_pImpDataDir->VirtualAddress); dwNewThunkDataVA = Img.m_pImpDataDir->VirtualAddress ; } else { //原IID的位置存放不下,使用新位置存放 pOriginalFirstThunk = (PULONG_PTR)((PBYTE)pBuildNewImpDesp + dwThunkDataOffsetByIID); dwNewThunkDataVA = dwVAToStoreNewIID + dwThunkDataOffsetByIID ; //在IID数据后面  } ZeroMemory(pOriginalFirstThunk,dwnewThunkDataSize); //留出两项内容,第一项稍后填充,第二项填0作为结束标记 PULONG_PTR pFirstThunk = pOriginalFirstThunk + 2 ; //留出两项内容,第一项稍后填充,第二项填0作为结束标记,之后作为Dll名称 PCHAR pDllName = (PCHAR)(pFirstThunk + 2); //保存dll名称  strcpy(pDllName,szDllName); SIZE_T DllNameLen = strlen(szDllName); pDllName[DllNameLen] = 0; //接下来作为一个PIMPORT_BY_NAME结构 PIMAGE_IMPORT_BY_NAME pImpName = (PIMAGE_IMPORT_BY_NAME)(pDllName + DllNameLen + 1); //填充它 pImpName->Hint = 0; strcpy((char*)pImpName->Name,szDllExportFunName); printf("[*] 新导入表IID子结构构造完毕.\n"); //计算结束位置 PCHAR pEnd = (PCHAR)pImpName + sizeof(pImpName->Hint) + strlen((char*)pImpName->Name) + 1; //计算总占用的空间大小 DWORD dwNewIIDEntrySizeUsed = (DWORD)pEnd - (DWORD)pOriginalFirstThunk; printf("[*] 新IID成员占用的空间大小 = 0x%X\n",dwNewIIDEntrySizeUsed); //返过来填充OriginalFirstThunk和FirstThunk //根据定义,OriginalFirst应指向IMAGE_IMPORT_BY_NAME结构的偏移 pOriginalFirstThunk[0] = dwNewThunkDataVA + ((PBYTE)pImpName - (PBYTE)pOriginalFirstThunk); pFirstThunk[0] = pOriginalFirstThunk[0]; //最后填充新的IID项,计算各项的RVA pNewImpEntry->OriginalFirstThunk = dwNewThunkDataVA; pNewImpEntry->Name = dwNewThunkDataVA + sizeof(ULONG_PTR)*4;//OriginalFirstThunk + FirstThunk的大小 pNewImpEntry->FirstThunk = dwNewThunkDataVA + sizeof(ULONG_PTR)*2; printf("[*] 新IID填充完毕.\n"); //更新PE头中的几个值 //新的导入表大小 Img.m_pImpDataDir->Size = dwNewIIDSize; //新的导入表IID的起始偏移 Img.m_pImpDataDir->VirtualAddress = dwVAToStoreNewIID; if (!bUseNewSection) { pImpSecHeader->Misc.VirtualSize += dwSizeNeed; } //如果ThunkData放在了原IID的位置,需要设置节为可写的 pImpSecHeader->Characteristics |= IMAGE_SCN_MEM_WRITE; //清空绑定输入表,强迫加载器重新加载IAT Img.m_pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; Img.m_pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; //设置感染标记 Img.m_pDosHeader->e_csum = INFECT_SIG; printf("[*] PE头更新完毕.\n"); //写入文件 printf("[*] 开始保存文件.\n"); //开始保存内存中的修改内容到文件中 //先写入新的PE头 DWORD dwFileOffset = 0; ULONG_PTR dwVAInMemory = 0 ; SetFilePointer(hFile,0,NULL,FILE_BEGIN); bResult = WriteFile(hFile,Img.m_hModule,Img.m_pOptHeader->SizeOfHeaders,&dwIoCnt,NULL); if (!bResult) { Img.FormatErrorMsg("[-] 写入文件失败!",GetLastError()); return FALSE; } printf("[*] PE头写入完毕. Offset = 0x%X Size = 0x%x\n",dwFileOffset,dwIoCnt); //写入新IID的子结构信息,位置在原导入表的开始处 dwVAInMemory = dwNewThunkDataVA ; dwFileOffset = Img.Rav2Raw(dwVAInMemory); SetFilePointer(hFile,dwFileOffset,NULL,FILE_BEGIN); bResult = WriteFile(hFile,pOriginalFirstThunk,dwNewIIDEntrySizeUsed,&dwIoCnt,NULL); if (!bResult) { Img.FormatErrorMsg("[-] 写入文件失败!",GetLastError()); return FALSE; } printf("[*] 新IID项的子结构写入完毕. Offset = 0x%X Size = 0x%x\n",dwFileOffset,dwIoCnt); //写入新的IID结构 dwVAInMemory = (ULONG_PTR)Img.m_pImpDataDir->VirtualAddress; dwFileOffset = Img.Rav2Raw(dwVAInMemory); SetFilePointer(hFile,dwFileOffset,NULL,FILE_BEGIN); bResult = WriteFile(hFile,pBuildNewImpDesp,dwNewIIDSize,&dwIoCnt,NULL); if (!bResult) { Img.FormatErrorMsg("[-] 写入文件失败!",GetLastError()); return FALSE; } printf("[*] 新导入表整体写入完毕. Offset = 0x%X Size = 0x%x\n",dwFileOffset,dwIoCnt); printf("[*] 导入表感染完毕.\n"); return TRUE; }

Image.h:

#if !defined(AFX_IMAGE_H__02D71CD1_E8A1_41B5_B185_A841A7F59658__INCLUDED_)
#define AFX_IMAGE_H__02D71CD1_E8A1_41B5_B185_A841A7F59658__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <windows.h>
#define PEHEADER_SIZE (0x1000)
#define ALIGN_SIZE_UP(Size,Alignment)  (((ULONG_PTR)(Size) + Alignment - 1) & ~(Alignment - 1))
#define FILED_OFFSET(EndAddr,StartAddr) ((ULONG)((ULONG_PTR)EndAddr - (ULONG_PTR)StartAddr))
class CImage  
{
public:
    DWORD m_dwPageSize;
    HANDLE m_hFile;
    HANDLE m_hProc;
    WORD m_SectionCnt;
    //以下这些PE结构指针,只有当加载的PE是在当前进程时,才指向真实的内存
    //如果要操作的PE是在其它进程中,那么以下指针全部指向内部保存的PE头数据
    PBYTE m_hModule;
    PIMAGE_DOS_HEADER m_pDosHeader;
    PIMAGE_NT_HEADERS m_pNtHeaders;
    PIMAGE_FILE_HEADER m_pFileHeader;
    PIMAGE_OPTIONAL_HEADER m_pOptHeader;
    PIMAGE_DATA_DIRECTORY m_pRelocTable;
    PIMAGE_SECTION_HEADER m_pSecHeader;
    PIMAGE_DATA_DIRECTORY m_pImpDataDir;
    PIMAGE_DATA_DIRECTORY m_pExpDataDir;
    PIMAGE_EXPORT_DIRECTORY m_pExportDir;
    PIMAGE_IMPORT_DESCRIPTOR m_pImportDesp;
    IMAGE_DATA_DIRECTORY m_OldImpDir;
    //PE头中的非指针类数据
    ULONG_PTR m_dwEntryPoint;
    DWORD m_TotalImageSize;
    ULONG_PTR m_ImageBase;
    BYTE m_HeaderData[0x1000];//保存一份PE头的数据内部使用
    DWORD Rav2Raw(DWORD VirtualAddr);
    DWORD GetTotalImageSize(DWORD Alignment);
    DWORD GetAlignedSize(DWORD theSize,DWORD Alignment);
    ULONG_PTR GetAlignedPointer(ULONG_PTR uPointer,DWORD Alignment);
    static DWORD _GetProcAddress(PBYTE pModule,char *szFuncName);
    PBYTE LoadImage(HANDLE hFile, BOOL bDoReloc = TRUE,ULONG_PTR RelocBase = 0,BOOL bDoImport = FALSE);
    PBYTE LoadImage(char *szPEPath,BOOL bDoReloc = TRUE,ULONG_PTR RelocBase = 0,BOOL bDoImport = FALSE);
    VOID FreePE();
    VOID InitializePEHeaders(PBYTE pBase);
    VOID ProcessRelocTable(ULONG_PTR RelocBase);
    BOOL ProcessImportTable();
    VOID AttachToMemory(PVOID pMemory);
    BOOL AttachToProcess(HANDLE hProc,PVOID ProcessImageBase);
    BOOL MakeFileHandleWritable();
    DWORD Raw2Rav(DWORD RawAddr);
    DWORD GetSectionPhysialPaddingSize(PIMAGE_SECTION_HEADER pSecHeader);
    DWORD GetSectionVirtualPaddingSize(PIMAGE_SECTION_HEADER pSecHeader);
    PIMAGE_SECTION_HEADER LocateSectionByRawOffset(DWORD dwRawOffset);
    PIMAGE_SECTION_HEADER LocateSectionByRVA(DWORD dwTargetAddr);
    PIMAGE_SECTION_HEADER AddNewSectionToFile(char *szSectionName,DWORD SectionSize);
    PIMAGE_SECTION_HEADER AddNewSectionToMemory(char *szSectionName,DWORD SectionSize);
    PIMAGE_SECTION_HEADER ExtraLastSectionSizeToFile(DWORD SectionAddSize);
    VOID FormatErrorMsg(char *szPrompt, DWORD ErrCode);
    LPSTR GetErrorMsg(char *szBuf,int BufSize);
    CImage();
    virtual ~CImage();
private:
    BOOL VerifyImage(PVOID pBase);
    BOOL SnapThunk(HMODULE hImpMode,char *szImpModeName,PBYTE ImageBase, PIMAGE_THUNK_DATA NameThunk, PIMAGE_THUNK_DATA AddrThunk);
    VOID Cleanup();
    char m_szErrorMsg[1024];
    char m_szPEPath[MAX_PATH];
};
#endif

Image.cpp:

#include "stdafx.h"
#include "Image.h"
#include <shlwapi.h>

#pragma comment(lib,"shlwapi.lib")
CImage::CImage()
{
    m_hFile = INVALID_HANDLE_VALUE;
    m_hModule = NULL;
    m_pDosHeader = NULL;
    m_pFileHeader = NULL ;
    m_pRelocTable = NULL;
    m_pSecHeader = NULL;
    m_pExportDir = NULL;
    m_pImportDesp = NULL;
    m_pOptHeader = NULL;

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    m_dwPageSize = sysinfo.dwPageSize;
}

CImage::~CImage()
{
    Cleanup();
}// Parameter: char * szPEPath , 待加载的PE模块的全路径
// Parameter: BOOL bDoReloc , 是否处理重定位
// Parameter: DWORD RelocBase , 重定位的基址,如果为0,则按实际加载位置重定位
// Parameter: BOOL bDoImport , 是否处理导入表
PBYTE CImage::LoadImage(HANDLE hFile, BOOL bDoReloc, ULONG_PTR RelocBase, BOOL bDoImport)
{
    WORD i=0;
    BYTE *pMemory=NULL;
    BYTE *MappedBase = NULL;
    PIMAGE_SECTION_HEADER pTmpSecHeader = NULL ;
    BOOL bResult = FALSE ;
    DWORD dwFileSize = 0 ; //一般PE文件大小不会超过4G
    DWORD dwIoCnt = 0 ;

    __try
    {
        
        m_hFile = hFile;
        //获取文件大小
        dwFileSize = GetFileSize(m_hFile,NULL);
        if (dwFileSize == 0)
        {
            lstrcpy(m_szErrorMsg,"文件大小为0!");
            __leave;
        }
        
        //读取PE头
        DWORD dwSizeToRead = (dwFileSize > PEHEADER_SIZE) ? PEHEADER_SIZE:dwFileSize;
        ZeroMemory(m_HeaderData,PEHEADER_SIZE);
        bResult = ReadFile(m_hFile,m_HeaderData,dwSizeToRead,&dwIoCnt,NULL);
        if (!bResult)
        {
            FormatErrorMsg("读取文件失败!",GetLastError());
            __leave;
        }
        
        if (!VerifyImage(m_HeaderData))
        {
            lstrcpy(m_szErrorMsg,"不是有效的PE映像!");
            __leave;
        }

        //解析各个PE头部结构
        InitializePEHeaders(m_HeaderData);

        pTmpSecHeader = m_pSecHeader;
        //开始申请内存,为避免麻烦,这里直接申请可读可写可执行的内存
        pMemory = m_hModule = (BYTE*)VirtualAlloc(NULL,m_TotalImageSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        if (m_hModule == NULL)
        {
            lstrcpy(m_szErrorMsg,"内存不足,申请内存失败!");
            __leave;
        }
        //printf("m_hModule = 0x%X\n",m_hModule);
        //先拷贝PE头到申请的内存
        memcpy(pMemory,m_HeaderData,m_pOptHeader->SizeOfHeaders);
        pMemory += GetAlignedSize(m_pOptHeader->SizeOfHeaders,m_pOptHeader->SectionAlignment);
        
        //printf("Section  VirtualAddress VirtualSize   PointertoRawData  RawSize\n");
        //printf("=================================================================\n");
        LARGE_INTEGER liFileOffset;
        for (i=0;i< m_SectionCnt;i++)
        {
            liFileOffset.QuadPart = pTmpSecHeader->PointerToRawData;
            bResult = SetFilePointerEx(m_hFile,liFileOffset,NULL,FILE_BEGIN);
            if (!bResult)
            {
                FormatErrorMsg("设置文件读写位置失败!",GetLastError());
                __leave;
            }
            
            //读取各个节
            bResult = ReadFile(m_hFile,pMemory,pTmpSecHeader->SizeOfRawData,&dwIoCnt,NULL);
            if (!bResult)
            {
                FormatErrorMsg("读取文件失败!",GetLastError());
                __leave;
            }
            pMemory += GetAlignedSize(pTmpSecHeader->Misc.VirtualSize,m_pOptHeader->SectionAlignment);
            pTmpSecHeader++;
        }
        
        //重新解析PE头
        InitializePEHeaders(m_hModule);
        
        //开始处理重定位数据
        if (bDoReloc)
        {
            //如果RelocBase为0,则按实际加载位置进行重定位
            ULONG_PTR BaseToReloc = (RelocBase == 0 )?(DWORD)m_hModule : RelocBase ;
            ProcessRelocTable(BaseToReloc);
        }
        
        //处理导入表
        if (bDoImport)
        {
            ProcessImportTable();
        }

        bResult = TRUE; //加载成功
    }
    __finally
    {
        if (!bResult)
        {
            if (m_hFile != INVALID_HANDLE_VALUE)
            {
                CloseHandle(m_hFile);
                m_hFile = INVALID_HANDLE_VALUE;
            }
        }
    }
    
    return m_hModule;
}

//以文件路径方式打开PE
PBYTE CImage::LoadImage(char *szPEPath, BOOL bDoReloc, ULONG_PTR RelocBase ,BOOL bDoImport)
{
    //保存PE路径
    lstrcpy(m_szPEPath,szPEPath);
    //以只读方式打开文件
    m_hFile = CreateFile(szPEPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if (m_hFile == INVALID_HANDLE_VALUE)
    {
        FormatErrorMsg("打开文件失败!",GetLastError());
        return NULL;
    }

    return LoadImage(m_hFile,bDoReloc,RelocBase,bDoImport);
}

VOID CImage::FreePE()
{
    VirtualFree(m_hModule,0,MEM_RELEASE);
    m_hModule = NULL;
}



DWORD CImage::GetAlignedSize(DWORD theSize, DWORD Alignment)
{
    DWORD dwAlignedVirtualSize=0;
    dwAlignedVirtualSize = ALIGN_SIZE_UP(theSize,Alignment);
    return dwAlignedVirtualSize;//返回对齐后的大小
}


ULONG_PTR CImage::GetAlignedPointer(ULONG_PTR uPointer, DWORD Alignment)
{
    DWORD dwAlignedAddress=0;
    dwAlignedAddress = ALIGN_SIZE_UP(uPointer,Alignment);
    return dwAlignedAddress;//返回对齐后的大小
}

DWORD CImage::_GetProcAddress(PBYTE pModule, char *szFuncName)
{
    //自己实现GetProcAddress
    DWORD retAddr=0;
    DWORD *namerav,*funrav;
    DWORD cnt=0;
    DWORD max,min,mid;
    WORD *nameOrdinal;
    WORD nIndex=0;
    int cmpresult=0;
    char *ModuleBase=(char*)pModule;
    char *szMidName = NULL ;
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS pNtHeader;
    PIMAGE_OPTIONAL_HEADER pOptHeader;
    PIMAGE_EXPORT_DIRECTORY pExportDir;

    if (ModuleBase == NULL)
    {
        return 0;
    }

    pDosHeader=(PIMAGE_DOS_HEADER)ModuleBase;
    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        return 0;
    }
    pNtHeader = (PIMAGE_NT_HEADERS)(ModuleBase+pDosHeader->e_lfanew);
    if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
    {
        return 0 ;
    }

    pOptHeader = &pNtHeader->OptionalHeader;
    pExportDir=(PIMAGE_EXPORT_DIRECTORY)(ModuleBase+pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    namerav=(DWORD*)(ModuleBase+pExportDir->AddressOfNames);
    funrav=(DWORD*)(ModuleBase+pExportDir->AddressOfFunctions);
    nameOrdinal=(WORD*)(ModuleBase+pExportDir->AddressOfNameOrdinals);

    if ((DWORD)szFuncName < 0x0000FFFF)
    {
        retAddr=(DWORD)(ModuleBase+funrav[(WORD)szFuncName]);
    }
    else
    {
        //二分法查找
        max = pExportDir->NumberOfNames ;
        min = 0;
        mid = (max+min)/2;
        while (min < max)
        {
            szMidName = ModuleBase+namerav[mid] ;
            cmpresult=strcmp(szFuncName,szMidName);
            if (cmpresult < 0)
            {
                //比中值小,则取中值-1为最大值
                max = mid -1 ;
            }
            else if (cmpresult > 0)
            {
                //比中值大,则取中值+1为最小值
                min = mid + 1;
            }
            else
            {
                break;
            }
            mid=(max+min)/2;
            
        }
        
        if (strcmp(szFuncName,ModuleBase+namerav[mid]) == 0)
        {
            nIndex=nameOrdinal[mid];
            retAddr=(DWORD)(ModuleBase+funrav[nIndex]);
        }
    }
    return retAddr;
}

DWORD CImage::GetTotalImageSize(DWORD Alignment)
{
    DWORD TotalSize=0;
    DWORD tmp=0;
    PIMAGE_SECTION_HEADER pTmpSecHeader = m_pSecHeader;
    TotalSize+=GetAlignedSize(m_pOptHeader->SizeOfHeaders,Alignment);
    for (WORD i=0;i< m_SectionCnt;i++)
    {
        tmp=GetAlignedSize(pTmpSecHeader->Misc.VirtualSize,Alignment);
        TotalSize+=tmp;
        pTmpSecHeader++;
    }
    return TotalSize;
}

DWORD CImage::Rav2Raw(DWORD VirtualAddr)
{
    DWORD RawAddr=0;
    if (VirtualAddr < m_pOptHeader->SizeOfHeaders)
    {
        RawAddr = VirtualAddr;
        return RawAddr;
    }
    PIMAGE_SECTION_HEADER pTmpSecHeader = LocateSectionByRVA(VirtualAddr);
    if (pTmpSecHeader != NULL)
    {
        RawAddr = VirtualAddr - pTmpSecHeader->VirtualAddress + pTmpSecHeader->PointerToRawData;
    }

    return RawAddr;
}

DWORD CImage::Raw2Rav(DWORD RawAddr)
{
    DWORD RavAddr=0;
    if (RawAddr < m_pOptHeader->SizeOfHeaders)
    {
        RavAddr = RawAddr;
        return RavAddr;
    }
    PIMAGE_SECTION_HEADER pTmpSecHeader = LocateSectionByRawOffset(RawAddr);
    if (pTmpSecHeader != NULL)
    {
        RavAddr = RawAddr - pTmpSecHeader->PointerToRawData + pTmpSecHeader->VirtualAddress;
    }
    
    return RavAddr;
}


VOID CImage::FormatErrorMsg(char *szPrompt, DWORD ErrCode)
{
    LPVOID lpMsgBuf;
    FormatMessage( 
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM | 
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        ErrCode,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR) &lpMsgBuf,
        0,
        NULL 
        );
    sprintf(m_szErrorMsg,"%s 错误代码:%d 原因:%s",szPrompt,ErrCode,(LPCTSTR)lpMsgBuf);
    LocalFree( lpMsgBuf );
}

VOID CImage::Cleanup()
{
    if (m_hFile != INVALID_HANDLE_VALUE)
    {
        CloseHandle(m_hFile);
        m_hFile = INVALID_HANDLE_VALUE ;
    }
    
    if (m_hModule != NULL)
    {
        FreePE();
    }
}

VOID CImage::InitializePEHeaders(PBYTE pBase)
{
    //解析各个PE头部结构
    m_hModule = pBase ;
    m_pDosHeader =(PIMAGE_DOS_HEADER)pBase;
    m_pNtHeaders = (PIMAGE_NT_HEADERS)(pBase + m_pDosHeader->e_lfanew);
    m_pFileHeader = &m_pNtHeaders->FileHeader;
    m_SectionCnt = m_pFileHeader->NumberOfSections;
    m_pOptHeader = &m_pNtHeaders->OptionalHeader;
    m_pRelocTable = &(m_pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]);
    m_pSecHeader = (PIMAGE_SECTION_HEADER)((BYTE*)m_pOptHeader+sizeof(IMAGE_OPTIONAL_HEADER));
    m_dwEntryPoint = m_pOptHeader->AddressOfEntryPoint;
    m_TotalImageSize = m_pOptHeader->SizeOfImage ;
    m_ImageBase = (ULONG_PTR)m_pOptHeader->ImageBase ;

    //导入表
    m_pImpDataDir = &m_pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    //因为导入表可能会被修改,所以先保存旧的导入表数据
    m_OldImpDir.VirtualAddress = m_pImpDataDir->VirtualAddress;
    m_OldImpDir.Size = m_pImpDataDir->Size;
    if (m_pImpDataDir->VirtualAddress != NULL)
    {
        m_pImportDesp = (PIMAGE_IMPORT_DESCRIPTOR)(pBase + m_pImpDataDir->VirtualAddress);
    }

    //导出表
    m_pExpDataDir = &m_pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    if (m_pExpDataDir->VirtualAddress != NULL)
    {
        m_pExportDir = (PIMAGE_EXPORT_DIRECTORY)(pBase + m_pExpDataDir->VirtualAddress);
    }
    
    
    
}

VOID CImage::ProcessRelocTable(ULONG_PTR RelocBase)
{
    WORD i = 0 ;
    PIMAGE_BASE_RELOCATION pRelocBlock = NULL ;
    if (m_pRelocTable->VirtualAddress != NULL)
    {
        pRelocBlock=(PIMAGE_BASE_RELOCATION)(m_hModule + m_pRelocTable->VirtualAddress);
        //printf("After Loaded,Reloc Table=0x%08X\n",pRelocBlock);
        do
        {//处理一个接一个的重定位块,最后一个重定位块以RAV=0结束
            //需要重定位的个数,是本块的大小减去块头的大小,结果是以DWORD表示的大小
            //而重定位数据是16位的,那就得除以2
            int numofReloc=(pRelocBlock->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION))/2;
            //printf("Reloc Data num=%d\n",numofReloc);
            //重定位数据是16位的
            WORD offset=0;
            WORD *pRelocData=(WORD*)((BYTE*)pRelocBlock + sizeof(IMAGE_BASE_RELOCATION));
            for (i=0;i<numofReloc;i++)//循环,或直接判断*pData是否为0也可以作为结束标记
            {
                ULONG_PTR *RelocAddress=0;//需要重定位的地址
#ifdef _WIN64
                WORD RelocFlag = IMAGE_REL_BASED_DIR64 ;
#else
                WORD RelocFlag = IMAGE_REL_BASED_HIGHLOW ;
#endif
                //IMAGE_REL_BASED_DIR64
                //重定位的高4位是重定位类型,
                if (((*pRelocData)>>12) == RelocFlag)//判断重定位类型是否为IMAGE_REL_BASED_HIGHLOW,x86
                {
                    //计算需要进行重定位的地址
                    //重定位数据的低12位再加上本重定位块头的RAV即真正需要重定位的数据的RAV
                    offset=(*pRelocData)&0xFFF;//小偏移
                    RelocAddress=(ULONG_PTR*)(m_hModule+pRelocBlock->VirtualAddress+offset);
                    //对需要重定位的数据进行修正
                    //修正方法:减去IMAGE_OPTINAL_HEADER中的基址,再加上新的基址即可
                    *RelocAddress=*RelocAddress - m_pOptHeader->ImageBase + RelocBase;
                }
                pRelocData++;
                
            }
            //指向下一个重定位块
            pRelocBlock=(PIMAGE_BASE_RELOCATION)((char*)pRelocBlock+pRelocBlock->SizeOfBlock);
            
        }while (pRelocBlock->VirtualAddress);
    }
}

BOOL CImage::ProcessImportTable()
{
    BOOL bResult = TRUE ;
    char szPreDirectory[MAX_PATH]={0};
    char szCurDirectory[MAX_PATH]={0};
    char szPrompt[256]={0};
    PIMAGE_IMPORT_DESCRIPTOR  pImportDescriptor = m_pImportDesp;
    PIMAGE_THUNK_DATA         NameThunk = NULL , AddrThunk = NULL;
    PIMAGE_IMPORT_BY_NAME      pImpName = NULL ;
    HMODULE hMod = NULL ;
    char *szImpModName = NULL ;

    if (pImportDescriptor == NULL)
    {
        //无导入表,不需要处理
        return TRUE;
    }

    //更改当前路径,否则加载某些第三方dll时将找不到模块
    GetCurrentDirectory(MAX_PATH,szPreDirectory);
    lstrcpy(szCurDirectory,m_szPEPath);
    PathRemoveFileSpec(szCurDirectory);
    SetCurrentDirectory(szCurDirectory);
    while (pImportDescriptor->Name && pImportDescriptor->OriginalFirstThunk)
    {
        szImpModName = (char*)m_hModule + pImportDescriptor->Name ;
        hMod = LoadLibrary(szImpModName);
        if (hMod == NULL)
        {
            sprintf(szPrompt,"加载导入表模块 %s 失败!",szImpModName);
            FormatErrorMsg(szImpModName,GetLastError());
            return FALSE;
        }
        
        //printf("处理导入表模块 : %s\n",szImpModName);
        NameThunk = (PIMAGE_THUNK_DATA)(m_hModule + (ULONG)pImportDescriptor->OriginalFirstThunk);
        AddrThunk = (PIMAGE_THUNK_DATA)(m_hModule + (ULONG)pImportDescriptor->FirstThunk);
        
        while (NameThunk->u1.AddressOfData)
        {
            bResult = SnapThunk (hMod,szImpModName,m_hModule,NameThunk,AddrThunk);
            if (!bResult)
            {
                bResult = FALSE ;
                break;
            }
            NameThunk++;
            AddrThunk++;
        }
        
        if (!bResult)
        {
            break;
        }
        pImportDescriptor++;
    }
    
    SetCurrentDirectory(szPreDirectory);
    return bResult;
}

BOOL CImage::SnapThunk(HMODULE hImpMode,char *szImpModeName,PBYTE ImageBase, PIMAGE_THUNK_DATA NameThunk, PIMAGE_THUNK_DATA AddrThunk)
{
    BOOL bResult = FALSE ;
    PIMAGE_IMPORT_BY_NAME      pImpName = NULL ;
    DWORD dwFunAddr = 0 ;
    ULONG Ordinal = 0 ;

    if (NameThunk->u1.AddressOfData & IMAGE_ORDINAL_FLAG32)
    {
        Ordinal = IMAGE_ORDINAL(NameThunk->u1.Ordinal);
        dwFunAddr = (DWORD)GetProcAddress(hImpMode,(LPCSTR)Ordinal);
        //printf("0x%08X 按序号导入 : %d\n",dwFunAddr,Ordinal);
        if (dwFunAddr == 0)
        {
            sprintf(m_szErrorMsg,"无法在导入模块%s中定位导入函数:%d (序号)",szImpModeName,Ordinal);
        }
    }
    else
    {
        pImpName = (PIMAGE_IMPORT_BY_NAME)(m_hModule + (ULONG)NameThunk->u1.AddressOfData);
        dwFunAddr = (DWORD)GetProcAddress(hImpMode,(LPCSTR)pImpName->Name);
        //printf("0x%08X 按名称导入 : %s\n",dwFunAddr,pImpName->Name);
        if (dwFunAddr == 0)
        {
            sprintf(m_szErrorMsg,"无法在导入模块%s中定位导入函数:%s ",szImpModeName,pImpName->Name);
        }
    }

    if (dwFunAddr != 0)
    {
        AddrThunk->u1.Function = dwFunAddr;
        bResult = TRUE;
    }

    return bResult;
}

//根据PE文件头,简单判断PE文件的有效性
BOOL CImage::VerifyImage(PVOID pBase)
{
    //解析各个PE头部结构
    m_pDosHeader =(PIMAGE_DOS_HEADER)pBase;
    if (m_pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        return FALSE;
    }
    m_pNtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)pBase + m_pDosHeader->e_lfanew);
    if (m_pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
    {
        return FALSE;
    }
    
    return TRUE;
}

LPSTR CImage::GetErrorMsg(char *szBuf, int BufSize)
{
    int len = lstrlen(m_szErrorMsg);
    if (len <= BufSize )
    {
        lstrcpy(szBuf,m_szErrorMsg);
        return szBuf;
    }
    return NULL;
}

//根据相对虚拟地址查找所在的节
PIMAGE_SECTION_HEADER CImage::LocateSectionByRVA(DWORD dwRVA)
{
    WORD i = 0;
    PIMAGE_SECTION_HEADER pTemp = m_pSecHeader;
    for (i=0;i<m_SectionCnt;i++)
    {
        if (pTemp->VirtualAddress <= dwRVA
            && dwRVA <(pTemp->VirtualAddress + pTemp->Misc.VirtualSize))
        {
            return pTemp;
        }
        pTemp++;
    }
    return NULL;
}

//根据文件偏移确定所在的节
PIMAGE_SECTION_HEADER CImage::LocateSectionByRawOffset(DWORD dwRawOffset)
{
    WORD i = 0;
    PIMAGE_SECTION_HEADER pTemp = m_pSecHeader;
    for (i=0;i<m_SectionCnt;i++)
    {
        if (pTemp->PointerToRawData <= dwRawOffset
            && dwRawOffset <(pTemp->PointerToRawData + pTemp->SizeOfRawData))
        {
            return pTemp;
        }
        pTemp++;
    }
    return NULL;
}

//计算某个节按虚拟地址对齐后的空隙大小
DWORD CImage::GetSectionVirtualPaddingSize(PIMAGE_SECTION_HEADER pSecHeader)
{
    DWORD AlignedSize = GetAlignedSize(pSecHeader->Misc.VirtualSize,m_pOptHeader->SectionAlignment);
    return AlignedSize - pSecHeader->Misc.VirtualSize;
}

//计算某个节按虚拟地址对齐后的空隙大小
//VirtualSize和RawSize不确定哪个比较大
DWORD CImage::GetSectionPhysialPaddingSize(PIMAGE_SECTION_HEADER pSecHeader)
{
    DWORD dwPaddingSize = 0 ;
    if (pSecHeader->Misc.VirtualSize < pSecHeader->SizeOfRawData)
    {
        //节的内存大小小于文件大小
        /*
        .text name
        7748 virtual size
        1000 virtual address
        7800 size of raw data
        */
        dwPaddingSize = pSecHeader->SizeOfRawData - pSecHeader->Misc.VirtualSize ;
    }
    else
    {
        //节的内存大小大于等于文件中的大小,则认为不存在空隙
        dwPaddingSize = 0 ;

    }
    return dwPaddingSize;
}

//默认情况下是以只读方式打开目标文件的,必要时转换为可写的
BOOL CImage::MakeFileHandleWritable()
{
    BOOL bResult = FALSE;
    HANDLE hNew = INVALID_HANDLE_VALUE;
    HANDLE hProc = OpenProcess(PROCESS_DUP_HANDLE,FALSE,GetCurrentProcessId());
    if (hProc == NULL)
    {
        return FALSE;
    }
    bResult = DuplicateHandle(
        hProc,
        m_hFile,
        hProc,
        &hNew,
        GENERIC_READ,
        FALSE,
        0
        );

    if (bResult)
    {
        CloseHandle(m_hFile);//关闭之前的Handle
        m_hFile = hNew;
    }
    else
    {
        FormatErrorMsg("更改句柄权限失败!",GetLastError());
    }
    
    CloseHandle(hProc);
    return bResult;
}

//解析当前内存中的PE结构
VOID CImage::AttachToMemory(PVOID pMemory)
{
    if (pMemory != NULL)
    {
        InitializePEHeaders((PBYTE)pMemory);
    }
}

//解析其它进程中的PE结构
BOOL CImage::AttachToProcess(HANDLE hProc ,PVOID ProcessImageBase)
{
    BOOL bResult = FALSE ;
    SIZE_T dwIoCnt = 0;
    m_hProc = hProc;
    m_ImageBase = (ULONG_PTR)ProcessImageBase;
    bResult = ReadProcessMemory(m_hProc,(LPVOID)m_ImageBase,m_HeaderData,0x1000,&dwIoCnt);
    if (!bResult)
    {
        FormatErrorMsg("ReadProcessMemory失败!",GetLastError());
        return FALSE;
    }

    //初始化PE结构
    InitializePEHeaders(m_HeaderData);
    return bResult;
}

//在文件中添加一个新节并返回新节的数据
PIMAGE_SECTION_HEADER CImage::AddNewSectionToFile(char *szSectionName, DWORD SectionSize)
{
    PIMAGE_SECTION_HEADER pNewSecHeader = m_pSecHeader + m_SectionCnt ;
    PIMAGE_SECTION_HEADER pLastSecHeader = m_pSecHeader + m_SectionCnt  - 1;
    DWORD dwSectionVA,dwSectionRawOffset,dwSectionSize;
    LARGE_INTEGER liFileOffset;
    BOOL bResult = FALSE ;
    DWORD dwIoCnt = 0 ;
    
    //计算新节的起始虚拟内存偏移
    dwSectionVA = pLastSecHeader->VirtualAddress + GetAlignedSize(pLastSecHeader->Misc.VirtualSize,m_pOptHeader->SectionAlignment);
    //计算新节的物理起始偏移
    dwSectionRawOffset = pLastSecHeader->PointerToRawData + GetAlignedSize(pLastSecHeader->SizeOfRawData,m_pOptHeader->FileAlignment);
    //计算新节的大小,按文件对齐粒度对齐
    dwSectionSize = GetAlignedSize(SectionSize,m_pOptHeader->FileAlignment);
    
    //设置文件指针位置
    liFileOffset.QuadPart = dwSectionRawOffset + dwSectionSize;
    bResult = SetFilePointerEx(m_hFile,liFileOffset,NULL,FILE_BEGIN);
    if (!bResult)
    {
        FormatErrorMsg("添加新节时设置文件指针错误!",GetLastError());
        return NULL;
        
    }

    bResult = SetEndOfFile(m_hFile);
    if (!bResult)
    {
        FormatErrorMsg("添加新节时设置文件结束位置错误!",GetLastError());
        return NULL;
        
    }
    
    //填充SectionHeader
    ZeroMemory(pNewSecHeader,sizeof(IMAGE_SECTION_HEADER));
    strncpy((char*)pNewSecHeader->Name,szSectionName,8);
    pNewSecHeader->Misc.VirtualSize = dwSectionSize;
    pNewSecHeader->VirtualAddress = dwSectionVA;
    pNewSecHeader->PointerToRawData = dwSectionRawOffset ;
    pNewSecHeader->SizeOfRawData = dwSectionSize;
    pNewSecHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE;
    
    //更新PE头中的节个数
    m_pFileHeader->NumberOfSections += 1;
    m_SectionCnt++ ;
    //更新PE头中的总映像大小
    m_pOptHeader->SizeOfImage += dwSectionSize;

    //保存PE头到文件中
    liFileOffset.QuadPart = 0;
    bResult = SetFilePointerEx(m_hFile,liFileOffset,NULL,FILE_BEGIN);
    if (!bResult)
    {
        FormatErrorMsg("添加新节保存PE时设置文件指针错误!",GetLastError());
        return NULL;
        
    }

    bResult = WriteFile(m_hFile,m_hModule,m_pOptHeader->SizeOfHeaders,&dwIoCnt,NULL);
    if (!bResult)
    {
        FormatErrorMsg("添加新节保存PE时写入文件错误!",GetLastError());
        return NULL;
        
    }
    
    FlushFileBuffers(m_hFile);
    return pNewSecHeader;
}

//在内存中添加一个新节并返回新节的数据
PIMAGE_SECTION_HEADER CImage::AddNewSectionToMemory(char *szSectionName, DWORD SectionSize)
{
    PIMAGE_SECTION_HEADER pNewSecHeader = m_pSecHeader + m_SectionCnt ;
    PIMAGE_SECTION_HEADER pLastSecHeader = m_pSecHeader + m_SectionCnt  - 1;
    DWORD dwSectionVA,dwSectionRawOffset,dwSectionSize;
    BOOL bResult = FALSE ;
    SIZE_T dwIoCnt = 0 ;
    HANDLE hProc = (m_hProc == NULL )? GetCurrentProcess():m_hProc;
    ULONG_PTR  HighestUserAddress = 0;
    BYTE PEHeader[0x1000]={0};
    
    //获取基本的地址空间信息
    SYSTEM_INFO sysinfo;
    ZeroMemory(&sysinfo,sizeof(SYSTEM_INFO));
    GetSystemInfo(&sysinfo);
    HighestUserAddress = (ULONG_PTR)sysinfo.lpMaximumApplicationAddress;
    
    //计算新节的起始虚拟内存偏移
    dwSectionVA = pLastSecHeader->VirtualAddress + ALIGN_SIZE_UP(pLastSecHeader->Misc.VirtualSize,m_pOptHeader->SectionAlignment);
    //计算新节的物理起始偏移
    dwSectionRawOffset = pLastSecHeader->PointerToRawData + GetAlignedSize(pLastSecHeader->SizeOfRawData,m_pOptHeader->FileAlignment);
    //计算新节的大小,按文件对齐粒度对齐
    dwSectionSize = GetAlignedSize(SectionSize,m_pOptHeader->FileAlignment);
    
    ULONG_PTR dwNewSectionStartAddr = m_ImageBase + dwSectionVA;
    ULONG_PTR AddressToAlloc = GetAlignedPointer(dwNewSectionStartAddr,sysinfo.dwAllocationGranularity);
    PBYTE AllocatedMem = NULL ;
    //从PE最后一个节开始,向后申请内存
    for (AddressToAlloc = dwNewSectionStartAddr; AddressToAlloc < HighestUserAddress;AddressToAlloc += sysinfo.dwAllocationGranularity)
    {
        //申请地址
        AllocatedMem = (PBYTE)VirtualAllocEx(hProc,(PVOID)AddressToAlloc,dwSectionSize,MEM_RESERVE |MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        if (AllocatedMem != NULL)
        {
            break;
        }
    }
    
    if (AllocatedMem == NULL)
    {
        FormatErrorMsg("添加新节时在目标进程中申请内存失败!",GetLastError());
        return NULL;
    }
    //printf("[*] NewSection Address = 0x%p Size = 0x%X\n",AllocatedMem,dwSectionSize);
    dwSectionVA = FILED_OFFSET(AllocatedMem,m_ImageBase);

    //填充SectionHeader
    ZeroMemory(pNewSecHeader,sizeof(IMAGE_SECTION_HEADER));
    strncpy((char*)pNewSecHeader->Name,szSectionName,8);
    pNewSecHeader->Misc.VirtualSize = dwSectionSize;
    pNewSecHeader->VirtualAddress = dwSectionVA;
    pNewSecHeader->PointerToRawData = dwSectionRawOffset ;
    pNewSecHeader->SizeOfRawData = dwSectionSize;
    pNewSecHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE;
    
    //更新PE头中的节个数
    m_pFileHeader->NumberOfSections += 1;
    m_SectionCnt++ ;
    //更新PE头中的总映像大小
    m_pOptHeader->SizeOfImage += dwSectionSize;
    
    
    //更新目标进程的PE头
    DWORD dwOldProtect = 0 ;
    bResult = VirtualProtectEx(hProc,(LPVOID)m_ImageBase,m_pOptHeader->SizeOfHeaders,PAGE_READWRITE,&dwOldProtect);
    if (!bResult)
    {
        FormatErrorMsg("修改目标进程内存属性时失败!",GetLastError());
        return NULL;
    }
    
    bResult = WriteProcessMemory(hProc,(LPVOID)m_ImageBase,m_HeaderData,m_pOptHeader->SizeOfHeaders,&dwIoCnt);
    if (!bResult)
    {
        FormatErrorMsg("向目标进程写入PE头数据时错误!",GetLastError());
        return NULL;
        
    }

    return pNewSecHeader;
}

PIMAGE_SECTION_HEADER CImage::ExtraLastSectionSizeToFile(DWORD SectionAddSize)
{
    PIMAGE_SECTION_HEADER pLastSecHeader = m_pSecHeader + m_SectionCnt  - 1;
    DWORD dwSectionNewVirtualSize,dwSectionNewRawOffset,dwSectionNewRawSize;
    DWORD dwOldSectionVirtualSize = 0 ;
    LARGE_INTEGER liFileOffset;
    BOOL bResult = FALSE ;
    DWORD dwIoCnt = 0 ;
    
    //在扩展最后一个节的情况下,需要更改最后一个节的RawSize和VirtualSize,起始偏移均不变
    //计算新节的物理大小,按文件对齐粒度对齐
    dwSectionNewRawOffset = pLastSecHeader->PointerToRawData ;
    dwSectionNewRawSize = GetAlignedSize(pLastSecHeader->SizeOfRawData + SectionAddSize,m_pOptHeader->FileAlignment);
    dwOldSectionVirtualSize = dwSectionNewVirtualSize =  GetAlignedSize(pLastSecHeader->Misc.VirtualSize , m_pOptHeader->SectionAlignment);
    //计处新节的VirtualSize大小,仅当内存大小小于文件大小时,需要增加
    if (pLastSecHeader->Misc.VirtualSize < dwSectionNewRawSize)
    {
        dwSectionNewVirtualSize += SectionAddSize;
    }
    
    //设置文件指针位置
    liFileOffset.QuadPart = dwSectionNewRawOffset +  pLastSecHeader->SizeOfRawData + SectionAddSize;
    bResult = SetFilePointerEx(m_hFile,liFileOffset,NULL,FILE_BEGIN);
    if (!bResult)
    {
        FormatErrorMsg("添加新节时设置文件指针错误!",GetLastError());
        return NULL;
        
    }
    
    bResult = SetEndOfFile(m_hFile);
    if (!bResult)
    {
        FormatErrorMsg("添加新节时设置文件结束位置错误!",GetLastError());
        return NULL;
        
    }
    
    //填充SectionHeader
    pLastSecHeader->Misc.VirtualSize = dwSectionNewVirtualSize;
    pLastSecHeader->SizeOfRawData = dwSectionNewRawSize;
    pLastSecHeader->Characteristics |=  IMAGE_SCN_MEM_READ;
    
    //更新PE头中的总映像大小
    m_pOptHeader->SizeOfImage = m_pOptHeader->SizeOfImage - dwOldSectionVirtualSize 
        + GetAlignedSize(pLastSecHeader->Misc.VirtualSize,m_pOptHeader->SectionAlignment);
    
    //保存PE头到文件中
    liFileOffset.QuadPart = 0;
    bResult = SetFilePointerEx(m_hFile,liFileOffset,NULL,FILE_BEGIN);
    if (!bResult)
    {
        FormatErrorMsg("添加新节保存PE时设置文件指针错误!",GetLastError());
        return NULL;
        
    }
    
    bResult = WriteFile(m_hFile,m_hModule,m_pOptHeader->SizeOfHeaders,&dwIoCnt,NULL);
    if (!bResult)
    {
        FormatErrorMsg("添加新节保存PE时写入文件错误!",GetLastError());
        return NULL;  
    }
    FlushFileBuffers(m_hFile);
    return pLastSecHeader;
}

 测试结果:

程序:

InfectImport("S:\\HostProc64.exe","123.dll","NULL");

 

s   [es]   详细 X
基本翻译
n. 
abbr. 圣人,圣徒 (Saint) ;(尤指服装的尺码)小号的 (small) ;南方的 (South);西门子(电导单位)(siemens)
网络释义
S Doradus: 剑鱼座S
Airbus S: 空中客车公司
s Bootsrennen: 赛艇比赛
X   [eks]   X&type=1 详细 X

猜你喜欢

转载自www.cnblogs.com/jentleTao/p/12720243.html
今日推荐