Buy Me a Coffee

Buy Me a Coffee!

Thursday, February 9, 2017

Reading Structured Binary files in C#: Part 5

The next step is to decode the Section Tables.  We get the number of tables from the COFF header, but all of the tables share the same format.  We only need to generate one new struct and then use a loop to pull out the sections.  Here is the loop:


                for (int i = 0; i < coffHeader.Value.NumberOfSections; i++)
                {

                    SectionTable?
                        sectionTable = inputFile.
                            ReadStructure<SectionTable>();
                    Console.WriteLine(
                        sectionTable.ToString());
                    sectionTables.Add(sectionTable.Value.Name, sectionTable);
                }

Here is the struct:


    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)]
    public struct SectionTable
    {
        [FieldOffset(0x0)]
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x8)]
        public string Name;

        [FieldOffset(0x8)]
        [MarshalAs(UnmanagedType.U4)]
        UInt32 VirtualSize;

        [FieldOffset(0xC)]
        [MarshalAs(UnmanagedType.U4)]
        UInt32 VirtualAddress;

        [FieldOffset(0x10)]
        [MarshalAs(UnmanagedType.U4)]
        UInt32 SizeOfRawData;

        [FieldOffset(0x14)]
        [MarshalAs(UnmanagedType.U4)]
        UInt32 PointerToRawData;

        [FieldOffset(0x18)]
        [MarshalAs(UnmanagedType.U4)]
        UInt32 PointerToRelocations;

        [FieldOffset(0x1C)]
        [MarshalAs(UnmanagedType.U4)]
        UInt32 PointerToLinenumbers;

        [FieldOffset(0x20)]
        [MarshalAs(UnmanagedType.U2)]
        UInt16 NumberOfRelocations;

        [FieldOffset(0x22)]
        [MarshalAs(UnmanagedType.U2)]
        UInt16 NumberOfLinenumbers;

        [FieldOffset(0x24)]
        [MarshalAs(UnmanagedType.U4)]
        UInt32 Characteristics;

        public override string ToString()
        {
            StringBuilder returnValue = new StringBuilder();
            returnValue.AppendFormat("Name: {0}", Name);
            returnValue.AppendLine();
            returnValue.AppendFormat("VirtualSize: {0}", VirtualSize);
            returnValue.AppendLine();
            returnValue.AppendFormat("VirtualAddress: 0x{0:X}",
                VirtualAddress);
            returnValue.AppendLine();
            returnValue.AppendFormat("SizeOfRawData: {0}", SizeOfRawData);
            returnValue.AppendLine();
            returnValue.AppendFormat("PointerToRawData: 0x{0:X}",
                PointerToRawData);
            returnValue.AppendLine();
            returnValue.AppendFormat("PointerToRelocations: 0x{0:X}",
                PointerToRelocations);
            returnValue.AppendLine();
            returnValue.AppendFormat("PointerToLinenumbers: 0x{0:X}",
                PointerToLinenumbers);
            returnValue.AppendLine();
            returnValue.AppendFormat("NumberOfRelocations: {0}",
                NumberOfRelocations);
            returnValue.AppendLine();
            returnValue.AppendFormat("NumberOfLinenumbers: {0}",
                NumberOfLinenumbers);
            returnValue.AppendLine();
            returnValue.AppendFormat("Characteristics: 0x{0:X}",
                Characteristics);
            returnValue.AppendLine();
            returnValue.AppendFormat("Characteristics (decoded): {0}",
                DecodeCharacteristics(Characteristics));
            returnValue.AppendLine();
            return returnValue.ToString();
        }

        private string DecodeCharacteristics(uint characteristics)
        {
            List<string> setCharacteristics = new List<string>();
            if ((characteristics == 0x00000000))
            {
                //                0x00000000  Reserved for future use.
                setCharacteristics.Add("Reserved flag set");
            }
            if ((characteristics & 0x00000001) != 0)
            {
                //                0x00000001  Reserved for future use.
                setCharacteristics.Add("Reserved flag set");
            }
            if ((characteristics & 0x00000002) != 0)
            {
                //                0x00000002  Reserved for future use.
                setCharacteristics.Add("Reserved flag set");
            }
            if ((characteristics & 0x00000004) != 0)
            {
                //                0x00000004  Reserved for future use.
                setCharacteristics.Add("Reserved flag set");
            }
            if ((characteristics & 0x00000008) != 0)
            {
                //IMAGE_SCN_TYPE_NO_PAD   0x00000008  The section should not
                //              be padded to the next boundary.This flag is
                //              obsolete and is replaced by
                //              IMAGE_SCN_ALIGN_1BYTES.This is valid only for
                //              object files.
                setCharacteristics.Add("IMAGE_SCN_TYPE_NO_PAD");
            }
            if ((characteristics & 0x00000010) != 0)
            {
                //  0x00000010  Reserved for future use.
                setCharacteristics.Add("Reserved flag set");
            }
            if ((characteristics & 0x00000020) != 0)
            {
                //IMAGE_SCN_CNT_CODE  0x00000020  The section contains
                //              executable code.
                setCharacteristics.Add("IMAGE_SCN_CNT_CODE");
            }
            if ((characteristics & 0x00000040) != 0)
            {
                //IMAGE_SCN_CNT_INITIALIZED_DATA  0x00000040  The section
                //              contains initialized data.
                setCharacteristics.Add("IMAGE_SCN_CNT_INITIALIZED_DATA");
            }
            if ((characteristics & 0x00000080) != 0)
            {
                //IMAGE_SCN_CNT_UNINITIALIZED_ DATA   0x00000080  The section
                //              contains uninitialized data.
                setCharacteristics.Add("IMAGE_SCN_CNT_UNINITIALIZED_DATA");
            }
            if ((characteristics & 0x00000100) != 0)
            {
                //IMAGE_SCN_LNK_OTHER 0x00000100  Reserved for future use.
                setCharacteristics.Add("IMAGE_SCN_LNK_OTHER");
            }
            if ((characteristics & 0x00000200) != 0)
            {
                //IMAGE_SCN_LNK_INFO  0x00000200  The section contains
                //              comments or other information.The.drectve
                //              section has this type.This is valid for object
                //              files only.
                setCharacteristics.Add("IMAGE_SCN_LNK_INFO");
            }
            if ((characteristics & 0x00000400) != 0)
            {
                // 0x00000400  Reserved for future use.
                setCharacteristics.Add("Reserved flag set");
            }
            if ((characteristics & 0x00000800) != 0)
            {
                //IMAGE_SCN_LNK_REMOVE    0x00000800  The section will not
                //              become part of the image.This is valid only
                //              for object files.
                setCharacteristics.Add("IMAGE_SCN_LNK_REMOVE");
            }
            if ((characteristics & 0x00001000) != 0)
            {
                //IMAGE_SCN_LNK_COMDAT    0x00001000  The section contains
                //              COMDAT data.For more information, see section
                //              5.5.6, “COMDAT Sections(Object Only).” This is
                //              valid only for object files.
                setCharacteristics.Add("IMAGE_SCN_LNK_COMDAT");
            }
            if ((characteristics & 0x00008000) != 0)
            {
                //IMAGE_SCN_GPREL 0x00008000  The section contains data
                //              referenced through the global pointer(GP).
                setCharacteristics.Add("IMAGE_SCN_GPREL");
            }
            if ((characteristics & 0x00020000) != 0)
            {
                //IMAGE_SCN_MEM_PURGEABLE 0x00020000  Reserved for future use.
                setCharacteristics.Add("IMAGE_SCN_MEM_PURGEABLE");
            }
            if ((characteristics & 0x00020000) != 0)
            {
                //IMAGE_SCN_MEM_16BIT 0x00020000  Reserved for future use.
                setCharacteristics.Add("IMAGE_SCN_MEM_16BIT");
            }
            if ((characteristics & 0x00040000) != 0)
            {
                //IMAGE_SCN_MEM_LOCKED    0x00040000  Reserved for future use.
                setCharacteristics.Add("IMAGE_SCN_MEM_LOCKED");
            }
            if ((characteristics & 0x00080000) != 0)
            {
                //IMAGE_SCN_MEM_PRELOAD   0x00080000  Reserved for future
                //              use.
                setCharacteristics.Add("IMAGE_SCN_MEM_PRELOAD");
            }
            if ((characteristics & 0x00100000) != 0)
            {
                //IMAGE_SCN_ALIGN_1BYTES  0x00100000  Align data on a 1 -
                //              byte boundary.Valid only for object files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_1BYTES");
            }
            if ((characteristics & 0x00200000) != 0)
            {
                //IMAGE_SCN_ALIGN_2BYTES  0x00200000  Align data on a 2 -
                //              byte boundary.Valid only for object files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_2BYTES");
            }
            if ((characteristics & 0x00300000) != 0)
            {
                //IMAGE_SCN_ALIGN_4BYTES  0x00300000  Align data on a 4 -
                //              byte boundary.Valid only for object files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_4BYTES");
            }
            if ((characteristics & 0x00400000) != 0)
            {
                //IMAGE_SCN_ALIGN_8BYTES  0x00400000  Align data on an 8 -
                //              byte boundary.Valid only for object files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_8BYTES");
            }
            if ((characteristics & 0x00500000) != 0)
            {
                //IMAGE_SCN_ALIGN_16BYTES 0x00500000  Align data on a 16 -
                //              byte boundary.Valid only for object files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_16BYTES");
            }
            if ((characteristics & 0x00600000) != 0)
            {
                //IMAGE_SCN_ALIGN_32BYTES 0x00600000  Align data on a 32 -
                //              byte boundary.Valid only for object files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_32BYTES");
            }
            if ((characteristics & 0x00700000) != 0)
            {
                //IMAGE_SCN_ALIGN_64BYTES 0x00700000  Align data on a 64 -
                //              byte boundary.Valid only for object files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_64BYTES");
            }
            if ((characteristics & 0x00800000) != 0)
            {
                //IMAGE_SCN_ALIGN_128BYTES    0x00800000  Align data on a
                //              128 - byte boundary.Valid only for object
                //              files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_128BYTES");
            }
            if ((characteristics & 0x00900000) != 0)
            {
                //IMAGE_SCN_ALIGN_256BYTES    0x00900000  Align data on a
                //              256 - byte boundary.Valid only for object
                //              files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_256BYTES");
            }
            if ((characteristics & 0x00A00000) != 0)
            {
                //IMAGE_SCN_ALIGN_512BYTES    0x00A00000  Align data on a
                //              512 - byte boundary.Valid only for object
                //              files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_512BYTES");
            }
            if ((characteristics & 0x00B00000) != 0)
            {
                //IMAGE_SCN_ALIGN_1024BYTES   0x00B00000  Align data on a
                //              1024 - byte boundary.Valid only for object
                //              files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_1024BYTES");
            }
            if ((characteristics & 0x00C00000) != 0)
            {
                //IMAGE_SCN_ALIGN_2048BYTES   0x00C00000  Align data on a
                //              2048 - byte boundary.Valid only for object
                //              files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_2048BYTES");
            }
            if ((characteristics & 0x00D00000) != 0)
            {
                //IMAGE_SCN_ALIGN_4096BYTES   0x00D00000  Align data on a
                //              4096 - byte boundary.Valid only for object
                //              files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_4096BYTES");
            }
            if ((characteristics & 0x00E00000) != 0)
            {
                //IMAGE_SCN_ALIGN_8192BYTES   0x00E00000  Align data on an
                //              8192 - byte boundary.Valid only for object
                //              files.
                setCharacteristics.Add("IMAGE_SCN_ALIGN_8192BYTES");
            }
            if ((characteristics & 0x01000000) != 0)
            {
                //IMAGE_SCN_LNK_NRELOC_OVFL   0x01000000  The section
                //              contains extended relocations.
                setCharacteristics.Add("IMAGE_SCN_LNK_NRELOC_OVFL");
            }
            if ((characteristics & 0x02000000) != 0)
            {
                // IMAGE_SCN_MEM_DISCARDABLE   0x02000000  The section can
                //              be discarded as needed.
                setCharacteristics.Add("IMAGE_SCN_MEM_DISCARDABLE");
            }
            if ((characteristics & 0x04000000) != 0)
            {
                // IMAGE_SCN_MEM_NOT_CACHED    0x04000000  The section
                //              cannot be cached.
                setCharacteristics.Add("IMAGE_SCN_MEM_NOT_CACHED");
            }
            if ((characteristics & 0x08000000) != 0)
            {
                // IMAGE_SCN_MEM_NOT_PAGED 0x08000000  The section is not
                //              pageable.
                setCharacteristics.Add("IMAGE_SCN_MEM_NOT_PAGED");
            }
            if ((characteristics & 0x10000000) != 0)
            {
                // IMAGE_SCN_MEM_SHARED    0x10000000  The section can be
                //              shared in memory.
                setCharacteristics.Add("IMAGE_SCN_MEM_SHARED");
            }
            if ((characteristics & 0x20000000) != 0)
            {
                // IMAGE_SCN_MEM_EXECUTE   0x20000000  The section can be
                //              executed as code.
                setCharacteristics.Add("IMAGE_SCN_MEM_EXECUTE");
            }
            if ((characteristics & 0x40000000) != 0)
            {
                // IMAGE_SCN_MEM_READ  0x40000000  The section can be read.
                setCharacteristics.Add("IMAGE_SCN_MEM_READ");
            }
            if ((characteristics & 0x80000000) != 0)
            {
                // IMAGE_SCN_MEM_WRITE 0x80000000  The section can be
                //              written to.
                setCharacteristics.Add("IMAGE_SCN_MEM_WRITE");
            }
            return string.Join(",", setCharacteristics);
        }
    }

And here is the output of the new portion of the code:

Name: .text
VirtualSize: 948
VirtualAddress: 0x2000
SizeOfRawData: 1024
PointerToRawData: 0x200
PointerToRelocations: 0x0
PointerToLinenumbers: 0x0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
Characteristics: 0x60000020
Characteristics (decoded): IMAGE_SCN_CNT_CODE,IMAGE_SCN_MEM_EXECUTE,IMAGE_SCN_ME
M_READ

Name: .rsrc
VirtualSize: 720
VirtualAddress: 0x4000
SizeOfRawData: 1024
PointerToRawData: 0x600
PointerToRelocations: 0x0
PointerToLinenumbers: 0x0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
Characteristics: 0x40000040
Characteristics (decoded): IMAGE_SCN_CNT_INITIALIZED_DATA,IMAGE_SCN_MEM_READ

Name: .reloc
VirtualSize: 12
VirtualAddress: 0x6000
SizeOfRawData: 512
PointerToRawData: 0xA00
PointerToRelocations: 0x0
PointerToLinenumbers: 0x0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
Characteristics: 0x42000040
Characteristics (decoded): IMAGE_SCN_CNT_INITIALIZED_DATA,IMAGE_SCN_MEM_DISCARDA
BLE,IMAGE_SCN_MEM_READ

Press return to exit

The code is getting longer, so the next post will be about creating an open source project on GitHub. I am going to release it under the MIT license. That way you can try it out yourself, and perhaps help me build something interesting.
Keep coding!