konrad-kruczynski / elfsharp

Pure managed C# library for reading ELF, UImage, Mach-O binaries.
https://elfsharp.it
Other
159 stars 57 forks source link

Fix macho64 Segment offset parsing error #66

Closed UlyssesWu closed 4 years ago

UlyssesWu commented 4 years ago
struct section_64 {
        char            sectname[16];
        char            segname[16];
        uint64_t        addr;
        uint64_t        size;
        uint32_t        offset;
        uint32_t        align;
        uint32_t        reloff;
        uint32_t        nreloc;
        uint32_t        flags;
        uint32_t        reserved1;
        uint32_t        reserved2;
        uint32_t        reserved3;
};

offset is always 4 bytes. The unfixed version may cause exception when using Section.GetData().

konrad-kruczynski commented 4 years ago

Hi @UlyssesWu ! These are really nice changes. Only some of the release-related stuff is missing. If you could:

the patch would be complete, ready to merge and release. If something is unclear, just ask. Once again thank you for your contribution.

konrad-kruczynski commented 4 years ago

Also, do you think you could cover the case with a unit test (or simply write a test scenario, so I'll be able to add a test easily)?

UlyssesWu commented 4 years ago

Just modified as you required.

As for the test, I'm unable to produce a test binary by myself, and I just grab a binary from http://johan.margueritte.free.fr/buildbot/ios-arm64/ .

You can test the file with the following code, the unfixed version throws a System.ArgumentOutOfRangeException:

    [TestFixture]
    class MachoArmTests
    {
        [Test]
        public static void ShouldFindSectionWithProperDataArm64()
        {
            var macho = MachOReader.Load(@"3dengine_libretro_ios.dylib");
            var segs = macho.GetCommandsOfType<Segment>();
            try
            {
                var textData = segs.FirstOrDefault(seg => seg.Name == "__TEXT")?.Sections.FirstOrDefault(sec => sec.Name == "__text")?.GetData();
            }
            catch (ArgumentOutOfRangeException e)
            {
                Assert.Fail(e.Message); //ArgumentOutOfRangeException since the offset is wrong parsed
            }
        }

        [Test]
        public static void ShouldFindSectionWithNoDataArm64()
        {
            var macho = MachOReader.Load(@"3dengine_libretro_ios.dylib");
            var segs = macho.GetCommandsOfType<Segment>();
            try
            {
                var textData = segs.FirstOrDefault(seg => seg.Name == "__DATA")?.Sections.FirstOrDefault(sec => sec.Name == "__bss")?.GetData();
            }
            catch (ArgumentOutOfRangeException e)
            {
                Assert.Fail(e.Message); //ArgumentOutOfRangeException since the offset is actually 0
            }
        }
    }

test-macho_thin-arm64_and_fat-arm64.zip

For now ElfSharp cannot handle "Fat header" mach-o file (header starts with CAFEBABE). In fact it's kind of difficult to find such a thin header mach-o file for this test.

The support for fat header mach-o should be implemented but that's another story. I also provided a fat header mach-o file getting from https://github.com/pwn20wndstuff/Undecimus/releases .

konrad-kruczynski commented 4 years ago

Great, I'm merging it now. I'll add test later on (probably next weekend). I'll also add a ticket for the fat header, thanks for your input in that matter.