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\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");
基本翻译
n.
abbr. 圣人,圣徒 (Saint) ;(尤指服装的尺码)小号的 (small) ;南方的 (South);西门子(电导单位)(siemens)