• R/O
  • SSH
  • HTTPS

peframework: Commit


Commit MetaInfo

Revision4 (tree)
Time2017-04-12 02:26:05
Authorquiret

Log Message

- fixed writing of resource directories; they are now sorted properly for binary searching

Change Summary

Incremental Difference

--- include/peloader.h (revision 3)
+++ include/peloader.h (revision 4)
@@ -1491,9 +1491,9 @@
14911491 std::wstring GetName( void ) const;
14921492
14931493 eType itemType;
1494- std::u16string name; // valid if hasIdentifierName == false
1495- std::uint16_t identifier; // valid if hasIdentifierName == true
1496- bool hasIdentifierName; // if true then identifier field is valid, name is not
1494+ std::u16string name; // valid if hasIdentifierName == false
1495+ std::uint16_t identifier; // valid if hasIdentifierName == true
1496+ bool hasIdentifierName; // if true then identifier field is valid, name is not
14971497 };
14981498
14991499 struct PEResourceInfo : public PEResourceItem
@@ -1531,12 +1531,19 @@
15311531 {
15321532 // We need to destroy all our children, because they are
15331533 // dynamically allocated.
1534- for ( PEResourceItem *item : this->children )
1534+ for ( PEResourceItem *item : this->namedChildren )
15351535 {
15361536 delete item;
15371537 }
15381538
1539- this->children.clear();
1539+ this->namedChildren.clear();
1540+
1541+ for ( PEResourceItem *item : this->idChildren )
1542+ {
1543+ delete item;
1544+ }
1545+
1546+ this->idChildren.clear();
15401547 }
15411548
15421549 inline PEResourceDir& operator = ( const PEResourceDir& right ) = delete;
@@ -1545,15 +1552,77 @@
15451552 // Helper API.
15461553 PEResourceItem* FindItem( bool isIdentifierName, const std::u16string& name, std::uint16_t identifier );
15471554
1555+ bool AddItem( PEResourceItem *theItem );
15481556 bool RemoveItem( const PEResourceItem *theItem );
1557+ bool IsEmpty( void ) const
1558+ {
1559+ return ( this->namedChildren.empty() && this->idChildren.empty() );
1560+ }
15491561
1562+ template <typename callbackType>
1563+ inline void ForAllChildren( callbackType& cb ) const
1564+ {
1565+ for ( const PEResourceItem *childItem : this->namedChildren )
1566+ {
1567+ cb( childItem, false );
1568+ }
1569+
1570+ for ( const PEResourceItem *childItem : this->idChildren )
1571+ {
1572+ cb( childItem, true );
1573+ }
1574+ }
1575+
15501576 std::uint32_t characteristics;
15511577 std::uint32_t timeDateStamp;
15521578 std::uint16_t majorVersion;
15531579 std::uint16_t minorVersion;
15541580
1581+ private:
1582+ struct _compareNamedEntry
1583+ {
1584+ inline bool operator() ( const PEResourceItem *left, const PEResourceItem *right ) const
1585+ {
1586+ return ( left->name < right->name );
1587+ }
1588+
1589+ inline bool operator() ( const std::u16string& left, const PEResourceItem *right ) const
1590+ {
1591+ return ( left < right->name );
1592+ }
1593+
1594+ inline bool operator() ( const PEResourceItem *left, const std::u16string& right ) const
1595+ {
1596+ return ( left->name < right );
1597+ }
1598+
1599+ typedef std::u16string is_transparent;
1600+ };
1601+
1602+ struct _compareIDEntry
1603+ {
1604+ inline bool operator() ( const PEResourceItem *left, const PEResourceItem *right ) const
1605+ {
1606+ return ( left->identifier < right->identifier );
1607+ }
1608+
1609+ inline bool operator() ( std::uint16_t left, const PEResourceItem *right ) const
1610+ {
1611+ return ( left < right->identifier );
1612+ }
1613+
1614+ inline bool operator() ( const PEResourceItem *left, std::uint16_t right ) const
1615+ {
1616+ return ( left->identifier < right );
1617+ }
1618+
1619+ typedef std::uint16_t is_transparent;
1620+ };
1621+
1622+ public:
15551623 // We contain named and id entries.
1556- std::vector <PEResourceItem*> children;
1624+ std::set <PEResourceItem*, _compareNamedEntry> namedChildren;
1625+ std::set <PEResourceItem*, _compareIDEntry> idChildren;
15571626 };
15581627 PEResourceDir resourceRoot;
15591628
--- src/peloader.write.cpp (revision 3)
+++ src/peloader.write.cpp (revision 4)
@@ -116,20 +116,18 @@
116116 std::uint32_t name_off; // Offset to the name string (unicode); only valid if child
117117 std::uint32_t dataitem_off; // Offset to the resource data item info; only valid if leaf
118118
119- std::unordered_map <size_t, item_allocInfo> children;
119+ std::unordered_map <const PEFile::PEResourceItem*, item_allocInfo> children;
120120 };
121121
122122 template <typename callbackType>
123123 static AINLINE void ForAllResourceItems( const PEFile::PEResourceDir& resDir, item_allocInfo& allocItem, callbackType& cb )
124124 {
125- size_t numChildren = resDir.children.size();
126-
127- for ( size_t n = 0; n < numChildren; n++ )
125+ // Named children.
126+ resDir.ForAllChildren(
127+ [&]( const PEFile::PEResourceItem *childItem, bool hasIdentiferName )
128128 {
129- const PEFile::PEResourceItem *childItem = resDir.children[ n ];
129+ auto& childAllocItemNode = allocItem.children.find( childItem );
130130
131- auto& childAllocItemNode = allocItem.children.find( n );
132-
133131 assert( childAllocItemNode != allocItem.children.end() );
134132
135133 item_allocInfo& childAllocItem = childAllocItemNode->second;
@@ -144,7 +142,7 @@
144142 // Now for all children.
145143 ForAllResourceItems( *childItemDir, childAllocItem, cb );
146144 }
147- }
145+ });
148146 }
149147
150148 };
@@ -674,8 +672,13 @@
674672 std::uint32_t itemSize = sizeof(PEStructures::IMAGE_RESOURCE_DIRECTORY);
675673
676674 // and the items following it.
677- std::uint32_t numChildren = (std::uint32_t)itemDir->children.size();
675+ size_t numNamedChildren = itemDir->namedChildren.size();
676+ size_t numIDChildren = itemDir->idChildren.size();
678677
678+ std::uint32_t numChildren =
679+ (std::uint32_t)numNamedChildren +
680+ (std::uint32_t)numIDChildren;
681+
679682 itemSize += numChildren * sizeof(PEStructures::IMAGE_RESOURCE_DIRECTORY_ENTRY);
680683
681684 infoOut.entry_off = allocMan.AllocateAny( itemSize, sizeof(std::uint32_t) );
@@ -682,13 +685,10 @@
682685
683686 // Now allocate all children aswell.
684687 // First allocate the named entries.
685- for ( size_t n = 0; n < numChildren; n++ )
688+ for ( const PEFile::PEResourceItem *childItem : itemDir->namedChildren )
686689 {
687- const PEResourceItem *childItem = itemDir->children[n];
690+ assert ( childItem->hasIdentifierName == false );
688691
689- if ( childItem->hasIdentifierName != false )
690- continue;
691-
692692 item_allocInfo childAlloc = AllocateResourceDirectory_dirData( allocMan, childItem );
693693
694694 // We allocate name strings later.
@@ -695,23 +695,20 @@
695695 childAlloc.name_off = 0;
696696
697697 // Register this child alloc item.
698- infoOut.children.insert( std::make_pair( n, std::move( childAlloc ) ) );
698+ infoOut.children.insert( std::make_pair( childItem, std::move( childAlloc ) ) );
699699 }
700700
701701 // Now allocate all ID based entries.
702- for ( size_t n = 0; n < numChildren; n++ )
702+ for ( const PEFile::PEResourceItem *childItem : itemDir->idChildren )
703703 {
704- const PEResourceItem *childItem = itemDir->children[n];
704+ assert( childItem->hasIdentifierName == true );
705705
706- if ( childItem->hasIdentifierName != true )
707- continue;
708-
709706 item_allocInfo childAlloc = AllocateResourceDirectory_dirData( allocMan, childItem );
710707
711708 // Not named.
712709 childAlloc.name_off = 0;
713710
714- infoOut.children.insert( std::make_pair( n, std::move( childAlloc ) ) );
711+ infoOut.children.insert( std::make_pair( childItem, std::move( childAlloc ) ) );
715712 }
716713 }
717714 else if ( itemType == PEResourceItem::eType::DATA )
@@ -779,6 +776,51 @@
779776 });
780777 }
781778
779+ static void WriteResourceDataItem( const PEResourceInfo *dataItem, const item_allocInfo& dataAllocInfo, PESectionAllocation& writeBuf )
780+ {
781+ // TODO: once we support injecting data buffers into the resource directory,
782+ // we will have to extend this with memory stream reading support.
783+
784+ std::uint32_t fileWriteOff = dataAllocInfo.dataitem_off;
785+
786+ assert( fileWriteOff != 0 ); // invalid because already taken by root directory info.
787+
788+ PEDataStream fileSrcStream = PEDataStream::fromDataRef( dataItem->sectRef );
789+
790+ // Write data over.
791+ const std::uint32_t fileDataSize = dataItem->sectRef.GetDataSize();
792+ {
793+ char buffer[ 0x4000 ];
794+
795+ std::uint32_t curDataOff = 0;
796+
797+ while ( curDataOff < fileDataSize )
798+ {
799+ std::uint32_t actualProcCount = std::min( fileDataSize - curDataOff, (std::uint32_t)sizeof(buffer) );
800+
801+ fileSrcStream.Read( buffer, actualProcCount );
802+
803+ writeBuf.WriteToSection( buffer, actualProcCount, fileWriteOff + curDataOff );
804+
805+ curDataOff += sizeof(buffer);
806+ }
807+ }
808+
809+ std::uint32_t dataEntryOff = dataAllocInfo.entry_off;
810+
811+ PEStructures::IMAGE_RESOURCE_DATA_ENTRY nativeDataEntry;
812+ // We need to write the RVA later.
813+ nativeDataEntry.OffsetToData = 0;
814+ writeBuf.RegisterTargetRVA( dataEntryOff + offsetof(PEStructures::IMAGE_RESOURCE_DATA_ENTRY, OffsetToData), writeBuf.GetSection(), writeBuf.ResolveInternalOffset( fileWriteOff ) );
815+ nativeDataEntry.Size = fileDataSize;
816+ nativeDataEntry.CodePage = dataItem->codePage;
817+ nativeDataEntry.Reserved = dataItem->reserved;
818+
819+ assert( dataAllocInfo.entry_off != 0 ); // invalid because zero is already taken by root directory.
820+
821+ writeBuf.WriteToSection( &nativeDataEntry, sizeof(nativeDataEntry), dataAllocInfo.entry_off );
822+ }
823+
782824 static void WriteResourceDirectory( const PEResourceDir& writeNode, const item_allocInfo& allocNode, PESectionAllocation& writeBuf )
783825 {
784826 PEStructures::IMAGE_RESOURCE_DIRECTORY nativeResDir;
@@ -787,30 +829,13 @@
787829 nativeResDir.MajorVersion = writeNode.majorVersion;
788830 nativeResDir.MinorVersion = writeNode.minorVersion;
789831
790- // Count how many named and how many ID children we have.
791- std::uint16_t numNamedEntries = 0;
792- std::uint16_t numIDEntries = 0;
832+ // Count how many named and how many children we have.
833+ size_t numNamedEntries = writeNode.namedChildren.size();
834+ size_t numIDEntries = writeNode.idChildren.size();
793835
794- std::uint32_t numChildren = (std::uint32_t)writeNode.children.size();
795- {
796- for ( size_t n = 0; n < numChildren; n++ )
797- {
798- const PEResourceItem *childItem = writeNode.children[ n ];
836+ nativeResDir.NumberOfNamedEntries = (std::uint16_t)numNamedEntries;
837+ nativeResDir.NumberOfIdEntries = (std::uint16_t)numIDEntries;
799838
800- if ( !childItem->hasIdentifierName )
801- {
802- numNamedEntries++;
803- }
804- else
805- {
806- numIDEntries++;
807- }
808- }
809- }
810-
811- nativeResDir.NumberOfNamedEntries = numNamedEntries;
812- nativeResDir.NumberOfIdEntries = numIDEntries;
813-
814839 const std::uint32_t dirWriteOff = allocNode.entry_off;
815840
816841 writeBuf.WriteToSection( &nativeResDir, sizeof(nativeResDir), allocNode.entry_off );
@@ -818,12 +843,13 @@
818843 // Now write all children.
819844 const std::uint32_t linkWriteOff = ( dirWriteOff + sizeof(nativeResDir) );
820845
821- for ( std::uint32_t n = 0; n < numChildren; n++ )
846+ // First all named ones.
847+ size_t writeIndex = 0;
848+
849+ for ( const PEResourceItem *childItem : writeNode.namedChildren )
822850 {
823- const PEResourceItem *childItem = writeNode.children[ n ];
851+ auto& childAllocInfoNode = allocNode.children.find( childItem );
824852
825- auto& childAllocInfoNode = allocNode.children.find( n );
826-
827853 assert( childAllocInfoNode != allocNode.children.end() );
828854
829855 const item_allocInfo& childAllocInfo = childAllocInfoNode->second;
@@ -832,7 +858,6 @@
832858 PEStructures::IMAGE_RESOURCE_DIRECTORY_ENTRY lnkEntry = { 0 };
833859
834860 // Write and register ID information, be it name or number.
835- if ( !childItem->hasIdentifierName )
836861 {
837862 lnkEntry.NameIsString = true;
838863
@@ -851,14 +876,7 @@
851876 // Give the offset.
852877 lnkEntry.NameOffset = childAllocInfo.name_off;
853878 }
854- else
855- {
856- lnkEntry.NameIsString = false;
857879
858- // Just write the ID.
859- lnkEntry.Id = childItem->identifier;
860- }
861-
862880 PEResourceItem::eType itemType = childItem->itemType;
863881
864882 // Give information about the child we are going to write.
@@ -865,10 +883,13 @@
865883 lnkEntry.DataIsDirectory = ( itemType == PEResourceItem::eType::DIRECTORY );
866884 lnkEntry.OffsetToDirectory = ( childAllocInfo.entry_off );
867885
868- const std::uint32_t lnkEntryOff = ( linkWriteOff + n * sizeof(lnkEntry) );
886+ const std::uint32_t lnkEntryOff = ( linkWriteOff + writeIndex * sizeof(lnkEntry) );
869887
870888 writeBuf.WriteToSection( &lnkEntry, sizeof(lnkEntry), lnkEntryOff );
871889
890+ // Advance the write index.
891+ writeIndex++;
892+
872893 if ( itemType == PEResourceItem::eType::DIRECTORY )
873894 {
874895 const PEResourceDir *childDir = (const PEResourceDir*)childItem;
@@ -880,48 +901,60 @@
880901 {
881902 const PEResourceInfo *childData = (const PEResourceInfo*)childItem;
882903
883- // TODO: once we support injecting data buffers into the resource directory,
884- // we will have to extend this with memory stream reading support.
904+ WriteResourceDataItem( childData, childAllocInfo, writeBuf );
905+ }
906+ else
907+ {
908+ assert( 0 );
909+ }
910+ }
885911
886- std::uint32_t fileWriteOff = childAllocInfo.dataitem_off;
912+ // Now all ID ones.
913+ for ( const PEResourceItem *childItem : writeNode.idChildren )
914+ {
915+ auto& childAllocInfoNode = allocNode.children.find( childItem );
887916
888- assert( fileWriteOff != 0 ); // invalid because already taken by root directory info.
917+ assert( childAllocInfoNode != allocNode.children.end() );
889918
890- PEDataStream fileSrcStream = PEDataStream::fromDataRef( childData->sectRef );
919+ const item_allocInfo& childAllocInfo = childAllocInfoNode->second;
891920
892- // Write data over.
893- const std::uint32_t fileDataSize = childData->sectRef.GetDataSize();
894- {
895- char buffer[ 0x4000 ];
921+ // We write a link entry for this child.
922+ PEStructures::IMAGE_RESOURCE_DIRECTORY_ENTRY lnkEntry = { 0 };
896923
897- std::uint32_t curDataOff = 0;
898-
899- while ( curDataOff < fileDataSize )
900- {
901- std::uint32_t actualProcCount = std::min( fileDataSize - curDataOff, (std::uint32_t)sizeof(buffer) );
924+ // Write and register ID information, be it name or number.
925+ {
926+ lnkEntry.NameIsString = false;
902927
903- fileSrcStream.Read( buffer, actualProcCount );
928+ // Just write the ID.
929+ lnkEntry.Id = childItem->identifier;
930+ }
904931
905- writeBuf.WriteToSection( buffer, actualProcCount, fileWriteOff + curDataOff );
932+ PEResourceItem::eType itemType = childItem->itemType;
906933
907- curDataOff += sizeof(buffer);
908- }
909- }
934+ // Give information about the child we are going to write.
935+ lnkEntry.DataIsDirectory = ( itemType == PEResourceItem::eType::DIRECTORY );
936+ lnkEntry.OffsetToDirectory = ( childAllocInfo.entry_off );
910937
911- std::uint32_t dataEntryOff = childAllocInfo.entry_off;
938+ const std::uint32_t lnkEntryOff = ( linkWriteOff + writeIndex * sizeof(lnkEntry) );
912939
913- PEStructures::IMAGE_RESOURCE_DATA_ENTRY nativeDataEntry;
914- // We need to write the RVA later.
915- nativeDataEntry.OffsetToData = 0;
916- writeBuf.RegisterTargetRVA( dataEntryOff + offsetof(PEStructures::IMAGE_RESOURCE_DATA_ENTRY, OffsetToData), writeBuf.GetSection(), writeBuf.ResolveInternalOffset( fileWriteOff ) );
917- nativeDataEntry.Size = fileDataSize;
918- nativeDataEntry.CodePage = childData->codePage;
919- nativeDataEntry.Reserved = childData->reserved;
940+ writeBuf.WriteToSection( &lnkEntry, sizeof(lnkEntry), lnkEntryOff );
920941
921- assert( childAllocInfo.entry_off != 0 ); // invalid because zero is already taken by root directory.
942+ // Advance the write index.
943+ writeIndex++;
922944
923- writeBuf.WriteToSection( &nativeDataEntry, sizeof(nativeDataEntry), childAllocInfo.entry_off );
945+ if ( itemType == PEResourceItem::eType::DIRECTORY )
946+ {
947+ const PEResourceDir *childDir = (const PEResourceDir*)childItem;
948+
949+ // Just recurse to write more data.
950+ WriteResourceDirectory( *childDir, childAllocInfo, writeBuf );
924951 }
952+ else if ( itemType == PEResourceItem::eType::DATA )
953+ {
954+ const PEResourceInfo *childData = (const PEResourceInfo*)childItem;
955+
956+ WriteResourceDataItem( childData, childAllocInfo, writeBuf );
957+ }
925958 else
926959 {
927960 assert( 0 );
--- src/peloader.read.cpp (revision 3)
+++ src/peloader.read.cpp (revision 4)
@@ -1179,8 +1179,6 @@
11791179 }
11801180 };
11811181
1182- curDir.children.reserve( numNamedEntries + numIDEntries );
1183-
11841182 // Due to us using only one PEDataStream we need to seek to all our entries properly.
11851183 std::uint32_t subDirStartOff = rootStream.Tell();
11861184
@@ -1216,7 +1214,16 @@
12161214 PEResourceItem *resItem = resDataParser( false, std::move( nameOfItem ), 0, namedEntry );
12171215
12181216 // Store ourselves.
1219- curDir.children.push_back( resItem );
1217+ try
1218+ {
1219+ curDir.namedChildren.insert( resItem );
1220+ }
1221+ catch( ... )
1222+ {
1223+ delete resItem;
1224+
1225+ throw;
1226+ }
12201227 }
12211228
12221229 for ( std::uint32_t n = 0; n < numIDEntries; n++ )
@@ -1238,7 +1245,16 @@
12381245 PEResourceItem *resItem = resDataParser( true, std::u16string(), idEntry.Id, idEntry );
12391246
12401247 // Store it.
1241- curDir.children.push_back( resItem );
1248+ try
1249+ {
1250+ curDir.idChildren.insert( resItem );
1251+ }
1252+ catch( ... )
1253+ {
1254+ delete resItem;
1255+
1256+ throw;
1257+ }
12421258 }
12431259
12441260 return curDir;
--- src/peloader.resource.cpp (revision 3)
+++ src/peloader.resource.cpp (revision 4)
@@ -6,20 +6,22 @@
66 // Generic finder routine.
77 PEFile::PEResourceItem* PEFile::PEResourceDir::FindItem( bool isIdentifierName, const std::u16string& name, std::uint16_t identifier )
88 {
9- for ( PEResourceItem *resItem : this->children )
9+ if ( isIdentifierName )
1010 {
11- if ( resItem->hasIdentifierName != isIdentifierName )
12- continue;
11+ auto findIter = this->idChildren.find( identifier );
1312
14- if ( !isIdentifierName )
13+ if ( findIter != this->idChildren.end() )
1514 {
16- if ( resItem->name == name )
17- return resItem;
15+ return *findIter;
1816 }
19- else
17+ }
18+ else
19+ {
20+ auto findIter = this->namedChildren.find( name );
21+
22+ if ( findIter != this->namedChildren.end() )
2023 {
21- if ( resItem->identifier == identifier )
22- return resItem;
24+ return *findIter;
2325 }
2426 }
2527
@@ -44,14 +46,44 @@
4446 }
4547 }
4648
49+bool PEFile::PEResourceDir::AddItem( PEFile::PEResourceItem *theItem )
50+{
51+ if ( theItem->hasIdentifierName )
52+ {
53+ this->idChildren.insert( theItem );
54+ }
55+ else
56+ {
57+ this->namedChildren.insert( theItem );
58+ }
59+
60+ return true;
61+}
62+
4763 bool PEFile::PEResourceDir::RemoveItem( const PEFile::PEResourceItem *theItem )
4864 {
49- auto findIter = std::find( this->children.begin(), this->children.end(), theItem );
65+ if ( theItem->hasIdentifierName )
66+ {
67+ auto findIter = this->idChildren.find( theItem );
5068
51- if ( findIter == this->children.end() )
52- return false;
69+ if ( findIter != this->idChildren.end() )
70+ {
71+ this->idChildren.erase( findIter );
72+
73+ return true;
74+ }
75+ }
76+ else
77+ {
78+ auto findIter = this->namedChildren.find( theItem );
5379
54- this->children.erase( findIter );
80+ if ( findIter != this->namedChildren.end() )
81+ {
82+ this->namedChildren.erase( findIter );
5583
56- return true;
84+ return true;
85+ }
86+ }
87+
88+ return false;
5789 }
\ No newline at end of file
Show on old repository browser