亚洲日本免费-啊轻点灬太粗太长了三男一女-麻豆av电影在线观看-日韩一级片毛片|www.grbbt.com

iOS 表情符號(hào)拒絕服務(wù)漏洞詳情披露(CVE-2018-4290)

前言

在我們深入討論之前,請(qǐng)注意:

  • 這個(gè)bug只是拒絕服務(wù)(相對(duì)于遠(yuǎn)程編碼執(zhí)行)。
  • 這個(gè)bug僅影響某些“無區(qū)域”配置中的iOS設(shè)備。
  • 這個(gè)bug在iOS 11.4.1已被修補(bǔ)為CVE-2018-4290。

話雖如此,這個(gè)bug還是可以遠(yuǎn)程觸發(fā)的,而且可以導(dǎo)致受影響的設(shè)備上任何正在處理遠(yuǎn)程消息(iMessage、Facebook Messenger、WhatsApp等)的iOS應(yīng)用程序都會(huì)崩潰!

背景

“Patrick,我想中國(guó)黑了我的iPhone”

雖然我通常會(huì)對(duì)這種難以置信的情景一笑置之,但我正在研究我的情緒智力,耐心地詢問為什么我的臺(tái)灣朋友會(huì)這樣想。

她聲稱,每當(dāng)她輸入臺(tái)灣或更糟的詞時(shí),都會(huì)收到一條帶有臺(tái)灣旗幟(????)的消息,這會(huì)讓她的iOS設(shè)備上的應(yīng)用程序崩潰。

我仍然有點(diǎn)懷疑,但如下所示,這正是正在發(fā)生的事情!

我給她發(fā)了多個(gè)臺(tái)灣旗幟,導(dǎo)致她的iMessage、Facebook Messenger和WhatsApp持續(xù)崩潰。

在這篇文章中,我們將說明如何分析和跟蹤這個(gè)遠(yuǎn)程iOS缺陷的根本原因。

崩潰

崩潰的設(shè)備是運(yùn)行iOS 11.3(當(dāng)時(shí)最新版本的iOS)的iPhone 7:

Device: iPhone 7, iPhone9,1 (US)
iOS: 11.3 (15E216)
Language: English, followed by Chinese
Region: United States
Jailbroken: No

以下是iMessenger(MobileSMS)提供的經(jīng)過刪減的崩潰報(bào)告。它是從設(shè)備(通過Settings -> Privacy, Analytics, Analytics Data)獲取的:

{"app_name":"MobileSMS","timestamp":"2018-04-18 22:27:25.13 -0700","app_version":"5.0",  
"slice_uuid":"feac9bde-20a2-37c2-86e0-119fb8b9b650","adam_id":0,"build_version":"1.0",  
"bundleID":"com.apple.MobileSMS","share_with_app_devs":false,"is_first_party":true,  
"bug_type":"109","os_version":"iPhone OS 11.3  
 (15E216)","incident_id":"9EE5610B-7A0C-4558-895F-CF876DEB6B07","name":"MobileSMS"}  

Incident Identifier: 9EE5610B-7A0C-4558-895F-CF876DEB6B07
CrashReporter Key:   69340bb1126c092b97b9af069f4f6f037466ee0c
Hardware Model:      iPhone9,1
Process:             MobileSMS [10417]
Path:                /Applications/MobileSMS.app/MobileSMS
Identifier:          com.apple.MobileSMS
Version:             1.0 (5.0)
Code Type:           ARM-64 (Native)
Role:                Foreground
Parent Process:      launchd [1]
Coalition:           com.apple.MobileSMS [2015]


Date/Time:           2018-04-18 22:27:24.9896 -0700
Launch Time:         2018-04-18 22:26:16.9044 -0700
OS Version:          iPhone OS 11.3 (15E216)
Baseband Version:    3.66.00
Report Version:      104

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000

Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [0]
Triggered by Thread:  6

Filtered syslog:
None found

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib            0x00000001824b3e08 0x1824b3000 + 3592
1   libsystem_kernel.dylib            0x00000001824b3c80 0x1824b3000 + 3200
2   CoreFoundation                    0x00000001829f6e40 0x182909000 + 974400
3   CoreFoundation                    0x00000001829f4908 0x182909000 + 964872
4   CoreFoundation                    0x0000000182914da8 0x182909000 + 48552
5   GraphicsServices                  0x00000001848f7020 0x1848ec000 + 45088
6   UIKit                             0x000000018c8f578c 0x18c5d8000 + 3266444
7   MobileSMS                         0x0000000100e1867c 0x100df8000 + 132732
8   libdyld.dylib                     0x00000001823a5fc0 0x1823a5000 + 4032

....

Thread 6 name:  Dispatch queue: com.apple.ResponseKit
Thread 6 Crashed:
0   CoreFoundation                    0x0000000182922efc 0x182909000 + 106236
1   CoreEmoji                         0x00000001886b2354 0x1886a6000 + 50004
2   CoreEmoji                         0x00000001886b2354 0x1886a6000 + 50004
3   CoreEmoji                         0x00000001886b2c80 0x1886a6000 + 52352
4   CoreEmoji                         0x00000001886a8ebc 0x1886a6000 + 11964
5   ResponseKit                       0x00000001968754ac 0x19683d000 + 230572
6   ResponseKit                       0x0000000196872e9c 0x19683d000 + 220828
7   ResponseKit                       0x00000001968739b4 0x19683d000 + 223668
8   ResponseKit                       0x0000000196862e78 0x19683d000 + 155256
9   ResponseKit                       0x0000000196862c00 0x19683d000 + 154624
10  ResponseKit                       0x00000001968619f0 0x19683d000 + 150000
11  libdispatch.dylib                 0x0000000182340b24 0x18233f000 + 6948
12  libdispatch.dylib                 0x0000000182340ae4 0x18233f000 + 6884
13  libdispatch.dylib                 0x000000018234aa38 0x18233f000 + 47672
14  libdispatch.dylib                 0x000000018234b380 0x18233f000 + 50048
15  libdispatch.dylib                 0x000000018234bd4c 0x18233f000 + 52556
16  libdispatch.dylib                 0x000000018235411c 0x18233f000 + 86300
17  libsystem_pthread.dylib           0x0000000182673e70 0x182673000 + 3696
18  libsystem_pthread.dylib           0x0000000182673b08 0x182673000 + 2824


Thread 6 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x00000001add1ad38   x2: 0x0000000000000000   x3: 0x00000001ad364438
    x4: 0x0000000000000000   x5: 0x0000000000000001   x6: 0x0000000000000000   x7: 0x0000000000000000
    x8: 0x0000000000000000   x9: 0x00000001b4e15930  x10: 0x0000000ffffffff8  x11: 0x0000000000000040
   x12: 0xffffffffffffffff  x13: 0x0000000000000001  x14: 0x0000000000000000  x15: 0x00002d0000002d00
   x16: 0x0000000000000000  x17: 0x0000000000002d00  x18: 0x0000000000000000  x19: 0x0000000000000000
   x20: 0x00000001add1ad38  x21: 0x0000000000000000  x22: 0x0000000000000000  x23: 0x00000001c4864cc0
   x24: 0x00000001000404ef  x25: 0x0000000000050000  x26: 0x0000000103d059e4  x27: 0x0000000103d059e4
   x28: 0x0000000000000000   fp: 0x000000016f1a5b20   lr: 0x00000001886b2354
    sp: 0x000000016f1a5b00   pc: 0x0000000182922efc cpsr: 0x80000000

Binary Images:
0x100df8000 - 0x100e43fff MobileSMS arm64  <feac9bde20a237c286e0119fb8b9b650> /Applications/MobileSMS.app/MobileSMS

0x182909000 - 0x182c9ffff CoreFoundation arm64  <cf162b3ca2883453b2914300d4f19612> /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
0x1886a6000 - 0x1886b7fff CoreEmoji arm64  <6d18237f09d23ce6aa6abb287d7aa515> /System/Library/PrivateFrameworks/CoreEmoji.framework/CoreEmoji
0x19683d000 - 0x19693ffff ResponseKit arm64  <4f7abc9a8f803cb2bff0172b8c69f13e> /System/Library/PrivateFrameworks/ResponseKit.framework/ResponseKit

我們將更詳細(xì)地討論這個(gè)問題,但是簡(jiǎn)單說就是在地址0x00000000000000處發(fā)生一個(gè)EXC_BAD_ACCESS (SIGSEGV) (Exception Subtype: KERN_INVALID_ADDRESS)。

這類崩潰通常表示空指針解引用(NULL-pointer dereference)。在這里,這個(gè)錯(cuò)誤似乎是在iOS執(zhí)行某種類型的表情處理時(shí)觸發(fā)的(這與iMessenger接收到的臺(tái)灣標(biāo)志的觸發(fā)相吻合)。

iOS系統(tǒng)崩潰報(bào)告中的其他相關(guān)信息包括:

  • 故障指令地址(0x0000000182922efc)
  • 崩潰前線程(#6)的調(diào)用堆棧
  • 相關(guān)的dylib(即調(diào)用堆棧中的那些)

崩潰分析

我們的目標(biāo)是現(xiàn)在追查崩潰的原因。也就是說,為什么0x0000000182922efc上的指令取消引用一個(gè)空指針?

我們將從反轉(zhuǎn)調(diào)用堆棧中出現(xiàn)的動(dòng)態(tài)庫(ResponseKit、CoreEmoji和CoreFoundation)開始。具體來說,我們將檢查在調(diào)用堆棧中出現(xiàn)的這些dylib中的地址的代碼。

因?yàn)槲遗笥训氖謾C(jī)沒有越獄,所以我們只能從設(shè)備中獲取dylib二進(jìn)制文件.我們必須從其他地方獲取它們。事實(shí)證明,最簡(jiǎn)單的是來自于iOS 11.3的恢復(fù)映像。這類還原映像包含iOS系統(tǒng)二進(jìn)制文件,例如我們要尋找的dylib。我們可以從ipsw.me獲取iOS 11.3還原映像(iPhone_4.7_P3_11.0_11.3_15E216_Restore.ipsw)

下載這個(gè)文件后,我們就可以通過hdiutil命令掛載058-97716-127.dmg磁盤映像:

$ hdiutil attach iPhone_4.7_P3_11.0_11.3_15E216_Restore/058-97716-127.dmg expected CRC32 $BDE79F12 /dev/disk2 GUID_partition_scheme
/dev/disk2s1 EFI
/dev/disk2s2 Apple_APFS
/dev/disk3 EF57347C-0000-11AA-AA11-0030654 /dev/disk3s1 41504653-0000-11AA-AA11-0030654 /Volumes/Emet15E216.D10D101D20D201OS

由于我們要尋找的dylib被嵌入到dyld共享緩存(dyld_shared_cache_arm64)中,所以我們必須提取它們。

使用jtool,這是最直接的,只需指定要提取的dylib的名稱(例如CoreEmoji),然后指定共享緩存的路徑:

jtool -e "CoreEmoji" /Volumes/Emet15E216.D10D101D20D201OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64
Extracting /System/Library/PrivateFrameworks/CoreEmoji.framework/CoreEmoji at 0x6b4e000 into dyld_shared_cache_arm64.CoreEmoji

提取了以下dylib(在崩潰線程的調(diào)用堆棧中分別引用了這些dylib):

yld_shared_cache_arm64_CoreEmoji
version: 69.3.0
sha1: 20F6BECF7C76A3FEAFEB8D2321F593388A3CB9B6

dyld_shared_cache_arm64_CoreFoundation
version: 1452.23.0
sha1: AD3A226884BB3612694B9AB37DF18F42452D5139

dyld_shared_cache_arm64_ResponseKit
version 109.0.0
sha1: BDA7F1F329321C20539499EAF1C36693823CF60E

不幸的是,我們必須符號(hào)化這些dylib,因?yàn)樗麄兊拇蠖鄶?shù)符號(hào)都被“編輯”了:

$ nm dyld_shared_cache_arm64_ResponseKit
0000000194ce6f9c t <redacted>
0000000194ce701c t <redacted>
0000000194ce7090 t <redacted>
0000000194ce70c4 t <redacted>
0000000194ce71e4 t <redacted>
0000000194ce72e0 t <redacted>
0000000194ce72e8 t <redacted>
0000000194ce72f0 t <redacted>
0000000194ce735c t <redacted>
0000000194ce7444 t <redacted>
...

不過,首先讓我們對(duì)提取的iOS dylib進(jìn)行重新定位,以便它們的地址(在反匯編程序/反編譯器中查看時(shí))與崩潰報(bào)告中的地址相匹配。

要對(duì)每個(gè)提取的dylib進(jìn)行重新定位,我們使用崩潰報(bào)告中的基地址(例如CoreEmoji的0x1886a6000)。在Hopper中,可以通過Modify -> Change File Base Address…來重新建立二進(jìn)制文件的基地址:

t012c57ac7295f94a20

一旦重設(shè)好了,我們就可以解決符號(hào)的問題了。

我不確定這樣做的最佳方式,所以我只是利用了每個(gè)dylib的MacOS版本。具體來說,我將符號(hào)化的x64匯編(MacOS)與無符號(hào)的ARM64匯編(iOS)“匹配”。雖然有手動(dòng)過程,但這工作得很好!

例如,以地址0x0000000196862c00(來自調(diào)用堆棧中的第9幀)為例。下面是方法的完整反編譯(在IOS ResponseKit dylib中),其中包含地址0x00000196862c00:

//iOS ResponseKit
int <redacted>_194d0ab58(int arg0) {
    r25 = loc_19147d5e0(r2);
    r22 = loc_19147d5e0(r4);
    loc_19147d5e0(r5);
    r27 = *_RKMessageResponseDontOverrideLanguageID | r7;
    loc_19147d5e0(r6);
    loc_19147d5d8(arg0, 0x1b3e37900, r25, r3, r22, r5, &var_58, 0x0, r27);
    loc_19147d5e8();
    loc_19147d5dc(r26);
    loc_19147d5dc(r22);
    loc_19147d5dc(r25);
    loc_19147d5e0(var_58);
    loc_19147d5dc(r20);
    loc_19147d5dc(r21);
    r0 = loc_19147d7cc(r19);
    return r0;
}

如果我們反編譯MacOS的ResponseKit(/System/Library/PrivateFrameworks/ResponseKit.framework),我們可以在RKMessageResponseManager responsesForMessageImp:maximumResponses:forConversationHistory:forContext:withLanguage:options:方法中找到“匹配的”x64反編譯(請(qǐng)注意對(duì)RKMessageResponseDontOverrideLanguageID符號(hào)的引用):

* @class RKMessageResponseManager */
-(void *)responsesForMessageImp:(void *)arg2 maximumResponses:(unsigned long long)arg3 forConversationHistory:(void *)arg4 forContext:(void *)arg5 withLanguage:(void *)arg6 options:(unsigned long long)arg7 {
    r14 = [arg2 retain];
    r15 = [arg4 retain];
    var_38 = [arg5 retain];
    var_30 = arg6;
    rbx = *_RKMessageResponseDontOverrideLanguageID;
    r13 = [arg6 retain];
    rax = [self responsesForMessageWithLanguageDetectionImp:r14 maximumResponses:arg3 forConversationHistory:r15 forContext:arg5 withLanguage:&var_30 inputModes:0x0 options:rbx | arg7];
    [var_38 release];
    [r15 release];
    [r14 release];
    r14 = [rax retain];
    rbx = [var_30 retain];
    [r13 release];
    [rbx release];
    rax = [r14 autorelease];
    return rax;
}

現(xiàn)在我們知道iOS ResponseKit dylib中的int_194d0ab58方法實(shí)際上是RKMessageResponseManager responsesForMessageImp:maximumResponses:forConversationHistory:forContext:withLanguage:options:方法(注意對(duì)RKMessageResponseDontOverrideLanguageID符號(hào)的引用)。

一旦對(duì)dylib進(jìn)行了重新基和(手動(dòng))符號(hào)化,就更容易理解這個(gè)bug了,因?yàn)榉椒麑?duì)它們的用途有相當(dāng)?shù)拿枋鲂浴?/p>

我們將從分析崩潰線程(線程6)的調(diào)用堆棧中的地址開始,以揭示這個(gè)遠(yuǎn)程iOS bug的根本原因。

跳過對(duì)libDispatch.dylib的調(diào)用,從堆棧幀#10開始,并將每個(gè)地址映射到它所屬的符號(hào)化方法(或塊):

#10  ResponseKit   0x00000001968619f0
-[RKMessageResponseManager responsesForMessage:maximumResponses:forContext:withLanguage:options:completionBlock:]

#9 ResponseKit  0x0000000196862c00
-[RKMessageResponseManager responsesForMessageImp:maximumResponses:forConversationHistory:forContext:withLanguage:options:]

#8 ResponseKit  0x0000000196862e78
-[RKMessageResponseManager responsesForMessageWithLanguageDetectionImp:maximumResponses:forConversationHistory:forContext:withLanguage:inputModes:options:]:

#7 ResponseKit  0x00000001968739b4
 +[RKMessageClassifier messageClassification:withLanguageIdentifier:conversationTurns:]:

#6 ResponseKit  0x0000000196872e9c
-[NSLinguisticTagger languageOfRange:withAdditionalContext:withPreferredLanguages:]

#5 ResponseKit  0x00000001968754ac
+[RKUtilities removeEmoji:]

#4 CoreEmoji  0x00000001886a8ebc
CEMStringContainsEmoji

#3 CoreEmoji  0x00000001886b2c80
unnamed subroutine

#2 CoreEmoji  0x00000001886b2354
unnamed subroutine

#1 CoreEmoji  0x00000001886b2354
unnamed subroutine

#0 CoreFoundation  0x0000000182922efc
CFStringCompare + 0x38

好吧發(fā)生什么事了?看起來是這樣的,當(dāng)接收到消息時(shí),ResponseKit會(huì)對(duì)消息進(jìn)行分類,并且(如果某些分類是真的話)調(diào)用+[RKUtilities removeEmoji:]方法。這方法調(diào)用CoreEmoji動(dòng)態(tài)庫來執(zhí)行實(shí)際的表情符號(hào)移除。

iOS為什么要?jiǎng)h除表情符號(hào)?我們很快就會(huì)講到的!

在調(diào)用一些未命名的子程序后,CoreEmoji調(diào)用CFStringCompare函數(shù),該函數(shù)在地址0x0000000182922efc處的指令處崩潰。

地址0x0000000182922efc是故障指令的地址。它是調(diào)用堆棧(即幀#0)中的最終地址,也是崩潰報(bào)告“ARM線程狀態(tài)”部分中的pc(程序計(jì)數(shù)器)寄存器中的最終地址。

CFStringCompare在0x0000000182922efc有什么指令?

0000000180dcaefc         ldr        x8, [x21]

ldr arm指令將“程序相對(duì)偏移或外部地址加載到寄存器”(arm)。在這里,它試圖取消引用,并將值從x21寄存器加載到x8寄存器中。

查看崩潰報(bào)告中的“ARM線程狀態(tài)”部分,可以看到x21寄存器在崩潰時(shí)是空的(0x00000000000000):

Thread 6 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x00000001add1ad38   x2: 0x0000000000000000   x3: 0x00000001ad364438
    x4: 0x0000000000000000   x5: 0x0000000000000001   x6: 0x0000000000000000   x7: 0x0000000000000000
    x8: 0x0000000000000000   x9: 0x00000001b4e15930  x10: 0x0000000ffffffff8  x11: 0x0000000000000040
   x12: 0xffffffffffffffff  x13: 0x0000000000000001  x14: 0x0000000000000000  x15: 0x00002d0000002d00
   x16: 0x0000000000000000  x17: 0x0000000000002d00  x18: 0x0000000000000000  x19: 0x0000000000000000
   x20: 0x00000001add1ad38  x21: 0x0000000000000000  x22: 0x0000000000000000  x23: 0x00000001c4864cc0
   x24: 0x00000001000404ef  x25: 0x0000000000050000  x26: 0x0000000103d059e4  x27: 0x0000000103d059e4
   x28: 0x0000000000000000   fp: 0x000000016f1a5b20   lr: 0x00000001886b2354
    sp: 0x000000016f1a5b00   pc: 0x0000000182922efc cpsr: 0x80000000

如果試圖取消引用空地址(指針),這將與EXC_BAD_ACCESS(SIGSEGV)一起崩潰,這正是崩潰報(bào)告中給出的確切原因:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000

那么x21中的值應(yīng)該是什么呢?很明顯,一個(gè)有效地址。

但是,查看故障指令之前的指令(在CFStringCompare函數(shù)中)的arm64反匯編代碼,我們可以看到它是傳遞給CFStringCompare的第一個(gè)參數(shù)。

_CFStringCompare:
0000000182922ec4         stp        x22, x21, [sp, #-0x30]!                     
0000000182922ec8         stp        x20, x19, [sp, #0x10]
0000000182922ecc         stp        x29, x30, [sp, #0x20]
0000000182922ed0         add        x29, sp, #0x20
0000000182922ed4         mov        x19, x2
0000000182922ed8         mov        x20, x1
0000000182922edc         mov        x21, x0
0000000182922ee0         tbz        x21, 0x3f, loc_182922efc        ;take this

loc_182922ee4:
0000000182922ee4         adrp       x8, #0x1b3519000                            
0000000182922ee8         ldr        x1, [x8, #0x308]                            
0000000182922eec         mov        x0, x21
0000000182922ef0         bl         0x181c1c900
0000000182922ef4         mov        x3, x0
0000000182922ef8         b          loc_182922fd0

loc_182922efc:
0000000182922efc         ldr        x8, [x21]                       ; b00m, we crash as x21 is NULL

也許反編譯更能說明問題:

_CFStringCompare

r21 = theString1;
if ((r21 & 0xffffffff80000000) != 0x0) {
     r3 = loc_181c1c900(r21, *0x1b3519308);
}
else
{
     r8 = *r21; //b00m, we crash as this is NULL
}

反匯編0x0000000182922edc,我們可以看到第一個(gè)參數(shù)(在X0寄存器中傳遞)被移動(dòng)到x21寄存器中:

mov        x21, x0

在0x0000000182922ee0(檢測(cè)指針是否被“標(biāo)記”)的測(cè)試之后,代碼跳轉(zhuǎn)到地址0x0000000182922efc,在那里取消對(duì)空x21寄存器的引用,從而導(dǎo)致崩潰。

寄存器x21上的檢查(在此程序集指令中實(shí)現(xiàn);TBZ x21、0x3f、loc_182922efc)是檢查指針是否“標(biāo)記”的檢查。
標(biāo)記指針是在iOS 7和MacOSX10.7中為64位架構(gòu)引入的.帶標(biāo)記的指針是一種特殊的指針,它將數(shù)據(jù)直接存儲(chǔ)到指針中,而不是進(jìn)行內(nèi)存分配。這具有明顯的性能優(yōu)勢(shì)。blog.timac.org

CFStringCompare的函數(shù)定義是:

CFComparisonResult CFStringCompare(CFStringRef theString1, CFStringRef theString2, CFStringCompareFlags compareOptions);

第一個(gè)參數(shù)是一個(gè)命名為theString1的CFStringRef。由于崩潰是對(duì)第一個(gè)參數(shù)(X0,移動(dòng)到x21)的取消引用,我們現(xiàn)在知道有些東西正在傳入theString1參數(shù)的空值!

好了,我們已經(jīng)找到了崩潰的直接原因:傳遞給CFStringCompare的空字符串。

讓我們回顧一下調(diào)用堆棧跟蹤,找出為什么會(huì)錯(cuò)誤地傳入這樣一個(gè)空值!

回想一下,CFStringCompare是由地址為0x00000001886b22ec的CoreEmoji.dylib(dyld_shared_cache_arm64_CoreEmoji)中的一個(gè)未命名函數(shù)調(diào)用的。

由于提取的CoreEmoji二進(jìn)制文件(來自dyld共享緩存)不是符號(hào)化的,因此只需從dylib的MacOS版本中刪除這個(gè)子例程的分解代碼就更簡(jiǎn)單了。

下面是這兩個(gè)版本的反編譯代碼(為了說明MacOS和iOS版本中的代碼是相同的):

//iOS (arm64)
int <redacted>_186b5a2ec {
    var_10 = r20;
    stack[-24] = r19;
    r31 = r31 + 0xffffffffffffffe0;
    saved_fp = r29;
    stack[-8] = r30;
    if (*qword_1b1c9baf8 != -0x1) {
            dispatch_once(0x1b37f3af8, 0x1add1a6f8);
    }
    r20 = loc_182938048();
    r19 = loc_1829387c8();
    loc_1829111e8(r20);
    if (*(int8_t *)byte_1b1c9bb00 != 0x0) {
            r0 = 0x0;
    }
    else {
            r0 = loc_182922ec4(r19, 0x1add1ad38, 0x0);
            if (r0 != 0x0) {
                    if (CPU_FLAGS & NE) {
                            r0 = 0x1;
                    }
            }
    }
    return r0;
}
//macOS (x64)
int sub_b9fe() {
    if (*qword_128e8 != -1)
    {
            dispatch_once(qword_128e8, ^ {/* block implemented at sub_ba72 */ } });
    }
    rbx = CFLocaleCopyCurrent();
    r14 = CFLocaleGetValue(rbx, **_kCFLocaleCountryCode);
    CFRelease(rbx);
    if (*(int8_t *)byte_128f0 != 0x0) {
            rax = 0x0;
    }
    else {
            rax = CFStringCompare(r14, @"CN", 0x0);
            rax = rax != 0x0 ? 0x1 : 0x0;
    }
    return rax;
}

在arm64反編譯中,以下行表示對(duì)CFStringCompare的調(diào)用:

r0 = loc_182922ec4(r19, 0x1add1ad38, 0x0);

寄存器r19是第一個(gè)空參數(shù)(theString1),因此觸發(fā)了崩潰。

再查找?guī)仔校覀兛梢钥吹絩19被設(shè)置為調(diào)用loc_1829387c8()的返回值;

r19 = loc_1829387c8();

多虧了MacOS符號(hào)化的反編譯,我們可以看到這是對(duì)CFLocaleGetValue()的調(diào)用。

Apple記錄了以下功能:

CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFLocaleKey key);返回區(qū)域設(shè)置的鍵值對(duì)的給定鍵的對(duì)應(yīng)值。

通過反編譯,我們可以確定locale是來自CFLocaleCopyCurrent()的返回值,而鍵是_kCFLocaleCountryCode。

因此,源代碼看起來可能如下所示:

CFLocaleRef locale = CFLocaleCopyCurrent();
CFStringRef countryCode = CFLocaleGetValue (locale, kCFLocaleCountryCode);

這段代碼后面緊接著是對(duì)布爾標(biāo)志的檢查(iOS:byte_1b1c9bb00,MacOS:byte_128f0)。

堅(jiān)持使用符號(hào)化的macOS dylib,我們可以找到這個(gè)值的交叉引用(x-ref),以確定它設(shè)置在哪里(sub_ba72):

void sub_ba72(void * _block) {
    rbx = CFPreferencesCopyValue(@"Country", **_kCFPreferencesAnyApplication, **_kCFPreferencesAnyUser, **_kCFPreferencesCurrentHost);
    if (rbx != 0x0) {
            r14 = CFEqual(rbx, @"CN") != 0x0 ? 0x1 : 0x0;
            CFRelease(rbx);
    }
    else {
            r14 = 0x0;
    }
    *(int8_t *)byte_128f0 = r14;
    return;
}

這段代碼(sub_ba72)確定用戶當(dāng)前的‘國(guó)家’首選項(xiàng)。

如果不是中國(guó)(“cn”),則該標(biāo)志設(shè)置為0x1(True)。如果國(guó)家是中國(guó),或者CFPreferencesCopyValue()中止并返回NULL,則標(biāo)志設(shè)置為0x0(False)。

我朋友手機(jī)的區(qū)域和語言沒有設(shè)置為“cn”,所以這個(gè)標(biāo)志(AFAIK)應(yīng)該設(shè)置為0x1(真):

但是,由于代碼用了else(反過來調(diào)用CFStringCompare(),它將指示該標(biāo)志必須為0x0。

//check some flag ('CN')
if (*(int8_t *)byte_1b1c9bb00 != 0x0) {
    r0 = 0x0;
}

//we take this path
else {

  //call to CFStringCompare() that crashes
  r0 = loc_182922ec4(r19, 0x1add1ad38, 0x0);

  ... 

}

一種解釋是,由于某些原因,對(duì)CFPreferencesCopyValue(@“Country”.)調(diào)用失敗,會(huì)將標(biāo)志設(shè)置為0x0。或者代碼認(rèn)為由于某種(未知的)原因,手機(jī)的區(qū)域設(shè)置為“cn”?

無論如何,調(diào)用CFStringCompare時(shí),第一個(gè)參數(shù)(寄存器r19)設(shè)置為NULL:

//call CFStringCompare()
// first parameter is NULL, and thus crashes
// second parameter is @"CN"
r0 = loc_182922ec4(r19, 0x1add1ad38, 0x0);

請(qǐng)注意,只有在對(duì)CFLocaleGetValue()的調(diào)用失敗(即返回NULL)時(shí),r19寄存器才能為空。

一種解釋是,對(duì)CFLocaleCopyCurrent的調(diào)用返回null,這反過來會(huì)導(dǎo)致CFLocaleGetValue也返回null(這反過來會(huì)將null傳遞給CFStringCompare(),從而導(dǎo)致崩潰)。

如果我們查看蘋果代碼中的其他地方,比如它們的CFStringCompareWithOptionsAndLocale函數(shù),可以看到它們?cè)谶@里檢查CFLocaleCopyCurrent()的返回值:

locale = CFLocaleCopyCurrent();
langCode = ((NULL == locale) ? NULL : (const uint8_t *)_CFStrGetLanguageIdentifierForLocale(locale));

這意味著CFLocaleCopyCurrent()確實(shí)可能失敗,并返回NULL(因此應(yīng)該檢查!)

不幸的是,我的理解只到這一點(diǎn)上了。也就是說,我不知道為什么以及在什么條件下:CFLocaleGetValue(CFLocaleCopyCurrent(),kCFLocaleNationalCode)可以返回NULL。但是它可以,而且這是不做檢查的!因此,用NULL調(diào)用CFStringCompare(),應(yīng)用程序就會(huì)崩潰!

蘋果強(qiáng)調(diào):

在某些情況下,如果設(shè)備的語言/區(qū)域設(shè)置不正確,即缺少區(qū)域代碼,則可以返回NULL。若要觸發(fā)此操作,必須將設(shè)備設(shè)置為不支持區(qū)域的無支持狀態(tài)。

 

修復(fù)

兩年多來,她的手機(jī)一直無法輸入“臺(tái)灣”,或者每當(dāng)手機(jī)收到臺(tái)灣旗幟表情符號(hào)時(shí),她的手機(jī)就會(huì)被“遠(yuǎn)程攻擊”,只不過是把這個(gè)地區(qū)從美國(guó)、中國(guó)大陸,再回到美國(guó),一目了然。

我不能百分之百地確定為什么(或者如何修復(fù)它),但我猜它要么將‘Country’值設(shè)置為‘us’,所以現(xiàn)在boolan標(biāo)志(在byte_1b1c9bb00處)被設(shè)置為0x1,這意味著CFStringCompare()從來沒有被調(diào)用過,或者,對(duì)CFLocaleCopyCurrent()/CFLocaleGetValue()的調(diào)用不再返回null,這意味著一個(gè)有效的字符串被傳遞給了CFStringCompare()。

由于我不確定還有多少其他iOS用戶受到影響,我也向蘋果報(bào)告了這個(gè)問題。他們給它分配了CVE-2018-4290,并在iOS 11.4.1中對(duì)其進(jìn)行了修復(fù):

我還沒有機(jī)會(huì)研究蘋果的補(bǔ)丁,但我提出以下建議作為一個(gè)簡(jiǎn)單的解決方案:

為了避免這種崩潰,代碼應(yīng)該只檢查調(diào)用CFLocaleGetValue()的結(jié)果,如果調(diào)用失敗(即返回NULL),則跳過對(duì)CFStringCompare()的調(diào)用:

CFLocaleRef locale = CFLocaleCopyCurrent();
CFStringRef countryCode = CFLocaleGetValue (locale, kCFLocaleCountryCode);

//fix!
// make sure to check this!!
if(NULL != countryCode)
{
     CFStringCompare(countryCode, @"CN", 0x0);
}

//otherwise handle case where `countryCode` is NULL
else
{
  .... 
}

回顧

到目前為止,本文深入研究揭示并解釋了一個(gè)(遠(yuǎn)程)iOS崩潰的技術(shù)原因。然而,仍然存在一個(gè)尚未回答但相當(dāng)有趣的問題:“不管怎么說,這段代碼到底想要完成什么?”

回顧:

  • 這起崩潰事件是由鍵入臺(tái)灣或接收任何帶有臺(tái)灣旗幟(????)的信息引發(fā)的。
  • 導(dǎo)致崩潰的方法(例如,RemoveEmoji)似乎與從接收到的消息中刪除表情符號(hào)有關(guān)。
  • 故障指令之前的各種代碼正在檢查中國(guó)(“CN”)用戶設(shè)備的語言/地區(qū)設(shè)置。
  • 傳遞給CFStringCompare(崩潰的函數(shù))的第二個(gè)參數(shù)設(shè)置為(“cn”)。

這么多中國(guó)!嗯,那又有什么用呢!

答案可以在表情包網(wǎng)站上找到,上面寫著:

此標(biāo)志隱藏在設(shè)置為中國(guó)的iOS設(shè)備上的表情符號(hào)鍵盤上。中國(guó)的iPhone不會(huì)顯示這個(gè)標(biāo)志,而是會(huì)顯示一個(gè)缺失的字符豆腐(?)。

結(jié)論

在本文中,我們找到了遠(yuǎn)程iOS缺陷的原因。

盡管它的影響僅限于拒絕服務(wù)(空指針取消引用),但它為分析iOS代碼提供了一個(gè)有趣的案例研究。

原文地址:https://objective-see.com/blog/blog_0x34.html

上一篇:中國(guó)互聯(lián)網(wǎng)大會(huì)共話防范打擊通訊信息詐騙 官方點(diǎn)贊騰訊神荼

下一篇:沙箱:挖掘你的安全隱患