Skip to content

Instantly share code, notes, and snippets.

@byss
Last active May 5, 2019 06:40
Show Gist options
  • Save byss/c9154a9b96a609786c712be2a2cb1f06 to your computer and use it in GitHub Desktop.
Save byss/c9154a9b96a609786c712be2a2cb1f06 to your computer and use it in GitHub Desktop.
Enables UIDebuggingOverlay by overriding all UIKit device checks
//
// 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