zoukankan      html  css  js  c++  java
  • DLL注入(1): 静态修改IID

     静态修改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
    ",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
    ",pNotepad);
    
        if (pNotepad == NULL)
        {
            printf("[-] 加载PE文件失败! %s
    ",Img.GetErrorMsg(szErrMsg,1024));
            return FALSE;
        }
        
        //检查是否被感染过
        if (Img.m_pDosHeader->e_csum == INFECT_SIG)
        {
            printf("[-] 文件已经被感染过!
    ");
            return FALSE;
        }
        printf("[*] 当前导入表信息 VA = 0x%p Size = 0x%X
    ",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
    ",dwOldIIDCnt,dwOldIIDSize);
        printf("[*] dwNewIIDCnt = %d  Size = 0x%X
    ",dwNewIIDCnt,dwNewIIDSize);
        
        dwSizeNeed = dwNewIIDSize; //所需的大小是新导入表IID结构的大小
    
        pImpSecHeader = Img.LocateSectionByRVA(Img.m_pImpDataDir->VirtualAddress);
        printf("[*] 导入表所在节  %s  RawOffset = 0x%X Size = 0x%X
    ",
            pImpSecHeader->Name,
            pImpSecHeader->PointerToRawData,
            pImpSecHeader->SizeOfRawData);
        
        DWORD dwPaddingSize = Img.GetSectionPhysialPaddingSize(pImpSecHeader);
        printf("[*] 导入表节空隙大小 = 0x%X
    ",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
    ",dwSizeNeed);
        //dwPaddingSize = 0 ;//测试,强制添加新节
        if (dwPaddingSize >= dwSizeNeed)
        {
            printf("[*] 节空隙可以放下新的导入表,不需添加新节!
    ");
            dwVAToStoreNewIID = pImpSecHeader->VirtualAddress + Img.GetAlignedSize(pImpSecHeader->Misc.VirtualSize,sizeof(DWORD));
            pTargetSecHeader = pImpSecHeader;
        }
        else
        {
            printf("[-] 节空隙不能放下新的导入表,需要添加新节!
    ");
            //根据所需的空间大小添加一个新节
            pNewSecHeader = Img.AddNewSectionToFile(".Patch",dwSizeNeed);
            printf("[*] 新节添加完毕! VA = 0x%X  RawOffset = 0x%X  RawSize = 0x%X
    ",
                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结构保存完毕.
    ");
        //指向一个新添加的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子结构构造完毕.
    ");
        
        //计算结束位置
        PCHAR pEnd = (PCHAR)pImpName + sizeof(pImpName->Hint) + strlen((char*)pImpName->Name) + 1;
        //计算总占用的空间大小
        DWORD dwNewIIDEntrySizeUsed = (DWORD)pEnd - (DWORD)pOriginalFirstThunk;
        printf("[*] 新IID成员占用的空间大小 = 0x%X
    ",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填充完毕.
    ");
    
        //更新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头更新完毕.
    ");
    
        //写入文件
        printf("[*] 开始保存文件.
    ");
    
        //开始保存内存中的修改内容到文件中
        //先写入新的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
    ",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
    ",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
    ",dwFileOffset,dwIoCnt);
        printf("[*] 导入表感染完毕.
    ");
    
        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
    ",m_hModule);
            //先拷贝PE头到申请的内存
            memcpy(pMemory,m_HeaderData,m_pOptHeader->SizeOfHeaders);
            pMemory += GetAlignedSize(m_pOptHeader->SizeOfHeaders,m_pOptHeader->SectionAlignment);
            
            //printf("Section  VirtualAddress VirtualSize   PointertoRawData  RawSize
    ");
            //printf("=================================================================
    ");
            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
    ",pRelocBlock);
            do
            {//处理一个接一个的重定位块,最后一个重定位块以RAV=0结束
                //需要重定位的个数,是本块的大小减去块头的大小,结果是以DWORD表示的大小
                //而重定位数据是16位的,那就得除以2
                int numofReloc=(pRelocBlock->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION))/2;
                //printf("Reloc Data num=%d
    ",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
    ",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
    ",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
    ",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
    ",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

  • 相关阅读:
    个人作业——软件评测
    软件工程实践2019第五次作业
    18年今日头条笔试第一题题解:球迷(fans)
    游戏2.1版本
    游戏2.0版本 代码
    游戏2.0版本
    改进版游戏代码
    改进版游戏
    2017.1.13之审判日
    找朋友 的内存超限代码
  • 原文地址:https://www.cnblogs.com/jentleTao/p/12720243.html
Copyright © 2011-2022 走看看