// Returns a copy of the requested resource // Returns 0 if the requested resource can't be found BYTE* CResourceEditor::GetResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) { if (!m_bKeepData) throw runtime_error("Can't GetResource() when bKeepData is false"); CResourceDirectory* nameDir = 0; CResourceDirectory* langDir = 0; CResourceDataEntry* data = 0; int i = m_cResDir->Find(szType); if (i > -1) { nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); i = nameDir->Find(szName); if (i > -1) { langDir = nameDir->GetEntry(i)->GetSubDirectory(); i = wLanguage ? langDir->Find(wLanguage) : 0; if (i > -1) { data = langDir->GetEntry(i)->GetDataEntry(); } } } if (data) { BYTE* toReturn = new BYTE[data->GetSize()]; CopyMemory(toReturn, data->GetData(), data->GetSize()); return toReturn; } else return NULL; }
// Returns the size of the requested resource // Returns -1 if the requested resource can't be found int CResourceEditor::GetResourceSize(char* szType, char* szName, LANGID wLanguage) { CResourceDirectory* nameDir = 0; CResourceDirectory* langDir = 0; CResourceDataEntry* data = 0; int i = m_cResDir->Find(szType); if (i > -1) { nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); i = nameDir->Find(szName); if (i > -1) { langDir = nameDir->GetEntry(i)->GetSubDirectory(); i = 0; if (wLanguage) i = langDir->Find(wLanguage); if (i > -1) { data = langDir->GetEntry(i)->GetDataEntry(); } } } if (data) return (int) data->GetSize(); else return -1; }
// Returns a copy of the requested resource // Returns 0 if the requested resource can't be found BYTE* CResourceEditor::GetResource(char* szType, char* szName, LANGID wLanguage) { CResourceDirectory* nameDir = 0; CResourceDirectory* langDir = 0; CResourceDataEntry* data = 0; int i = m_cResDir->Find(szType); if (i > -1) { nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); i = nameDir->Find(szName); if (i > -1) { langDir = nameDir->GetEntry(i)->GetSubDirectory(); i = 0; if (wLanguage) i = langDir->Find(wLanguage); if (i > -1) { data = langDir->GetEntry(i)->GetDataEntry(); } } } if (data) { BYTE* toReturn = new BYTE[data->GetSize()]; CopyMemory(toReturn, data->GetData(), data->GetSize()); return toReturn; } else return NULL; }
// Adds/Replaces/Removes a resource. // If lpData is 0 UpdateResource removes the resource. bool CResourceEditor::UpdateResource(char* szType, char* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { CResourceDirectory* nameDir = 0; CResourceDirectory* langDir = 0; CResourceDataEntry* data = 0; IMAGE_RESOURCE_DIRECTORY rd = {0, /*time(0),*/}; int iTypeIdx = -1, iNameIdx = -1, iLangIdx = -1; iTypeIdx = m_cResDir->Find(szType); if (iTypeIdx > -1) { nameDir = m_cResDir->GetEntry(iTypeIdx)->GetSubDirectory(); iNameIdx = nameDir->Find(szName); if (iNameIdx > -1) { langDir = nameDir->GetEntry(iNameIdx)->GetSubDirectory(); iLangIdx = langDir->Find(wLanguage); if (iLangIdx > -1) { data = langDir->GetEntry(iLangIdx)->GetDataEntry(); } } } if (lpData) { // Replace/Add the resource if (data) { data->SetData(lpData, dwSize); return true; } if (!nameDir) { // Type doesn't yet exist nameDir = new CResourceDirectory(&rd); m_cResDir->AddEntry(new CResourceDirectoryEntry(szType, nameDir)); } if (!langDir) { // Name doesn't yet exist langDir = new CResourceDirectory(&rd); nameDir->AddEntry(new CResourceDirectoryEntry(szName, langDir)); } if (!data) { // Language doesn't yet exist, hence data nither data = new CResourceDataEntry(lpData, dwSize); langDir->AddEntry(new CResourceDirectoryEntry(MAKEINTRESOURCE(wLanguage), data)); } } else if (data) { // Delete the resource delete data; langDir->RemoveEntry(iLangIdx); // Delete directories holding the resource if empty if (!langDir->CountEntries()) { delete langDir; nameDir->RemoveEntry(iNameIdx); if (!nameDir->CountEntries()) { delete nameDir; m_cResDir->RemoveEntry(iTypeIdx); } } } else return false; return true; }
// Returns the offset of the requested resource in the original PE // Returns -1 if the requested resource can't be found DWORD CResourceEditor::GetResourceOffsetW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) { CResourceDirectory* nameDir = 0; CResourceDirectory* langDir = 0; CResourceDataEntry* data = 0; int i = m_cResDir->Find(szType); if (i > -1) { nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); i = nameDir->Find(szName); if (i > -1) { langDir = nameDir->GetEntry(i)->GetSubDirectory(); i = 0; if (wLanguage) i = langDir->Find(wLanguage); if (i > -1) { data = langDir->GetEntry(i)->GetDataEntry(); } } } if (data) return data->GetOffset(); else return DWORD(-1); }
// This function writes into a given place in memory (pbRsrcSec) the edited resource section void CResourceEditor::WriteRsrcSec(BYTE* pbRsrcSec) { BYTE* seeker = pbRsrcSec; queue<CResourceDirectory*> qDirs; // Used to scan the tree by level queue<CResourceDataEntry*> qDataEntries; // Used for writing the data entries queue<CResourceDataEntry*> qDataEntries2; // Used for writing raw resources data queue<CResourceDirectoryEntry*> qStrings; // Used for writing resources' names qDirs.push(m_cResDir); while (!qDirs.empty()) { CResourceDirectory* crd = qDirs.front(); IMAGE_RESOURCE_DIRECTORY rdDir = crd->GetInfo(); rdDir.NumberOfNamedEntries = ConvertEndianness(rdDir.NumberOfNamedEntries); rdDir.NumberOfIdEntries = ConvertEndianness(rdDir.NumberOfIdEntries); CopyMemory(seeker, &rdDir, sizeof(IMAGE_RESOURCE_DIRECTORY)); crd->m_ulWrittenAt = (ULONG_PTR)(seeker); seeker += sizeof(IMAGE_RESOURCE_DIRECTORY); for (unsigned int i = 0; i < crd->CountEntries(); i++) { if (crd->GetEntry(i)->HasName()) qStrings.push(crd->GetEntry(i)); if (crd->GetEntry(i)->IsDataDirectory()) qDirs.push(crd->GetEntry(i)->GetSubDirectory()); else { qDataEntries.push(crd->GetEntry(i)->GetDataEntry()); qDataEntries2.push(crd->GetEntry(i)->GetDataEntry()); } MY_IMAGE_RESOURCE_DIRECTORY_ENTRY rDirE; ZeroMemory(&rDirE, sizeof(rDirE)); rDirE.UOffset.DirectoryOffset.DataIsDirectory = crd->GetEntry(i)->IsDataDirectory(); rDirE.UName.Id = crd->GetEntry(i)->HasName() ? 0 : crd->GetEntry(i)->GetId(); rDirE.UName.Id = ConvertEndianness(rDirE.UName.Id); rDirE.UName.NameString.NameIsString = (crd->GetEntry(i)->HasName()) ? 1 : 0; CopyMemory(seeker, &rDirE, sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY)); crd->GetEntry(i)->m_ulWrittenAt = (ULONG_PTR)(seeker); seeker += sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY); } qDirs.pop(); } /* * Write IMAGE_RESOURCE_DATA_ENTRYs. */ while (!qDataEntries.empty()) { CResourceDataEntry* cRDataE = qDataEntries.front(); IMAGE_RESOURCE_DATA_ENTRY rDataE = {0,}; rDataE.CodePage = ConvertEndianness(cRDataE->GetCodePage()); rDataE.Size = ConvertEndianness(cRDataE->GetSize()); CopyMemory(seeker, &rDataE, sizeof(IMAGE_RESOURCE_DATA_ENTRY)); cRDataE->m_ulWrittenAt = (ULONG_PTR)(seeker); seeker += sizeof(IMAGE_RESOURCE_DATA_ENTRY); qDataEntries.pop(); } /* * Write strings */ while (!qStrings.empty()) { CResourceDirectoryEntry* cRDirE = qStrings.front(); PMY_IMAGE_RESOURCE_DIRECTORY_ENTRY(cRDirE->m_ulWrittenAt)->UName.NameString.NameOffset = ConvertEndianness((DWORD) (seeker - pbRsrcSec)); const WINWCHAR* szName = cRDirE->GetName(); WORD iLen = (WORD) WinWStrLen(szName) + 1; *(WORD*)seeker = ConvertEndianness(iLen); CopyMemory(seeker + sizeof(WORD), szName, iLen*sizeof(WINWCHAR)); seeker += RALIGN(iLen * sizeof(WINWCHAR) + sizeof(WORD), 4); qStrings.pop(); } /* * Write raw resource data and set offsets in IMAGE_RESOURCE_DATA_ENTRYs. */ while (!qDataEntries2.empty()) { CResourceDataEntry* cRDataE = qDataEntries2.front(); CopyMemory(seeker, cRDataE->GetData(), cRDataE->GetSize()); PIMAGE_RESOURCE_DATA_ENTRY(cRDataE->m_ulWrittenAt)->OffsetToData = ConvertEndianness((DWORD)(seeker - pbRsrcSec) + m_dwResourceSectionVA); seeker += RALIGN(cRDataE->GetSize(), 8); qDataEntries2.pop(); } /* * Set all of the directory entries offsets. */ SetOffsets(m_cResDir, (ULONG_PTR)(pbRsrcSec)); }
// This function writes into a given place in memory (pbRsrcSec) the edited resource section void CResourceEditor::WriteRsrcSec(BYTE* pbRsrcSec) { BYTE* seeker = pbRsrcSec; queue<CResourceDirectory*> qDirs; // Used to scan the tree by level queue<CResourceDataEntry*> qDataEntries; // Used for writing the data entries queue<CResourceDataEntry*> qDataEntries2; // Used for writing raw resources data queue<CResourceDirectoryEntry*> qStrings; // Used for writing resources' names qDirs.push(m_cResDir); while (!qDirs.empty()) { CResourceDirectory* crd = qDirs.front(); IMAGE_RESOURCE_DIRECTORY rdDir = crd->GetInfo(); CopyMemory(seeker, &rdDir, sizeof(IMAGE_RESOURCE_DIRECTORY)); crd->m_dwWrittenAt = DWORD(seeker); seeker += sizeof(IMAGE_RESOURCE_DIRECTORY); for (int i = 0; i < crd->CountEntries(); i++) { if (crd->GetEntry(i)->HasName()) qStrings.push(crd->GetEntry(i)); if (crd->GetEntry(i)->IsDataDirectory()) qDirs.push(crd->GetEntry(i)->GetSubDirectory()); else { qDataEntries.push(crd->GetEntry(i)->GetDataEntry()); qDataEntries2.push(crd->GetEntry(i)->GetDataEntry()); } MY_IMAGE_RESOURCE_DIRECTORY_ENTRY rDirE; ZeroMemory(&rDirE, sizeof(rDirE)); rDirE.DirectoryOffset.DataIsDirectory = crd->GetEntry(i)->IsDataDirectory(); rDirE.Id = (crd->GetEntry(i)->HasName()) ? 0 : crd->GetEntry(i)->GetId(); rDirE.NameString.NameIsString = (crd->GetEntry(i)->HasName()) ? 1 : 0; CopyMemory(seeker, &rDirE, sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY)); crd->GetEntry(i)->m_dwWrittenAt = DWORD(seeker); seeker += sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY); } qDirs.pop(); } /* * Write IMAGE_RESOURCE_DATA_ENTRYs. */ while (!qDataEntries.empty()) { CResourceDataEntry* cRDataE = qDataEntries.front(); IMAGE_RESOURCE_DATA_ENTRY rDataE = {0,}; rDataE.CodePage = cRDataE->GetCodePage(); rDataE.Size = cRDataE->GetSize(); CopyMemory(seeker, &rDataE, sizeof(IMAGE_RESOURCE_DATA_ENTRY)); cRDataE->m_dwWrittenAt = DWORD(seeker); seeker += sizeof(IMAGE_RESOURCE_DATA_ENTRY); qDataEntries.pop(); } /* * Write strings */ while (!qStrings.empty()) { CResourceDirectoryEntry* cRDirE = qStrings.front(); PMY_IMAGE_RESOURCE_DIRECTORY_ENTRY(cRDirE->m_dwWrittenAt)->NameString.NameOffset = DWORD(seeker) - DWORD(pbRsrcSec); char* szName = cRDirE->GetName(); WORD iLen = strlen(szName) + 1; WCHAR *szwName = new WCHAR[iLen]; // MultiByteToWideChar return value includes the null char, so -1 iLen = MultiByteToWideChar(CP_ACP, 0, szName, iLen, szwName, iLen) - 1; if (iLen == (WORD) -1) throw runtime_error("Unicode conversion failed"); *(WORD*)seeker = iLen; seeker += sizeof(WORD); CopyMemory(seeker, szwName, iLen*sizeof(WCHAR)); seeker += iLen*sizeof(WCHAR); // Even though the number of chars is predefined a null termination is required *(WORD*)seeker = 0; seeker += sizeof(WORD); delete [] szName; delete [] szwName; qStrings.pop(); } /* * Write raw resource data and set offsets in IMAGE_RESOURCE_DATA_ENTRYs. */ while (!qDataEntries2.empty()) { CResourceDataEntry* cRDataE = qDataEntries2.front(); CopyMemory(seeker, cRDataE->GetData(), cRDataE->GetSize()); PIMAGE_RESOURCE_DATA_ENTRY(cRDataE->m_dwWrittenAt)->OffsetToData = seeker - pbRsrcSec + m_dwResourceSectionVA; seeker += RALIGN(cRDataE->GetSize(), 8); qDataEntries2.pop(); } /* * Set all of the directory entries offsets. */ SetOffsets(m_cResDir, DWORD(pbRsrcSec)); }