背景
iOS14 系統(tǒng)下,只要使用了[UIPasteboard generalPasteboard].string
讀取剪切板, APP頂部都會(huì)出現(xiàn)讀取剪切板的提示淹仑。 為了保護(hù)用戶隱私(避免輿論?險(xiǎn)), 可以使用iOS14 的新API來判斷剪切板中的內(nèi)容格式巨坊。 使用下面這兩個(gè) API 不會(huì)觸發(fā)系統(tǒng)剪切板提示(但是也拿不到剪切板的具體內(nèi)容):
- (void)detectPatternsForPatterns:(NSSet<UIPasteboardDetectionPattern> *)patte rns completionHandler:(void(^)(NSSet<UIPasteboardDetectionPattern> * _Nullabl e, NSError * _Nullable))completionHandler NS_REFINED_FOR_SWIFT API_AVAILABLE(i os(14.0));
- (void)detectPatternsForPatterns:(NSSet<UIPasteboardDetectionPattern> *)patte rns inItemSet:(NSIndexSet * _Nullable)itemSet completionHandler:(void(^)(NSArr ay<NSSet<UIPasteboardDetectionPattern> *> * _Nullable, NSError * _Nullable))co mpletionHandler NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(14.0));
demo如下:
NSString *testStr = @"8-:/ Юt7hud";
[[UIPasteboard generalPasteboard] setString:testStr];
__block BOOL enablePasteboard = NO;
NSSet *patterns = [[NSSet alloc] initWithObjects:UIPasteboardDetectionPatternProbableWebURL, nil];
[[UIPasteboard generalPasteboard] detectPatternsForPatterns:patterns
completionHandler:^(NSSet<UIPasteboardDetectionPattern> * _Nullable result, NSError * _Nullable error) {
BOOL hasURL = [result containsObject:UIPasteboardDetectionPatternProbableWebURL];
if (!hasURL) {
enablePasteboard = NO;
}
enablePasteboard = YES;
}];
識(shí)別口令等場景下柬采,我們可以自己使用上面detectPatternsForPatterns
的UIPasteboardDetectionPatternProbableWebURL
參數(shù)耕赘,這樣只有剪切板里有類似url格式時(shí),我們才進(jìn)一步處理口令寒矿,而其他格式的剪切板不會(huì)觸發(fā)剪切板讀取告警蹋半。
但是 UIPasteboardDetectionPatternProbableWebURL
這個(gè)參數(shù),蘋果文檔沒有嚴(yán)格的定義,存在如下幾個(gè)正常和不正常的case:
// 正常匹配ProbableWebURL
testStr = @"8.:/ Юt7hud";
testStr = @"8-:/ Юt7hud";
testStr = @"3[得意]`:/ ?按復(fù)制此條消息,打開XXX,口令xxx";
// 匹配不了ProbableWebURL
testStr = @"8~:/ Юt7hud";
testStr = @"3 8`:/ ?按復(fù)制此條消息,打開XXX,口令xxx";
本文通過逆向蘋果的UIPasteboardDetectionPatternProbableWebURL
邏輯,來達(dá)到靈活配置口令的目的(即比較奇怪的口令也能被蘋果識(shí)別成URL)账阻。
逆向
具體逆向過程不寫了蒂秘。大概過程如下:
- 通過模擬器調(diào)試,調(diào)試并查找符號(hào)
detectPatternsForPatterns
- 定位到和遠(yuǎn)程xpc調(diào)用有關(guān)淘太,遠(yuǎn)程調(diào)用的方法是
requestPatternDetectionsFromPasteboardWithName
- 調(diào)試發(fā)現(xiàn)是pasted進(jìn)程在提供這個(gè)服務(wù)姻僧,用lldb調(diào)試該進(jìn)程。
- 通過分析輸入輸出蒲牧,最終確定是
PBProbableWebDataDetective
類在處理這個(gè)識(shí)別邏輯撇贺。 - 逆向和分析
PBProbableWebDataDetective
類,并翻譯成oc代碼冰抢。
最終找到如下核心函數(shù),參數(shù)是剪切板板字符串,返回是匹配結(jié)果,轉(zhuǎn)換的代碼如下:
其中核心的核心是 sub_100011D1C
函數(shù),在其中判斷字符串是否可能是url,完整翻譯后可運(yùn)行代碼如下:
<script src="https://gist.github.com/ohswift/fb8a0ffd68335b95a5b59bc96e1856a1.js"></script>
逆向后的代碼整體表現(xiàn)和系統(tǒng)pasted進(jìn)程里的 PBProbableWebDataDetective 表現(xiàn)一致松嘶。如果有badcase的話,可以通過lldb pasted進(jìn)程,手動(dòng)調(diào)用數(shù)據(jù)進(jìn)行調(diào)試:
# lldb -n '/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.1.simruntim e/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/Pasteboard.f ramework/Support/pasted'
斷點(diǎn)并調(diào)試pasted進(jìn)程:
(lldb) expr @import Foundation
(lldb) expr PBProbableWebDataDetective *$ddd = [PBProbableWebDataDetective new]
(lldb) expr -i0 -- (id)[$ddd detectedPatternValuesInValue:@"8~:/ Юt7hud"]
規(guī)則
根據(jù)逆向后的邏輯,更新可利用的口令規(guī)則:
-
:/ 前面,添加不包含(decimalDigitCharacterSet, punctuationCharacterSet, symbolCharacterSet)的字符,并且:/后面緊跟空格或者后面的字符中有 ? 或者 #
提供了如下可行規(guī)則和字符集:
eg: 8?:/ Юt7hud :/后面是空格
eg: 8 ?:/索索?Юt7hud :/后面字符中有?
eg: 8 ?:/索索#Юt7hud= :/后面字符中有#
?就是在decimalDigitCharacterSet, punctuationCharacterSet, symbolCharacterSet之外的一個(gè)字符,當(dāng)然其他的還有很多:https://unicode-table.com/cn/0D81/
- 包含 c.om x.om n.et o.gr (.com等域名的簡單混淆,可以看代碼里的映射表) 等字符,可以識(shí)別為URL,不需要 :/ 規(guī)則
- 調(diào)試翻譯出來的代碼看是否還有其他可以潛在邏輯可以利用,代碼邏輯比較繞。