很多人寫文章棋凳,喜歡把什么行業(yè)現(xiàn)狀啊,研究現(xiàn)狀啊什么的寫了一大通连躏,感覺好像在寫畢業(yè)論文似的剩岳,我這不廢話,先直接上幾個圖入热,感受一下拍棕。
第一張圖是在把代碼注入到地圖里面,啟動首頁的時候彈出個浮窗勺良,下載網(wǎng)絡(luò)的圖片绰播,蒼老師你們不會不認識吧?
第二張圖是微信運動步數(shù)作弊尚困,6不6蠢箩?
ok,那我們從頭說起……
1.反編譯
Android 的反編譯,相信大家都應(yīng)該有所了解谬泌,apktool滔韵、JEB 等工具。
我們先看一下 Apk 文件的結(jié)構(gòu)吧呵萨,如下圖:
1.META-INF:簽名文件(這個是如何生成的后面會提到)奏属。
2.res:資源文件,里面的 xml 格式文件在編譯過程中由文本格式轉(zhuǎn)化為二進制的 AXML 文件格式潮峦。
3.AndroidManifest.xml:Android 配置文件囱皿,編譯過程依然被轉(zhuǎn)換為 AXML 格式。
4.classes.dex:java 代碼編譯后產(chǎn)生的類似字節(jié)碼的文件(dalvik 字節(jié)碼)忱嘹。
5.resources.arsc:具有 id 值資源的索引表(asserts 文件夾中的資源不會生成索引)嘱腥。
6.其他文件:可由開發(fā)者自己添加,諸如 assets 等拘悦,或者 lib(native so 代碼)等目錄齿兔。
(Android 編譯打包過程分析參看: http://www.open-open.com/lib/view/open1463109448350.html
Apk 的核心邏輯主要在 classes.dex 中,破解和二次打包也基本上對這個文件做手腳础米,所以對這個文件的保護也尤為重要分苇。
上圖為一般 Apk 的破解過程(windows 畫圖工具畫的比較搓)。
我們首先用 apktool 工具反編譯:java -jar apktool.jar d -f xxx.apk outDir(PS:outDir 不寫會在當前目錄輸出)。
反編譯后的目錄結(jié)構(gòu)如下:
這里,res 里的 xml 和 manifset.xml 都已經(jīng)是解出后的 xml 了巡揍,不是 axml 格式了,res 目錄里的 values 目錄下的 public.xml 可以看到資源對應(yīng)的 id靖秩。
如果命令 java -jar apktool.jar d -f再加入 -r 代表資源文件不反編譯,上圖的目錄中將依然有resources.arsc竖瘾,xml 都是 axml 格式的沟突,也找不到 public.xml。
其實我們主要關(guān)注的是 smali 這個目錄捕传,里面是按照 android 程序編寫的時候 java 文件的目錄格式生成的惠拭,但是里面的文件并不是 java 格式的,而是 smali 格式的乐横,類似 MainActivity.smali求橄。
那么什么是 smali 文件呢?
1.Smali 是 Android 的 Dalvik 虛擬機所使用的一種 dex 格式的中間語言葡公。
2.可以理解為罐农,C 語言和匯編語言的編譯與反編譯,把 smali 理解為一種匯編語言催什。
我們可以打開一個 smali 文件看看涵亏,我們可以使用 notepad++ 打開,然后定一下 smali 語法的高亮顯示。
將下面內(nèi)容保存到 C:\Users\用戶名\AppData\Roaming\Notepad++下气筋,文件名為 userDefineLang.xml拆内。
可以參看 http://www.ourunix.org/post/117.html 操作。打開 MainActivity.smali 文件宠默,頭三行代碼大致如下:
.class public Lcom/example/hacktest/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"
smali 語法這里就不介紹了麸恍,自己查資料就好 smali 文件語法參考: http://www.open-open.com/lib/view/open1463109691826.html
這里舉個例子,我們寫個程序搀矫,一個 edittext 一個 button抹沪,當 edit 里面輸入正確的文字的時候,點擊 button 才會彈出正確的 toast瓤球。
我們看一下融欧,反編譯后的關(guān)鍵代碼:
可以看到這是一個參數(shù)為 string,返回值為 boolean 名叫 check 的函數(shù)卦羡,當輸入為“11”的時候才返回 true噪馏。
我們可以把第一個紅框位置的 if-eqz 改成 if-nez,這樣你輸入除了11的任何字符都會返回 true。
或者把第二個紅框位置的 0x1绿饵,改成 0x0,(0代表 true)欠肾,這樣這個函數(shù)不管輸入什么都返回 true。
OK拟赊,這樣我們就改完了董济,我們重新編譯:java -jar apktool.jar b -f outDir xxx.apk(PS:xxx.apk 可以不寫,會在 outDir 里生成 dist 目錄要门,編譯好的 Apk 在這里面)。
簽名:可以網(wǎng)上下載工具 autoSign廓啊,使用方法略…
安裝 Apk 后驗證欢搜,通過。
但是事情并不總是如我們所愿谴轮,有些 Apk 會做一些盜版檢測機制炒瘟,就是為了防止二次重打包。
以手機XX應(yīng)用為例第步,當你按照上述步驟反編譯疮装,重新編譯,簽名之后粘都,進入 APP 會出現(xiàn)這個頁面廓推,無法正常使用。
因為你并沒有這個 APP 的正版簽名文件(關(guān)于簽名相關(guān)的東西翩隧,在后面我再仔細講)樊展。
那么這個原理是什么呢,我們大膽猜測一下,無非就是和上一個例子類似的check函數(shù)专缠,兩個值的對比雷酪,那么這個值一定是簽名。
我們先通過方法拿到正版的簽名md5涝婉,然后在反編譯后的代碼中搜索一下這個值哥力。
然而并沒有搜到,再換個思路墩弯,我們搜索獲取簽名的這個函數(shù)吩跋,從而定位關(guān)鍵代碼,獲取應(yīng)用簽名的java代碼類似是:
PackageInfo pi = context.getPackageManager.().getPackageInfo(packname,packageManager.GET_SIGNATURES);
對應(yīng)的smali代碼類似是:
Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature
我們再搜用這段代碼搜索,在 StormUtils2.smali 里面找到了最住,發(fā)現(xiàn)在函數(shù) getSignInfo 里面钞澳,繼續(xù)跟蹤到 checkPiracy 函數(shù)。
看到這個函數(shù)發(fā)現(xiàn)就和上例中的 check 函數(shù)類似了涨缚,改一下返回值為 true 就好了轧粟。
我們再仔細看看這個函數(shù),發(fā)現(xiàn)關(guān)鍵的簽名 md5 值被拆開存放了脓魏,所以我們才沒有搜到兰吟,這也是防范搜索的一個舉措吧(雖然我覺得并沒什么用)。
const-string/jumbo v3, "dbbf****96b326003"
const-string/jumbo v0, "c388a****1578d5"
好的茂翔,修改后混蔼,我們再重新編譯、簽名珊燎,驗證通過惭嚣。
(PS:關(guān)于簽名檢測的除了 java 層的,可能還有再 so 里面校驗的和服務(wù)器驗證的方式悔政,在 so 里的用 IDA 打開 so 跟蹤修改晚吞,服務(wù)器驗證的抓包查看,再模擬發(fā)包重放攻擊就好了谋国,這里就不具體介紹了)
2. Android 的簽名保護機制到底是什么槽地?
Android 系統(tǒng)禁止更新安裝簽名不一致的 Apk,如果我們修改了 Apk 又用別的簽名文件簽名芦瘾,肯定是不一致的捌蚊。
我們從簽名工具 autoSign 分析,看一下 sign.bat 文件內(nèi)容:
-----------------------------------
@ECHO OFF
Echo Auto-sign Created By Dave Da illest 1
Echo Update.zip is now being signed and will be renamed to update_signed.zip
java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk
Echo Signing Complete
Pause
EXIT
-----------------------------------
看一下 java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk 這行的意義:
以testkey.x509.pem 這個公鑰文件和 testkey.pk8 這個私鑰文件對 update.apk 進行簽名近弟,簽名后保存為 update_signed.apk缅糟。
我們可以看到簽名前和簽名后比較,簽名后的文件中多了一個文件夾“META-INF”藐吮,里面有三個文件 MANIFEST.MF 溺拱、 CERT.SF 逃贝、 CERT.RSA。
我們通過 jd-gui 工具打開 signapk.jar迫摔,找到 main 函數(shù)沐扳,通過這個函數(shù)跟蹤代碼
1. addDigestsToManifest 這個函數(shù),遍歷 Apk 中所有文件句占,對非文件夾非簽名文件的文件逐個生成 SHA1 數(shù)字簽名信息沪摄,再 base64 編碼。
然后再寫入 MANIFEST.MF 文件中纱烘,生成文件如下:
-----------------------------------
Manifest-Version: 1.0
Created-By: 1.0 (Android)
Name: res/drawable-xhdpi/ic_launcher.png
SHA1-Digest: AfPh3OJoypH966MludSW6f1RHg4=
Name: AndroidManifest.xml
SHA1-Digest: NaPhUBH5WO7uGk/CfRu/SHsCvW0=
Name: res/drawable-mdpi/ic_launcher.png
SHA1-Digest: RRxOSvpmhVfCwiprVV/wZlaqQpw=
Name: res/drawable-hdpi/ic_launcher.png
SHA1-Digest: Nq8q3HeTluE5JNCBpVvNy3BXtJI=
Name: res/layout/activity_main.xml
SHA1-Digest: kxwMyILwF2K+n9ziNhcQqcCGWIU=
Name: resources.arsc
SHA1-Digest: q7Ystu6WoSWih53RGKXtE3LeTdc=
Name: classes.dex
SHA1-Digest: Ao1WOs5PXMxsWTDsjSijS2tfnHo=
Name: res/drawable-xxhdpi/ic_launcher.png
SHA1-Digest: GVIfdEOBv4gEny2T1jDhGGsZOBo=
-----------------------------------
SHA1 生成的摘要信息杨拐,如果你修改了某個文件,Apk 安裝校驗時擂啥,取到的該文件的摘要與 MANIFEST.MF 中對應(yīng)的摘要不同哄陶,則安裝不成功。
2. 接下來對之前生成的 manifest 使用 SHA1withRSA 算法哺壶, 用私鑰簽名屋吨,writeSignatureFile 這個函數(shù),最后生成 CERT.SF 文件山宾,如下:
-----------------------------------
Signature-Version: 1.0
Created-By: 1.0 (Android)
SHA1-Digest-Manifest: pNZ9UXN9GMqTgqAwKD6uEN6aD34=
Name: res/drawable-xhdpi/ic_launcher.png
SHA1-Digest: cIga++hy5wqjHl9IHSfbg8tqCug=
Name: AndroidManifest.xml
SHA1-Digest: oRzzLkwuvxC78suvJcAEvTqcjSA=
Name: res/drawable-mdpi/ic_launcher.png
SHA1-Digest: VY7kOF8E3rn8EUTvQC/DcBEN6kQ=
Name: res/drawable-hdpi/ic_launcher.png
SHA1-Digest: stS7pUucSY0GgAVoESyO3Y7SanU=
Name: res/layout/activity_main.xml
SHA1-Digest: Yr3img6SqiKB+1kwcg/Fga2fwcc=
Name: resources.arsc
SHA1-Digest: j1g8I4fI9dM9hAFKEtS9dHsqo5E=
Name: classes.dex
SHA1-Digest: Sci9MmGXNGnZ1d04rCrEEV7MWn4=
Name: res/drawable-xxhdpi/ic_launcher.png
SHA1-Digest: KKqaLh/DVvFp+v1KoaDw7xETvrI=
-----------------------------------
用私鑰通過 RSA 算法對 manifest 里的摘要信息進行加密至扰,安裝的時候只能通過公鑰解密,解密之后才能獲得正確的摘要资锰,再對比敢课。
3. 最后就是如何生成 CERT.RSA,打開這個文件看到的是亂碼绷杜,說明整個文件都被編碼加密了直秆,而且這個文件和公鑰有關(guān),從源碼中看出他是通過 PKCS7 將整個文件加密了鞭盟。
總結(jié): 1.簽名只是對完整性和簽名發(fā)布機構(gòu)的校驗機制 2.不能阻止 Apk 被修改切厘,只是簽名無法保持一致 3.不同私鑰對應(yīng)著不同的公鑰,實質(zhì)上不同的公鑰就代表了不同的簽名懊缺。
3. Android 系統(tǒng)如何獲取簽名
我們從獲取下面一段代碼開始分析:
packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES );
Signature[] signs = packageInfo.signatures;
md5 = getMD5Str(signs[ 0].toByteArray());
context.getPackageManager()其實拿到的是ApplicationPackageManager
看一下 context 的實現(xiàn)類 contextImpl 里的 getPackageManager()。
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager ;
}
IPackageManager pm = ActivityThread.getPackageManager ();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null ;
}
可以看到 ActivityThread 中方法 getPackageManager 獲取 IPackageManager培他。
繼續(xù)看 ActivityThread 的代碼:
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager ;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
看源碼知道是通過 ServiceManager.getService(“package”);獲取 PackageManagerService 并得到 IBinder對象鹃两,然后通過 asInterface 函數(shù)取得接口類 IPackageManager 實例。
然后作為參數(shù)構(gòu)造 ApplicationPackageManager舀凛,再看 ApplicationPackageManager 這個類里的方法:
@Override
public PackageInfo getPackageInfo(String packageName, int flags)
throws NameNotFoundException {
try {
PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId());
if (pi != null) {
return pi;
}
} catch (RemoteException e) {
throw new RuntimeException( "Package manager has died" , e);
}
throw new NameNotFoundException(packageName);
}
這里的mPM就是上面構(gòu)造函數(shù)傳進來的 IPackageManager俊扳,就可以調(diào)用 PackageManagerService 的方法了。
下圖是 PackagerManager 靜態(tài)類結(jié)構(gòu)圖:
ok猛遍,看完上圖的結(jié)構(gòu)圖馋记,繼續(xù)跟代碼 号坡,看到這里是 mPM 繼續(xù)調(diào)用的getPackageInfo(代理模式),通過進程通信到 PackageManagerService 中執(zhí)行響應(yīng)操作:
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
enforceCrossUserPermission(Binder.getCallingUid (), userId, false, "get package info");
// reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if (DEBUG_PACKAGE_INFO)
Log.v (TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
return generatePackageInfo(p, flags, userId);
}
if((flags & PackageManager. GET_UNINSTALLED_PACKAGES ) != 0) {
return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
}
}
return null ;
}
這里 mPackages 是 hashMap梯醒,其調(diào)用put方法的時機是在 scanPackageLI 方法中宽堆,而 scanPackageLI 的調(diào)用地方是在程序安裝和替換函數(shù)中,還有就是 scanDirLi 中茸习,代碼略畜隶。
scanDirLi 是用來掃描一些系統(tǒng)目錄的的,在 PackageManagerService 的構(gòu)造函數(shù)中調(diào)用的:
File dataDir = Environment. getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLibInstallDir = new File(dataDir, "app-lib" );
mAsecInternalPath = new File(dataDir, "app-asec" ).getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private" );
上面是掃描的位置↑↑↑↑↑↑↑
PackageManagerService 處理各種應(yīng)用的安裝号胚、卸載籽慢、管理等工作,開機時由 systemServer 啟動此服務(wù)猫胁。就是說之前安裝過的應(yīng)用或者系統(tǒng)應(yīng)用信息都會在開機掃描過程中存到 mPackages 這個 hashMap 中箱亿。開機后用戶的安裝操作也會同樣存到這個 hashMap 里面。
繼續(xù)看 getPackageInfo弃秆,調(diào)用的 generatePackageInfo 届惋, 里面調(diào)用的是 PackageParser 中的 generatePackageInfo,繼續(xù)跟驾茴。
這個函數(shù)的代碼比較長盼樟,只貼出部分關(guān)鍵代碼:
if ((flags&PackageManager. GET_SIGNATURES ) != 0) {
int N = (p.mSignatures != null) ? p.mSignatures.length : 0;
if (N > 0) {
pi.signatures = new Signature[N];
System.arraycopy (p.mSignatures, 0, pi. signatures, 0 , N);
}
}
return pi;
這段代碼之前主要是做一些復制的操作,就是 new 一個 PackageInfo锈至,然后把 PackageParser.Package 對象中的一些內(nèi)容復制到這個 PackageInfo 中晨缴。
從這段代碼可以看出來,最終得到的 signatures 信息就是中 p(PackageParser.Package )中的成員 mSignatures 中得來的峡捡。
好了击碗,現(xiàn)在就是看這個PackageParser.Package是從哪來的了,通過跟蹤代碼们拙,installPackageLI 和 scanPackageLI 中的:
final PackageParser.Package pkg = pp.parsePackag (tmpPackageFile, null, mMetrics, parseFlags);
這行代碼只是生成了 pkg稍途,并沒有賦值里面的 mSignatures,繼續(xù)跟蹤砚婆,找到函數(shù) collectCertificatesLI械拍,找到 pp.collectCertificates(pkg , parseFlags)。
PS:最終又進行了一系列的跟代碼装盯,找到了 JarVerifier.java 這個類的 readCertificates 這個就是用來讀取.RSA 文件的,最終我們看到的里面的代碼是通過 loadCertificates 取得的 certs 賦值給了 pkg.mSignatures坷虑。
至此,獲取簽名的所有邏輯就算是簡單的過一遍了埂奈,以下是簡略流程圖:(發(fā)現(xiàn) ppt 畫圖比 Windows 畫圖工具好用多了迄损,哈哈)
在跟代碼的過程中也找到了簽名對比的函數(shù) compareSignatures ,有空自己看看就好了账磺。
OK芹敌,繞了這么久我們終于找到源頭了痊远,獲取簽名就是在 META-INF 中尋找,并解析氏捞。試想一下碧聪,如果我們修改了這個函數(shù),讓他解析原來正版的 META-INF 中的 CERT.RSA 文件幌衣,這樣就可以偽造為真正的簽名了矾削。
那么我們就想到了 HOOK,(很多人都是從看雪論壇上找到的一篇文章看到的 http://bbs.pediy.com/showthread.php?t=186054 hook 的原來簡單來說就是豁护,找到原函數(shù)和新函數(shù)的指針位置哼凯,然后兌換內(nèi)容,將新函數(shù)替代原函數(shù)楚里。
關(guān)于 hook 呢断部,網(wǎng)上也有很多框架可以使用,比如:
1.Cydia substrate :
http://www.cydiasubstrate.com/ 2.Xposed : http://repo.xposed.info/ 網(wǎng)上也有很多教程可以看看班缎。
烏云(wooyun)上有一篇很有意思的教程蝴光,就是利用 hook 進行微信運動作弊,原帖地址: http://drops.wooyun.org/tips/8416
下圖就是我用了上面的方法產(chǎn)生的效果达址,還差點被微信部門的人請去喝茶蔑祟。
這里用的是 Xposed 框架,原理就是 hook 了手機的計步傳感器的隊列函數(shù)沉唠,然后把步數(shù)的返回值每步乘1000返回疆虚,前提是,你的手機硬件本身有計步傳感器功能满葛,這里微信運動里面列出了支持的手機列表: https://kf.qq.com/touch/sappfaq/151013AvyyeQ151013r63qmq.html?platform=15 好像最高就是98800了径簿,可能是微信做了步數(shù)限制吧。
我這里用的是小米4聯(lián)通版嘀韧,發(fā)現(xiàn)雖然是1000基數(shù)的加篇亭,但是好像隔了很久才變化,估計又是 MIUI 做了一些省電策略锄贷,傳感器的采集做了對齊吧译蒂?
Xposed 框架,很多玩機愛好者谊却,會拿它修改一些主題蹂随,字體之類的,或者系統(tǒng)界面因惭,定制自己想要的系統(tǒng)插件等等。然而绩衷,也有缺點蹦魔,需要手機root激率,而且這個框架,還有可能讓手機變磚勿决,還有的系統(tǒng)可能對這個框架支持的不好乒躺,或者不支持。XDA 論壇里面也有很多大神把 Xposed 對某些機型做了適配低缩,大神一般都是說嘉冒,如果手機變磚他們不負責,哈哈咆繁。
正式由于這些框架的諸多不便讳推,root 等等的問題,于是就有了一些非 root 的 hook 的黑科技玩般,比如阿里巴巴的開源框架 Dexposed( https://github.com/alibaba/dexposed )其也是根據(jù) Xposed 框架修改而來的银觅,不過看 github 上他們也好久沒更新了。
也有像其他個人寫的和這種比較類似的框架坏为,這里就不介紹了究驴。但是這類框架的缺點就是,只能在該進程下hook匀伏,不能全局 hook洒忧,即只對這個進程的應(yīng)用起作用,不能對另一個應(yīng)用起作用够颠,優(yōu)點是可以 hook 自定義函數(shù)也能hook 系統(tǒng)函數(shù)熙侍,并且不用 root 和重啟。阿里用這個框架來打在線熱補丁摧找。
那對于 App 內(nèi)部簽名校驗的就不用再搜相應(yīng)的代碼了核行,直接 hook 就一步到位了,android.app.ApplicationPackageManager 這個類的 getPackageInfo 這個方法直接把正確的簽名返回就好了蹬耘,接下來我們就需要把hook的代碼注入到某個 App 里就好了芝雪。
4. 關(guān)于如何注入?
開篇的時候有個圖片就是我在地圖里面注入了一個蒼老師的圖片其實就是综苔,自己寫了個 imageloader惩系,用來下載網(wǎng)絡(luò)圖片,再寫個 activity 或者 dialog 來承載這個 imageview如筛,然后編譯堡牡,再反編譯,取出相應(yīng)的smali等文件杨刨,比如貼到已經(jīng)反編譯好的地圖的里面晤柄,把開啟這個蒼老師圖片下載的啟動代碼放到合適位置,最后再把地圖重新打包簽名妖胀,就ok 了芥颈。
hook 代碼也是同理注入惠勒,驗證一下,成功(我這塊寫的比較粗略爬坑,代碼比較多纠屋,只說思路了)那么這種代碼注入和 hook 相結(jié)合的方式能干什么呢,我們也不妨搞出點事情來盾计。同樣我們還是進行微信運動作弊的事情售担,其實很多運動類的軟件都可以把自己的數(shù)據(jù)同步到微信運動里,比如小米手環(huán)署辉,樂動力族铆,悅動圈等等。
那我們就先拿一個來開刀吧:
經(jīng)過一系列的跟蹤代碼定位涨薪,最終定位到了這個類 cn.ledongli.ldl.cppwrapper.DailyStats 里的 f 方法(f 是因為代碼混淆了)然后我們注入并 hook 方法骑素,讓它返回66666,ok刚夺,我們看到了如下效果:
然后我們在應(yīng)用里面登陸微信賬號献丑,和對接到微信運動的功能,發(fā)現(xiàn)不好用侠姑,是因為创橄,微信里面做了對應(yīng)用的簽名校驗,應(yīng)用的簽名已經(jīng)變了莽红。
所以我們只能破解微信了(悶聲作大死)妥畏,同樣注入 hook 代碼,讓微信獲取樂動力的簽名的時候取得正確簽名安吁,關(guān)鍵代碼:
if( packageName.equals( "cn.ledongli.ldl")){
if ( result instanceof PackageInfo) {
PackageInfo info = (PackageInfo) result;
info. signatures[0] = new Signature( myHexLedongli);
param.setResult( info);
}
}
再把這個盜版的微信重新打包簽名醉蚁,重新進行應(yīng)用的同步數(shù)據(jù)操作,再進微信運動看看鬼店,是不是已經(jīng)66666了网棍。至此作弊完成。
♂♂♂♂♂♂♂♂♂♂我是畫風不同的分割線♂♂♂♂♂♂♂♂♂♂♂♂
說了這么多破解的妇智,也該聊聊防破解的了滥玷。
google 最早給的就是代碼混淆的方案,其實一般的混淆只是降低了代碼的可讀性巍棱,讓你對反編譯出來的函數(shù)命名等不知道什么意思惑畴,不過解讀出來只是時間問題。后來還有資源混淆的航徙,但是意義不大如贷。
后來有了核心代碼用 C 實現(xiàn),寫成 SO,加花指令的辦法杠袱,這個辦法確實會阻止一大部分人的繼續(xù)破解泻红,但是對于經(jīng)常做逆向的工程師來說也不是什么難題。
其實做這么多大多數(shù)軟件的初衷就是不想軟件被盜版霞掺,然后被注入亂七八糟的廣告,或者被盜取信息等讹躯,后來就有了盜版檢測機制菩彬。比如:JAVA 層的簽名校驗,NDK 層校驗潮梯,分段存放簽名 Hash 串骗灶,服務(wù)器校驗等等,但是這些方法我都在上面說了破解方法秉馏。
現(xiàn)在國內(nèi)的一般應(yīng)用市場都有對 APP 簽名的檢測耙旦,在你下載的時候會告訴你這個 APP 是不是盜版的,從而讓用戶區(qū)分出來萝究。但是應(yīng)用市場自己本身又被盜版了怎么辦呢免都?
再后來,就有了像360加固保和騰訊的樂固等產(chǎn)品帆竹,so 做了加密绕娘,真正的 dex 也藏起來了,不過個人覺得栽连,就算真正的 dex 也需要變成 odex 了险领,root 的手機取到 odex,再轉(zhuǎn)回 dex秒紧,就能拿到真正的 dex(雖然我沒試過绢陌,但是我覺得可能是一個思路),所以這個方法就更難破解了熔恢。
雖然加固產(chǎn)品很厲害脐湾,但是也會有他的缺陷,Android 系統(tǒng)不斷的更新升級绩聘,也許就換了某些模式等等沥割,比如 ART 剛出來的時候,加固保加固后的 Apk凿菩,在 ART 模式運行下就會 Crash机杜。這些加固產(chǎn)品要不斷的適配各種型號的手機,CPU 類型衅谷,運行模式等等椒拗,所以很多 APP 為了考慮兼容性,他們也不會輕易去加固自己的產(chǎn)品。
♂♂♂♂♂♂♂♂♂♂我是畫風不同的分割線♂♂♂♂♂♂♂♂♂♂♂♂
關(guān)于逆向破解 Android 應(yīng)用蚀苛,我覺得耐心很重要吧在验,代碼跟來跟去確實很枯燥,總結(jié)幾點小技巧吧:
1.信息反饋:通過界面的一些彈出信息堵未,界面特點尋找突破點腋舌。
2.特征函數(shù):比如搜 Toast,Log渗蟹,getSignature 等块饺。
3.代碼注入:把 toast 或者 log 函數(shù)注入到程序中,跟蹤位置雌芽。
4.打印堆棧:插入 new Exception(“定位”).printStackTrace();
5.網(wǎng)絡(luò)抓包:通過抓包得到的關(guān)鍵字段授艰,在代碼中定位。
寫在后面:
這篇文章整理了有一段時間了世落,覺得還是應(yīng)該寫出來淮腾,也不是什么高深的技術(shù)文章,就是個人總結(jié)的一點心得而已屉佳。
關(guān)于破解應(yīng)用很多人可能會去破解別人的應(yīng)用注入廣告來獲取利益谷朝,也有可能盜取別人的信息。
不過我們作為有節(jié)操的開發(fā)工程師忘古,應(yīng)該本著瑞雪的精神看待技術(shù)徘禁,學習技術(shù),而不是亂♂搞髓堪。但是我們也應(yīng)該知道送朱,我們的應(yīng)用有可能會被別人怎么搞……
最后推薦一本資料書,大家可以有空看看干旁。
via: http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=974