前言
在iOS7之前我們可以通過- (NSString *)uniqueIdentifier這個方法擷取iPhone的唯一辨別符,也叫作UDID。不過自從iOS7蘋果就把這個方法給禁了,此時我們想要擷取iPhone的唯一辨別符就很困難。
不過蘋果提供一個叫做IDFA的辨別符,這個IDFA是廣告辨別符用來追蹤廣告投放的,不過使用者可以在設定中手動重置IDFA,可靠性很低,目前常見的兩種标記iPhone的方式為
openUDID
IDFA或UUID+keychain
這兩種模式都有個弊端,使用者重置手機或者刷機唯一辨別符會發生變化,不過對于大多數情況是夠用了。看來蘋果是把路給封死了,有沒有辦法拿到之前的UDID呢?我們注意到iPhone的設定通用關于裡面有手機的硬體資訊,其中有一個serialNumber,這個serialnumber就是我們查詢手機是否過保的依據,那麼它肯定是唯一的,是以下文是圍繞這個進行的探索。最終是可以拿到這個serialNumber的, 不過由于蘋果的沙盒限制,是以隻能在越獄機中拿到,如果想在非越獄機中拿到必須添加entitlements檔案來擷取權限,可想而知這個應用是無法上架的。下文僅作為逆向工程的一種思路和探索。
正文
一、SSH連接配接手機(USB模式)
1.映射端口
LeonLei-MBP:~ gaoshilei$ /Users/gaoshilei/Desktop/reverse/USBSSH/tcprelay.py -t 22:6666
Forwarding local port 6666 to remote port 22
2.連接配接手機,并且用grep指令快速篩選目前我們要調試的應用Preferences,附加debugserver開始1234端口等待lldb調試
LeonLei-MBP:~ gaoshilei$ ssh [email protected] -p 6666
iPhone-5S:~ root# ps -e | grep Pre
270 ?? 0:00.29 /System/Library/PrivateFrameworks/MobileSoftwareUpdate.framework/XPCServices/com.apple.MobileSoftwareUpdate.CleanupPreparePathService.xpc/com.apple.MobileSoftwareUpdate.CleanupPreparePathService
1192 ?? 0:14.26 /var/db/stash/_.fP74Fg/Applications/Preferences.app/Preferences
1289 ttys000 0:00.01 grep Pre
iPhone-5S:~ root# debugserver *:1234 -a "Preferences"
[email protected](#)PROGRAM:debugserver PROJECT:debugserver-340.3.51.1
for arm64.
Attaching to process Preferences...
Listening to port 1234 for a connection from *...
3.完成以上兩步接下來就可以進行lldb調試了,首先要把遠端(手機)的1234端口映射到本地,跟前面提到的SSH端口映射一樣
LeonLei-MBP:~ gaoshilei$ /Users/gaoshilei/Desktop/reverse/USBSSH/tcprelay.py -t 1234:1234
Forwarding local port 1234 to remote port 1234
二、通過LLDB、IDA尋找線索
lldb的調試端口已經打開,此時我們可以進入調試
LeonLei-MBP:~ gaoshilei$ lldb
(lldb) process connect connect://localhost:1234
Process 1192 stopped
* thread #1: tid = 0x523a6, 0x000000019a3c8a40 libsystem_kernel.dylib`mach_msg_trap + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x000000019a3c8a40 libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
-> 0x19a3c8a40 : ret
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0x19a3c8a44 : movn x16, #0x1f
0x19a3c8a48 : svc #0x80
0x19a3c8a4c : ret
此時我們已經成功進入Preferences的調試階段,先c一下,讓程式繼續運作
(lldb) c
Process 1192 resuming
這麼做的原因是我們待會要列印image的基位址偏移,有可能在我們列印的image list中沒有我們想要的image。
此時我們已經找到到Preference.framework的基位址偏移,見下圖
(lldb) im li -o -f
[ 0] 0x00000000000dc000 /var/db/stash/_.fP74Fg/Applications/Preferences.app/Preferences(0x00000001000dc000)
[ 1] 0x0000000100100000 /Library/MobileSubstrate/MobileSubstrate.dylib(0x0000000100100000)
[ 2] 0x0000000002e50000 /Users/gaoshilei/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/System/Library/PrivateFrameworks/BulletinBoard.framework/BulletinBoard
[ 3] 0x0000000002e50000 /Users/gaoshilei/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
[ 4] 0x0000000002e50000 /Users/gaoshilei/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit
…
[ 44] 0x0000000002e50000 /Users/gaoshilei/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/System/Library/PrivateFrameworks/Preferences.framework/Preferences
…
我們要找的image的序号在這裡是44,它的基位址偏移為0x2e50000,我們把從iPhone中導出的PrivateFrameworks中的Preferences.framework丢到IDA中進行分析,這個二進制檔案比較小,很快就分析完成,在前面我們已經知道iPhone的唯一序列号serial number是通過PSListController生成的,并且我們知道這是一個cell,我們要去調試[PSListController tableView:cellForRowAtIndexPath:]這個方法,從中找到cell值的來源,進而找到擷取序列号的方法。
__text:00000001908040C8 ; -[PSListController tableView:cellForRowAtIndexPath:]
__text:00000001908040C8 __PSListController_tableView_cellForRowAtIndexPath__
__text:00000001908040C8 ; DATA XREF: __objc_const:000000019C069B88�o
__text:00000001908040C8
__text:00000001908040C8 var_80 = -0x80
__text:00000001908040C8 var_78 = -0x78
__text:00000001908040C8 var_70 = -0x70
__text:00000001908040C8 var_68 = -0x68
__text:00000001908040C8 var_60 = -0x60
__text:00000001908040C8 var_50 = -0x50
__text:00000001908040C8 var_40 = -0x40
__text:00000001908040C8 var_30 = -0x30
__text:00000001908040C8 var_20 = -0x20
__text:00000001908040C8 var_10 = -0x10
__text:00000001908040C8
__text:00000001908040C8 STP X28, X27, [SP,#var_60]!
__text:00000001908040CC STP X26, X25, [SP,#0x60+var_50]
__text:00000001908040D0 STP X24, X23, [SP,#0x60+var_40]
__text:00000001908040D4 STP X22, X21, [SP,#0x60+var_30]
__text:00000001908040D8 STP X20, X19, [SP,#0x60+var_20]
__text:00000001908040DC STP X29, X30, [SP,#0x60+var_10]
__text:00000001908040E0 ADD X29, SP, #0x60+var_10
__text:00000001908040E4 SUB SP, SP, #0x20
__text:00000001908040E8 MOV X21, X3
__text:00000001908040EC MOV X20, X0
__text:00000001908040F0 MOV X0, X2
__text:00000001908040F4 BL 0x96C400A0
__text:00000001908040F8 MOV X26, X0
__text:00000001908040FC ADRP X8, #[email protected]
__text:0000000190804100 LDR X1, [X8,#[email protected]]
__text:0000000190804104 MOV X0, X20
__text:0000000190804108 MOV X2, X21
__text:000000019080410C BL 0x96C39BC0
__text:0000000190804110 MOV X2, X0
__text:0000000190804114 ADRP X8, #[email protected] ; NSArray *_specifiers;
__text:0000000190804118 LDRSW X27, [X8,#[email protected]] ; NSArray *_specifiers;
__text:000000019080411C LDR X0, [X20,X27]
__text:0000000190804120 ADRP X8, #[email protected]
……
我們在Preference.framework中基位址為0x190804114的位置打個斷點,具體的做法是:
(lldb) br s -a 0x190804114+0x2e50000
Breakpoint 1: where = Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 76, address = 0x0000000193654114
Process 1192 stopped
* thread #1: tid = 0x523a6, 0x0000000193654114 Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 76, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000193654114 Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 76
Preferences`-[PSListController tableView:cellForRowAtIndexPath:]:
-> 0x193654114 : adrp x8, 53965
0x193654118 : ldrsw x27, [x8, #516]
0x19365411c : ldr x0, [x20, x27]
0x193654120 : adrp x8, 53960
這裡斷點這樣打是因為系統加載可執行檔案和各種framework的時候會有一個位址偏移,我們在打斷點的時候要把這個偏移量加上,這樣我們打的斷點才是準确的。
可以看到我們已經成功打了一個斷點,斷點的address = 0x193654114。此時我們列印變量x0和x27的值
(lldb) po $x0
13
(lldb) po $x27
1104
我們執行ni讓程式繼續(這裡的ni指令相當于Xcode的那個下箭頭指令,也就是下一行)
(lldb) ni
Process 1192 stopped
* thread #1: tid = 0x523a6, 0x0000000193654118 Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 80, queue = 'com.apple.main-thread', stop reason = instruction step over
frame #0: 0x0000000193654118 Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 80
Preferences`-[PSListController tableView:cellForRowAtIndexPath:]:
-> 0x193654118 : ldrsw x27, [x8, #516]
0x19365411c : ldr x0, [x20, x27]
0x193654120 : adrp x8, 53960
0x193654124 : ldr x22, [x8, #1368]
(lldb) ni
Process 1192 stopped
* thread #1: tid = 0x523a6, 0x000000019365411c Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 84, queue = 'com.apple.main-thread', stop reason = instruction step over
frame #0: 0x000000019365411c Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 84
Preferences`-[PSListController tableView:cellForRowAtIndexPath:]:
-> 0x19365411c : ldr x0, [x20, x27]
0x193654120 : adrp x8, 53960
0x193654124 : ldr x22, [x8, #1368]
0x193654128 : mov x1, x22
(lldb) po $x27
848
(lldb) po $x0
13
我們ni的兩次,程式已經走到0x19080411C的位置,然後我們繼續列印變量x0和x27的值
(lldb) po $x0
13
(lldb) po $x27
1104
列印出來的x0和x27都是随機數,還是沒有什麼收獲,我們繼續
(lldb) ni
Process 1192 stopped
* thread #1: tid = 0x523a6, 0x0000000193654120 Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 88, queue = 'com.apple.main-thread', stop reason = instruction step over
frame #0: 0x0000000193654120 Preferences`-[PSListController tableView:cellForRowAtIndexPath:] + 88
Preferences`-[PSListController tableView:cellForRowAtIndexPath:]:
-> 0x193654120 : adrp x8, 53960
0x193654124 : ldr x22, [x8, #1368]
0x193654128 : mov x1, x22
0x19365412c : bl 0x199a89bc0 ; objc_msgSend
(lldb) po $x0
<__nsarrayi>(
G: > 0x12ff50cf0,
>,
G: > 0x12ff51680,
>,
>,
>,
>,
>,
>,
>,
>,
>,
>,
>,
>,
>,
>,
G: > 0x131031e90,
>,
G: > 0x131029dc0,
>
)
我們讓程式執行下一步,發現此時x0已經有值了,可以明顯的看出,x0的值是在0x190804114~0x19080411C這段代碼生成的,下面我們的工作重點就是尋找這段代碼幹了什麼,勝利就在眼前!下面我們驗證一下這裡面到底有沒有我們要的序列号:
(lldb) po [[$x0 objectAtIndex:13] class]
PSSpecifier
(lldb) po [[$x0 objectAtIndex:13] properties]
{
cellObject = "; layer = >";
id = SerialNumber;
isCopyable = 1;
value = DNPMVG0EFF9V;
}
我們列印數組中存放cell資料的object屬于哪個類,發現是PSSpecifier,我們找到之前導出的類的頭檔案,發現這個類有一個叫做properties的執行個體方法,我們調用一下發現我們要的序列号就在裡面value = DNPMVG0EFF9V,這跟iPhone設定中看到的序列号是一緻的。猜測這個數組裡面存放着系統設定中PSUIAboutController中所有cel的資料,這個數組下一個肯定要傳遞到cell生成的方法中,這個就不做驗證了,大事重要,我們繼續找序列号的生成方法。
這個PSSpecifier中有一個AboutDataSource對象,這個非常可疑,從名稱上可以判斷,這個類是專門用于資料處理的,不過在這之前我們還是先驗證一下,在0x190804114~0x19080411C這段位址中,執行了_PSListController._specifiers,我們從PSListController的頭檔案(下文有講怎麼擷取)中可以看到有一個specifiers屬性,我們在IDA分析的檔案中找到[PSListController specifiers],我們先定位到方法在二進制檔案中的位置:
__text:00000001907FE4A8 ; -[PSListController specifiers]
__text:00000001907FE4A8 __PSListController_specifiers_ ; DATA XREF: __objc_const:000000019C069A08�o
__text:00000001907FE4A8
__text:00000001907FE4A8 var_40 = -0x40
__text:00000001907FE4A8 var_30 = -0x30
__text:00000001907FE4A8 var_20 = -0x20
__text:00000001907FE4A8 var_10 = -0x10
__text:00000001907FE4A8
__text:00000001907FE4A8 STP X24, X23, [SP,#var_40]!
__text:00000001907FE4AC STP X22, X21, [SP,#0x40+var_30]
__text:00000001907FE4B0 STP X20, X19, [SP,#0x40+var_20]
__text:00000001907FE4B4 STP X29, X30, [SP,#0x40+var_10]
__text:00000001907FE4B8 ADD X29, SP, #0x40+var_10
__text:00000001907FE4BC MOV X19, X0
__text:00000001907FE4C0 ADRP X8, #[email protected] ; NSArray *_specifiers;
__text:00000001907FE4C4 LDRSW X22, [X8,#[email protected]] ; NSArray *_specifiers;
__text:00000001907FE4C8 LDR X8, [X19,X22]
__text:00000001907FE4CC CBNZ X8, loc_1907FE5E0
__text:00000001907FE4D0 ADRP X8, #[email protected] ; id _dataSource;
__text:00000001907FE4D4 LDRSW X8, [X8,#[email protected]] ; id _dataSource;
__text:00000001907FE4D8 LDR X9, [X19,X8]
__text:00000001907FE4DC CBZ X9, loc_1907FE550
__text:00000001907FE4E0 ADRP X9, #_O[email protected]PAGE ; bool _requestingSpecifiersFromDataSource;
__text:00000001907FE4E4 LDRSW X23, [X9,#_O[email protected]PAGEOFF] ; bool _requestingSpecifiersFromDataSource;
__text:00000001907FE4E8 MOV W9, #1
__text:00000001907FE4EC STRB W9, [X19,X23]
__text:00000001907FE4F0 LDR X20, [X19,X8]
__text:00000001907FE4F4 ADRP X8, #[email protected]
__text:00000001907FE4F8 LDR X1, [X8,#[email protected]]
__text:00000001907FE4FC MOV X0, X19
__text:00000001907FE500 BL 0x96C39BC0
__text:00000001907FE504 MOV X29, X29
__text:00000001907FE508 BL 0x96C41EF0
__text:00000001907FE50C MOV X21, X0
__text:00000001907FE510 ADRP X8, #[email protected]
__text:00000001907FE514 LDR X1,
……
然後在這裡面下個斷點看看會發生什麼
(lldb) br s -a 0x1907FE4D0+0x198e58640
Breakpoint 9: where = Preferences`-[PSListController specifiers] + 40, address = 0x000000019364e4d0
我們從設定中進入通用>關于,發現一開始就走到了這個斷點,我們猜測,一進入關于頁面,系統會首先把所有cell的資料都準備好,然後加載UI
Process 1192 stopped
* thread #1: tid = 0x523a6, 0x000000019364e4d0 Preferences`-[PSListController specifiers] + 40, queue = 'com.apple.main-thread', stop reason = breakpoint 9.1
frame #0: 0x000000019364e4d0 Preferences`-[PSListController specifiers] + 40
Preferences`-[PSListController specifiers]:
-> 0x19364e4d0 : adrp x8, 53971
0x19364e4d4 : ldrsw x8, [x8, #536]
0x19364e4d8 : ldr x9, [x19, x8]
0x19364e4dc : cbz x9, 0x19364e550 ;
我們列印變量x8和x9的值,看一下系統做了什麼
(lldb) po $x8
(lldb) po $x9
PSUIAboutController
并沒有資料之類的東西值得我們關注,讓斷點繼續往下走,走到0x19364e4dc的位置,我們再次列印變量x8和x9的值
(lldb) n
Process 1192 stopped
* thread #1: tid = 0x523a6, 0x000000019364e4dc Preferences`-[PSListController specifiers] + 52, queue = 'com.apple.main-thread', stop reason = instruction step over
frame #0: 0x000000019364e4dc Preferences`-[PSListController specifiers] + 52
Preferences`-[PSListController specifiers]:
-> 0x19364e4dc : cbz x9, 0x19364e550 ;
0x19364e4e0 : adrp x9, 53971
0x19364e4e4 : ldrsw x23, [x9, #540]
0x19364e4e8 : orr w9, wzr, #0x1
(lldb) po $x8
952
(lldb) po $x9
此時的變量x9已經變成了AboutDataSource,這裡驗證了我們上一步的猜想,是以我們重點來研究它,我們先找到這個類在哪個framework中,這裡使用的是grep指令
LeonLei-MBP:~ gaoshilei$ grep AboutDataSource -r /Users/gaoshilei/Desktop/reverse/iOS-Runtime-Headers-9.1
/Users/gaoshilei/Desktop/reverse/iOS-Runtime-Headers-9.1/PrivateFrameworks/PreferencesUI.framework/AboutDataSource.h:@interface AboutDataSource : PSSpecifierDataSource {
這裡要說明一下iOS-Runtime-Headers-9.1這個檔案夾是iOS9.1系統的所有頭檔案(共有+私有),這個你可以自己導(iOS9之後隻能用runtime導,class-dump已經不行了),你也可以拿現成的用,github上面已經有雷鋒把所有系統的頭檔案都導出來了,直接下載下傳就可以了。我們發現AboutDataSource這個類在PrivateFrameworks/PreferencesUI.framework中,先看一下這個類裡面有什麼方法和屬性,有一個方法- (void)_loadValues; 我們對它進行分析。這裡又要借助IDA分析,把PreferencesUI這個二進制檔案丢到IDA裡面,在0x19091EBB8這個位置打個斷點
(lldb) br s -a 0x19091EBB8+0x2e50000
Breakpoint 3: where = PreferencesUI`-[AboutDataSource _loadValues] + 1956, address = 0x000000019376ebb8
接下來我們進入關于來觸發斷點
(lldb) po (char *) $x28
"_setValue:forSpecifierWithKey:"
在這裡列印變量x28的值,發現它是一個方法名,從名稱來看是給specifier指派的,看來我們要尋找的真相已經很近了,讓代碼走到下面的位置0x19376ebd8
Process 2107 stopped
* thread #1: tid = 0xe8e23, 0x000000019376ebd8 PreferencesUI`-[AboutDataSource _loadValues] + 1988, queue = 'com.apple.main-thread', stop reason = instruction step over
frame #0: 0x000000019376ebd8 PreferencesUI`-[AboutDataSource _loadValues] + 1988
PreferencesUI`-[AboutDataSource _loadValues]:
-> 0x19376ebd8 : bl 0x198e58640 ; MGCopyAnswer
0x19376ebdc : mov x22, x0
0x19376ebe0 : mov x1, x19
0x19376ebe4 : bl 0x199a89bc0 ; objc_msgSend
(lldb) po $x0
SerialNumber
此時我們列印的x0是一個NSCFConstantString,本質就是一個NSString,繼續ni讓程式運作到0x19376ebdc
Process 2107 stopped
* thread #1: tid = 0xe8e23, 0x000000019376ebdc PreferencesUI`-[AboutDataSource _loadValues] + 1992, queue = 'com.apple.main-thread', stop reason = instruction step over
frame #0: 0x000000019376ebdc PreferencesUI`-[AboutDataSource _loadValues] + 1992
PreferencesUI`-[AboutDataSource _loadValues]:
-> 0x19376ebdc : mov x22, x0
0x19376ebe0 : mov x1, x19
0x19376ebe4 : bl 0x199a89bc0 ; objc_msgSend
0x19376ebe8 : cbnz x0, 0x19376ec4c ;
(lldb) po $x0
DNPMVG0EFF9V
在這裡我們列印了變量x0的值為DNPMVG0EFF9V,這就是我們苦苦尋找的序列号。不難看出,序列号就是在0x19376ebd8這行拿到的,範圍越來越小,敵人無路可逃!下面我們就要對這行進行分析,我們按照之前的步驟,再次走到0x19376ebd8這個位置,這不過這次我們不要step-over,我們用si跳入看看
(lldb) si
Process 2107 stopped
* thread #1: tid = 0xe8e23, 0x0000000198e58640 libMobileGestalt.dylib`MGCopyAnswer, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x0000000198e58640 libMobileGestalt.dylib`MGCopyAnswer
libMobileGestalt.dylib`MGCopyAnswer:
-> 0x198e58640 : movz x1, #0
0x198e58644 : b 0x198e58648 ; ___lldb_unnamed_symbol64$$libMobileGestalt.dylib
libMobileGestalt.dylib`___lldb_unnamed_symbol64$$libMobileGestalt.dylib:
0x198e58648 : stp x24, x23, [sp, #-64]!
0x198e5864c : stp x22, x21, [sp, #16]
此時跳入了一個靜态庫libMobileGestalt.dylib,我們可以在usr/lib/ibMobileGestalt.dylib找到它,我們将它扔進IDA,用目前的addr減去libMobileGestalt.dylib的基位址偏移得到它的靜态位址0x196008640,對應的是一個函數MGCopyAnswer
__text:0000000196008640
__text:0000000196008640 ; =============== S U B R O U T I N E =======================================
__text:0000000196008640
__text:0000000196008640
__text:0000000196008640 EXPORT _MGCopyAnswer
__text:0000000196008640 _MGCopyAnswer ; CODE XREF: sub_196005958+30�p
__text:0000000196008640 ; sub_196006258+28�p ...
__text:0000000196008640 MOV X1, #0
__text:0000000196008644 B sub_196008648
__text:0000000196008644 ; End of function _MGCopyAnswer
這個函數最外層隻有兩行代碼,将立即數0賦給x1,然後跳進了子程式sub_196008648,跳進去之後進行了一些很複雜的運算,這裡就不做介紹了,裡面的實作大概是這樣的:
x0是作為一個參數傳入的,并且這裡x0的值為SerialNumber,在位址為0x196008678的地方,這個函數中x1變成了一串随機數,有點像MD5加密之後的東西,應該是“鑰匙”
(lldb) po (char*) $x1
"l92SaBpqIvQs+KBljuwGA"
在0x196008690這裡,我們setp-into這個函數,在函數的末尾傳回值的地方0x196007474打個斷點,列印傳回值x0
(lldb) po $x0
DNPMVG0EFF9V
這裡的x0由SerialNumber變成了真正的序列号,并且就是在0x196008690對應的子程式sub_19600738C裡面拿到的,是以我們就這樣一個猜測,在MGCopyAnswer函數中,x0作為一個參數傳入,并且在内部進行了一系列複雜的運算,拿到了擷取序列号的“鑰匙”x1,然後在sub_19600738C中拿到了最終的序列号。這裡筆者也沒有對序列号的拿到在進行進一步的深究,這裡蘋果做了很大的限制,再繼續研究恐怕也是收獲不大,而且我們在這裡已經能拿到序列号了。
三、驗證結果
接下來就是驗證的過程了,我們寫一個tweak來驗證,當然也可以用其他方式來驗證:
tweak的建立這裡就不贅述了,我把我的tweak和makefile檔案内容貼一下:
tweak檔案:
tweak.xm:
extern "C" NSString *MGCopyAnswer(NSString*);
%hook SpringBoard
- (void)applicationDidFinishLaunching:(id)application {
%orig;
NSString *serialNumber = [NSString stringWithFormat:@"%@",[MGCopyAnswer(@"SerialNumber") autorelease]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:serialNumber message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}
%end
這裡注入系統的SpringBoard,在SB啟動的時候hook住applicationDidFinishLaunching:函數,并且在這個函數裡面添加擷取序列号的代碼,并且以彈框的形式展現出來。
makefile檔案:
THEOS_DEVICE_IP = 192.168.0.115
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = SerialNumber
SerialNumber_FILES = Tweak.xm
include $(THEOS_MAKE_PATH)/tweak.mk
SerialNumber_LDFLAGS = -lMobileGestalt
after-install::
install.exec "killall -9 SpringBoard"
其中有一行SerialNumber_LDFLAGS = -lMobileGestalt千萬要注意,使用的時候要加載這個靜态庫,因為SpringBoard加載的時候我也不确定是否有加載這個庫,然後我們驗證一下吧!
序列号驗證-擷取
序列号驗證-系統