//换图标
BOOL ChangeIcon(HWND hDlg)
{
TCHAR szPath_App[MAX_PATH];
TCHAR szPath_Ico[MAX_PATH];
GetDlgItemText(hDlg, IDC_EDIT_APPPATH, szPath_App, MAX_PATH);
if(_tcslen(szPath_App) == 0)
{
MessageBox(hDlg, _T("请输入程序的路径"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
GetDlgItemText(hDlg, IDC_EDIT_ICOPATH, szPath_Ico, MAX_PATH);
if(_tcslen(szPath_Ico) == 0)
{
MessageBox(hDlg, _T("请输入图标的路径"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
//先把程序全部读入内存
HANDLE hFile = CreateFile(szPath_App,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(hDlg, _T("打开程序文件失败。"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
DWORD dwBytesRead = 0;
DWORD dwAppFileSize = GetFileSize(hFile, NULL);
PBYTE lpBaseAddress = (PBYTE)malloc(dwAppFileSize);
if(lpBaseAddress == NULL)
{
CloseHandle(hFile);
MessageBox(hDlg, _T("内存不足。"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
if(!ReadFile(hFile, lpBaseAddress, dwAppFileSize, &dwBytesRead, NULL) || dwBytesRead != dwAppFileSize)
{
CloseHandle(hFile);
free(lpBaseAddress);
MessageBox(hDlg, _T("读取APP文件失败。"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
CloseHandle(hFile); //关闭文件
//
// 加载图标
//
if(!g_IcoFile.LoadFile(szPath_Ico))
{
free(lpBaseAddress);
MessageBox(hDlg, _T("读取ICO文件失败。"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
//现在准备路径
TCHAR szPath_AppBackup[MAX_PATH];
TCHAR szPath_AppModified[MAX_PATH];
//TCHAR szDriver[4], szDir[MAX_PATH], szFilename[MAX_PATH], szExt[8];
//_tsplitpath(szPath_App, szDrive, szDir, szFilename, szExt);
_stprintf(szPath_AppBackup, _T("%s.Backup"), szPath_App);
_stprintf(szPath_AppModified, _T("%s.Modified"), szPath_App);
if(!CopyFile(szPath_App, szPath_AppBackup, TRUE))
{
free(lpBaseAddress);
MessageBox(hDlg, _T("备份APP文件失败。"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
//
// 在内存中替换 ICON (覆写内存数据)
//
int totalImgCount = 0, replacedImgCount = 0;
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBaseAddress;
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(lpBaseAddress + pDosHeader->e_lfanew);
BOOL bFindIcon = FALSE;
//资源表的rva
DWORD rva_resTable = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
if(rva_resTable > 0)
{
//this->LoadResTable(lpBaseAddress, pNtHeaders, rva_resTable);
PIMAGE_RESOURCE_DIRECTORY pResTable = (PIMAGE_RESOURCE_DIRECTORY)ImageRvaToVa(
pNtHeaders,
lpBaseAddress,
rva_resTable,
NULL);
PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pResTable + sizeof(IMAGE_RESOURCE_DIRECTORY));
//寻找 Icon 子节点(在第一层上)
for(int i = 0; i < (pResTable->NumberOfNamedEntries + pResTable->NumberOfIdEntries); i++)
{
//this->AddChildNode(hItem_Res, lpBaseAddress, pNtHeaders, (DWORD)pResTable, pEntries + i, 1);
if(!pEntries[i].NameIsString && pEntries[i].Id == 3) //找到了Icon?
{
bFindIcon = TRUE;
//
// 现在遍历每个Icon 并尝试替换叶子节点上的图标数据
//
DWORD tableAddress = (DWORD)pResTable;
PIMAGE_RESOURCE_DIRECTORY pDir = (PIMAGE_RESOURCE_DIRECTORY)(tableAddress + pEntries[i].OffsetToDirectory);
PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntries_Icon = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pDir + sizeof(IMAGE_RESOURCE_DIRECTORY));
totalImgCount = pDir->NumberOfNamedEntries + pDir->NumberOfIdEntries;
for(int j = 0; j < totalImgCount; j++)
{
OverwriteIcon(lpBaseAddress, pNtHeaders, tableAddress, pEntries_Icon + j, &replacedImgCount);
}
break;
}
}
}
if(!bFindIcon)
{
free(lpBaseAddress);
MessageBox(hDlg, _T("程序文件中没有图标,所以无须替换。"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
//保存到修改后的内容到 APP.exe.Modified
HANDLE hFile2 = CreateFile(szPath_AppModified,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile2 == INVALID_HANDLE_VALUE)
{
free(lpBaseAddress);
MessageBox(hDlg, _T("保存修改后的程序文件失败。"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
DWORD dwBytesTotal = dwAppFileSize;
DWORD dwBytesToWrite = 0, dwBytesWritten = 0;
PBYTE pBytePos = lpBaseAddress;
while(dwBytesTotal > 0)
{
dwBytesToWrite = min(1024, dwBytesTotal);
WriteFile(hFile2, pBytePos, dwBytesToWrite, &dwBytesWritten, NULL);
dwBytesTotal -= dwBytesToWrite;
pBytePos += dwBytesToWrite;
}
CloseHandle(hFile2);
//释放内存
free(lpBaseAddress);
lpBaseAddress = NULL;
g_IcoFile.Clear();
if(!CopyFile(szPath_AppModified, szPath_App, FALSE))
{
MessageBox(hDlg, _T("替换程序文件失败。"), _T("warning"), MB_OK | MB_ICONWARNING);
return FALSE;
}
DeleteFile(szPath_AppModified);
TCHAR szMsg[256];
_stprintf(szMsg, _T("替换程序图标成功! \r\n其中图像总数 %ld 个,成功替换 %ld 个。"),
totalImgCount, replacedImgCount);
MessageBox(hDlg, szMsg, _T("success"), MB_OK | MB_ICONINFORMATION);
return TRUE;
}
//【递归函数】一个Icon的子结点,但不是叶子节点,递归到叶子节点后进行数据覆盖
void OverwriteIcon(LPVOID lpBaseAddress,
PIMAGE_NT_HEADERS pNtHeaders,
DWORD tableAddress,
PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry,
int* pReplacedCount)
{
//再确定节点类型(目录还是叶子)
if(pEntry->DataIsDirectory)
{
PIMAGE_RESOURCE_DIRECTORY pDir = (PIMAGE_RESOURCE_DIRECTORY)(tableAddress + pEntry->OffsetToDirectory);
PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pDir + sizeof(IMAGE_RESOURCE_DIRECTORY));
for(int i = 0; i <(pDir->NumberOfNamedEntries + pDir->NumberOfIdEntries); i++)
{
OverwriteIcon(lpBaseAddress, pNtHeaders, tableAddress, pEntries + i, pReplacedCount);
}
}
else
{
//已经叶子节点!
PIMAGE_RESOURCE_DATA_ENTRY pDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)(tableAddress + pEntry->OffsetToData);
//具体的资源属于位于:pData->OffsetToData,这是一个RVA(不是相对于资源表头部的偏移!!!)
//去定位到实际的资源数据
PBYTE lpIconData = (PBYTE)ImageRvaToVa(pNtHeaders, lpBaseAddress, pDataEntry->OffsetToData, NULL);
/*_stprintf(nodeText, _T("FileAddr: %08X; RVA: %08X; Size = %ld Bytes; "),
pData - (DWORD)lpBaseAddress,
pDataEntry->OffsetToData,
pDataEntry->Size);*/
PBITMAPINFOHEADER pBmInfoHdr = (PBITMAPINFOHEADER)lpIconData;
int imgIndex = g_IcoFile.GetImageIndex(pBmInfoHdr->biWidth, pBmInfoHdr->biHeight, pBmInfoHdr->biBitCount);
if(imgIndex >= 0)
{
//覆盖BitmapInfoHeader部分
int bytesCopy = sizeof(BITMAPINFOHEADER) + g_IcoFile.m_pImages[imgIndex].nPaletteSize * sizeof(RGBQUAD);
memcpy(lpIconData, g_IcoFile.m_pImages[imgIndex].lpInfo, bytesCopy);
lpIconData += bytesCopy;
//覆盖XOR Mask部分
bytesCopy = g_IcoFile.m_pImages[imgIndex].nSize_XOR;
memcpy(lpIconData, g_IcoFile.m_pImages[imgIndex].lpXOR, bytesCopy);
lpIconData += bytesCopy;
//覆盖And Mask部分
bytesCopy = g_IcoFile.m_pImages[imgIndex].nSize_AND;
memcpy(lpIconData, g_IcoFile.m_pImages[imgIndex].lpAND, bytesCopy);
lpIconData += bytesCopy;
//增加替换图像数
*pReplacedCount = *pReplacedCount + 1;
}
}
}