蒲公英:超級簽名
反編譯工具:
Tips
要想保留原APP的bundleId不變,則重簽名的證書的bundleId規則如下:
原App的bundleId:?com.abc.hell
用于重簽名的bundleId:com.abc.hell.xyz
保證原APP的bundleId是重簽名的bundleId的前綴
超級簽名-原理/機制/技術細節-完全解析
隨著蘋果對于企業分發證書的頻繁吊銷和日益收緊,代簽名行業也隨之迭代出了黑科技,即所謂的超級簽名。
從整個安裝流程上來看,超級簽名少了在設置里面信任企業證書的步驟,體驗上要比企業分發更簡單和容易接受,同時分發價格也貴的離譜,不禁讓人好奇這新瓶里面到底裝的是什么酒。
今天就來幫大家解析一下其中的門門道道,以及這套機制的技術難點。
image
據說某分發平臺價格表,來源網絡,本人對圖片真實性不負責
簽名原理
簽名原理其實就一句話,使用了蘋果提供給開發者的Ad-Hoc分發通道,把安裝設備當做開發設備進行分發。
既然簽名用是 Ad-Hoc ,那么 Ad-Hoc 所具有的優劣勢也一并繼承了下來:
優勢:
直接分發,安裝即可運行,不需要用戶做企業證書的信任操作
目前穩定,不會有證書吊銷導致的業務風險(后續蘋果政策風險非常高)
缺點:
單開發者賬號的iPhone設備數量只有100個,導致分發成本非常高(99美元/1年/100個設備)
開發者賬號需要預先寫入安裝設備的UDID,在工具鏈不通的情況下,獲取用戶的UDID相對困難和繁瑣,而且手動寫入UDID不存在商用可行性,當然目前這個缺點被解決了
整體架構
接下來我們就看看整套機制是如何進行的:
整體架構
設備安裝描述文件后,會向服務器發送設備的UDID。
服務器收到UDID后,將UDID注冊到某個開發者賬號下。
再生成簽名用的描述文件,給IPA簽名。
然后iPA傳Server,使用itms-services方式讓用戶下載。
技術細節
使用配置文件獲取UDID
蘋果公司允許開發者通過IOS設備和Web服務器之間的某個操作,來獲得IOS設備的UDID(包括其他的一些參數)。這里的一個概述:
在你的Web服務器上創建一個.mobileconfig的XML格式的描述文件;
用戶在所有操作之前必須通過某個點擊操作完成.mobileconfig描述文件的安裝;
服務器需要的數據,比如:UDID,需要在.mobileconfig描述文件中配置好,以及服務器接收數據的URL地址;
當用戶設備安裝描述文件后,設備會回調你設置的URL,如果你的URL返回302跳轉的話,Safari瀏覽器會跳轉到你所給的地址;
Apple Developer Center 自動化工具
接下來的關鍵點就是如何在獲取到用戶的UDID之后,秒級完成注冊新的開發者設備+更新Provisioning Profile的。 這里我們需要借助開源工具(Spaceship):
image
spaceship公開了Apple Developer Center的API,而且執行速度比解析開發者Web頁面快兩個數量級,從而在非常短的時間內搞定Provisioning Profile。 這個框架解決了整套機制的關鍵問題,成為整個工具鏈的基石。其實某平臺早就完成了UDID獲取和應用簽名分發的技術儲備,只差這套API。
下面是解析開發者Web頁面和直接訪問API的速度對比圖:
SpaceshipRecording
image
安裝spaceship
sudo gem install fastlane -n /usr/local/binsudo gem install pry? -n /usr/local/bin fastlane spaceship
spaceship使用說明DeveloperPortal.md
Cool!!!!!!! 非常棒!再次為Spaceship鼓掌????????
如何自動簽名封包
此處其實應該有一萬個解決方案,通過命令行腳本/Python腳本/或者其他第三方都能實現。
這里推薦使用?Sigh這個框架來解決這個問題。
image
Sigh的用法和配置都非常簡單,一個純命令工具,豐富的配置選項(自行查閱文檔),活躍的社區,完全夠用了。
直接上演示圖:
image
OTA 分發已簽名的應用
emmmm 此處也應該有一萬個解決方案,那就選擇?AppDeploy?吧。入選原因非常簡單,這個框架有Logo(看臉的社會就是那么真實...)。
AppDeploy Logo
可視化部署流程如下圖(同時支持命令行調用):
Apk
結語
通過開源社區的力量,我們成功搞清了整個機制上的關鍵技術點,必須要說fastlane團隊非常優秀的提供了工具鏈關鍵一環(Spaceship)從而使Ad-Hoc自動分發成為可能。
蘋果對于App的分發審核管控可以說是非常嚴苛,這背后既有安全考慮,也有壟斷利益。但無論如何,對于終端用戶都是利大于弊的措施,App審核保護了無數的手機用戶免受惡意程序的侵害。 個人強烈反對這種繞過審核的分發形式。同時我要指出,分發平臺以這種情況繞過蘋果的審核是嚴重違反?APPLE 開發商計劃許可協議的3.3.3條款:
未經 Apple 預先書面核準或依照第 3.3.25 條 (In-App Purchase API) 得到允許,應用程序不可經由 App Store、Custom App Distribution 或 TestFlight 以外的分銷渠道提供、解鎖或激活附加的特征或功能。
開源工具鏈
獲取設備UDID的第三方庫:
使用Safari瀏覽器自動打開證書然后跳轉到安裝描述文件的步驟
<html><header><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="edge"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="renderer"content="webkit"><metaname="renderer"content="ie-comp"><metahttp-equiv="Pragma"content="no-cache"><metahttp-equiv="Cache-Control"content="no-cache"><metahttp-equiv="Expires"content="0"><metaname="viewport"content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"><metaname="format-detection"content="telephone=no"><metaname="format-detection"content="email=no"></header><body><ahref="javascript:install();">安裝APP</a><br/><script>//? ? ? ? ? ? function install(){? ? ? ? ? ? ? // 安裝獲取udid的證書? ? ? ? ? ? ? setTimeout(function() {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? location.href = './read_udid_path.mobileconfig';? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, 1000)? ? ? ? ? ? ? // 打開描述證書設置頁面? ? ? ? ? ? ? setTimeout(function() {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? location.href = './setup.mobileprovision';? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, 3000)? ? ? ? ? ? }? ? ? ? ? // 加載完自動安裝證書并打開證書管理? ? ? ? ? install()</script></body></html>
獲取Java UDID上傳
import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.util.HashMap;@RestController@RequestMapping("/json")public class JsonController {? ? ? ? ? @RequestMapping(value = "/uploadUDID",method? = {RequestMethod.GET,RequestMethod.POST})? public void uploadUDID(HttpServletRequest request,HttpServletResponse response){? ? ? ? try {? ? ? ? ? ? response.setContentType("text/html;charset=UTF-8");? ? ? ? ? ? request.setCharacterEncoding("UTF-8");? ? ? ? ? ? //獲取HTTP請求的輸入流? ? ? ? ? ? InputStream is = request.getInputStream();? ? ? ? ? ? //已HTTP請求輸入流建立一個BufferedReader對象? ? ? ? ? ? BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));? ? ? ? ? ? StringBuilder sb = new StringBuilder();? ? ? ? ? ? //讀取HTTP請求內容? ? ? ? ? ? String buffer = null;? ? ? ? ? ? while ((buffer = br.readLine()) != null) {? ? ? ? ? ? ? ? sb.append(buffer);? ? ? ? ? ? }? ? ? ? ? ? String content = sb.toString().substring(sb.toString().indexOf("")+8);? ? ? ? ? ? //content就是接收到的xml字符串? ? ? ? ? ? content = content.replaceAll("\t","");? ? ? ? ? ? int from = content.indexOf("")+"".length();? ? ? ? ? ? content = content.substring(from);? ? ? ? ? ? int to = content.indexOf("");? ? ? ? ? ? content = content.substring(0,to);? ? ? ? ? ? content = content.replaceAll("","");? ? ? ? ? ? content = content.replaceAll("","=");? ? ? ? ? ? content = content.replaceAll("","");? ? ? ? ? ? content = content.replaceAll("","#*#");? ? ? ? ? ? HashMap plistMap = new HashMap();? ? ? ? ? ? String[] list = content.split("#*#");? ? ? ? ? ? for (String var : list){? ? ? ? ? ? ? ? String[] keyVals = var.split("=");? ? ? ? ? ? ? if(keyVals.length == 2){? ? ? ? ? ? ? ? ? plistMap.put(keyVals[0],keyVals[1]);? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? ? ? System.out.println(plistMap);? ? ? ? ? ? String udid = plistMap.get("UDID");? ? ? ? ? ? response.setStatus(301); //301之后iOS設備會自動打開safari瀏覽器? ? ? ? ? ? response.setHeader("Location", "http://192.168.3.57:8080/mysign/index2.html?UDID="+udid);? ? ? ? ? ? //http://192.168.1.106:8080/udid.jsp 是用于顯示udid的頁面,也可以利用之前的下載mobileprofile文件頁面? ? ? ? }catch (Exception e){? ? ? ? }? ? }
{
SERIAL=FK3V不展示全包含隱私,
CHALLENGE=4C1B718D不展示全包含隱私,
PRODUCT=iPhone10,3不展示全包含隱私,
VERSION=16G不展示全包含隱私,
UDID=94不展示全包含隱私
}
Apple Developer Center 自動化工具:
自動簽名封包工具:
OTA 分發應用工具:
參考資料
Over-the-Air Profile Delivery Concepts(獲取設備UDID官方文檔):developer.apple.com/library/arc…
APPLE 開發商計劃許可協議:download.developer.apple.com/Documentati…