動(dòng)態(tài)鏈接庫加載拾遺&dladdr函數(shù)使用

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);
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市妆毕,隨后出現(xiàn)的幾起案子慎玖,更是在濱河造成了極大的恐慌,老刑警劉巖笛粘,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趁怔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡薪前,警方通過查閱死者的電腦和手機(jī)润努,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來示括,“玉大人铺浇,你說我怎么就攤上這事±鳎” “怎么了随抠?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)繁涂。 經(jīng)常有香客問我拱她,道長(zhǎng),這世上最難降的妖魔是什么扔罪? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任秉沼,我火速辦了婚禮,結(jié)果婚禮上矿酵,老公的妹妹穿的比我還像新娘唬复。我一直安慰自己,他們只是感情好全肮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布敞咧。 她就那樣靜靜地躺著,像睡著了一般辜腺。 火紅的嫁衣襯著肌膚如雪休建。 梳的紋絲不亂的頭發(fā)上乍恐,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音测砂,去河邊找鬼茵烈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛砌些,可吹牛的內(nèi)容都是我干的呜投。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼存璃,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼仑荐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起有巧,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤释漆,失蹤者是張志新(化名)和其女友劉穎悲没,沒想到半個(gè)月后篮迎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡示姿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年甜橱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栈戳。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡岂傲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出子檀,到底是詐尸還是另有隱情镊掖,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布褂痰,位于F島的核電站亩进,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏缩歪。R本人自食惡果不足惜归薛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望匪蝙。 院中可真熱鬧主籍,春花似錦、人聲如沸逛球。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颤绕。三九已至幸海,卻和暖如春蜡歹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涕烧。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工月而, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人议纯。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓父款,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親瞻凤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子憨攒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,383評(píng)論 8 265
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,715評(píng)論 0 9
  • 使用原生JavaScript制作一個(gè)漂亮的音樂播放器【html阀参、css肝集、jq】制作一個(gè)簡(jiǎn)潔的音樂播放器Rythm....
    環(huán)零弦閱讀 147評(píng)論 0 0
  • 今日的主題衙荐,希望寶貝近期不要過于勞累了捞挥,明天周五了,還有一天可以見到寶貝了忧吟,真開心…睡覺晚安砌函! ...
    青春獻(xiàn)給老酒桌閱讀 118評(píng)論 0 0
  • 五點(diǎn)多,鬧鈴響了溜族,我慢慢睜開眼睛讹俊,透過半掩的窗戶,望向窗外煌抒。天灰蒙蒙的仍劈,怕驚醒熟睡的朋友,每次都在黑暗中慢慢摸著昨...
    雨憶半陽閱讀 168評(píng)論 0 0