(五) Hook C和Swift函數(shù)

1.用dlopen和dlsym進(jìn)行Hook或執(zhí)行代碼

1.1 Objective-C運(yùn)行時(shí)和Swift與C

  • Objective-C是動(dòng)態(tài)語(yǔ)言,當(dāng)objc_msgSend調(diào)用時(shí)在知道要怎么執(zhí)行。
  • Swift和C/C++表現(xiàn)類似锐想。如果不需要?jiǎng)討B(tài)性缀旁,編譯器就不會(huì)用蚪黑。所以你在看Swift匯編時(shí)抗楔,匯編直接調(diào)用方法地址就可以執(zhí)行惯雳。這種直接調(diào)用的方式就是dlopendlsym真正發(fā)揮的地方了已添。

1.2 簡(jiǎn)單模式Hook C函數(shù)

項(xiàng)目效果

一個(gè)簡(jiǎn)單的加水印的圖片妥箕。但是我們查看Assets.xcassets或者逆向工程師查看Assets.car都找不到這張圖片。因?yàn)樗菍?xiě)死在代碼里面的更舞,就像這樣

unsigned char ds_private_data_[] = {
  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, 0x02, 0x02,
  0x08, 0x06, 0x00, 0x00, 0x00, 0x13, 0x73, 0xb3, 0x4d, 0x00, 0x00, 0x00,
  0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b,
...}

我們先在項(xiàng)目里下了一個(gè)斷點(diǎn)畦幢,并打印RDI寄存器。

getenv
"MallocDebugReport"
"MallocErrorStop"
"MallocErrorSleep"
"MallocNanoMaxMagazines"
"_MallocNanoMaxMagazines"
"LIBDISPATCH_STRICT"
"DYLD_INSERT_LIBRARIES"
"NSZombiesEnabled"
...

在我們程序啟動(dòng)前getenv就已經(jīng)被執(zhí)行了缆蝉。如果你取消掉自動(dòng)繼續(xù)選項(xiàng)宇葱,你就會(huì)發(fā)現(xiàn)調(diào)用棧里面根本沒(méi)有main函數(shù)。

因?yàn)镃沒(méi)有動(dòng)態(tài)派發(fā)刊头,要hook一個(gè)函數(shù)必須要在它被加載之前攔截它黍瞧。另一方面來(lái)說(shuō),C函數(shù)相對(duì)容易獲取原杂,而且你只需要獲取函數(shù)方法名(不需要參數(shù))和C函數(shù)所在的動(dòng)態(tài)庫(kù)的名字印颤。

C函數(shù)的hook有很多方式,只是復(fù)雜度不同穿肄。如果你只是想在你的可執(zhí)行文件內(nèi)進(jìn)行hook年局,那還比較簡(jiǎn)單。但是如果你想在main函數(shù)前hook一個(gè)函數(shù)咸产,復(fù)雜度就提升了一個(gè)等級(jí)矢否。

一旦main函數(shù)被執(zhí)行,所有的動(dòng)態(tài)庫(kù)也都已加載完畢脑溢。dyld以深度優(yōu)先的方式遞歸加載動(dòng)態(tài)庫(kù)僵朗。一般來(lái)說(shuō),大多數(shù)外部函數(shù)是懶加載的,除非你用了特殊的鏈接配置衣迷。對(duì)于懶加載的外部函數(shù)來(lái)說(shuō)畏鼓,函數(shù)第一次調(diào)用時(shí),會(huì)觸發(fā)很多操作壶谒。dyld會(huì)找到這個(gè)模塊云矫,定位到這個(gè)函數(shù)。然后把這個(gè)值保存到內(nèi)存的一個(gè)特定部分(__DATA.__la_symbol_ptr)汗菜。一旦這個(gè)外部函數(shù)定下來(lái)了让禀,以后的調(diào)用就不需要用dyld來(lái)處理了。

如果你想在程序啟動(dòng)前就hook函數(shù)陨界,你就需要?jiǎng)?chuàng)建一個(gè)動(dòng)態(tài)庫(kù)來(lái)執(zhí)行hook操作巡揍,那么在main函數(shù)執(zhí)行前就已經(jīng)可用了。

我們?cè)诔绦騿?dòng)后獲取HOME環(huán)境變量菌瘪,然后進(jìn)行打印腮敌。HOME環(huán)境變量就是模擬器運(yùn)行app的地址。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
  if let cString = getenv("HOME") {
    let homeEnv = String(cString: cString)
    print("HOME env: \(homeEnv)")
  }
return true
}

//HOME env: /Users/xxx/Library/Developer/CoreSimulator/Devices/85225EEE-8D5B-4091-A742-5BEBAE1C4906/data/Containers/Data/Application/A3CF2AF5-6FB3-43E0-B809-C36F899FC72A

下面我們來(lái)hook一下getenv函數(shù)俏扩。先創(chuàng)建一個(gè)HookingC動(dòng)態(tài)庫(kù)糜工,語(yǔ)言選擇OC。并在這個(gè)庫(kù)里面創(chuàng)建一個(gè)getenvhook.h.c录淡。

HookingC

getenvhook.c中進(jìn)行替換捌木,注釋是在項(xiàng)目中的作用。

#import <dlfcn.h> // 引入dlopen和dlsym
#import <assert.h> // 測(cè)試包含getenv函數(shù)的庫(kù)是否正確加載
#import <stdio.h> // printf
#import <dispatch/dispatch.h> // dispatch_once
#import <string.h> // strcmp

char * getenv(const char *name) {
  return "YAY!";
}

//運(yùn)行后后臺(tái)打印
//HOME env: YAY!

如果輸入其他參數(shù)的時(shí)候嫉戚,想要進(jìn)行原來(lái)的操作刨裆,我們需要先找一下原來(lái)函數(shù)的名字。

(lldb) image lookup -s getenv
1 symbols match 'getenv' in /Users/xxx/Library/Developer/Xcode/DerivedData/Watermark-eecizmuedigyaobuhjmnlfaqxfgk/Build/Products/Debug-iphonesimulator/Watermark.app/Frameworks/HookingC.framework/HookingC:
        Address: HookingC[0x0000000000000f60] (HookingC.__TEXT.__text + 0)
        Summary: HookingC`getenv at getenvhook.c:15
1 symbols match 'getenv' in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/libsystem_c.dylib:
        Address: libsystem_c.dylib[0x000000000005a167] (libsystem_c.dylib.__TEXT.__text + 364823)
        Summary: libsystem_c.dylib`getenv

除了我們HookingC動(dòng)態(tài)庫(kù)彬檀,還有一個(gè)libsystem_c.dylib庫(kù)有這個(gè)函數(shù)帆啃,它的完整地址為/usr/lib/ system/libsystem_c.dylib。既然我們知道了函數(shù)在哪兒凤覆,下滿我們來(lái)用dlopen链瓦,函數(shù)簽名如下

extern void * dlopen(const char * __path, int __mode);

dlopen接受一個(gè)char *類型的路徑,和一個(gè)整型來(lái)決定它如何加載模塊盯桦。如果成功返回一個(gè)void *句柄,否則返回NULL渤刃。

dlopen返回一個(gè)對(duì)模塊的引用后拥峦,就可以使用dlsym來(lái)獲取對(duì)函數(shù)getenv的引用了。dlsym的函數(shù)簽名如下

extern void * dlsym(void * __handle, const char * __symbol);

第一個(gè)參數(shù)為dlopen返回的void *句柄卖子,第二個(gè)參數(shù)為要獲取的函數(shù)的名字略号。成功的話,會(huì)返回第二個(gè)指定的函數(shù)的地址,否則返回NULL玄柠。

替換原來(lái)的函數(shù)突梦,并執(zhí)行,我們會(huì)看到兩個(gè)getenv函數(shù)地址羽利。

char * getenv(const char *name) {
  void *handle = dlopen("/usr/lib/system/libsystem_c.dylib", RTLD_NOW);
  assert(handle);
  void *real_getenv = dlsym(handle, "getenv");
  printf("Real getenv: %p\nFake getenv: %p\n", real_getenv, getenv);
  return "YAY!";
}

//Real getenv: 0x7fff5232b167
//Fake getenv: 0x106c5fd80
//HOME env: YAY!

RTLD_NOW的意思是宫患,不需要進(jìn)行懶加載,立即加載这弧。

由于返回函數(shù)類型是void *娃闲,但實(shí)際我們知道函數(shù)的類型,我們來(lái)優(yōu)化一下匾浪。

char * getenv(const char *name) {
  static void *handle;
  static char * (*real_getenv)(const char *);
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    handle = dlopen("/usr/lib/system/libsystem_c.dylib", RTLD_NOW);
    assert(handle);
    real_getenv = dlsym(handle, "getenv");
  });
  //以上是利用static屬性皇帮,只獲取一次原始方法的句柄
  if (strcmp(name, "HOME") == 0) {
    return "/";
  }
  return real_getenv(name);
}

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
    if let cString = getenv("HOME") {
      let homeEnv = String(cString: cString)
      print("HOME env: \(homeEnv)")
    }
    if let cString = getenv("PATH") {
      let homeEnv = String(cString: cString)
      print("PATH env: \(homeEnv)")
    }
    return true
  }
HOME&PATH

可以看到現(xiàn)在hook只對(duì)HOME生效,對(duì)PATH來(lái)說(shuō)是可以拿到原本數(shù)據(jù)的蛋辈。

注意:如果調(diào)用了一個(gè)UIKit方法属拾,然后UIKit調(diào)用了getenv,那么新的getenv方法并不會(huì)被調(diào)用冷溶。因?yàn)?code>getenv的地址在UIKit的代碼被加載的時(shí)候已經(jīng)被解析了渐白。
如果你要修改UIKitgetenv,就需要操作間接符號(hào)表的知識(shí)挂洛,并修改__DATA.__la_symbol_ptr段中對(duì)應(yīng)getenv的函數(shù)地址了礼预。
這部分會(huì)涉及到使用fishhook,原理可參考fishhook x MachOView源碼閱讀虏劲。

1.3 困難模式Hook Swift函數(shù)

非動(dòng)態(tài)的Swift代碼就像C函數(shù)一樣托酸。這種方法有一些復(fù)雜的地方,使得它更難融入快速的方法中柒巫。

首先励堡,Swift在開(kāi)發(fā)中經(jīng)常使用類或結(jié)構(gòu)。這是一個(gè)獨(dú)特的挑戰(zhàn)堡掏,因?yàn)?code>dlsym只能提供一個(gè)C函數(shù)应结。我們需要擴(kuò)展這個(gè)函數(shù),以便Swift方法可以在獲取實(shí)例方法時(shí)引用self泉唁,或者在調(diào)用類方法時(shí)引用類鹅龄。當(dāng)訪問(wèn)屬于類的方法時(shí),程序匯編代碼在執(zhí)行該方法時(shí)通常會(huì)引用self或類的偏移量亭畜。由于dlysm只能提供一個(gè)C類型的函數(shù)扮休,因此我們需要利用匯編、參數(shù)和寄存器的知識(shí)拴鸵,將該C函數(shù)轉(zhuǎn)換為一個(gè)Swift方法玷坠。

第二個(gè)需要擔(dān)心的問(wèn)題是Swift會(huì)弄亂方法的名稱蜗搔。在代碼中看到的漂亮的名字,在模塊符號(hào)表中實(shí)際上是可怕的長(zhǎng)名字八堡。為了通過(guò)dlysm引用Swift方法樟凄,需要找到此方法弄亂后的正確名稱。

下面我們來(lái)看看怎么操作兄渺。

HookingSwift庫(kù)中有一個(gè)CopyrightImageGenerator類缝龄,但我們只能訪問(wèn)到公開(kāi)的watermarkedImage計(jì)算屬性,而私有的originalImage屬性訪問(wèn)不了溶耘。

public class CopyrightImageGenerator {

  // MARK: - Properties
  private var imageData: Data? {
    guard let data = ds_private_data else { return nil }

    return Data(bytes: data, count: Int(ds_private_data_len))
  }

  private var originalImage: UIImage? {
    guard let imageData = imageData else { return nil }

    return UIImage(data: imageData)
  }

  public var watermarkedImage: UIImage? {
    guard let originalImage = originalImage,
      let topImage = UIImage(named: "copyright",
                             in: Bundle(identifier: "com.razeware.HookingSwift"),
                             compatibleWith: nil) else {
        return nil
    }

    let size = originalImage.size
    UIGraphicsBeginImageContext(size)

    let area = CGRect(x: 0, y: 0, width: size.width, height: size.height)
    originalImage.draw(in: area)

    topImage.draw(in: area, blendMode: .normal, alpha: 0.50)

    let mergedImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return mergedImage
  }

  // MARK: - Initializers
  public init() {}
}

Watermark.app包里面二拐,我們可以看到HookingSwift.framework

HookingSwift

因?yàn)橹?code>originalImage是用Swift實(shí)現(xiàn)的凳兵,我們需要用Swift模式來(lái)進(jìn)行image搜索百新。

(lldb) image lookup -rn HookingSwift.*originalImage
1 match found in /Users/xxx/Library/Developer/Xcode/DerivedData/Watermark-eecizmuedigyaobuhjmnlfaqxfgk/Build/Products/Debug-iphonesimulator/Watermark.app/Frameworks/HookingSwift.framework/HookingSwift:
        Address: HookingSwift[0x0000000000000f70] (HookingSwift.__TEXT.__text + 512)
        Summary: HookingSwift`HookingSwift.CopyrightImageGenerator.(originalImage in _71AD57F3ABD678B113CF3AD05D01FF41).getter : Swift.Optional<__C.UIImage> at CopyrightImageGenerator.swift:42

函數(shù)地址是0x0000000000000f70,但這只是在HookingSwift庫(kù)中的地址庐扫。我們繼續(xù)饭望。

(lldb) image dump symtab -m HookingSwift
...
[    4]     51 D X Code            0x0000000000000f70 0x0000000106368f70 0x0000000000000100 0x000f0000 $s12HookingSwift23CopyrightImageGeneratorC08originalD033_71AD57F3ABD678B113CF3AD05D01FF41LLSo7UIImageCSgvg
...

通過(guò)0x0000000000000f70進(jìn)行搜索,我們可以看到這個(gè)方法名叫

$s12HookingSwift23CopyrightImageGeneratorC08originalD033_71AD57F3ABD678B113CF3AD05D01FF41LLSo7UIImageCSgvg

現(xiàn)在我們拿到了模塊和相應(yīng)的方法名形庭,就可以利用dlopendlsym來(lái)找到函數(shù)地址了铅辞。

if let handle = dlopen("./Frameworks/HookingSwift.framework/HookingSwift", RTLD_NOW),
      let sym = dlsym(handle, "$s12HookingSwift23CopyrightImageGeneratorC08originalD033_71AD57F3ABD678B113CF3AD05D01FF41LLSo7UIImageCSgvg") {
      print("\(sym)")
}

//打印
0x000000010f354f70

//在上面的地址處設(shè)置一個(gè)斷點(diǎn),看一下對(duì)不對(duì)
(lldb) b 0x000000010f354f70
Breakpoint 1: where = HookingSwift`HookingSwift.CopyrightImageGenerator.(originalImage in _71AD57F3ABD678B113CF3AD05D01FF41).getter : Swift.Optional<__C.UIImage> at CopyrightImageGenerator.swift:42, address = 0x000000010f354f70

好了萨醒,我們找到了函數(shù)地址斟珊。那我們?cè)趺凑{(diào)用它呢?幸好富纸,我們可以用Swift的關(guān)鍵字typealias來(lái)進(jìn)行函數(shù)的類型轉(zhuǎn)換囤踩。

let imageGenerator = CopyrightImageGenerator()
if let handle = dlopen("./Frameworks/HookingSwift.framework/HookingSwift", RTLD_NOW),
  let sym = dlsym(handle, "$s12HookingSwift23CopyrightImageGeneratorC08originalD033_71AD57F3ABD678B113CF3AD05D01FF41LLSo7UIImageCSgvg") {
  typealias privateMethodAlias = @convention(c) (Any) -> UIImage? // 1
  let originalImageFunction = unsafeBitCast(sym, to: privateMethodAlias.self) // 2
  let originalImage = originalImageFunction(imageGenerator) // 3
  imageView.image = originalImage // 4
}
  1. 定義類型。Swift的方法里面originalImage并不需要參數(shù)晓褪,為什么這里的方法會(huì)帶一個(gè)Any類型的參數(shù)呢堵漱?因?yàn)楹瘮?shù)執(zhí)行時(shí),匯編代碼會(huì)從RDI寄存器中獲取self涣仿,所以我們需要把實(shí)例作為第一個(gè)參數(shù)傳進(jìn)去勤庐。否者,程序就會(huì)崩潰好港。
  2. 我們定義完類型就可以進(jìn)行類型轉(zhuǎn)換了愉镰。我們把sym指針轉(zhuǎn)換成對(duì)應(yīng)的函數(shù)類型。然后我們就可以通過(guò)originalImageFunction進(jìn)行調(diào)用了钧汹。
  3. 我們通過(guò)傳入imageGenerator實(shí)例對(duì)象岛杀,獲取原始的圖像,放到originalImage中崭孤。
  4. 我們把沒(méi)有水印的圖片放到視圖中类嗤。


    去水印
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市辨宠,隨后出現(xiàn)的幾起案子遗锣,更是在濱河造成了極大的恐慌,老刑警劉巖嗤形,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件精偿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡赋兵,警方通過(guò)查閱死者的電腦和手機(jī)笔咽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)霹期,“玉大人叶组,你說(shuō)我怎么就攤上這事±欤” “怎么了甩十?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吭产。 經(jīng)常有香客問(wèn)我侣监,道長(zhǎng),這世上最難降的妖魔是什么臣淤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任橄霉,我火速辦了婚禮,結(jié)果婚禮上邑蒋,老公的妹妹穿的比我還像新娘姓蜂。我一直安慰自己,他們只是感情好寺董,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布覆糟。 她就那樣靜靜地躺著,像睡著了一般遮咖。 火紅的嫁衣襯著肌膚如雪滩字。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天御吞,我揣著相機(jī)與錄音麦箍,去河邊找鬼。 笑死陶珠,一個(gè)胖子當(dāng)著我的面吹牛挟裂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播揍诽,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼诀蓉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼栗竖!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起渠啤,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤狐肢,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后沥曹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體份名,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年妓美,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了僵腺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡壶栋,死狀恐怖辰如,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情委刘,我是刑警寧澤丧没,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站锡移,受9級(jí)特大地震影響呕童,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜淆珊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一夺饲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧施符,春花似錦往声、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至听哭,卻和暖如春慢洋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背陆盘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工普筹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人隘马。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓太防,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親酸员。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蜒车,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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

  • hook C函數(shù) 先拿一個(gè)簡(jiǎn)單的c函數(shù)getenv上手讳嘱。這個(gè)函數(shù)接受一個(gè)char *類型的參數(shù)(得是null te...
    blueshadow閱讀 5,784評(píng)論 0 7
  • Preload簡(jiǎn)介L(zhǎng)inux常見(jiàn)Hook技術(shù)對(duì)比函數(shù)調(diào)用類型內(nèi)核模塊Hook應(yīng)用層Inline HookGot表應(yīng)...
    超哥__閱讀 15,857評(píng)論 1 3
  • 我們?cè)谧鯝pp逆向時(shí),會(huì)遇到各種類型App醇王,雖然大部分是OC工程呢燥,越來(lái)越多App采用了混合(OC和Swift)開(kāi)發(fā)...
    史貴嶺閱讀 10,223評(píng)論 3 17
  • 動(dòng)態(tài)鏈接,在可執(zhí)行文件裝載時(shí)或運(yùn)行時(shí)寓娩,由操作系統(tǒng)的裝載程序加載庫(kù)。大多數(shù)操作系統(tǒng)將解析外部引用(比如庫(kù))作為加載過(guò)...
    小5筒閱讀 5,476評(píng)論 0 3
  • 1. 背景 在我們的日常工作中經(jīng)常會(huì)遇到一些BUG呼渣,而且這些BUG發(fā)生在native層棘伴,也就是在我們的so共...
    2baf611355d8閱讀 17,095評(píng)論 3 41