移动导出表到新增节
一、為什么要移動導出表
移動導出表是指將導出表以及其內部的三張子表移動到新增節,這個操作是軟件加密的第一步。因為軟件加密會把節進行加密,而數據目錄是在節里的,加密后操作系統不認識了,因此我們要把數據目錄里面的東西移動到一個新的節里。
二、怎么移動
上圖是導出表的結構,移動導出表的步驟,我個人的做法分為以下幾步:
三、代碼實現
// 移動導出表到新增節 DWORD MoveExportTableToNewSection(LPVOID pFileBuffer, LPVOID *pNewFileBuffer, DWORD dwFileBufferSize) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + \RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[0].VirtualAddress));PDWORD pAddressOfFunctions = (PDWORD)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pExportTable->AddressOfFunctions));PWORD pAddressOfNameOrdinals = (PWORD)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pExportTable->AddressOfNameOrdinals));PDWORD pAddressOfNames = (PDWORD)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pExportTable->AddressOfNames));// 計算新增節的大小// = NumberOfFunctions * 4 + NumberOfNames * (2 + 4) + 所有函數名的字節 + sizeof(_IMAGE_EXPORT_DIRECTORY)// 然后文件對齊DWORD dwNewSectionSize = 0;dwNewSectionSize += pExportTable->NumberOfFunctions * 4; // AddressOfFunctions 的空間dwNewSectionSize += pExportTable->NumberOfNames * (2 + 4); // AddressOfNames + AddressOfNameOrdinals 的空間size_t i = 0;for (i = 0; i < pExportTable->NumberOfNames; i++){ LPCSTR lpszFuncName = (LPCSTR)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pAddressOfNames[i]));dwNewSectionSize += strlen(lpszFuncName) + 1;}dwNewSectionSize += sizeof(_IMAGE_EXPORT_DIRECTORY);dwNewSectionSize = Align(dwNewSectionSize, pOptionHeader->FileAlignment);//printf("新增節的大小 = %x\n", dwNewSectionSize);DWORD dwNewBufferSize = AddSection(pFileBuffer, pNewFileBuffer, dwFileBufferSize, dwNewSectionSize);pDosHeader = (PIMAGE_DOS_HEADER)*pNewFileBuffer;pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);// 修改新增節屬性為可讀、含已初始化數據pSectionHeader[pPEHeader->NumberOfSections - 1].Characteristics = 0x40000040;pExportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)*pNewFileBuffer + \RvaToFoa(*pNewFileBuffer, pOptionHeader->DataDirectory[0].VirtualAddress));pAddressOfFunctions = (PDWORD)((DWORD)*pNewFileBuffer + RvaToFoa(*pNewFileBuffer, pExportTable->AddressOfFunctions));pAddressOfNameOrdinals = (PWORD)((DWORD)*pNewFileBuffer + RvaToFoa(*pNewFileBuffer, pExportTable->AddressOfNameOrdinals));pAddressOfNames = (PDWORD)((DWORD)*pNewFileBuffer + RvaToFoa(*pNewFileBuffer, pExportTable->AddressOfNames));// 把3張子表拷貝到新節,更新指針LPVOID pInsert = (LPVOID)((DWORD)*pNewFileBuffer + pSectionHeader[pPEHeader->NumberOfSections - 1].PointerToRawData);memcpy(pInsert, pAddressOfFunctions, 4 * pExportTable->NumberOfFunctions);pAddressOfFunctions = (PDWORD)pInsert;pInsert = (LPVOID)((DWORD)pInsert + 4 * pExportTable->NumberOfFunctions);memcpy(pInsert, pAddressOfNameOrdinals, 2 * pExportTable->NumberOfNames);pAddressOfNameOrdinals = (PWORD)pInsert;pInsert = (LPVOID)((DWORD)pInsert + 2 * pExportTable->NumberOfNames);memcpy(pInsert, pAddressOfNames, 4 * pExportTable->NumberOfNames);pAddressOfNames = (PDWORD)pInsert;pInsert = (LPVOID)((DWORD)pInsert + 4 * pExportTable->NumberOfNames);// 拷貝函數名for (i = 0; i < pExportTable->NumberOfNames; i++){LPCSTR lpszFuncName = (LPCSTR)((DWORD)*pNewFileBuffer + RvaToFoa(*pNewFileBuffer, pAddressOfNames[i]));memcpy(pInsert, lpszFuncName, strlen(lpszFuncName) + 1);// 更新函數名的RVA地址pAddressOfNames[i] = FoaToRva(*pNewFileBuffer, (DWORD)pInsert - (DWORD)*pNewFileBuffer);pInsert = (LPVOID)((DWORD)pInsert + strlen(lpszFuncName) + 1);}// 拷貝導出表memcpy(pInsert, pExportTable, sizeof(_IMAGE_EXPORT_DIRECTORY));pExportTable = (PIMAGE_EXPORT_DIRECTORY)pInsert;pExportTable->AddressOfFunctions = FoaToRva(*pNewFileBuffer, (DWORD)pAddressOfFunctions - (DWORD)*pNewFileBuffer);pExportTable->AddressOfNameOrdinals = FoaToRva(*pNewFileBuffer, (DWORD)pAddressOfNameOrdinals - (DWORD)*pNewFileBuffer);pExportTable->AddressOfNames = FoaToRva(*pNewFileBuffer, (DWORD)pAddressOfNames - (DWORD)*pNewFileBuffer);// 修改目錄項,指向新的導出表pOptionHeader->DataDirectory[0].VirtualAddress = FoaToRva(*pNewFileBuffer, (DWORD)pExportTable - (DWORD)*pNewFileBuffer);return dwNewBufferSize; }四、運行結果
depends walker 和 LordPE 識別正確
調用新DLL的函數,沒有問題。
五、完整代碼
https://blog.csdn.net/Kwansy/article/details/106234264
總結
- 上一篇: GetProcAddress 根据 or
- 下一篇: 移动重定位表到新增节