You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/* * The following functions allow you to iterate through all loaded images. * This is not a thread safe operation. Another thread can add or remove * an image during the iteration. * * Many uses of these routines can be replace by a call to dladdr() which * will return the mach_header and name of an image, given an address in * the image. dladdr() is thread safe. */externuint32_t_dyld_image_count(void) __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
externconststructmach_header*_dyld_get_image_header(uint32_timage_index) __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
externintptr_t_dyld_get_image_vmaddr_slide(uint32_timage_index) __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
externconstchar*_dyld_get_image_name(uint32_timage_index) __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
On Linux, dlopen doesn't return the address where the ELF binary was loaded. It returns struct link_map instead, which has .l_addr member. So you'll want something like:
However, despite what comment in /usr/include/link.h says, .l_addr is actually not a load address either. Instead, it's the difference between where ELF image was linked to load, and where it was actually loaded.
struct link_map
{
/* These first few members are part of the protocol with the debugger.
This is the same format used in SVR4. */
ElfW(Addr) l_addr; /* Difference between the address in the ELF
file and the addresses in memory. */
char *l_name; /* Absolute file name object was found in. */
ElfW(Dyn) *l_ld; /* Dynamic section of the shared object. */
struct link_map *l_next, *l_prev; /* Chain of loaded objects. */
};
这里我们简单的复制此关键部分,并修改为
struct link_map
{
/* These first few members are part of the protocol with the debugger.
This is the same format used in SVR4. */
void l_addr; /* Difference between the address in the ELF
file and the addresses in memory. */
char *l_name; /* Absolute file name object was found in. */
void*l_ld; /* Dynamic section of the shared object. */
struct link_map *l_next, *l_prev; /* Chain of loaded objects. */
};
structsoinfo {
public:
charname[SOINFO_NAME_LEN];
constElf32_Phdr*phdr;
size_tphnum;
Elf32_Addrentry;
Elf32_Addrbase;
unsignedsize;
uint32_tunused1; // DO NOT USE, maintained for compatibility.Elf32_Dyn*dynamic;
uint32_tunused2; // DO NOT USE, maintained for compatibilityuint32_tunused3; // DO NOT USE, maintained for compatibilitysoinfo*next;
unsignedflags;
constchar*strtab;
Elf32_Sym*symtab;
size_tnbucket;
size_tnchain;
unsigned*bucket;
unsigned*chain;
unsigned*plt_got;
Elf32_Rel*plt_rel;
size_tplt_rel_count;
Elf32_Rel*rel;
size_trel_count;
linker_function_t*preinit_array;
size_tpreinit_array_count;
linker_function_t*init_array;
size_tinit_array_count;
linker_function_t*fini_array;
size_tfini_array_count;
linker_function_tinit_func;
linker_function_tfini_func;
#if defined(ANDROID_ARM_LINKER)
// ARM EABI section used for stack unwinding.unsigned*ARM_exidx;
size_tARM_exidx_count;
#elif defined(ANDROID_MIPS_LINKER)
unsignedmips_symtabno;
unsignedmips_local_gotno;
unsignedmips_gotsym;
#endifsize_tref_count;
link_map_tlink_map;
boolconstructors_called;
// When you read a virtual address from the ELF file, add this// value to get the corresponding address in the process' address space.Elf32_Addrload_bias;
boolhas_text_relocations;
boolhas_DT_SYMBOLIC;
voidCallConstructors();
voidCallDestructors();
voidCallPreInitConstructors();
private:
voidCallArray(constchar*array_name, linker_function_t*functions, size_tcount, boolreverse);
voidCallFunction(constchar*function_name, linker_function_tfunction);
};
/* * The value of the link editor defined symbol _MH_DYLIB_SYM is the address * of the mach header in a Mach-O dylib file type. It does not appear in * any file type other than a MH_DYLIB file type. The type of the symbol is * an N_SECT symbol even thought the header is not part of any section. This * symbol is private to the code in the library it is a part of. */#define_MH_DYLIB_SYM "__mh_dylib_header"
#defineMH_DYLIB_SYM "_mh_dylib_header"
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * * Copyright (c) 2004-2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@*/
#ifndef __IMAGELOADER__
#define__IMAGELOADER__
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<mach/mach_time.h>// struct mach_timebase_info
#include<mach/mach_init.h>// struct mach_thread_self
#include<mach/shared_region.h>
#include<mach-o/loader.h>
#include<mach-o/nlist.h>
#include<stdint.h>
#include<stdlib.h>
#include<TargetConditionals.h>
#include<vector>
#include<new>
#include<uuid/uuid.h>
#if __arm__
#include<mach/vm_page_size.h>
#endif
#if __x86_64__ || __i386__
#include<CrashReporterClient.h>
#else// work around until iOS has CrashReporterClient.h
#defineCRSetCrashLogMessage(x)
#defineCRSetCrashLogMessage2(x)
#endif
#ifndef SHARED_REGION_BASE_ARM64
#defineSHARED_REGION_BASE_ARM640x7FFF80000000LL
#endif
#ifndef SHARED_REGION_SIZE_ARM64
#defineSHARED_REGION_SIZE_ARM640x10000000LL
#endif
#defineLOG_BINDINGS0
#include"mach-o/dyld_images.h"
#include"mach-o/dyld_priv.h"
#include"DyldSharedCache.h"
#if __i386__
#defineSHARED_REGION_BASE SHARED_REGION_BASE_I386
#defineSHARED_REGION_SIZE SHARED_REGION_SIZE_I386
#elif __x86_64__
#defineSHARED_REGION_BASE SHARED_REGION_BASE_X86_64
#defineSHARED_REGION_SIZE SHARED_REGION_SIZE_X86_64
#elif __arm__
#defineSHARED_REGION_BASE SHARED_REGION_BASE_ARM
#defineSHARED_REGION_SIZE SHARED_REGION_SIZE_ARM
#elif __arm64__
#defineSHARED_REGION_BASE SHARED_REGION_BASE_ARM64
#defineSHARED_REGION_SIZE SHARED_REGION_SIZE_ARM64
#endif
#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
#defineEXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER0x10
#endif
#ifndef EXPORT_SYMBOL_FLAGS_REEXPORT
#defineEXPORT_SYMBOL_FLAGS_REEXPORT0x08
#endif
#ifndef LC_MAIN
#defineLC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */structentry_point_command {
uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */uint32_t cmdsize; /* 24 */uint64_t entryoff; /* file (__TEXT) offset of main() */uint64_t stacksize;/* if not zero, initial stack size */
};
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#defineSPLIT_SEG_SHARED_REGION_SUPPORT0
#defineSPLIT_SEG_DYLIB_SUPPORT0
#definePREBOUND_IMAGE_SUPPORT __arm__
#defineTEXT_RELOC_SUPPORT __i386__
#defineSUPPORT_OLD_CRT_INITIALIZATION0
#defineSUPPORT_LC_DYLD_ENVIRONMENT1
#defineSUPPORT_VERSIONED_PATHS1
#defineSUPPORT_CLASSIC_MACHO __arm__
#defineSUPPORT_ZERO_COST_EXCEPTIONS (!__USING_SJLJ_EXCEPTIONS__)
#defineINITIAL_IMAGE_COUNT150
#defineSUPPORT_ACCELERATE_TABLES !TARGET_IPHONE_SIMULATOR
#defineSUPPORT_ROOT_PATH TARGET_IPHONE_SIMULATOR
#defineUSES_CHAINED_BINDS (__arm64e__)
#else
#defineSPLIT_SEG_SHARED_REGION_SUPPORT0
#defineSPLIT_SEG_DYLIB_SUPPORT __i386__
#definePREBOUND_IMAGE_SUPPORT __i386__
#defineTEXT_RELOC_SUPPORT __i386__
#defineSUPPORT_OLD_CRT_INITIALIZATION __i386__
#defineSUPPORT_LC_DYLD_ENVIRONMENT (__i386__ || __x86_64__)
#defineSUPPORT_VERSIONED_PATHS1
#defineSUPPORT_CLASSIC_MACHO1
#defineSUPPORT_ZERO_COST_EXCEPTIONS1
#defineINITIAL_IMAGE_COUNT200
#defineSUPPORT_ACCELERATE_TABLES0
#defineSUPPORT_ROOT_PATH1
#defineUSES_CHAINED_BINDS0
#endif
#defineMAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE (32*1024)
#defineMH_HAS_OBJC0x40000000// <rdar://problem/13590567> optimize away dyld's initializers
#defineVECTOR_NEVER_DESTRUCTED(type) \
namespacestd { \
template <> \
__vector_base<type, std::allocator<type> >::~__vector_base() { } \
}
#defineVECTOR_NEVER_DESTRUCTED_EXTERN(type) \
namespacestd { \
template <> \
__vector_base<type, std::allocator<type> >::~__vector_base(); \
}
#defineVECTOR_NEVER_DESTRUCTED_IMPL(type) \
namespacestd { \
template <> \
__vector_base<type, std::allocator<type> >::~__vector_base() { } \
}
// utilitiesnamespacedyld {
extern__attribute__((noreturn)) void throwf(constchar* format, ...) __attribute__((format(printf, 1, 2)));
externvoidlog(constchar* format, ...) __attribute__((format(printf, 1, 2)));
externvoidwarn(constchar* format, ...) __attribute__((format(printf, 1, 2)));
externconstchar* mkstringf(constchar* format, ...) __attribute__((format(printf, 1, 2)));
#if LOG_BINDINGS
externvoidlogBindings(constchar* format, ...) __attribute__((format(printf, 1, 2)));
#endif
}
extern"C"intvm_alloc(vm_address_t* addr, vm_size_t size, uint32_t flags);
extern"C"void* xmmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
#if __LP64__
structmacho_header : publicmach_header_64 {};
structmacho_nlist : publicnlist_64 {};
#elsestructmacho_header : publicmach_header {};
structmacho_nlist : publicnlist {};
#endif
#if __arm64__
#definedyld_page_trunc(__addr) (__addr & (-16384))
#definedyld_page_round(__addr) ((__addr + 16383) & (-16384))
#definedyld_page_size16384
#elif __arm__
#definedyld_page_trunc(__addr) trunc_page_kernel(__addr)
#definedyld_page_round(__addr) round_page_kernel(__addr)
#definedyld_page_sizevm_kernel_page_size
#else
#definedyld_page_trunc(__addr) (__addr & (-4096))
#definedyld_page_round(__addr) ((__addr + 4095) & (-4096))
#definedyld_page_size4096
#endifstructProgramVars
{
constvoid* mh;
int* NXArgcPtr;
constchar*** NXArgvPtr;
constchar*** environPtr;
constchar** __prognamePtr;
};
//// ImageLoader is an abstract base class. To support loading a particular executable// file format, you make a concrete subclass of ImageLoader.//// For each executable file (dynamic shared object) in use, an ImageLoader is instantiated.//// The ImageLoader base class does the work of linking together images, but it knows nothing// about any particular file format.////classImageLoader {
public:typedefuint32_t DefinitionFlags;
staticconst DefinitionFlags kNoDefinitionOptions = 0;
staticconst DefinitionFlags kWeakDefinition = 1;
typedefuint32_t ReferenceFlags;
staticconst ReferenceFlags kNoReferenceOptions = 0;
staticconst ReferenceFlags kWeakReference = 1;
staticconst ReferenceFlags kTentativeDefinition = 2;
enum PrebindMode { kUseAllPrebinding, kUseSplitSegPrebinding, kUseAllButAppPredbinding, kUseNoPrebinding };
enum BindingOptions { kBindingNone, kBindingLazyPointers, kBindingNeverSetLazyPointers };
enum SharedRegionMode { kUseSharedRegion, kUsePrivateSharedRegion, kDontUseSharedRegion, kSharedRegionIsSharedCache };
structSymbol; // abstact symbolstructMappedRegion {
uintptr_t address;
size_t size;
};
structRPathChain {
RPathChain(const RPathChain* n, std::vector<constchar*>* p) : next(n), paths(p) {};
const RPathChain* next;
std::vector<constchar*>* paths;
};
structDOFInfo {
void* dof;
const mach_header* imageHeader;
constchar* imageShortName;
};
structDynamicReference {
ImageLoader* from;
ImageLoader* to;
};
structInitializerTimingList
{
uintptr_t count;
struct {
constchar* shortName;
uint64_t initTime;
} images[1];
voidaddTime(constchar* name, uint64_t time);
};
typedefvoid (^CoalesceNotifier)(const Symbol* implSym, const ImageLoader* implIn, const mach_header* implMh);
structLinkContext {
ImageLoader* (*loadLibrary)(constchar* libraryName, bool search, constchar* origin, const RPathChain* rpaths, bool enforceIOSMac, unsigned& cacheIndex);
void (*terminationRecorder)(ImageLoader* image);
bool (*flatExportFinder)(constchar* name, const Symbol** sym, const ImageLoader** image);
bool (*coalescedExportFinder)(constchar* name, const Symbol** sym, const ImageLoader** image, CoalesceNotifier);
unsignedint (*getCoalescedImages)(ImageLoader* images[], unsigned imageIndex[]);
void (*undefinedHandler)(constchar* name);
MappedRegion* (*getAllMappedRegions)(MappedRegion*);
void * (*bindingHandler)(constchar *, constchar *, void *);
void (*notifySingle)(dyld_image_states, const ImageLoader* image, InitializerTimingList*);
void (*notifyBatch)(dyld_image_states state, bool preflightOnly);
void (*removeImage)(ImageLoader* image);
void (*registerDOFs)(const std::vector<DOFInfo>& dofs);
void (*clearAllDepths)();
void (*printAllDepths)();
unsignedint (*imageCount)();
void (*setNewProgramVars)(const ProgramVars&);
bool (*inSharedCache)(constchar* path);
void (*setErrorStrings)(unsigned errorCode, constchar* errorClientOfDylibPath,
constchar* errorTargetDylibPath, constchar* errorSymbol);
ImageLoader* (*findImageContainingAddress)(constvoid* addr);
void (*addDynamicReference)(ImageLoader* from, ImageLoader* to);
#if SUPPORT_ACCELERATE_TABLES
void (*notifySingleFromCache)(dyld_image_states, const mach_header* mh, constchar* path);
dyld_image_state_change_handler (*getPreInitNotifyHandler)(unsigned index);
dyld_image_state_change_handler (*getBoundBatchHandler)(unsigned index);
#endif
#if SUPPORT_OLD_CRT_INITIALIZATION
void (*setRunInitialzersOldWay)();
#endif
BindingOptions bindingOptions;
int argc;
constchar** argv;
constchar** envp;
constchar** apple;
constchar* progname;
ProgramVars programVars;
ImageLoader* mainExecutable;
constchar* const * imageSuffix;
#if SUPPORT_ROOT_PATH
constchar** rootPaths;
#endifconst DyldSharedCache* dyldCache;
const dyld_interpose_tuple* dynamicInterposeArray;
size_t dynamicInterposeCount;
PrebindMode prebindUsage;
SharedRegionMode sharedRegionMode;
bool dyldLoadedAtSameAddressNeededBySharedCache;
bool strictMachORequired;
bool allowAtPaths;
bool allowEnvVarsPrint;
bool allowEnvVarsPath;
bool allowEnvVarsSharedCache;
bool allowClassicFallbackPaths;
bool allowInsertFailures;
bool mainExecutableCodeSigned;
bool preFetchDisabled;
bool prebinding;
bool bindFlat;
bool linkingMainExecutable;
bool startedInitializingMainExecutable;
#if __MAC_OS_X_VERSION_MIN_REQUIRED
bool marzipan;
#endifbool verboseOpts;
bool verboseEnv;
bool verboseLoading;
bool verboseMapping;
bool verboseRebase;
bool verboseBind;
bool verboseWeakBind;
bool verboseInit;
bool verboseDOF;
bool verbosePrebinding;
bool verboseCoreSymbolication;
bool verboseWarnings;
bool verboseRPaths;
bool verboseInterposing;
bool verboseCodeSignatures;
};
structCoalIterator
{
ImageLoader* image;
constchar* symbolName;
unsignedint loadOrder;
bool weakSymbol;
bool symbolMatches;
bool done;
// the following are private to the ImageLoader subclassuintptr_t curIndex;
uintptr_t endIndex;
uintptr_t address;
uintptr_t type;
uintptr_t addend;
uintptr_t imageIndex;
};
virtualvoidinitializeCoalIterator(CoalIterator&, unsignedint loadOrder, unsigned imageIndex) = 0;
virtualboolincrementCoalIterator(CoalIterator&) = 0;
virtualuintptr_tgetAddressCoalIterator(CoalIterator&, const LinkContext& context) = 0;
virtualvoidupdateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, unsigned targetIndex, const LinkContext& context) = 0;
structUninitedUpwards
{
uintptr_t count;
ImageLoader* images[1];
};
// constructor is protected, but anyone can delete an imagevirtual~ImageLoader();
// link() takes a newly instantiated ImageLoader and does all // fixups needed to make it usable by the processvoidlink(const LinkContext& context, bool forceLazysBound, bool preflight, bool neverUnload, const RPathChain& loaderRPaths, constchar* imagePath);
// runInitializers() is normally called in link() but the main executable must // run crt code before initializersvoidrunInitializers(const LinkContext& context, InitializerTimingList& timingInfo);
// called after link() forces all lazy pointers to be boundvoidbindAllLazyPointers(const LinkContext& context, bool recursive);
// used by dyld to see if a requested library is already loaded (might be symlink)boolstatMatch(conststructstat& stat_buf) const;
// get short name of this imageconstchar* getShortName() const;
// returns leaf namestaticconstchar* shortName(constchar* fullName);
// get path used to load this image, not necessarily the "real" pathconstchar* getPath() const { returnfPath; }
uint32_tgetPathHash() const { returnfPathHash; }
// get the "real" path for this image (e.g. no @rpath)constchar* getRealPath() const;
// get path this image is intended to be placed on disk or NULL if no preferred install locationvirtualconstchar* getInstallPath() const = 0;
// image was loaded with NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME and all clients are looking for install pathboolmatchInstallPath() const;
voidsetMatchInstallPath(bool);
// mark that this image's exported symbols should be ignored when linking other images (e.g. RTLD_LOCAL)voidsetHideExports(bool hide = true);
// check if this image's exported symbols should be ignored when linking other images boolhasHiddenExports() const;
// checks if this image is already linked into the processboolisLinked() const;
// even if image is deleted, leave segments mapped invoidsetLeaveMapped();
// even if image is deleted, leave segments mapped inboolleaveMapped() { returnfLeaveMapped; }
// image resides in dyld shared cachevirtualboolinSharedCache() const { returnfalse; };
// checks if the specifed address is within one of this image's segmentsvirtualboolcontainsAddress(constvoid* addr) const;
// checks if the specifed symbol is within this image's symbol tablevirtualboolcontainsSymbol(constvoid* addr) const = 0;
// checks if the specifed address range overlaps any of this image's segmentsvirtualbooloverlapsWithAddressRange(constvoid* start, constvoid* end) const;
// adds to list of ranges of memory mapped invoidgetMappedRegions(MappedRegion*& region) const;
// st_mtime from stat() on filetime_tlastModified() const;
// only valid for main executables, returns a pointer its entry point from LC_MAINvirtualvoid* getEntryFromLC_MAIN() const = 0;
// only valid for main executables, returns a pointer its main from LC_UNIXTHREADvirtualvoid* getEntryFromLC_UNIXTHREAD() const = 0;
// dyld API's require each image to have an associated mach_headervirtualconststructmach_header* machHeader() const = 0;
// dyld API's require each image to have a slide (actual load address minus preferred load address)virtualuintptr_tgetSlide() const = 0;
// last address mapped by imagevirtualconstvoid* getEnd() const = 0;
// image has exports that participate in runtime coalescingvirtualboolhasCoalescedExports() const = 0;
// search symbol table of definitions in this image for requested namevirtualboolfindExportedSymbolAddress(const LinkContext& context, constchar* symbolName,
const ImageLoader* requestorImage, int requestorOrdinalOfDef,
bool runResolver, const ImageLoader** foundIn, uintptr_t* address) const;
// search symbol table of definitions in this image for requested namevirtualconst Symbol* findExportedSymbol(constchar* name, bool searchReExports, constchar* thisPath, const ImageLoader** foundIn) const = 0;
// search symbol table of definitions in this image for requested namevirtualconst Symbol* findExportedSymbol(constchar* name, bool searchReExports, const ImageLoader** foundIn) const {
returnfindExportedSymbol(name, searchReExports, this->getPath(), foundIn);
}
// gets address of implementation (code) of the specified exported symbolvirtualuintptr_tgetExportedSymbolAddress(const Symbol* sym, const LinkContext& context,
const ImageLoader* requestor=NULL, bool runResolver=false, constchar* symbolName=NULL) const = 0;
// gets attributes of the specified exported symbolvirtual DefinitionFlags getExportedSymbolInfo(const Symbol* sym) const = 0;
// gets name of the specified exported symbolvirtualconstchar* getExportedSymbolName(const Symbol* sym) const = 0;
// gets how many symbols are exported by this imagevirtualuint32_tgetExportedSymbolCount() const = 0;
// gets the i'th exported symbolvirtualconst Symbol* getIndexedExportedSymbol(uint32_t index) const = 0;
// find exported symbol as if imported by this image// used by RTLD_NEXTvirtualconst Symbol* findExportedSymbolInDependentImages(constchar* name, const LinkContext& context, const ImageLoader** foundIn) const;
// find exported symbol as if imported by this image// used by RTLD_SELFvirtualconst Symbol* findExportedSymbolInImageOrDependentImages(constchar* name, const LinkContext& context, const ImageLoader** foundIn) const;
// gets how many symbols are imported by this imagevirtualuint32_tgetImportedSymbolCount() const = 0;
// gets the i'th imported symbolvirtualconst Symbol* getIndexedImportedSymbol(uint32_t index) const = 0;
// gets attributes of the specified imported symbolvirtual ReferenceFlags getImportedSymbolInfo(const Symbol* sym) const = 0;
// gets name of the specified imported symbolvirtualconstchar* getImportedSymbolName(const Symbol* sym) const = 0;
// find the closest symbol before addrvirtualconstchar* findClosestSymbol(constvoid* addr, constvoid** closestAddr) const = 0;
// for use with accelerator tablesvirtualconstchar* getIndexedPath(unsigned) const { returngetPath(); }
virtualconstchar* getIndexedShortName(unsigned) const { returngetShortName(); }
// checks if this image is a bundle and can be loaded but not linkedvirtualboolisBundle() const = 0;
// checks if this image is a dylib virtualboolisDylib() const = 0;
// checks if this image is a main executable virtualboolisExecutable() const = 0;
// checks if this image is a main executable virtualboolisPositionIndependentExecutable() const = 0;
// only for main executablevirtualboolforceFlat() const = 0;
// called at runtime when a lazily bound function is first calledvirtualuintptr_tdoBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
// called at runtime when a fast lazily bound function is first calledvirtualuintptr_tdoBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context,
void (*lock)(), void (*unlock)()) = 0;
// calls termination routines (e.g. C++ static destructors for image)virtualvoiddoTermination(const LinkContext& context) = 0;
// return if this image has initialization routinesvirtualboolneedsInitialization() = 0;
// return if this image has specified section and set start and lengthvirtualboolgetSectionContent(constchar* segmentName, constchar* sectionName, void** start, size_t* length) = 0;
// fills in info about __eh_frame and __unwind_info sectionsvirtualvoidgetUnwindInfo(dyld_unwind_sections* info) = 0;
// given a pointer into an image, find which segment and section it is invirtualconststructmacho_section* findSection(constvoid* imageInterior) const = 0;
// given a pointer into an image, find which segment and section it is invirtualboolfindSection(constvoid* imageInterior, constchar** segmentName, constchar** sectionName, size_t* sectionOffset) = 0;
// the image supports being preboundvirtualboolisPrebindable() const = 0;
// the image is prebindable and its prebinding is validvirtualboolusablePrebinding(const LinkContext& context) const = 0;
// add all RPATH paths this image containsvirtualvoidgetRPaths(const LinkContext& context, std::vector<constchar*>&) const = 0;
// image has or uses weak definitions that need runtime coalescingvirtualboolparticipatesInCoalescing() const = 0;
// if image has a UUID, copy into parameter and return truevirtualboolgetUUID(uuid_t) const = 0;
// dynamic interpose values onto this imagevirtualvoiddynamicInterpose(const LinkContext& context) = 0;
// record interposing for any late bindingvoidaddDynamicInterposingTuples(conststructdyld_interpose_tuple array[], size_t count);
virtualconstchar* libPath(unsignedint) const = 0;
// Image has objc sections, so information objc about when it comes and goesvirtualboolnotifyObjC() const { returnfalse; }
virtualbooloverridesCachedDylib(uint32_t& num) const { returnfalse; }
virtualvoidsetOverridesCachedDylib(uint32_t num) { }
//// A segment is a chunk of an executable file that is mapped into memory. //virtualunsignedintsegmentCount() const = 0;
virtualconstchar* segName(unsignedint) const = 0;
virtualuintptr_tsegSize(unsignedint) const = 0;
virtualuintptr_tsegFileSize(unsignedint) const = 0;
virtualboolsegHasTrailingZeroFill(unsignedint) = 0;
virtualuintptr_tsegFileOffset(unsignedint) const = 0;
virtualboolsegReadable(unsignedint) const = 0;
virtualboolsegWriteable(unsignedint) const = 0;
virtualboolsegExecutable(unsignedint) const = 0;
virtualboolsegUnaccessible(unsignedint) const = 0;
virtualboolsegHasPreferredLoadAddress(unsignedint) const = 0;
virtualuintptr_tsegPreferredLoadAddress(unsignedint) const = 0;
virtualuintptr_tsegActualLoadAddress(unsignedint) const = 0;
virtualuintptr_tsegActualEndAddress(unsignedint) const = 0;
// info from LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOSvirtualuint32_tsdkVersion() const = 0;
virtualuint32_tminOSVersion() const = 0;
// if the image contains interposing functions, register themvirtualvoidregisterInterposing(const LinkContext& context) = 0;
virtualboolusesChainedFixups() const { returnfalse; }
// when resolving symbols look in subImage if symbol can't be foundvoidreExport(ImageLoader* subImage);
virtualvoidrecursiveBind(const LinkContext& context, bool forceLazysBound, bool neverUnload);
virtualvoidrecursiveBindWithAccounting(const LinkContext& context, bool forceLazysBound, bool neverUnload);
voidweakBind(const LinkContext& context);
voidapplyInterposing(const LinkContext& context);
dyld_image_states getState() { return (dyld_image_states)fState; }
ino_tgetInode() const { returnfInode; }
dev_tgetDevice() const { returnfDevice; }
// used to sort images bottom-upintcompare(const ImageLoader* right) const;
voidincrementDlopenReferenceCount() { ++fDlopenReferenceCount; }
booldecrementDlopenReferenceCount();
voidprintReferenceCounts();
uint32_tdlopenCount() const { returnfDlopenReferenceCount; }
voidsetCanUnload() { fNeverUnload = false; fLeaveMapped = false; }
boolneverUnload() const { returnfNeverUnload; }
voidsetNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
voidsetNeverUnloadRecursive();
boolisReferencedDownward() { returnfIsReferencedDownward; }
virtualuintptr_tresolveWeak(const LinkContext& context, constchar* symbolName, bool weak_import, bool runResolver,
const ImageLoader** foundIn) { return0; }
// triggered by DYLD_PRINT_STATISTICS to write info on work done and how faststaticvoidprintStatistics(unsignedint imageCount, const InitializerTimingList& timingInfo);
staticvoidprintStatisticsDetails(unsignedint imageCount, const InitializerTimingList& timingInfo);
// used with DYLD_IMAGE_SUFFIXstaticvoidaddSuffix(constchar* path, constchar* suffix, char* result);
staticuint32_thash(constchar*);
staticconstuint8_t* trieWalk(constuint8_t* start, constuint8_t* end, constchar* stringToFind);
// used instead of directly deleting imagestaticvoiddeleteImage(ImageLoader*);
staticboolhaveInterposingTuples() { return !fgInterposingTuples.empty(); }
staticvoidclearInterposingTuples() { fgInterposingTuples.clear(); }
staticvoidapplyInterposingToDyldCache(const LinkContext& context);
booldependsOn(ImageLoader* image);
voidsetPath(constchar* path);
voidsetPaths(constchar* path, constchar* realPath);
voidsetPathUnowned(constchar* path);
voidclearDepth() { fDepth = 0; }
intgetDepth() { returnfDepth; }
voidsetBeingRemoved() { fBeingRemoved = true; }
boolisBeingRemoved() const { returnfBeingRemoved; }
voidmarkNotUsed() { fMarkedInUse = false; }
voidmarkedUsedRecursive(const std::vector<DynamicReference>&);
boolisMarkedInUse() const { returnfMarkedInUse; }
voidsetAddFuncNotified() { fAddFuncNotified = true; }
booladdFuncNotified() const { returnfAddFuncNotified; }
structInterposeTuple {
uintptr_t replacement;
ImageLoader* neverImage; // don't apply replacement to this image
ImageLoader* onlyImage; // only apply replacement to this imageuintptr_t replacee;
};
staticuintptr_tread_uleb128(constuint8_t*& p, constuint8_t* end);
staticintptr_tread_sleb128(constuint8_t*& p, constuint8_t* end);
voidvmAccountingSetSuspended(const LinkContext& context, bool suspend);
protected:// abstract base class so all constructors protectedImageLoader(constchar* path, unsignedint libCount);
ImageLoader(const ImageLoader&);
voidoperator=(const ImageLoader&);
voidoperatordelete(void* image) throw() { ::free(image); }
structLibraryInfo {
uint32_t checksum;
uint32_t minVersion;
uint32_t maxVersion;
};
structDependentLibrary {
ImageLoader* image;
uint32_t required : 1,
checksumMatches : 1,
isReExported : 1,
isSubFramework : 1;
};
structDependentLibraryInfo {
constchar* name;
LibraryInfo info;
bool required;
bool reExported;
bool upward;
};
typedefvoid (*Initializer)(int argc, constchar* argv[], constchar* envp[], constchar* apple[], const ProgramVars* vars);
typedefvoid (*Terminator)(void);
unsignedintlibraryCount() const { returnfLibraryCount; }
virtual ImageLoader* libImage(unsignedint) const = 0;
virtualboollibReExported(unsignedint) const = 0;
virtualboollibIsUpward(unsignedint) const = 0;
virtualvoidsetLibImage(unsignedint, ImageLoader*, bool, bool) = 0;
// To link() an image, its dependent libraries are loaded, it is rebased, bound, and initialized.// These methods do the above, exactly once, and it the right ordervirtualvoidrecursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths, constchar* loadPath);
virtualunsignedrecursiveUpdateDepth(unsignedint maxDepth);
virtualvoidrecursiveRebase(const LinkContext& context);
virtualvoidrecursiveApplyInterposing(const LinkContext& context);
virtualvoidrecursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs);
virtualvoidrecursiveInitialization(const LinkContext& context, mach_port_t this_thread, constchar* pathToInitialize,
ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&);
// fill in information about dependent libraries (array length is fLibraryCount)virtualvoiddoGetDependentLibraries(DependentLibraryInfo libs[]) = 0;
// called on images that are libraries, returns info about itselfvirtual LibraryInfo doGetLibraryInfo(const LibraryInfo& requestorInfo) = 0;
// do any fix ups in this image that depend only on the load address of the imagevirtualvoiddoRebase(const LinkContext& context) = 0;
// do any symbolic fix ups in this imagevirtualvoiddoBind(const LinkContext& context, bool forceLazysBound) = 0;
// called later via API to force all lazy pointer to be boundvirtualvoiddoBindJustLazies(const LinkContext& context) = 0;
// if image has any dtrace DOF sections, append them to list to be registeredvirtualvoiddoGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs) = 0;
// do interposevirtualvoiddoInterpose(const LinkContext& context) = 0;
// run any initialization routines in this imagevirtualbooldoInitialization(const LinkContext& context) = 0;
// return if this image has termination routinesvirtualboolneedsTermination() = 0;
// support for runtimes in which segments don't have to maintain their relative positionsvirtualboolsegmentsMustSlideTogether() const = 0;
// built with PIC code and can load at any addressvirtualboolsegmentsCanSlide() const = 0;
// set how much all segments slidevirtualvoidsetSlide(intptr_t slide) = 0;
// returns if all dependent libraries checksum's were as expected and none slideboolallDependentLibrariesAsWhenPreBound() const;
// in mach-o a child tells it parent to re-export, instead of the other way around...virtualboolisSubframeworkOf(const LinkContext& context, const ImageLoader* image) const = 0;
// in mach-o a parent library knows name of sub libraries it re-exports..virtualboolhasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0;
virtualboolweakSymbolsBound(unsigned index) { returnfWeakSymbolsBound; }
virtualvoidsetWeakSymbolsBound(unsigned index) { fWeakSymbolsBound = true; }
// set fState to dyld_image_state_memory_mappedvoidsetMapped(const LinkContext& context);
voidsetFileInfo(dev_t device, ino_t inode, time_t modDate);
voidsetDepth(uint16_t depth) { fDepth = depth; }
staticuintptr_tinterposedAddress(const LinkContext& context, uintptr_t address, const ImageLoader* notInImage, const ImageLoader* onlyInImage=NULL);
staticuintptr_t fgNextPIEDylibAddress;
staticuint32_t fgImagesWithUsedPrebinding;
staticuint32_t fgImagesUsedFromSharedCache;
staticuint32_t fgImagesHasWeakDefinitions;
staticuint32_t fgImagesRequiringCoalescing;
staticuint32_t fgTotalRebaseFixups;
staticuint32_t fgTotalBindFixups;
staticuint32_t fgTotalBindSymbolsResolved;
staticuint32_t fgTotalBindImageSearches;
staticuint32_t fgTotalLazyBindFixups;
staticuint32_t fgTotalPossibleLazyBindFixups;
staticuint32_t fgTotalSegmentsMapped;
staticuint32_t fgSymbolTrieSearchs;
staticuint64_t fgTotalBytesMapped;
staticuint64_t fgTotalBytesPreFetched;
staticuint64_t fgTotalLoadLibrariesTime;
public:staticuint64_t fgTotalObjCSetupTime;
staticuint64_t fgTotalDebuggerPausedTime;
staticuint64_t fgTotalRebindCacheTime;
staticuint64_t fgTotalRebaseTime;
staticuint64_t fgTotalBindTime;
staticuint64_t fgTotalWeakBindTime;
staticuint64_t fgTotalDOF;
staticuint64_t fgTotalInitTime;
protected:static std::vector<InterposeTuple> fgInterposingTuples;
constchar* fPath;
constchar* fRealPath;
dev_tfDevice;
ino_tfInode;
time_tfLastModified;
uint32_tfPathHash;
uint32_tfDlopenReferenceCount; // count of how many dlopens have been done on this imagestructrecursive_lock {
recursive_lock(mach_port_t t) : thread(t), count(0) {}
mach_port_t thread;
int count;
};
voidrecursiveSpinLock(recursive_lock&);
voidrecursiveSpinUnLock();
private:const ImageLoader::Symbol* findExportedSymbolInDependentImagesExcept(constchar* name, const ImageLoader** dsiStart,
const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const;
voidprocessInitializers(const LinkContext& context, mach_port_t this_thread,
InitializerTimingList& timingInfo, ImageLoader::UninitedUpwards& ups);
recursive_lock* fInitializerRecursiveLock;
uint16_tfDepth;
uint16_tfLoadOrder;
uint32_tfState : 8,
fLibraryCount : 10,
fAllLibraryChecksumsAndLoadAddressesMatch : 1,
fLeaveMapped : 1, // when unloaded, leave image mapped in cause some other code may have pointers into itfNeverUnload : 1, // image was statically loaded by main executablefHideSymbols : 1, // ignore this image's exported symbols when linking other imagesfMatchByInstallName : 1,// look at image's install-path not its load pathfInterposed : 1,
fRegisteredDOF : 1,
fAllLazyPointersBound : 1,
fMarkedInUse : 1,
fBeingRemoved : 1,
fAddFuncNotified : 1,
fPathOwnedByImage : 1,
fIsReferencedDownward : 1,
fWeakSymbolsBound : 1;
staticuint16_t fgLoadOrdinal;
};
VECTOR_NEVER_DESTRUCTED_EXTERN(ImageLoader::InterposeTuple);
#endif
如此之长的头文件,我们去掉方法和静态成员,整理以后,只有以下成员
const char* fPath;
const char* fRealPath;
dev_t fDevice;
ino_t fInode;
time_t fLastModified;
uint32_t fPathHash;
uint32_t fDlopenReferenceCount; // count of how many dlopens have been done on this image
recursive_lock* fInitializerRecursiveLock;
uint16_t fDepth;
uint16_t fLoadOrder;
uint32_t fState : 8,
fLibraryCount : 10,
fAllLibraryChecksumsAndLoadAddressesMatch : 1,
fLeaveMapped : 1, // when unloaded, leave image mapped in cause some other code may have pointers into it
fNeverUnload : 1, // image was statically loaded by main executable
fHideSymbols : 1, // ignore this image's exported symbols when linking other images
fMatchByInstallName : 1,// look at image's install-path not its load path
fInterposed : 1,
fRegisteredDOF : 1,
fAllLazyPointersBound : 1,
fMarkedInUse : 1,
fBeingRemoved : 1,
fAddFuncNotified : 1,
fPathOwnedByImage : 1,
fIsReferencedDownward : 1,
fWeakSymbolsBound : 1;
内容摘要
近日我在开发一个小工具的时候,用到了一个加载动态库的函数
dlopen
,基于我的windows平台的开发背景,我想当然的认为其返回值是当前module
的load address
,即模块基地址。然后经验证后发现,其和windows
下的LoadLibrary
还是有本质的差别。那么,它返回的究竟是一个什么东西呢?又该如何通过这样的返回值,来顺利获取到我们需要的load address
甚至其它更重要的信息呢?带着这样的疑惑,我与几位资深经验的开发者对这个问题进行了深入的探究。本文是探究思路和研究过程的记录。在读文本文后,你应当会对此方面了解有所加深,并且上述疑惑应当能够释疑。前知储备
本文面向有一定技术水准的读者,所以不再赘述
模块
,基地址
等相关定义。但相对地,下文出现的一些术语或者俗语,在此做一个简短的说明,如果需要进一步了解,请参考附录或者自行检索相关资料。aslr(Address space layout randomization)
,加载地址随机化,通俗来讲,就是同一个模块在每个进程每次被加载后的地址(可能)不一致。load address
,模块加载地址,即模块基地址
,也等同于header address
。patch
补丁,这里名次动用做打补丁
。为什么需要
load address
在通常开发情境下,一般地代码片段如下:
但特殊情况下,我们无法通过
dlsym
来完成符号的寻找。如该模块根本没有导出符号,或者我们想要显式的调用某个未导出符号的函数,或者我们需要patch
掉header
中的某个字段等情形时,我们就需要知道该模块的load address
。如何获取
load address
由于
aslr
的原因,现行通用的解决方案是通过遍历模块来获取。典型的代码片段如下:这样,我们就通过对比名字的方式,来获取到了
header address
。然而我们思考一下,这样做真的没有问题吗???
我认为,起码有两三个问题。
大意是要警惕在遍历时其它进程的添加或者修改操作。那么。显然地,假使我们在遍历的过程中,其它线程删除了一个模块,那么将导致我们的索引移位,得到一个完全不匹配的结果,同时也有可能造成内存访问错误。
那么,要想同时解决以上三个问题,(我认为)最优秀的解决应当是通过
dlopen
返回的结果来获取。从推理上来讲,dlsym
既然能通过这个参数来获取到符号信息,而符号表是需要通过header
来计算的。换言之,通过这个dlopen
的返回值一定可以获取到header
。搜索了一番,网上对此没有任何资料。但理论上行得通的事情,实际上应该是可以的。于是我开始了探寻。
探寻过程
有了上文的资料,显然,
dlopen
的返回值必定是一个结构
。我们由此来做发散思维。与此同时,我与几位大佬交流后,他们也都给出了非常重要的建议。头文件及注释
这个是一个最简单的方案,我们去看一下
dlopen
的头文件声明,其位于/usr/include/dlfcn.h
然而这里面定义它为void* 类型,且变量名字为
handle
。我们幻想中此处应为一个结构体指针的美梦破碎了。
借用linux头文件
此方案由
咸🐟
提出。看到这份资料的时候我还是比较兴奋的,因为这无疑证明了我们的推断是正确的。然而我一番寻找,发现在macos下根本没有
link.h
这个头文件。一番搜索没有答案之下,我们安装windows subsystem
然后顺利找到这个头文件。其中关键部分如下:
这里我们简单的复制此关键部分,并修改为
我们的代码如下:
运行之后神奇的事情发生了,模块名字竟然正确的输出了!虽然基地址返回的明显不对。但至少证明了它确实是有组织的。但可能因为苹果做了修改导致了不同。
我们继续尝试,发现除了名字奇迹般的正确输出以外,其它的无一相符。
这里提一句题外话,我们显然可以看到linux下的设计还是比较精巧的,它使用了链表来存在模块信息,方便插入和遍历。这一点上和windows是一致的。在此情形下,我们需要隐藏模块的话,就需要修改相邻的两个链表左右节点,也就是所谓的“断链”。有兴趣的话,可以自行研究。
借用anroid头文件
linux
的头文件无法适用于ios
,是否是因为版本的问题呢,android是否可行?一番搜索之下我们找到来安卓的对应头文件然而一番尝试后同样无果,这彻底说明了,至少这部分apple是有自己的实现。
特殊符号定位法
注意,这里的特殊符号不是指的标点符号,而是特殊的
symbol
。此方案同样由
咸🐟
提出,并由Zhang
扩充。原理是通过macho里导出的特殊符号来直接获取。具体的符号如
我们修改代码如下:
结果均获取不到这两个符号,推测为我这边测试环境的问题,或者在链接的过程中被去掉了。
特定符号偏移修正法
此方案由
柳下惠
提出,原理是通过查找给定的某个符号,然后减去对应的偏移来获取。这种是理论上肯定能行得通的解决方案,但实际上如若是遇到某个模块根本没有导出符号的话,此方案也是束手无策。此处有jmpzws
基于此而来的优化方案。即是查找dyld_stub_binder
这个特定的符号,align然后减去0x4000。但同样地,我这边也是无法获取到这个符号。
回调获取法
此方案由
Zhang
提出,原理是先通过_dyld_register_func_for_add_image
来注册一个回调,然后再dlopen
即可。因为此回调回调用void (*func)(const mach_header *mh, intptr_t vmaddr_slide)
这样的callback,在参数里面刚好就有mach_header
,以此来获取模块基地址。此方案从理论上来讲,是完全可行的。但由于操作过于复杂,且(我)没有找到对应的取消注册钩子的办法导致使用代价过大,所以没有深入探寻。暴力偏移法
多番尝试无果后,现行简单粗暴的方法。即
dump
出疑似结构的handle的内存,观察load address
的位置,然后计算偏移,往后通过偏移来获取。这种思路类似于游戏外挂的思路,即不管缘由,不考虑理论,先行实现。
于是我们修改代码如下
果然,我们在第0x58个成员的位置找到了疑似
load address
的位置。但这在实际使用上会有很大的问题。其中最为麻烦的是32位和64位的问题,由于类型长度可能不一致,所以在32位下未必是0x58/2,而且在执行时要定义宏或者手动判断系统位数,显然是一个比较繁琐的事情。但这进一步说明了我们的思路的正确的,一定存在这样的一个结构体。正是由于种种方案给定我们信心,我们才能坚定的走下去。
所以我们下一步就是要找到这个头文件,如果找不到,那我们就需要猜测,然后自行做一个这样的头文件。(反正
windows
下都是这么做的。)源码追溯法
正在此时,突然想起来
jmpzws
曾发的一个截图。那么,这个
ImageLoader
可不就是我们苦苦寻找的结构体吗?于是我们找到对应的dyld的源码。我们一番寻找后,发现其原来是个类,头文件如下
如此之长的头文件,我们去掉方法和静态成员,整理以后,只有以下成员
根据我们上次dump的结果来看,然后是不够的,至少这里面根本没有我们需要的
load address
。那么,这是什么原因呢?
由于c++继承的特性,在c++里,类指针的第一个成员是
虚表地址
,往后依次是父类的成员(包括私有成员)和自己类成员。显然这里真正的类型应是它的某个子类。结合我们上面的dump结果和apple的源码,一番尝试后,我们可以总结出它的结构如下
由此,我们可以顺利的通过以下代码来获取到他基地址。
当然
fMachOData
也是可以的,但考虑到后面的注释我们还是优先使用
fLinkEditBase
。此外,我们也可以通过此头文件来获取其它未公开的成员。
到此为止,我们不但达到了我们获取基地址的需求,还能够额外的获取甚至关键的信息。
免责声明
本文所公开的技术细节仅做技术交流,任何权利责任人需自行承担其用途产生的后果。另外,转载本文需注明来源及作者信息。
鸣谢
排名不分先后
资料文献
The text was updated successfully, but these errors were encountered: