@@ -1744,6 +1744,12 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
17441744 semantics = ReadWriteDataSectionSemantics;
17451745 if (strncmp (header.sections [i].segname , " __DATA_CONST" , sizeof (header.sections [i].segname )) == 0 )
17461746 semantics = ReadOnlyDataSectionSemantics;
1747+ if (strncmp (header.sections [i].sectname , " __chain_starts" , sizeof (header.sections [i].sectname )) == 0
1748+ && header.sections [i].size < UINT32_MAX)
1749+ {
1750+ header.chainStartsPresent = true ;
1751+ header.chainStarts = header.sections [i];
1752+ }
17471753
17481754 AddAutoSection (header.sectionNames [i], header.sections [i].addr , header.sections [i].size , semantics, type, header.sections [i].align );
17491755 }
@@ -2855,6 +2861,11 @@ void MachoView::ParseSymbolTable(BinaryReader& reader, MachOHeader& header, cons
28552861 m_logger->LogDebug (" Chained Fixups" );
28562862 ParseChainedFixups (header, header.chainedFixups );
28572863 }
2864+ else if (header.chainStartsPresent )
2865+ {
2866+ m_logger->LogDebug (" Chained Starts" );
2867+ ParseChainedStarts (header, header.chainStarts );
2868+ }
28582869 if (header.exportTriePresent && header.isMainHeader )
28592870 ParseExportTrie (reader, header.exportTrie );
28602871
@@ -3452,6 +3463,195 @@ void MachoView::ParseChainedFixups(MachOHeader& header, linkedit_data_command ch
34523463}
34533464
34543465
3466+ void MachoView::ParseChainedStarts (MachOHeader& header, section_64 chainedStarts)
3467+ {
3468+ if (!chainedStarts.offset )
3469+ return ;
3470+
3471+ m_logger->LogDebug (" Processing Chained Starts" );
3472+
3473+ // Dummy relocation
3474+ BNRelocationInfo reloc;
3475+ memset (&reloc, 0 , sizeof (BNRelocationInfo));
3476+ reloc.type = StandardRelocationType;
3477+ reloc.size = m_addressSize;
3478+ reloc.nativeType = BINARYNINJA_MANUAL_RELOCATION;
3479+
3480+ bool processBinds = true ;
3481+
3482+ BinaryReader parentReader (GetParentView ());
3483+ BinaryReader mappedReader (this );
3484+
3485+ try {
3486+ uint64_t fixupHeaderAddress = m_universalImageOffset + chainedStarts.offset ;
3487+ parentReader.Seek (fixupHeaderAddress);
3488+
3489+ uint32_t pointerFormat = parentReader.Read32 ();
3490+ uint32_t startsCount = parentReader.Read32 ();
3491+ std::vector<uint32_t > startsOffsets;
3492+ for (size_t i = 0 ; i < startsCount; i++)
3493+ {
3494+ startsOffsets.push_back (parentReader.Read32 ());
3495+ }
3496+
3497+ uint8_t strideSize;
3498+ ChainedFixupPointerGeneric format;
3499+
3500+ // Firmware formats will require digging up whatever place they're being used and reversing it.
3501+ // They are not handled by dyld.
3502+ switch (pointerFormat) {
3503+ case DYLD_CHAINED_PTR_ARM64E:
3504+ case DYLD_CHAINED_PTR_ARM64E_USERLAND:
3505+ case DYLD_CHAINED_PTR_ARM64E_USERLAND24:
3506+ strideSize = 8 ;
3507+ format = GenericArm64eFixupFormat;
3508+ break ;
3509+ case DYLD_CHAINED_PTR_ARM64E_KERNEL:
3510+ strideSize = 4 ;
3511+ format = GenericArm64eFixupFormat;
3512+ break ;
3513+ // case DYLD_CHAINED_PTR_ARM64E_FIRMWARE: Unsupported.
3514+ case DYLD_CHAINED_PTR_64:
3515+ case DYLD_CHAINED_PTR_64_OFFSET:
3516+ case DYLD_CHAINED_PTR_64_KERNEL_CACHE:
3517+ strideSize = 4 ;
3518+ format = Generic64FixupFormat;
3519+ break ;
3520+ case DYLD_CHAINED_PTR_32:
3521+ case DYLD_CHAINED_PTR_32_CACHE:
3522+ strideSize = 4 ;
3523+ format = Generic32FixupFormat;
3524+ break ;
3525+ case DYLD_CHAINED_PTR_32_FIRMWARE:
3526+ strideSize = 4 ;
3527+ format = Firmware32FixupFormat;
3528+ break ;
3529+ case DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE:
3530+ strideSize = 1 ;
3531+ format = Generic64FixupFormat;
3532+ break ;
3533+ default :
3534+ {
3535+ m_logger->LogError (" Chained Starts: Unknown or unsupported pointer format %d, "
3536+ " unable to process chain starts" , pointerFormat);
3537+ return ;
3538+ }
3539+ }
3540+
3541+ for (uint32_t offset : startsOffsets)
3542+ {
3543+ uint64_t chainEntryAddress = m_universalImageOffset + offset;
3544+
3545+ bool fixupsDone = false ;
3546+
3547+ while (!fixupsDone)
3548+ {
3549+ ChainedFixupPointer pointer;
3550+ parentReader.Seek (chainEntryAddress);
3551+ mappedReader.Seek (chainEntryAddress - m_universalImageOffset + GetStart ());
3552+ if (format == Generic32FixupFormat || format == Firmware32FixupFormat)
3553+ pointer.raw32 = (uint32_t )(uintptr_t )mappedReader.Read32 ();
3554+ else
3555+ pointer.raw64 = (uintptr_t )mappedReader.Read64 ();
3556+
3557+ bool bind = false ;
3558+ uint64_t nextEntryStrideCount;
3559+
3560+ switch (format)
3561+ {
3562+ case Generic32FixupFormat:
3563+ bind = pointer.generic32 .bind .bind ;
3564+ nextEntryStrideCount = pointer.generic32 .rebase .next ;
3565+ break ;
3566+ case Generic64FixupFormat:
3567+ bind = pointer.generic64 .bind .bind ;
3568+ nextEntryStrideCount = pointer.generic64 .rebase .next ;
3569+ break ;
3570+ case GenericArm64eFixupFormat:
3571+ bind = pointer.arm64e .bind .bind ;
3572+ nextEntryStrideCount = pointer.arm64e .rebase .next ;
3573+ break ;
3574+ case Firmware32FixupFormat:
3575+ nextEntryStrideCount = pointer.firmware32 .next ;
3576+ bind = false ;
3577+ break ;
3578+ }
3579+
3580+ m_logger->LogTrace (" Chained Starts: @ 0x%llx ( 0x%llx ) - %d 0x%llx" , chainEntryAddress,
3581+ GetStart () + (chainEntryAddress - m_universalImageOffset),
3582+ bind, nextEntryStrideCount);
3583+
3584+ if (bind && processBinds)
3585+ {
3586+ m_logger->LogWarn (" Chained Starts: Bind pointers not supported in Chained Starts" );
3587+ chainEntryAddress += (nextEntryStrideCount * strideSize);
3588+ if (nextEntryStrideCount == 0 )
3589+ fixupsDone = true ;
3590+ continue ;
3591+ }
3592+ else if (!bind)
3593+ {
3594+ uint64_t entryOffset;
3595+ switch (pointerFormat)
3596+ {
3597+ case DYLD_CHAINED_PTR_ARM64E:
3598+ case DYLD_CHAINED_PTR_ARM64E_KERNEL:
3599+ case DYLD_CHAINED_PTR_ARM64E_USERLAND:
3600+ case DYLD_CHAINED_PTR_ARM64E_USERLAND24:
3601+ {
3602+ if (pointer.arm64e .bind .auth )
3603+ entryOffset = pointer.arm64e .authRebase .target ;
3604+ else
3605+ entryOffset = pointer.arm64e .rebase .target ;
3606+
3607+ if ( pointerFormat != DYLD_CHAINED_PTR_ARM64E || pointer.arm64e .bind .auth )
3608+ entryOffset += GetStart ();
3609+
3610+ break ;
3611+ }
3612+ case DYLD_CHAINED_PTR_64:
3613+ entryOffset = pointer.generic64 .rebase .target ;
3614+ break ;
3615+ case DYLD_CHAINED_PTR_64_OFFSET:
3616+ entryOffset = pointer.generic64 .rebase .target + GetStart ();
3617+ break ;
3618+ case DYLD_CHAINED_PTR_64_KERNEL_CACHE:
3619+ case DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE:
3620+ entryOffset = pointer.kernel64 .target ;
3621+ break ;
3622+ case DYLD_CHAINED_PTR_32:
3623+ case DYLD_CHAINED_PTR_32_CACHE:
3624+ entryOffset = pointer.generic32 .rebase .target ;
3625+ break ;
3626+ case DYLD_CHAINED_PTR_32_FIRMWARE:
3627+ entryOffset = pointer.firmware32 .target ;
3628+ break ;
3629+ }
3630+
3631+ reloc.address = GetStart () + (chainEntryAddress - m_universalImageOffset);
3632+ DefineRelocation (m_arch, reloc, entryOffset, reloc.address );
3633+ m_logger->LogDebug (" Chained Starts: Adding relocated pointer %llx -> %llx" , reloc.address , entryOffset);
3634+
3635+ if (m_objcProcessor)
3636+ {
3637+ m_objcProcessor->AddRelocatedPointer (reloc.address , entryOffset);
3638+ }
3639+ }
3640+
3641+ chainEntryAddress += (nextEntryStrideCount * strideSize);
3642+
3643+ if (nextEntryStrideCount == 0 )
3644+ fixupsDone = true ;
3645+ }
3646+ }
3647+ }
3648+ catch (ReadException&)
3649+ {
3650+ m_logger->LogError (" Chained Starts parsing failed" );
3651+ }
3652+ }
3653+
3654+
34553655uint64_t MachoView::PerformGetEntryPoint () const
34563656{
34573657 if (m_header.m_entryPoints .size () == 0 )
0 commit comments