1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
#pragma once
#include "machoview.h"
#include <functional>
#include <stdint.h>
#include <string_view>
#include <vector>
namespace BinaryNinja
{
enum class FixupType : uint8_t
{
Bind,
Rebase,
};
enum class AuthKeyType : uint8_t
{
IA,
IB,
DA,
DB,
None,
};
struct FixupInfo
{
union
{
struct
{
uint32_t ordinal = 0;
int32_t addend = 0;
} bind;
struct
{
uint64_t target = 0;
} rebase;
};
FixupType type : 1;
bool isAuthenticated : 1 = false;
AuthKeyType authKeyType : 3 = AuthKeyType::None;
bool usesAddressDiversity : 1 = false;
uint16_t addressDiversity = 0;
uint16_t next = 0;
};
struct ImportEntry
{
std::string_view name;
uint64_t addend;
int32_t libraryOrdinal;
bool weakImport = false;
};
class ChainedFixupProcessor
{
public:
ChainedFixupProcessor(Ref<BinaryView> raw, Ref<Logger> logger, uint64_t machOStartOffset, uint64_t preferredLoadAddress,
const linkedit_data_command& chainedFixupCommand, std::unordered_map<uint64_t, uint64_t> segmentVMAddrToFileOffset)
: m_raw(std::move(raw))
, m_logger(std::move(logger))
, m_machOStartOffset(machOStartOffset)
, m_fixupsStartOffset(OffsetInRaw(chainedFixupCommand.dataoff))
, m_fixupsSize(chainedFixupCommand.datasize)
, m_preferredLoadAddress(preferredLoadAddress)
, m_segmentVMAddrToFileOffset(std::move(segmentVMAddrToFileOffset))
{}
std::vector<ImportEntry> ProcessImports() const;
// Calls the provided handler for each fixup found. `offset` is relative to `machOStartOffset`.
//
// Note that `FixupInfo` references data owned by this object and so should not be used outside
// of the handler function.
void ProcessFixups(std::function<void(uint64_t offset, const FixupInfo&)> fixupHandler) const;
private:
dyld_chained_fixups_header ReadHeader(BinaryReader&) const;
void ProcessChainedFixups(const dyld_chained_fixups_header&, BinaryReader&) const;
void ProcessChainsInSegment(const dyld_chained_starts_in_segment&, BinaryReader&) const;
// Returns a vector of pairs of (page index, offset in page) representing the start of each fixup chain.
std::vector<std::pair<uint64_t, uint16_t>> ReadChainStartsInSegment(const dyld_chained_starts_in_segment&, BinaryReader&) const;
uint64_t OffsetInRaw(uint64_t offset) const { return m_machOStartOffset + offset; }
uint64_t OffsetInFixups(uint64_t offset) const { return m_fixupsStartOffset + offset; }
Ref<BinaryView> m_raw;
Ref<Logger> m_logger;
// Offset to the start of the Mach-O file within the BinaryView.
// This will be non-zero for Mach-O files within a universal binary.
uint64_t m_machOStartOffset;
// Offset to the start of the chained fixups data within the BinaryView.
uint64_t m_fixupsStartOffset;
// Total size of the chained fixups data.
uint64_t m_fixupsSize;
// The preferred load address of the __TEXT segment. Used for translating
// address-based fixups into offset-based fixups.
uint64_t m_preferredLoadAddress;
std::unordered_map<uint64_t, uint64_t> m_segmentVMAddrToFileOffset;
mutable std::function<void(uint64_t offset, const FixupInfo&)> m_fixupHandler;
mutable std::vector<char> m_symbolData;
};
} // namespace BinaryNinja
|