Last active
May 5, 2019 06:40
-
-
Save byss/c9154a9b96a609786c712be2a2cb1f06 to your computer and use it in GitHub Desktop.
Enables UIDebuggingOverlay by overriding all UIKit device checks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UIKitDebuggingOverlay.c | |
// Created by Kirill Bystrov on 5/4/19. | |
// | |
#include <dlfcn.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <sys/mman.h> | |
#include <mach-o/nlist.h> | |
#include <mach-o/loader.h> | |
void overrideUIKitChecks (void) __attribute__((constructor)); | |
struct dyld_cache_header { | |
char magic[16]; // e.g. "dyld_v0 i386" | |
uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info | |
uint32_t mappingCount; // number of dyld_cache_mapping_info entries | |
uint32_t imagesOffset; // file offset to first dyld_cache_image_info | |
uint32_t imagesCount; // number of dyld_cache_image_info entries | |
uint64_t dyldBaseAddress; // base address of dyld when cache was built | |
uint64_t codeSignatureOffset; // file offset of code signature blob | |
uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file) | |
uint64_t slideInfoOffset; // file offset of kernel slid info | |
uint64_t slideInfoSize; // size of kernel slid info | |
uint64_t localSymbolsOffset; // file offset of where local symbols are stored | |
uint64_t localSymbolsSize; // size of local symbols information | |
uint8_t uuid[16]; // unique value for each shared cache file | |
uint64_t cacheType; // 0 for development, 1 for production | |
uint32_t branchPoolsOffset; // file offset to table of uint64_t pool addresses | |
uint32_t branchPoolsCount; // number of uint64_t entries | |
uint64_t accelerateInfoAddr; // (unslid) address of optimization info | |
uint64_t accelerateInfoSize; // size of optimization info | |
uint64_t imagesTextOffset; // file offset to first dyld_cache_image_text_info | |
uint64_t imagesTextCount; // number of dyld_cache_image_text_info entries | |
}; | |
struct dyld_cache_local_symbols_info { | |
uint32_t nlistOffset; // offset into this chunk of nlist entries | |
uint32_t nlistCount; // count of nlist entries | |
uint32_t stringsOffset; // offset into this chunk of string pool | |
uint32_t stringsSize; // byte count of string pool | |
uint32_t entriesOffset; // offset into this chunk of array of dyld_cache_local_symbols_entry | |
uint32_t entriesCount; // number of elements in dyld_cache_local_symbols_entry array | |
}; | |
struct dyld_cache_local_symbols_entry { | |
uint32_t dylibOffset; // offset in cache file of start of dylib | |
uint32_t nlistStartIndex; // start index of locals for this dylib | |
uint32_t nlistCount; // number of local symbols for this dylib | |
}; | |
struct found_addr { | |
struct nlist_64 const *addr; | |
size_t data_idx; | |
}; | |
static struct { | |
char const *name; | |
size_t value_size; | |
char value [sizeof (intmax_t)]; | |
} const sharedCacheSearchData [] = { | |
{ .name = "_UIDebuggingOverlayIsEnabled.__overlayIsEnabled", .value_size = 1, .value = { 1 } }, | |
{ .name = "_UIDebuggingOverlayIsEnabled.onceToken", .value_size = 8, .value = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, | |
{ .name = "___fetchedInternalDeviceOnceToken", .value_size = 8, .value = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, | |
{ .name = "___isInternalDevice", .value_size = 1, .value = { 1 } }, | |
{ .name = "___UIGetDebuggingOverlayEnabledAssumingInternal.onceToken", .value_size = 8, .value = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, | |
{ .name = "___hasCachedDebuggingOverlayEnabled", .value_size = 1, .value = { 1 } }, | |
{ .name = "___cachedDebuggingOverlayEnabled", .value_size = 1, .value = { 1 } }, | |
}; | |
static size_t sharedCacheSearchDataCount = sizeof (sharedCacheSearchData) / sizeof (*sharedCacheSearchData); | |
extern char const *dyld_shared_cache_file_path (void); | |
extern void const *_dyld_get_shared_cache_range (size_t *length); | |
extern intptr_t _dyld_get_image_slide (struct mach_header const *mh); | |
void overrideUIKitChecks (void) { | |
int const dyld_cache_fd = open (dyld_shared_cache_file_path (), O_RDONLY); | |
struct dyld_cache_header dyld_cache_header; | |
read (dyld_cache_fd, &dyld_cache_header, sizeof (dyld_cache_header)); | |
struct dyld_cache_local_symbols_info const *const dyld_local_symbols_info = mmap (NULL, dyld_cache_header.localSymbolsSize, PROT_READ, MAP_PRIVATE, dyld_cache_fd, dyld_cache_header.localSymbolsOffset); | |
fprintf (stderr, "local symbols: %p (%llx size)\n", dyld_local_symbols_info, dyld_cache_header.localSymbolsSize); | |
close (dyld_cache_fd); | |
struct nlist_64 const *const nlist_start = ((void const *) dyld_local_symbols_info) + dyld_local_symbols_info->nlistOffset; | |
struct nlist_64 const *const nlist_end = nlist_start + dyld_local_symbols_info->nlistCount; | |
char const *const stringsStart = ((void const *) dyld_local_symbols_info) + dyld_local_symbols_info->stringsOffset; | |
char const *const stringsEnd = stringsStart + dyld_local_symbols_info->stringsSize; | |
bool found [sharedCacheSearchDataCount]; | |
bzero (found, sizeof (bool) * sharedCacheSearchDataCount); | |
size_t symaddrs_count = 0, symaddrs_allocated = 0x100; | |
struct found_addr *symaddrs = calloc (symaddrs_allocated, sizeof (struct found_addr)); | |
size_t not_found_count = sharedCacheSearchDataCount; | |
for (struct nlist_64 const *symbol = nlist_start; symbol < nlist_end; symbol++) { | |
char const *const symbol_name = stringsStart + symbol->n_un.n_strx; | |
if (symbol_name >= stringsEnd) { | |
continue; | |
} | |
for (size_t i = 0; i < sharedCacheSearchDataCount; i++) { | |
if (!strcmp (sharedCacheSearchData [i].name, symbol_name)) { | |
if (symaddrs_count == symaddrs_allocated) { | |
symaddrs_allocated <<= 1; | |
symaddrs = realloc (symaddrs, sizeof (struct found_addr) * symaddrs_allocated); | |
} | |
symaddrs [symaddrs_count++] = (struct found_addr) { .addr = symbol, .data_idx = i }; | |
if (!found [i]) { | |
found [i] = true; | |
--not_found_count; | |
} | |
} | |
} | |
} | |
if (not_found_count) { | |
fprintf (stderr, "Some symbols cannot be found in shared cache:"); | |
for (size_t i = 0; i < sharedCacheSearchDataCount; i++) { | |
if (!found [i]) { | |
fprintf (stderr, " %s", sharedCacheSearchData [i].name); | |
} | |
} | |
fprintf (stderr, "\n"); | |
munmap ((void *) dyld_local_symbols_info, dyld_cache_header.localSymbolsSize); | |
free (symaddrs); | |
return; | |
} | |
size_t real_cache_size; | |
void const *const real_shared_dyld_cache = _dyld_get_shared_cache_range (&real_cache_size); | |
struct dyld_cache_local_symbols_entry const *const local_entries_start = ((void *) dyld_local_symbols_info) + dyld_local_symbols_info->entriesOffset; | |
struct dyld_cache_local_symbols_entry const *const local_entries_end = local_entries_start + dyld_local_symbols_info->entriesCount; | |
not_found_count = symaddrs_count; | |
for (struct dyld_cache_local_symbols_entry const *local_entry = local_entries_start; local_entry < local_entries_end; local_entry++) { | |
for (struct found_addr *found_symbol = symaddrs; found_symbol < symaddrs + symaddrs_count; found_symbol++) { | |
if (!found_symbol->addr) { | |
continue; | |
} | |
uint32_t const nlist_idx = (uint32_t) (found_symbol->addr - nlist_start); | |
if ((local_entry->nlistStartIndex <= nlist_idx) && ((local_entry->nlistStartIndex + local_entry->nlistCount) > nlist_idx)) { | |
if (local_entry->dylibOffset > real_cache_size) { | |
fprintf (stderr, "%u is out of real cache bounds [0, %lu]\n", local_entry->dylibOffset, real_cache_size); | |
continue; | |
} | |
void const *const loaded_image = real_shared_dyld_cache + local_entry->dylibOffset; | |
void *const final_symbol_address = (void *) (found_symbol->addr->n_value + _dyld_get_image_slide (loaded_image)); | |
Dl_info dl_info; | |
dladdr (final_symbol_address, &dl_info); | |
fprintf (stderr, "Patching %s at %p in %s\n", sharedCacheSearchData [found_symbol->data_idx].name, final_symbol_address, dl_info.dli_fname); | |
memcpy (final_symbol_address, sharedCacheSearchData [found_symbol->data_idx].value, sharedCacheSearchData [found_symbol->data_idx].value_size); | |
found_symbol->addr = NULL; | |
not_found_count--; | |
} | |
} | |
} | |
if (not_found_count) { | |
fprintf (stderr, "Cannot find source images for symbols:"); | |
for (size_t i = 0; i < symaddrs_count; i++) { | |
if (symaddrs [i].addr) { | |
fprintf (stderr, " %s", sharedCacheSearchData [symaddrs [i].data_idx].name); | |
} | |
} | |
fprintf (stderr, "\n"); | |
} else { | |
fprintf (stderr, "Everything looks good, enjoy\n"); | |
} | |
munmap ((void *) dyld_local_symbols_info, dyld_cache_header.localSymbolsSize); | |
free (symaddrs); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment