// This function scans a give resource directory and return a CResourceDirectory object // rdRoot must point to the root directory of the resource section CResourceDirectory* CResourceEditor::ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan) { // Create CResourceDirectory from rdToScan CResourceDirectory* rdc = new CResourceDirectory(PIMAGE_RESOURCE_DIRECTORY(rdToScan)); char* szName; PIMAGE_RESOURCE_DATA_ENTRY rde = NULL; // Go through all entries of this resource directory for (int i = 0; i < rdToScan->Header.NumberOfNamedEntries + rdToScan->Header.NumberOfIdEntries; i++) { // If this entry points to data entry get a pointer to it if (!rdToScan->Entries[i].DirectoryOffset.DataIsDirectory) rde = PIMAGE_RESOURCE_DATA_ENTRY(rdToScan->Entries[i].OffsetToData + (BYTE*)rdRoot); // If this entry has a name, translate it from Unicode if (rdToScan->Entries[i].NameString.NameIsString) { PIMAGE_RESOURCE_DIR_STRING_U rds = PIMAGE_RESOURCE_DIR_STRING_U(rdToScan->Entries[i].NameString.NameOffset + (char*)rdRoot); int mbsSize = WideCharToMultiByte(CP_ACP, 0, rds->NameString, rds->Length, 0, 0, 0, 0); szName = new char[mbsSize+1]; if (!WideCharToMultiByte(CP_ACP, 0, rds->NameString, rds->Length, szName, mbsSize, 0, 0)) { throw runtime_error("Unicode conversion failed"); } szName[mbsSize] = 0; } // Else, set the name to this entry's id else szName = MAKEINTRESOURCE(rdToScan->Entries[i].Id); if (rdToScan->Entries[i].DirectoryOffset.DataIsDirectory) rdc->AddEntry( new CResourceDirectoryEntry( szName, ScanDirectory( rdRoot, PRESOURCE_DIRECTORY(rdToScan->Entries[i].DirectoryOffset.OffsetToDirectory + (BYTE*)rdRoot) ) ) ); else rdc->AddEntry( new CResourceDirectoryEntry( szName, new CResourceDataEntry( (BYTE*)rdRoot + rde->OffsetToData - m_dwResourceSectionVA, rde->Size, rde->CodePage ) ) ); // Delete the dynamicly allocated name if it is a name and not an id if (!IS_INTRESOURCE(szName)) delete [] szName; } return rdc; }
// 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; }
// 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 scans a given resource directory and returns a CResourceDirectory object // rdRoot must point to the root directory of the resource section CResourceDirectory* CResourceEditor::ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan) { // Create CResourceDirectory from rdToScan CResourceDirectory* rdc = new CResourceDirectory(PIMAGE_RESOURCE_DIRECTORY(rdToScan)); WINWCHAR* szName; PIMAGE_RESOURCE_DATA_ENTRY rde = NULL; // Go through all entries of this resource directory int entries = ConvertEndianness(rdToScan->Header.NumberOfNamedEntries); entries += ConvertEndianness(rdToScan->Header.NumberOfIdEntries); for (int i = 0; i < entries; i++) { MY_IMAGE_RESOURCE_DIRECTORY_ENTRY rd = rdToScan->Entries[i]; rd.UOffset.OffsetToData = ConvertEndianness(rd.UOffset.OffsetToData); rd.UName.Name = ConvertEndianness(rd.UName.Name); // If this entry points to data entry get a pointer to it if (!rd.UOffset.DirectoryOffset.DataIsDirectory) rde = PIMAGE_RESOURCE_DATA_ENTRY(rd.UOffset.OffsetToData + (BYTE*)rdRoot); // If this entry has a name, translate it from Unicode if (rd.UName.NameString.NameIsString) { PIMAGE_RESOURCE_DIR_STRING_U rds = PIMAGE_RESOURCE_DIR_STRING_U(rd.UName.NameString.NameOffset + (char*)rdRoot); size_t nameSize = ConvertEndianness(rds->Length); szName = new WINWCHAR[nameSize+1]; WinWStrNCpy(szName, WCHARPTR2WINWCHARPTR(rds->NameString), nameSize); szName[nameSize] = 0; } // Else, set the name to this entry's id else szName = MAKEINTRESOURCEWINW(ConvertEndianness(rdToScan->Entries[i].UName.Id)); if (rd.UOffset.DirectoryOffset.DataIsDirectory) { CResourceDirectoryEntry *pRDE = new CResourceDirectoryEntry( szName, ScanDirectory( rdRoot, PRESOURCE_DIRECTORY(rd.UOffset.DirectoryOffset.OffsetToDirectory + (LPBYTE)rdRoot) ) ); if (!rdc->AddEntry(pRDE)) delete pRDE; } else { LPBYTE pbData = (LPBYTE)rdRoot + ConvertEndianness(rde->OffsetToData) - m_dwResourceSectionVA; DWORD dwOffset = DWORD(pbData - m_pbPE); if (m_bKeepData) { if (dwOffset > DWORD(m_iSize)) { throw runtime_error("Invalid resource entry data pointer, possibly compressed resources"); } } else { pbData = m_pbPE; // dummy pointer to "nothing" } CResourceDirectoryEntry *pRDE = new CResourceDirectoryEntry( szName, new CResourceDataEntry( pbData, ConvertEndianness(rde->Size), ConvertEndianness(rde->CodePage), dwOffset ) ); if (!rdc->AddEntry(pRDE)) delete pRDE; } // Delete the dynamicly allocated name if it is a name and not an id if (!IS_INTRESOURCE(szName)) delete [] szName; } return rdc; }
// Adds/Replaces/Removes a resource. // If lpData is 0 UpdateResource removes the resource. bool CResourceEditor::UpdateResourceW(const WINWCHAR* szType, WINWCHAR* 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); CResourceDirectoryEntry *pRDE = new CResourceDirectoryEntry(szType, nameDir); if (!m_cResDir->AddEntry(pRDE)) delete pRDE; } if (!langDir) { // Name doesn't yet exist langDir = new CResourceDirectory(&rd); CResourceDirectoryEntry *pRDE = new CResourceDirectoryEntry(szName, langDir); if (!nameDir->AddEntry(pRDE)) delete pRDE; } if (!data) { // Language doesn't yet exist, hence data nither data = new CResourceDataEntry(lpData, dwSize); CResourceDirectoryEntry *pRDE = new CResourceDirectoryEntry(MAKEINTRESOURCEWINW(wLanguage), data); if (!langDir->AddEntry(pRDE)) delete pRDE; } } 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; }
// 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)); }
// This function scans a give resource directory and return a CResourceDirectory object // rdRoot must point to the root directory of the resource section CResourceDirectory* CResourceEditor::ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan) { // Create CResourceDirectory from rdToScan CResourceDirectory* rdc = new CResourceDirectory(PIMAGE_RESOURCE_DIRECTORY(rdToScan)); WCHAR* szName; PIMAGE_RESOURCE_DATA_ENTRY rde = NULL; // Go through all entries of this resource directory int entries = ConvertEndianness(rdToScan->Header.NumberOfNamedEntries); entries += ConvertEndianness(rdToScan->Header.NumberOfIdEntries); for (int i = 0; i < entries; i++) { MY_IMAGE_RESOURCE_DIRECTORY_ENTRY rd = rdToScan->Entries[i]; rd.OffsetToData = ConvertEndianness(rd.OffsetToData); rd.Name = ConvertEndianness(rd.Name); // If this entry points to data entry get a pointer to it if (!rd.DirectoryOffset.DataIsDirectory) rde = PIMAGE_RESOURCE_DATA_ENTRY(rd.OffsetToData + (BYTE*)rdRoot); // If this entry has a name, translate it from Unicode if (rd.NameString.NameIsString) { PIMAGE_RESOURCE_DIR_STRING_U rds = PIMAGE_RESOURCE_DIR_STRING_U(rd.NameString.NameOffset + (char*)rdRoot); size_t nameSize = ConvertEndianness(rds->Length); szName = new WCHAR[nameSize+1]; winchar_strncpy(szName, rds->NameString, nameSize); szName[nameSize] = 0; } // Else, set the name to this entry's id else szName = MAKEINTRESOURCEW(ConvertEndianness(rdToScan->Entries[i].Id)); if (rd.DirectoryOffset.DataIsDirectory) rdc->AddEntry( new CResourceDirectoryEntry( szName, ScanDirectory( rdRoot, PRESOURCE_DIRECTORY(rd.DirectoryOffset.OffsetToDirectory + (BYTE*)rdRoot) ) ) ); else rdc->AddEntry( new CResourceDirectoryEntry( szName, new CResourceDataEntry( (BYTE*)rdRoot + ConvertEndianness(rde->OffsetToData) - m_dwResourceSectionVA, ConvertEndianness(rde->Size), ConvertEndianness(rde->CodePage) ) ) ); // Delete the dynamicly allocated name if it is a name and not an id if (!IS_INTRESOURCE(szName)) delete [] szName; } return rdc; }