#ifndef _H_MACHOPLUSPLUS
#define _H_MACHOPLUSPLUS
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach-o/arch.h>
#include <security_utilities/globalizer.h>
#include <security_utilities/endian.h>
#include <security_utilities/unix++.h>
#include <security_utilities/cfutilities.h>
#include <map>
namespace Security {
class Architecture : public std::pair<cpu_type_t, cpu_subtype_t> {
typedef std::pair<cpu_type_t, cpu_subtype_t> _Pair;
public:
Architecture() { }
explicit Architecture(cpu_type_t type, cpu_subtype_t sub = CPU_SUBTYPE_MULTIPLE)
: std::pair<cpu_type_t, cpu_subtype_t>(type, sub) { }
Architecture(const fat_arch &archInFile);
Architecture(const char *name);
cpu_type_t cpuType() const { return this->first; }
cpu_subtype_t cpuSubtype() const { return this->second; }
const char *name() const; std::string displayName() const;
static const cpu_type_t none = 0;
operator bool () const { return cpuType() != none; }
bool operator ! () const { return cpuType() == none; }
public:
friend bool operator == (const Architecture &a1, const Architecture &a2)
{ return _Pair(a1) == _Pair(a2); }
friend bool operator < (const Architecture &a1, const Architecture &a2)
{ return _Pair(a1) < _Pair(a2); }
bool matches(const Architecture &templ) const;
public:
static Architecture local();
};
class MachOBase {
protected:
virtual ~MachOBase();
public:
template <class T>
T flip(T value) const
{ return mFlip ? Security::flip(value) : value; }
bool isFlipped() const { return mFlip; }
bool is64() const { return m64; }
const mach_header &header() const { return *mHeader; }
Architecture architecture() const;
uint32_t type() const;
uint32_t flags() const;
const load_command *loadCommands() const { return mCommands; }
const load_command *nextCommand(const load_command *command) const;
size_t commandLength() const { return flip(mHeader->sizeofcmds); }
const load_command *findCommand(uint32_t cmd) const;
const segment_command *findSegment(const char *segname) const;
const section *findSection(const char *segname, const char *sectname) const;
const char *string(const load_command *cmd, const lc_str &str) const;
const linkedit_data_command *findCodeSignature() const;
const linkedit_data_command *findLibraryDependencies() const;
const version_min_command *findMinVersion() const;
size_t signingOffset() const; size_t signingLength() const;
protected:
void initHeader(const mach_header *address);
void initCommands(const load_command *commands);
size_t headerSize() const; size_t commandSize() const;
private:
const mach_header *mHeader; const load_command *mCommands; const load_command *mEndCommands;
bool m64; bool mFlip; };
class MachO : public MachOBase, public UnixPlusPlus::FileDesc {
public:
MachO(FileDesc fd, size_t offset = 0, size_t length = 0);
~MachO();
size_t offset() const { return mOffset; }
size_t length() const { return mLength; }
size_t signingExtent() const;
void seek(size_t offset); CFDataRef dataAt(size_t offset, size_t size);
void validateStructure();
bool isSuspicious() const { return mSuspicious; }
private:
size_t mOffset; size_t mLength;
mach_header mHeaderBuffer; load_command *mCommandBuffer;
bool mSuspicious; };
class MachOImage : public MachOBase {
public:
MachOImage(const void *address);
const void *address() { return &this->header(); }
};
class MainMachOImage : public MachOImage {
public:
MainMachOImage();
static const void *mainImageAddress();
};
class Universal : public UnixPlusPlus::FileDesc {
public:
Universal(FileDesc fd, size_t offset = 0, size_t length = 0);
~Universal();
MachO *architecture() const; MachO *architecture(const Architecture &arch) const; MachO *architecture(size_t offset) const;
size_t archOffset() const; size_t archOffset(const Architecture &arch) const; size_t archLength(const Architecture &arch) const; bool narrowed() const { return mBase != 0; }
typedef std::set<Architecture> Architectures;
void architectures(Architectures &archs) const;
bool isUniversal() const { return mArchList != NULL; }
Architecture bestNativeArch() const;
size_t lengthOfSlice(size_t offset) const;
size_t offset() const { return mBase; }
size_t length() const { return mLength; }
bool isSuspicious() const;
public:
static uint32_t typeOf(FileDesc fd);
private:
const fat_arch *findArch(const Architecture &arch) const;
MachO *findImage(const Architecture &arch) const;
MachO *make(MachO* macho) const;
private:
fat_arch *mArchList; unsigned mArchCount; Architecture mThinArch; size_t mBase; size_t mLength; typedef std::map<size_t, size_t> OffsetsToLength;
OffsetsToLength mSizes; mutable uint32_t mMachType; bool mSuspicious; };
}
#endif // !_H_MACHOPLUSPLUS