讓別人的程序按自己的意願運行
小白:小程,你知道有些iOS程序是沒人性的嗎?老是不按我的意願來運行!
小程:我怎麽知道你的意願就是有人性的?
本文解決一個問題:修改別人的二進制程序並運行起來。
讓別人的程序按你的意願來運行,文明一點的做法就是拿到源碼後加上自己的修改再生成新的程序並安裝。
小白:哇,這句話好長,你能一口氣說完嗎?
但是,很多情況下我們是沒有源碼的,那怎麽辦呢?
一個辦法是把程序的指令或者數據改掉;另一個辦法是讓程序執行到自已的代碼上,再把流程或內存值給改掉。最終,讓程序按自己的想法來運作。
小白:還能讓程序執行到自己的代碼?這不就是乾坤大挪移嗎?
小程:這叫註入!
小白:那趕緊講註入吧。
小程:不!我先講硬改。
如何改掉程序的指令呢?
這裏從iOS上的程序入手,舉一個例子來說明。
這是一個會“過期”的程序,顯示主頁面的代碼是這樣的:
-(void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; UIAlertController* alertvc = nil; int expire = 1; if (expire) { alertvc = [UIAlertController alertControllerWithTitle:nil message:@"過期了!" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"算了" style:UIAlertActionStyleCancel handler:nil]; [alertvc addAction:cancel]; } else { alertvc = [UIAlertController alertControllerWithTitle:nil message:@"歡迎回來" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* ok = [UIAlertAction actionWithTitle:@"太客氣了" style:UIAlertActionStyleDefault handler:nil]; [alertvc addAction:ok]; } [self presentViewController:alertvc animated:YES completion:nil]; }
運行後會彈出一個框,可能是“歡迎回來”,也可能是“過期了”。
為了真實模擬,先把這個demo弄出一個ipa包,再來安裝(而不是直接用xcode安裝到手機),這個ipa包就是修改目標。
ipa是一個壓縮包,裏面包括了執行程序、配置文件、圖片等資源。
如果是從itunes下載的app,則可以這樣拿到ipa包:
這時,要對ipa做重簽名才能通過第三方工具安裝到越獄手機。
小白:小程,什麽是重簽名?
小程:簡單來說,簽名就是允許這個app以什麽方式安裝。上傳到aapstore的app都是以發布證書來簽名,允許通過itunes或appstore來安裝,但不允許用第三方的工具比pp助手、itools之類的工具來安裝。而這裏的重簽名,指的是用開發證書來簽名,允許通過第三方工具來安裝。
小白:咦?我為什麽要通過第三方工具來安裝?用appstore不是好好的嗎?
小程:但是,如果想修改代碼再運行,就只能通過第三方工具,難道你修改代碼後還上傳給aapstore嗎?
小白:也對。那就是說,只有通過appstore下載的ipa才需要重簽名了?如果原本就是第三方工具安裝的ipa就不需要重簽名了?
小程:是的。而且,很多第三方工具都提供自已的app庫,這些app都是重簽名了的。
小白:那重簽名後,再次修改過的app,要不要重簽名?
小程:實踐證明,這時不需要再簽名。
為了清除“修改了程序卻不能安裝”的障礙,這裏介紹一下重簽名的操作。
(一)重簽名的準備
(1)mobileprovision文件
重簽名需要用到描述文件即provision文件,並保證keychain裏面有對應的證書。
可以創建證書與provision,再安裝到keychain。或者讓別人發一個p12文件與對應的provision,再雙擊安裝。
(2)plist文件
重簽名時要使用一個entitlements.plist 文件,可以直接找一個這樣的文件來修改,保證get-task-allow字段為true即可。
也可以plistbuddy工具來生成一個plist:
/usr/libexec/PlistBuddy -x -c "print :Entitlements " /dev/stdin <<< $(security cms -D -i xxx.app/embedded.mobileprovision) > entitlements.plist
/usr/libexec/PlistBuddy -c ‘Set :get-task-allow true‘ entitlements.plist
xxx.app換成目標app,並且要cd到目標ipa的Payload目錄再進行操作
(二)重簽名
使用codesigh進行簽名:
cp "xxx.mobileprovision" "Payload/xxx.app/embedded.mobileprovision"
--使用mobileprovision文件,覆蓋app原有的(沒有也照樣拷貝過去)
/usr/bin/codesign -f -s "iPhone Developer: xxx (yyy)" --entitlements "Payload/entitlements.plist" "Payload/xxx.app"
--註意entitlements.plist要準備好
在codesign指定證書時,證書的名字(帶括號、空格之類的),最好到keychain裏面找到這個證書,然後右鍵在“簡介”裏面拷貝過去,避免“找不到”的提示。
把Payload壓縮成ipa,註意不是Payload的上一級目錄!
這個ipa安裝到越獄手機後,跑起來是這樣的:
小白:這麽可惡!這個框太不友好了!
要去掉這個框,先要分析一下代碼。
把ipa包解壓,再進到xx.app內,找到執行文件,分析這個文件,這裏用hopper來分析。
小白:hopper是什麽東東?
小程:是分析二進制代碼的倚天劍!
小白:有屠龍刀嗎?
小程:有,ida是也!
小白:好可怕,亮劍吧!
啟動hopper,小程的版本是這樣的:
可以看到,彈框的代碼是:
想要去掉彈框,可以選擇不同的辦法,比如把調用alertview的代碼改成nop,比如把比較的值改掉不讓它進過期的分支,比如把跳轉指令“取反”地改一下......
小白:nop是什麽?
小白:nooperation,空指令,什麽都不做的,但占指令執行時間。
小白:我也想什麽都nop!
這裏演示把跳轉指令改掉的辦法。
先確定跳轉的地方:
cbz,表示為0就跳轉,而且是跳轉到非過期的分支。也就是說,現在不是0,沒有跳轉。所以,修改的辦法就是改為“不為0就跳轉”。
把光標放在cbz命令行上,再切換至十六進制的表示頁面:
可以看到cbz對應的十六進制是這樣的(兩個字節):
cbz即是:62 06 00 34
而cbnz(不是0就跳轉)是:62 06 00 35
所以,修改為cbnz,就是這樣:
保存為另一個執行文件:
把修改後的執行文件覆蓋掉原文件,再把Payload目錄打包,重命名為.ipa文件,再用第三方工具安裝到手機(不需要重簽名)。
最終,過期的提示消失了,看到了另一個提示:
小白:Oh Yeah!
總結一下,關鍵流程是,用hopper定位到目標代碼的位置,並通過hopper修改保存。同時,應該註意ipa的重簽名等常規的知識。“硬改”的辦法,對匯編技能的要求較高,相對而言,如果只是想在iOS平臺控制目標程序的運作,hook會是一個更有想象力的選擇。
讓別人的程序按自己的意願運行