Я пытаюсь написать свои собственные malloc / free оболочки, чтобы перехватить переполнение буфера.Причина: Guard Malloc недостаточно агрессивен, потому что он не может поймать переполнения, если они не находятся вблизи границ страницы.Я не возражаю обнаруживать переполнение позже (когда память освобождается), но я делаю не возражаю против его обнаружения.
Я использовал вставку и DYLD_INSERT_LIBRARIES
, чтобы внедрить мои реализацииMalloc и бесплатно.Проблема в том, что похоже, что есть вызовы malloc, которые выполняются до загрузки моей динамической библиотеки.Когда эти объекты освобождены, мой free()
считает, что они повреждены, потому что пролог и эпилог, которые я хочу добавить, отсутствуют.
Мой код выглядит следующим образом:
#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \
__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };
static const char *premagic = "abcdefgh";
static const char *postmagic = "zyxwvuts";
static const size_t prologueLength = 16;
static const size_t sizeOffset = 8;
static const size_t preMagicOffset = 0;
static const size_t epilogueLength = 8;
static const size_t totalOverhead = prologueLength + epilogueLength;
static void WriteMetadata(void *p, size_t size) {
memmove(p + preMagicOffset, premagic, 8);
memmove(p + sizeOffset, &size, sizeof(size));
memmove(p + prologueLength + size, postmagic, 8);
}
static void CheckMemory(void *ptr) {
void *realP = ptr - prologueLength;
// Get size
size_t size;
memmove(&size, realP + sizeOffset, sizeof(size_t));
// Check premagic
if (memcmp(realP + preMagicOffset, premagic, 8)) {
while (1);
}
// Check postmagic
void *post = ptr + size;
if (memcmp(post, postmagic, 8)) {
while (1);
}
}
void *ITMalloc(size_t size) {
void *p = malloc(size + totalOverhead);
if (p == 0) {
return p;
}
WriteMetadata(p, size);
return p + prologueLength;
}
DYLD_INTERPOSE(ITMalloc, malloc);
void ITFree(void *ptr) {
CheckMemory(ptr);
void *realP = ptr - prologueLength;
free(realP);
}
DYLD_INTERPOSE(ITFree, free);
... and more for calloc, realloc, etc. ...
Воткак я ее запускаю:
DYLD_INSERT_LIBRARIES=libitmalloc.dylib ./helloworld
Проблема в том, что моя ITFree
функция вызывается с ptr
, который никогда не был выделен ITMalloc
.Используя MallocStackLogging
, я вижу, что он был выделен частью динамического загрузчика во время загрузки.Вот трассировка стека первого такого распределения:
0x10261d036 (dyld) _dyld_start
0x10261d503 (dyld) dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*)
0x102623709 (dyld) dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*)
0x10261e71f (dyld) dyld::initializeMainExecutable()
0x10262ee05 (dyld) ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&)
0x10262ed73 (dyld) ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&)
0x10262fb80 (dyld) ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&)
0x10262fb80 (dyld) ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&)
0x10262fb80 (dyld) ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&)
0x10262fb80 (dyld) ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&)
0x10262fb80 (dyld) ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&)
0x10262fbea (dyld) ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&)
0x102634798 (dyld) ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&)
0x102634592 (dyld) ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&)
0x7fff76ad49c5 (libSystem.B.dylib) libSystem_initializer
0x7fff79cccad2 (libdispatch.dylib) libdispatch_init
0x7fff79cc0e36 (libdispatch.dylib) _os_object_init
0x7fff784ce234 (libobjc.A.dylib) _objc_init
0x7fff79cf9a27 (libdyld.dylib) _dyld_objc_notify_register
0x10262162e (dyld) dyld::registerObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*))
0x10262147b (dyld) dyld::notifyBatchPartial(dyld_image_states, bool, char const* (*)(dyld_image_states, unsigned int, dyld_image_info const*), bool, bool)
0x7fff784e1560 (libobjc.A.dylib) map_images
0x7fff784cea50 (libobjc.A.dylib) map_images_nolock
0x7fff784cfa92 (libobjc.A.dylib) _read_images
0x7fff784d0847 (libobjc.A.dylib) NXCreateMapTable
0x7fff784d089d (libobjc.A.dylib) NXCreateMapTableFromZone
0x7fff784d09c0 (libobjc.A.dylib) NXCreateHashTable
0x7fff784d0aff (libobjc.A.dylib) NXCreateHashTableFromZone
0x7fff784d0de4 (libobjc.A.dylib) NXHashInsert
0x7fff79ebb1b0 (libsystem_malloc.dylib) malloc_zone_calloc
Могу ли я заключить, что единственное решение состоит в том, чтобы поддерживать вспомогательный стол «известных указателей», который, как я знаю, имеет мой пролог / эпилог, и неполагаться на перехват malloc
перед любыми другими пользователями этого?Или есть способ загрузить мой код ранее, который я не нашел?