1.獲取APP全部自定義類名
最近需要有個(gè)需求,涉及到runtime打印所有的自定義類名艘蹋,那么如何區(qū)分自己的類和系統(tǒng)定義的類呢瓶竭?查了些資料發(fā)現(xiàn)可用dladdr來實(shí)現(xiàn),在寒神的XXShield里面也有類似使用洛搀;dladdr可獲得一個(gè)函數(shù)所在模塊,名稱以及地址佑淀。
引入頭文件 #import <dlfcn.h>
獲取自定義類名:
int numClasses;
Class * classes = NULL;
classes = NULL;
numClasses = objc_getClassList(NULL, 0);
if (numClasses > 0 )
{
static struct dl_info app_info;
if (app_info.dli_saddr == NULL) {
dladdr((__bridge void *)[UIApplication.sharedApplication.delegate class], &app_info);
}
classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
for (int i = 0; i < numClasses; i++) {
Class c = classes[i];
struct dl_info self_info = {0};
dladdr((__bridge void *)c, &self_info);
// 忽略系統(tǒng)函數(shù)
if (self_info.dli_fname == NULL || strcmp(app_info.dli_fname, self_info.dli_fname)) {
}else{
//自定義函數(shù)
NSLog(@"%s", class_getName(c));
}
}
free(classes);
}
當(dāng)dladdr((__bridge void *)[self class], &self_info)中的self為我們自定義的一個(gè)UIViewController的時(shí)候留美。
self_info.dli_fname打印出的為模塊路徑:
/Users/ganvinalix/Library/Developer/CoreSimulator/Devices/13BD3F3B-2C8C-40BB-8CC1-96C71FD0CBBF/data/Containers/Bundle/Application/DF26258E-2F6F-418F-80C3-751D03FD1F21/XXShield_Example.app/XXShield_Example
當(dāng)dladdr((__bridge void *)[NSObject class], &self_info);NSObject是系統(tǒng)SDK函數(shù)。
self_info.dli_fname打印出的為模塊路徑:
"/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/libobjc.A.dylib"
app_info.dli_fname打印出的為模塊路徑:
"/Users/ganvinalix/Library/Developer/CoreSimulator/Devices/13BD3F3B-2C8C-40BB-8CC1-96C71FD0CBBF/data/Containers/Bundle/Application/3D34D2D9-4556-4E0B-93F4-08034E9975A4/XXShield_Example.app/XXShield_Example"
總之就是要比較的類的dli_fname,如果和app的sharedApplication.delegate類的dli_fname相同就為自定義類谎砾,否則為系統(tǒng)SDK類
當(dāng)然dladdr還可以做一些安全驗(yàn)證方面的事情逢倍。推薦慶哥早期文章,iOS安全–驗(yàn)證函數(shù)地址景图,檢測(cè)是否被替換较雕,反注;
http://www.blogfshare.com/ioss-validate-address.html
2.打印APP加載的所有動(dòng)態(tài)鏈接庫的名稱與大小等相關(guān)信息
#include <mach-o/getsect.h>
#include <mach-o/loader.h>
#include <mach-o/dyld.h>
#include <dlfcn.h>
#import <objc/runtime.h>
#import <objc/message.h>
#include <mach-o/ldsyms.h>
NSArray<NSString *>* KGReadConfiguration(char *sectionName,const struct mach_header *mhp);
static uint32_t _image_header_size(const struct mach_header *mh)
{
bool is_header_64_bit = (mh->magic == MH_MAGIC_64 || mh->magic == MH_CIGAM_64);
return (is_header_64_bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header));
}
static void _image_visit_load_commands(const struct mach_header *mh, void (^visitor)(struct load_command *lc, bool *stop))
{
assert(visitor != NULL);
uintptr_t lc_cursor = (uintptr_t)mh + _image_header_size(mh);
for (uint32_t idx = 0; idx < mh->ncmds; idx++) {
struct load_command *lc = (struct load_command *)lc_cursor;
bool stop = false;
visitor(lc, &stop);
if (stop) {
return;
}
lc_cursor += lc->cmdsize;
}
}
static uint64_t _image_text_segment_size(const struct mach_header *mh)
{
static const char *text_segment_name = "__TEXT";
__block uint64_t text_size = 0;
_image_visit_load_commands(mh, ^ (struct load_command *lc, bool *stop) {
if (lc->cmdsize == 0) {
return;
}
if (lc->cmd == LC_SEGMENT) {
struct segment_command *seg_cmd = (struct segment_command *)lc;
if (strcmp(seg_cmd->segname, text_segment_name) == 0) {
text_size = seg_cmd->vmsize;
*stop = true;
return;
}
}
if (lc->cmd == LC_SEGMENT_64) {
struct segment_command_64 *seg_cmd = (struct segment_command_64 *)lc;
if (strcmp(seg_cmd->segname, text_segment_name) == 0) {
text_size = seg_cmd->vmsize;
*stop = true;
return;
}
}
});
return text_size;
}
static const uuid_t *_image_retrieve_uuid(const struct mach_header *mh)
{
__block const struct uuid_command *uuid_cmd = NULL;
_image_visit_load_commands(mh, ^ (struct load_command *lc, bool *stop) {
if (lc->cmdsize == 0) {
return;
}
if (lc->cmd == LC_UUID) {
uuid_cmd = (const struct uuid_command *)lc;
*stop = true;
}
});
if (uuid_cmd == NULL) {
return NULL;
}
return &uuid_cmd->uuid;
}
static void _print_image(const struct mach_header *mh, bool added)
{
Dl_info image_info;
int result = dladdr(mh, &image_info);
if (result == 0) {
printf("Could not print info for mach_header: %p\n\n", mh);
return;
}
const char *image_name = image_info.dli_fname;
const intptr_t image_base_address = (intptr_t)image_info.dli_fbase;
const uint64_t image_text_size = _image_text_segment_size(mh);
char image_uuid[37];
const uuid_t *image_uuid_bytes = _image_retrieve_uuid(mh);
uuid_unparse(*image_uuid_bytes, image_uuid);
const char *log = added ? "Added" : "Removed";
printf("%s: 0x%02lx (0x%02llx) %s <%s>\n\n", log, image_base_address, image_text_size, image_name, image_uuid);
}
static void dyld_callback(const struct mach_header *mhp, intptr_t vmaddr_slide)
{
_print_image(mhp, true);
}
//注冊(cè)main之前的析構(gòu)函數(shù),析構(gòu)函數(shù)僅愛周注解才能生效
__attribute__((constructor))
void initProphet() {
//動(dòng)態(tài)鏈接庫加載的時(shí)候的hook挚币,可能會(huì)回調(diào)次數(shù)比較多亮蒋,可能不建議
_dyld_register_func_for_add_image(dyld_callback);
}