-Improved parsing files with thousands of sections. Sections that appear to be invalid will now be ignored and some of the checks have been optimized for the cases where a file still has many possibly valid sections.

git-svn-id: http://pefile.googlecode.com/svn/trunk@125 8842bc4e-7134-0410-8230-5dc5194fb5c1
diff --git a/pefile.py b/pefile.py
index 1b9b172..219c91a 100644
--- a/pefile.py
+++ b/pefile.py
@@ -1053,12 +1053,13 @@
         VirtualAddress_adj = self.pe.adjust_SectionAlignment( self.VirtualAddress,
             self.pe.OPTIONAL_HEADER.SectionAlignment, self.pe.OPTIONAL_HEADER.FileAlignment )
 
-        # Check if there's any further section that will start before the
-        # calculated end for the current one, if so cut the current's size
-        # to fit in the range until the next one starts.
-        for s in self.pe.sections:
-            if s.VirtualAddress > self.VirtualAddress and VirtualAddress_adj + size > s.VirtualAddress:
-                    size = s.VirtualAddress - VirtualAddress_adj
+        # Check whether there's any section after the current one that starts before the
+        # calculated end for the current one, if so, cut the current section's size
+        # to fit in the range up to where the next section starts.
+        if (self.next_section_virtual_address is not None and
+            self.next_section_virtual_address > self.VirtualAddress and
+            VirtualAddress_adj + size > self.next_section_virtual_address):
+                size = self.next_section_virtual_address - VirtualAddress_adj
 
         return VirtualAddress_adj <= rva < VirtualAddress_adj + size
 
@@ -1068,12 +1069,6 @@
         return self.contains_rva(rva)
 
 
-    #def set_data(self, data):
-    #    """Set the data belonging to the section."""
-    #
-    #    self.data = data
-
-
     def get_entropy(self):
         """Calculate and return the entropy for the section."""
 
@@ -1129,12 +1124,13 @@
 
 
 
-class DataContainer:
+class DataContainer(object):
     """Generic data container."""
 
     def __init__(self, **args):
+        bare_setattr = super(DataContainer, self).__setattr__
         for key, value in args.items():
-            setattr(self, key, value)
+            bare_setattr(key, value)
 
 
 
@@ -2203,11 +2199,17 @@
                 self.__warnings.append(
                     ('Error parsing section %d. ' % i) +
                     'PointerToRawData points beyond the end of the file.')
+                # Skip these. If we can't get to the raw data it will likely not be a
+                # real section.
+                continue
 
             if section.Misc_VirtualSize > 0x10000000:
                 self.__warnings.append(
                     ('Suspicious value found parsing section %d. ' % i) +
                     'VirtualSize is extremely large > 256MiB.')
+                # Skip these. It will likely not be a real section.
+                continue
+
 
             if self.adjust_SectionAlignment( section.VirtualAddress,
                 self.OPTIONAL_HEADER.SectionAlignment, self.OPTIONAL_HEADER.FileAlignment ) > 0x10000000:
@@ -2254,8 +2256,19 @@
                         'Both IMAGE_SCN_MEM_WRITE and IMAGE_SCN_MEM_EXECUTE are set. ' +
                         'This might indicate a packed executable.')
 
+
             self.sections.append(section)
 
+        # Sort the sections by their VirtualAddress and add a field to each of them
+        # with the VirtualAddress of the next section. This will allow to check
+        # for potentially overlapping sections in badly constructed PEs.
+        self.sections.sort(cmp=lambda a,b: cmp(a.VirtualAddress, b.VirtualAddress))
+        for idx, section in enumerate(self.sections):
+            if idx == len(self.sections)-1:
+                section.next_section_virtual_address = None
+            else:
+                section.next_section_virtual_address = self.sections[idx+1].VirtualAddress
+
         if self.FILE_HEADER.NumberOfSections > 0 and self.sections:
             return offset + self.sections[0].sizeof()*self.FILE_HEADER.NumberOfSections
         else:
@@ -3754,7 +3767,7 @@
         ImageBase+offset.
 
         The optional argument 'max_virtual_address' provides with means of limiting
-        which section are processed.
+        which sections are processed.
         Any section with their VirtualAddress beyond this value will be skipped.
         Normally, sections with values beyond this range are just there to confuse
         tools. It's a common trick to see in packed executables.