分析
源码
要移动导出表, 需要改变的地方有:
1 DataDirectory[5]->VirtualAddress
2 ExportDirector中的三个地址
代码
按照课程内容的顺序依次进行
步骤如下:
新增节省略
初始化
Header header;
SList slist;
DWORD fileSize = 0;
DWORD foaOfNewSection = 0;
DWORD foaExportDirectory = 0;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
pFileBuffer = ReadPeFile(inFilePath, &fileSize);
InitializePheader(pFileBuffer, &header, &slist);
pDataDirectory = header.pOptionalHeader->DataDirectory;
foaExportDirectory = RvaDataToFoaData(pFileBuffer, (*pDataDirectory).VirtualAddress, FALSE);
pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(foaExportDirectory + (DWORD)pFileBuffer);
二三四 复制地址
需要用三个变量存放存储当前片段的偏移, 方便后面修复
DWORD sizeOf_AddressOfFunctions = 4 * pExportDirectory->NumberOfFunctions;
DWORD sizeOf_AddressOfNames = 4 * pExportDirectory->NumberOfFunctions;
DWORD sizeOf_AddressOfNameOrdinals = 2 * pExportDirectory->NumberOfNames;
DWORD copyAddressOfFunctions = (DWORD)pFileBuffer + (header.pSecitonHeader + slist.numOfSections - 1)->PointerToRawData;
DWORD orginalAddressOfFunctions= (DWORD)pFileBuffer + RvaDataToFoaData(pFileBuffer, pExportDirectory->AddressOfFunctions, FALSE);
DWORD foaOf_AddressOfFunctions = copyAddressOfFunctions - (DWORD)pFileBuffer;
memcpy((LPVOID)copyAddressOfFunctions, (LPVOID)orginalAddressOfFunctions, sizeOf_AddressOfFunctions); //复制AddressOfFunctions
copyAddressOfFunctions += sizeOf_AddressOfFunctions;
orginalAddressOfFunctions = (DWORD)pFileBuffer + RvaDataToFoaData(pFileBuffer, pExportDirectory->AddressOfNames, FALSE);
DWORD foaOf_AddressOfNames = copyAddressOfFunctions - (DWORD)pFileBuffer; //为了后面修复
memcpy((LPVOID)copyAddressOfFunctions, (LPVOID)orginalAddressOfFunctions, sizeOf_AddressOfNames);
copyAddressOfFunctions += sizeOf_AddressOfNames;
orginalAddressOfFunctions = (DWORD)pFileBuffer + RvaDataToFoaData(pFileBuffer, pExportDirectory->AddressOfNameOrdinals, FALSE);
DWORD foaOf_AddressOfNameOrdinals = copyAddressOfFunctions - (DWORD)pFileBuffer;;
memcpy((LPVOID)copyAddressOfFunctions, (LPVOID)orginalAddressOfFunctions, sizeOf_AddressOfNameOrdinals);
copyAddressOfFunctions += sizeOf_AddressOfNameOrdinals;
五 复制函数名
strlen记得加1
DWORD oringinalAddressOfName = (DWORD)pFileBuffer + RvaDataToFoaData(pFileBuffer, pExportDirectory->AddressOfNames, FALSE);
DWORD sizeOfNames = 0;
char *nameOfFunction = (char *)((DWORD)(pFileBuffer)+RvaDataToFoaData(pFileBuffer, *(DWORD *)(oringinalAddressOfName), FALSE));
for (DWORD i = 0; i < pExportDirectory->NumberOfNames; i++)
{
puts(nameOfFunction);
sizeOfNames += strlen(nameOfFunction);
memcpy((DWORD *)copyAddressOfFunctions, nameOfFunction, sizeOfNames);
copyAddressOfFunctions = copyAddressOfFunctions + strlen(nameOfFunction) + 1;
nameOfFunction = (char *)((DWORD)nameOfFunction + strlen(nameOfFunction) + 1);
}
六 复制导出表结构
DWORD foaOf_AddressOfExportDirectory = copyAddressOfFunctions - (DWORD)pFileBuffer;
memcpy((PIMAGE_EXPORT_DIRECTORY)copyAddressOfFunctions, pExportDirectory, SIZE_OF_EXPORTDIRECTORY);
七 八 修复结构
PIMAGE_EXPORT_DIRECTORY movedExportDirectory = (PIMAGE_EXPORT_DIRECTORY)copyAddressOfFunctions;
movedExportDirectory->AddressOfFunctions = FoaDataToRvaData(pFileBuffer, (DWORD)foaOf_AddressOfFunctions);
movedExportDirectory->AddressOfNames = FoaDataToRvaData(pFileBuffer, (DWORD)foaOf_AddressOfNames);
movedExportDirectory->AddressOfNameOrdinals = FoaDataToRvaData(pFileBuffer, (DWORD)foaOf_AddressOfNameOrdinals);
pDataDirectory->VirtualAddress = FoaDataToRvaData(pFileBuffer, foaOf_AddressOfExportDirectory);
测试
ps: 没考虑过64位问题, 只用于32位测试
测试文件: cloudmusic.dll 某云
原始dll
移动导出表后dll
使用也无问题
一些问题
1 首先是新节的大小, 一开始用的0x10000感觉已经很大了, 没想到在测试的时候出了问题, 拖进lordpe一看, 这么多函数名字还都不短, 立马就又加了个0, 成功. 所以稳妥的做法是先判断所有name大小再开辟新节
2 关于FOA RVA惭愧的说, 这两个东西学到这才弄懂含义, FILE OFFSET ADDRESS 之前觉着是FILE OF ADDRESS…就导致写代码的时候会把加上缓冲区的地址当作foa, 意思就是单纯的偏移, 并不包含缓冲区的地址. 弄明白就不用在加不加缓冲区地址上浪费时间. 但这个并不影响关于移动表的理解.
3 尽管已经写完了 打印导出表, 在写这个函数的时候还是在转来转去的过程中差点晕过去, 但现在写完变得很清晰, 对PE结构的理解帮助很大.
建了个学习讨论q群, 欢迎新朋友加入:1094301686