Android高效調試技巧02——反編譯

今天要給大家介紹一項調試技巧——反編譯。因為我們遇到的問題有時會跟第三方應用有關,對于這些我們沒有代碼的應用,如果不進行反編譯,很難對其進行分析。

說到apk反編譯不得不說代碼混淆,在簽名打包時啟動代碼混淆可以幫助我們保護代碼。曾經聽說有小公司發布了未做代碼混淆的應用,結果被別人反編譯后上架,辛辛苦苦做出的應用就這樣被別人竊取了,所以保護好自己的勞動成果很重要。除了代碼混淆,有些應用商店還會要求開發者進行安裝包加固,以提高安全性。

反編譯就是把對代碼做的這些保護解開,讓我們了解別人代碼的部分細節。比如下面要介紹的例子,GoogleSetupWizard 引起的問題,雖然我們沒有它的源碼,但是通過反編譯我們可以了解內部的邏輯。

反編譯工具

在處理這個問題之前我用的反編譯工具一直是Dex2Jar+jd-gui,用法簡單,只要將 apk解壓縮,把解壓出的dex文件用Dex2Jar反編譯,然后用jd-gui工具閱讀即可,對于沒有混淆的apk,閱讀起來跟閱讀代碼體驗差不多。但是在反編譯 GoogleSetupWizard 的時候卻出錯(提示notsupport version)。咨詢了別的同事建議試試apktool,解出smali文件。關于smali,這里有一份文檔供大家參考Smali學習筆記

apktool的下載和使用: 將apktool.jar和apktool放到/usr/local/bin 目錄(需要root權限);運行apktool d <apk-file> 進行反編譯;

反編譯舉例

問題描述:
  在從Owner賬戶切換到Guest賬戶時失敗,自動又切回Owner賬戶,并且狀態欄無法正常下拉。

問題分析:
  該問題第一個難點是確認誰觸發了切回Owner賬戶的動作。這里我們用android.util.Log類的Log.getStackTraceString(newThrowable()) 方法來完成。賬戶切換會調用ActivityManagerNative類的switchUser方法,我們在該方法中添加如下語句:

Log.i(TAG,Log.getStackTraceString(newThrowable()));

這樣調用關系就一目了然了。結果如下:

ActivityManagerNative:  at android.app.ActivityManagerProxy.switchUser(ActivityManagerNative.java:5866)
ActivityManagerNative:  atcom.google.android.setupwizard.util.UserHelper.removeThisUser(UserHelper.java:43)
ActivityManagerNative:  atcom.google.android.setupwizard.lifecycle.ProvisioningFlagsLifecycleCallback.onExit
(ProvisioningFlagsLifecycleCallback.java:49)
ActivityManagerNative:  at com.google.android.setupwizard.lifecycle.LifecycleManager.notifyExit(LifecycleManager.java:115)
ActivityManagerNative:  atcom.google.android.setupwizard.util.ExitHelper.finishSetup(ExitHelper.java:45)
ActivityManagerNative:  at
**com.google.android.setupwizard.util.SetupWizardUserInitReceiver**
.onReceive (SetupWizardUserInitReceiver.java:33)

可以看出調用者是com.google.android.setupwizard應用的SetupWizardUserInitReceiver類,它是一個Google gms 應用。我們用apktool將其反編譯,SetupWizardUserInitReceiver.smali
文件如下:

.superLandroid/content/BroadcastReceiver;
.source"SetupWizardUserInitReceiver.java"
#direct methods

.methodpublic constructor <init>()V
.locals0
.prologue
.line 28
invoke-direct{p0}, Landroid/content/BroadcastReceiver;-><init>()V
return-void
.endmethod
#virtual methods
.methodpublic onReceive(Landroid/content/Context;Landroid/content/Intent;)V
.locals2
.paramp1, "context" # Landroid/content/Context;
.paramp2, "intent" # Landroid/content/Intent;
.prologue
.line 31

const-string/jumbov0, "android.intent.action.USER_INITIALIZE"
invoke-virtual{p2}, Landroid/content/Intent;->getAction()Ljava/lang/String;
move-result-objectv1
invoke-virtual{v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-resultv0
if-eqzv0, :cond_0
.line 32
invoke-static{p1},Landroid/os/UserManager;->get(Landroid/content/Context;)Landroid/os/UserManager;
move-result-objectv0
invoke-virtual{v0}, Landroid/os/UserManager;->isGuestUser()Z
move-resultv0
.line 31
if-eqzv0, :cond_0
.line 33
invoke-static{p1},Lcom/google/android/setupwizard/util/ExitHelper;->finishSetup(Landroid/content/Context;)V
.line 30
:cond_0
return-void
.endmethod

這是一個BroadcastReceiver,我們要關注的是它的onReceive方法。通過網上搜索smali語法,可以判斷出當為Guest用戶時會調用ExitHelper的finishSetup方法。我們再看這個方法,

.methodpublic static finishSetup(Landroid/content/Context;)V
.locals2
.paramp0, "context" # Landroid/content/Context;
.prologue
.line 45

invoke-static{},Lcom/google/android/setupwizard/lifecycle/LifecycleManager;->get()Lcom/google/android/setupwizard/lifecycle/LifecycleManager;
move-result-objectv0
invoke-virtual{v0, p0},Lcom/google/android/setupwizard/lifecycle/LifecycleManager;->notifyExit(Landroid/content/Context;)V
.line 49

>new-instancev0, Landroid/content/Intent;
const-string/jumbov1, "com.google.android.setupwizard.SETUP_WIZARD_FINISHED"
invoke-direct{v0, v1}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V
invoke-virtual{p0, v0},Landroid/content/Context;->sendBroadcast(Landroid/content/Intent;)V
.line 42
return-void
.endmethod

上面先拿到了一個LifecycleManager 實例,然后調用了LifecycleManager的notifyExit方法,再發送了一個com.google.android.setupwizard.SETUP_WIZARD_FINISHED廣播。最終,我們跟蹤到調用用戶切換的代碼如下:

50 const-string/jumbo v3, "device_provisioned"**
51 
52 invoke-static {v0, v3, v6},Landroid/provider/Settings$Global;>putInt(Landroid/content/ContentResolver;Ljava/lang/String;I)Z
53 
54 .line 56 
55 :cond_0 
56 :goto_0 
57 const-string/jumbo v3, "user_setup_complete" 
58 
59 invoke-static {v0, v3, v6},Landroid/provider/Settings$Secure;->putInt(Landroid/content/ContentResolver;Ljava/lang/String;I)Z
60 
61 .line 34 
62 return-void 
63 
64 .line 45 
65 :cond_1 
66 invoke-static {p1},Lcom/android/setupwizardlib/util/WizardManagerHelper;->isDeviceProvisioned(Landroid/content/Context;)Z
67 
68 move-result v3 
69 
70 if-nez v3, :cond_0 
71 
72 .line 48 
73 invoke-virtual {v2}, Landroid/os/UserManager;->getUserHandle()I 
74 
75 move-result v1 
76 
77 .line 49 
78 .local v1, "user":I 
79 invoke-static {p1},Lcom/google/android/setupwizard/util/UserHelper;->removeThisUser(Landroid/content/Context;)Z

上面會去讀device_provisioned這個setting項,當為false時會退出當前賬戶。通過在源碼下搜索,果然發現在packages/apps/Provision模塊下有對應的提交,這樣就定位到了問題點。

總結

反編譯作為一項調試技巧,在通往高手之路上是不必可少的。雖然反編譯后的代碼比較難懂,但是多加練習總有一天會得心應手。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容

  • 一、前言 今天我們開始apk破解的另外一種方式:動態代碼調試破解,之前其實已經在一篇文章中說到如何破解apk了: ...
    JiangWei_App閱讀 3,718評論 2 29
  • 大多數APP都對API接口進行了加密,防止第三方隨意調用接口,常用的方法是,設置一個key,在調用接口來發送請求時...
    vstorm閱讀 8,112評論 0 2
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,761評論 25 708
  • 【2015/2/26】 這一把鎖有個華麗的名字叫命運齒輪。 可惜它的形狀并不是齒輪狀,而是兩片銀色的金屬鉸合在一起...
    下不停的雨閱讀 370評論 0 0
  • 情緒每個人都有允許自己的情緒和情緒在一起,有情緒不可怕接受情緒不好處理好不逃避不害怕,情緒不可怕可怕自己不接納不理...
    下頁人氣閱讀 1,974評論 0 0