导入表注入:修改游戏EXE依赖dll树上找个结点,程序运行前加载,加载修改回导入表。
优:游戏依赖库多,不易用完整性来查验,同时客户端版本不同,更易躲过检测
缺点:文件操作明显,易被ProcessMonitor检测到
//BeModeImportTableExe.exe
void main(void)
{
int i = 0;
while(true)
{
__asm{
mov eax,i
inc eax
}
}
}
//修改导入表的exe
#include <Windows.h>
DWORD PEAlign(DWORD dwTarNum,DWORD dwAlignTo)
{
return(((dwTarNum+dwAlignTo-1)/dwAlignTo)*dwAlignTo);
}
//
//增加导入表项
//
BOOL AddNewSection(LPCTSTR lpStrModulePath, DWORD dwNewSectionSize)
{
bool bSuccess = false;
LPVOID lpMemModule = NULL;
LPBYTE lpData = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE, hFileMapping = INVALID_HANDLE_VALUE;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_SECTION_HEADER pNewSection = NULL, pLastSection = NULL;
OutputDebugString("[!] AddNewSection Enter!\n");
//TODO:可能还涉及关闭windows文件保护
__try
{
//pe文件映射到内存
hFile = CreateFile(
lpStrModulePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if ( INVALID_HANDLE_VALUE == hFile )
{
OutputDebugString("[-] AddNewSection CreateFile fail!\n");
goto _EXIT_;
}
DWORD dwFileSize = GetFileSize(hFile, NULL);
hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE/* | SEC_IMAGE*/, 0, dwFileSize, "WINSUN_MAPPING_FILE");
if ( NULL == hFileMapping )
{
OutputDebugString("[-] AddNewSection CreateFileMapping fail!\n");
goto _EXIT_;
}
lpMemModule = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, dwFileSize);
if ( NULL == lpMemModule )
{
OutputDebugString("[-] AddNewSection MapViewOfFile fail!\n");
goto _EXIT_;
}
lpData = (LPBYTE)lpMemModule;
//判断是否是PE文件
if (((PIMAGE_DOS_HEADER)lpData)->e_magic != IMAGE_DOS_SIGNATURE )
{
OutputDebugString("[-] AddNewSection PE Header MZ error!\n");
goto _EXIT_;
}
pNtHeader = (PIMAGE_NT_HEADERS)(lpData + ((PIMAGE_DOS_HEADER)(lpData))->e_lfanew);
if ( pNtHeader->Signature != IMAGE_NT_SIGNATURE )
{
OutputDebugString("[-] AddNewSection PE Header PE error!\n");
goto _EXIT_;
}
//判断是否可以增加一个新节
if ( ((pNtHeader->FileHeader.NumberOfSections + 1) * sizeof(IMAGE_SECTION_HEADER)) > (pNtHeader->OptionalHeader.SizeOfHeaders) )
{
OutputDebugString("[-] AddNewSection cannot add a new section!\n");
goto _EXIT_;
}
pNewSection = (PIMAGE_SECTION_HEADER)(pNtHeader+1) + pNtHeader->FileHeader.NumberOfSections;
pLastSection = pNewSection - 1;
DWORD rsize,vsize,roffset,voffset;
//对齐偏移和RVA
rsize=PEAlign(dwNewSectionSize,
pNtHeader->OptionalHeader.FileAlignment);
roffset=PEAlign(pLastSection->PointerToRawData+pLastSection->SizeOfRawData,
pNtHeader->OptionalHeader.FileAlignment);
vsize=PEAlign(dwNewSectionSize,
pNtHeader->OptionalHeader.SectionAlignment);
voffset=PEAlign(pLastSection->VirtualAddress+pLastSection->Misc.VirtualSize,
pNtHeader->OptionalHeader.SectionAlignment);
//填充新节表
memcpy(pNewSection->Name, "WINSUN", strlen("WINSUN"));
pNewSection->VirtualAddress = voffset;
pNewSection->PointerToRawData = roffset;
pNewSection->Misc.VirtualSize = vsize;
pNewSection->SizeOfRawData = rsize;
pNewSection->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
//修改IMAGE_NT_HEADERS,增加新节表
pNtHeader->FileHeader.NumberOfSections++;
pNtHeader->OptionalHeader.SizeOfImage += vsize;
pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
//增加新节到文件尾部
DWORD dwWriteBytes;
SetFilePointer(hFile,0,0,FILE_END);
PBYTE pbNewSectionContent = new BYTE[rsize];
ZeroMemory(pbNewSectionContent, rsize);
bSuccess = WriteFile(hFile, pbNewSectionContent, rsize, &dwWriteBytes, NULL);
if (!bSuccess)
{
MessageBox(NULL,"新增节失败","error",MB_OK);
goto _EXIT_;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
OutputDebugString("[-] AddImportTableItem Exception!\n");
return false;
}
OutputDebugString("[!] AddNewSection Exit!\n");
bSuccess = true;
_EXIT_:
if ( hFile )
{
CloseHandle(hFile);
}
if ( lpMemModule)
{
UnmapViewOfFile(lpMemModule);
}
if ( hFileMapping )
{
CloseHandle(hFileMapping);
}
return true;
}
//
PIMAGE_SECTION_HEADER ImageRVA2Section(PIMAGE_NT_HEADERS pImgNTHeader, DWORD dwRVA)
{
int i;
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(pImgNTHeader+1);
for(i=0;i<pImgNTHeader->FileHeader.NumberOfSections;i++)
{
if((dwRVA>=(pSectionHeader+i)->VirtualAddress) && (dwRVA<=((pSectionHeader+i)->VirtualAddress+(pSectionHeader+i)->SizeOfRawData)))
{
return ((PIMAGE_SECTION_HEADER)(pSectionHeader+i));
}
}
return(NULL);
}
//
// calulates the Offset from a RVA
// Base - base of the MMF
// dwRVA - the RVA to calculate
// returns 0 if an error occurred else the calculated Offset will be returned
DWORD RVA2Offset(PIMAGE_NT_HEADERS pImgNTHeader, DWORD dwRVA)
{
DWORD _offset;
PIMAGE_SECTION_HEADER section;
section=ImageRVA2Section(pImgNTHeader,dwRVA);//ImageRvaToSection(pimage_nt_headers,Base,dwRVA);
if(section==NULL)
{
return(0);
}
_offset=dwRVA+section->PointerToRawData-section->VirtualAddress;
return(_offset);
}
BOOL AddNewImportDescriptor(const char * szPEFilePath,char * szInjectDllName, char *szImportFuncName)
{
BOOL bSuccess = FALSE;
LPVOID lpMemModule = NULL;
LPBYTE lpData = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE, hFileMapping = INVALID_HANDLE_VALUE;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_IMPORT_DESCRIPTOR pstImportTable = NULL;
PIMAGE_SECTION_HEADER pstSectionHeader = NULL;
__try
{
//pe文件映射到内存
hFile = CreateFile(
szPEFilePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if ( INVALID_HANDLE_VALUE == hFile )
{
OutputDebugString("[-] AddNewImportDescriptor CreateFile fail!\n");
goto _EXIT_;
}
DWORD dwFileSize = GetFileSize(hFile, NULL);
hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE/* | SEC_IMAGE*/, 0, dwFileSize, "WINSUN_MAPPING_FILE");
if ( NULL == hFileMapping )
{
OutputDebugString("[-] AddNewImportDescriptor CreateFileMapping fail!\n");
goto _EXIT_;
}
lpMemModule = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, dwFileSize);
if ( NULL == lpMemModule )
{
OutputDebugString("[-] AddNewImportDescriptor MapViewOfFile fail!\n");
goto _EXIT_;
}
lpData = (LPBYTE)lpMemModule;
//判断是否是PE
if (((PIMAGE_DOS_HEADER)lpData)->e_magic != IMAGE_DOS_SIGNATURE )
{
OutputDebugString("[-] AddNewImportDescriptor PE Header MZ error!\n");
goto _EXIT_;
}
pNtHeader = (PIMAGE_NT_HEADERS)(lpData + ((PIMAGE_DOS_HEADER)(lpData))->e_lfanew);
if ( pNtHeader->Signature != IMAGE_NT_SIGNATURE )
{
OutputDebugString("[-] AddNewImportDescriptor PE Header PE error!\n");
goto _EXIT_;
}
pstImportTable = (PIMAGE_IMPORT_DESCRIPTOR)(lpData + RVA2Offset(pNtHeader,pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
BOOL bBoundImport = FALSE;
if (pstImportTable->Characteristics == 0 && pstImportTable->FirstThunk != 0)
{
bBoundImport = TRUE;
pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
}
pstSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeader+1)+pNtHeader->FileHeader.NumberOfSections-1;
PBYTE pbNewSection = pstSectionHeader->PointerToRawData + lpData;
int i = 0;
while(pstImportTable->FirstThunk != 0)
{
memcpy(pbNewSection, pstImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR));
pstImportTable++;
pbNewSection += sizeof(IMAGE_IMPORT_DESCRIPTOR);
i++;
}
memcpy(pbNewSection, (pbNewSection-sizeof(IMAGE_IMPORT_DESCRIPTOR)), sizeof(IMAGE_IMPORT_DESCRIPTOR));
DWORD dwDelt = pstSectionHeader->VirtualAddress - pstSectionHeader->PointerToRawData;
//avoid import not need table
PIMAGE_THUNK_DATA pImgThunkData = (PIMAGE_THUNK_DATA)(pbNewSection + sizeof(IMAGE_IMPORT_DESCRIPTOR)*2);
//import dll name
PBYTE pszDllNamePosition = (PBYTE)(pImgThunkData + 2);
memcpy(pszDllNamePosition, szInjectDllName, strlen(szInjectDllName));
pszDllNamePosition[strlen(szInjectDllName)] = 0;
//确定IMAGE_IMPORT_BY_NAM的位置
PIMAGE_IMPORT_BY_NAME pImgImportByName = (PIMAGE_IMPORT_BY_NAME)(pszDllNamePosition + strlen(szInjectDllName) + 1);
//init IMAGE_THUNK_DATA
pImgThunkData->u1.Ordinal = dwDelt + (DWORD)pImgImportByName - (DWORD)lpData ;
//init IMAGE_IMPORT_BY_NAME
pImgImportByName->Hint = 1;
memcpy(pImgImportByName->Name, szImportFuncName, strlen(szImportFuncName)); //== dwDelt + (DWORD)pszFuncNamePosition - (DWORD)lpData ;
pImgImportByName->Name[strlen(szImportFuncName)] = 0;
//init OriginalFirstThunk
if (bBoundImport)
{
((PIMAGE_IMPORT_DESCRIPTOR)pbNewSection)->OriginalFirstThunk = 0;
}
else
((PIMAGE_IMPORT_DESCRIPTOR)pbNewSection)->OriginalFirstThunk = dwDelt + (DWORD)pImgThunkData - (DWORD)lpData;
//init FirstThunk
((PIMAGE_IMPORT_DESCRIPTOR)pbNewSection)->FirstThunk = dwDelt + (DWORD)pImgThunkData - (DWORD)lpData;
//init Name
((PIMAGE_IMPORT_DESCRIPTOR)pbNewSection)->Name = dwDelt + (DWORD)pszDllNamePosition-(DWORD)lpData;
//改变导入表
pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = pstSectionHeader->VirtualAddress;
pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (i+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
OutputDebugString("[-] AddNewImportDescriptor Exception!\n");
return false;
}
_EXIT_:
if ( hFile )
{
CloseHandle(hFile);
}
if ( lpMemModule)
{
UnmapViewOfFile(lpMemModule);
}
if ( hFileMapping )
{
CloseHandle(hFileMapping);
}
return true;
}
BOOL AddImportTable(const char * szPEFilePath, char * szInjectDllName,char *szFuncName)
{
BOOL bSuccess = FALSE;
try
{
//增加一个叫"WINSUN"的节
bSuccess = AddNewSection(szPEFilePath, 256);
if (!bSuccess)
{
MessageBox(NULL,"add new section fail", "error", MB_OK);
return bSuccess;
}
//增加一个导入表
AddNewImportDescriptor(szPEFilePath, szInjectDllName,szFuncName);
}
catch ( ... )//CException* e)
{
return bSuccess;
}
return bSuccess;
}
void BackupPE(char * pszPeFilePath)
{
CHAR szPath[MAX_PATH] = {0};
PCHAR pszPath = pszPeFilePath;
pszPath = strrchr(pszPath, '\\');
*pszPath = '\0';
strcpy_s(szPath, strlen(pszPeFilePath)+1,pszPeFilePath);
strcat_s(szPath, strlen("\\backup_")+1,"\\backup_");
strcat_s(szPath, strlen(pszPath+1)+1,pszPath+1);
*pszPath = '\\';
CopyFile(pszPeFilePath, szPath, FALSE);
strncpy(pszPeFilePath, szPath, MAX_PATH);
return;
}
void main(int argc, char **argv)
{
AddImportTable("BeModeImportTableExe.exe","WaiGua.dll","InjectFunc");
}
//WaiGua.dll
// dllmain.cpp : Defines the entry point for the DLL application.
#include <Windows.h>
#ifdef __cplusplus
extern "C"
{
#endif
__declspec (dllexport) void InjectFunc(void);
#ifdef __cplusplus
}
#endif
void InjectFunc(void)
{
MessageBoxA(NULL, "Dll export Inject Success", "Dll Inject", MB_OKCANCEL);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBoxA(NULL, "the simple inject success", "Dll Inject", MB_OKCANCEL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
注入没问题,运行有问题,还有待调试。