編輯:關於Android編程
0x00
原理部分我不獻丑了,上面3篇文章說的很清楚,我直接實戰,講述從0開始如何最終實現加固的整個過程,踩了不少坑。
第一步創建被加固Apk,就是你的源碼Apk。你做的工作就是防止這個Apk被破解。這個APK要注意以下幾點:
從途中可知我們的主Activity為doctorq.com.mysourceapk.MainActivity
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPru509DSu7j2QWN0aXZpdHnD+86qPGNvZGU+ZG9jdG9ycS5jb20ubXlzb3VyY2VhcGsuLlN1YkFjdGl2aXR5PC9jb2RlPjwvcD4NCjxoMiBpZD0="記住你創建的application名">記住你創建的Application名
從圖中可知我們的Application為doctorq.com.mysourceapk.MyApplication
采用的方式和參考文章的做法是一樣的,顯式添加控件,如下:
TextView content = new TextView(this);
content.setText("I am Source Apk");
content.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(MainActivity.this, SubActivity.class);
startActivity(intent);
}
});
setContentView(content);
Log.i("demo", "app:" + getApplicationContext());
繼承於AppCompatActivity
在解殼程序中運行的時候報如下的錯誤,自身運行沒啥問題:
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: FATAL EXCEPTION: main
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: Process: xposed.doctorq.com.decode2, PID: 16721
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: java.lang.NoClassDefFoundError: doctorq/com/mysourceapk/SubActivity
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at doctorq.com.mysourceapk.MainActivity$1.onClick(MainActivity.java:21)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.view.View.performClick(View.java:4444)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.view.View$PerformClick.run(View.java:18440)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:733)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Looper.loop(Looper.java:136)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5001)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:806)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: Caused by: java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.DexFile.defineClassNative(Native Method)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.DexFile.defineClass(DexFile.java:222)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:215)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.DexPathList.findClass(DexPathList.java:322)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:54)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at doctorq.com.mysourceapk.MainActivity$1.onClick(MainActivity.java:21)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.view.View.performClick(View.java:4444)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.view.View$PerformClick.run(View.java:18440)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:733)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Looper.loop(Looper.java:136)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5001)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:806)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
這個demo就是主界面上有一個TextView,可以點擊跳轉到下一個Activity。
這個時候我們能APK文件,這個文件我們第三步需要用。
第二步解殼程序,也就是源程序的宿主,他也是一個APK,但是這個APK需要注意的地方更多,我踩了很多坑:
這個文件的修改位置很多,修改後如下所示:
主要修改位置有以下幾點:
這個APPLICATION_CLASS_NAME
指向的是我們源碼中的Application
的子類,這也是之前特別提醒的原因
我們要講解殼程序本身的Activity替換成源碼的主Activity,這個時候解殼程序裡的activity其實是沒有用的,刪掉也不影響。
我們在源碼程序的中activity都要在解殼程序的配置文件中配置:
主要修改就是主Activity的修改:
try {
Object actObj = dLoader.loadClass("doctorq.com.mysourceapk.MainActivity");
Log.i("demo", "actObj:" + actObj);
} catch (Exception e) {
Log.i("demo", "activity:" + Log.getStackTraceString(e));
}
因為你修改的包名啊,activity
名啊,是識別不了的,這個時候可以通過gradle
的assemble
來打包。
這個時候得到我們解殼程序的APK和dex文件,這兩個文件我們一會都要用。
第三步加固工具,這個工具是一個java項目,我們在eclipse中創建:具體的原理是將源碼APK加到解殼程序的dex文件後面。這個沒什麼坑,沒啥可講的,加固成功後,會得到一個產物,我們將這個產物命名為classes.dex,因為一會要替換到解殼APK中的classes.dex文件。
第四步是替換解殼程序中的classes.dex,這個時候用到WinRAR工具,首先找到解殼程序,然後刪除借殼程序中的classes.dex,添加第三部產生的classes.dex文件
第五步是重簽名,因為APK
被修改了,這個時候直接安裝,會報無簽名的錯誤,所以這個時候我們用Auto-sign
這個工具去簽名,具體做法我在Android安全專項測試之反編譯中講過。
安裝完畢後,可以打開我們的解殼程序了,這個時候一定要看清楚我們進的是解殼程序的app,而不是我們之前的源碼app:
源碼下載地址
這個demo
中我們的源碼中沒有布局文件,這在實際項目中是不可能,那麼這些布局文件怎麼添加,有人提出將所有布局文件添加到解殼程序中,這樣就能找到了。
我們做了這麼多,真的加固了麼?ok,我們來實驗下,我們用apktool來反編譯下:
58deMacBook-Pro-7:Auto-sign wuxian$ apktool d testerhome.apk
I: Using Apktool 2.0.3 on testerhome.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/wuxian/Library/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
實際上是成功的,有的人就會瘋了,你不是說加固了,怎麼還能被反編譯了,我們來看看反編譯後的產物:
你會發現,我們看不到源碼demo項目中的代碼,連包名都沒發現,你能看到的只是解殼程序的東西,我們加固的目的是起到了,但是解殼程序能被反編譯也是有風險的,畢竟我們的一些核心代碼寫在了ProxyApplication
中,這又怎麼辦呢?我暫時也不知道,思考一下吧
跟著代碼看一看豆瓣開源的混合開發框架Rexxaar // 初始化rexxar Rexxar.initialize(this);
本Demo中所含功能1:定位,顯示當前位置2:地圖多覆蓋物(地圖描點,彈出該點的詳細信息)3:坐標地址互相換算4:POI興趣點檢索5:線路查詢(步行,駕車,公交)6:繪制
Service簡介:Service 是Android的四大組件之一,一般用於沒有UI界面,長期執行的後台任務,即使程序退出時,後台任務還在執行。比如:音樂播放。Servi
本文實例講述了Android改變手機屏幕朝向的方法。分享給大家供大家參考。具體如下:模擬當點擊按鈕時,使手機朝向發生改變。main.xml布局文件:<?xm