http://shazhuzhu1.iteye.com/blog/1415328
很多人熱衷於逆向工程,其過程中既可以學習作者的思路,又可以鍛鍊自己的能力,可謂是一舉多得! 今天我來給大傢伙介紹介紹我所瞭解的apk反編譯的相關技術,和大家一起來做一個逆向工程.
提醒:未經授權而逆向別人的程序是違法行爲! 在此,我們只做學術研究,不搞破壞~
知識鋪墊:
1.反編譯的結果有兩種,一種是smali (java機器碼),還有一種是大家喜聞樂見的java代碼形式.
2.apk文件其實是一個zip壓縮包,裏面的目錄結構與android工程的結構很類似,其中我們的java源碼(包括R.java)在classes.dex文件中.
3.期間的工具大部分是java寫的,運行時需要具備java環境!
我先介紹大家喜聞樂見的形式吧,哈哈…
將apk反編譯爲源碼.
需要的工具:
1.dex2jar. dex2jar-0.0.7.10-SNAPSHOT.zip (590.31 KB, 下載次數: 44)
2.Jd-gui. jd-gui-0.3.3.osx.i686.zip (689.59 KB, 下載次數: 39)
3.AXMLPrinter2. AXMLPrinter2.zip (38.76 KB, 下載次數: 34)
逆向目標是前陣子懸賞區發過的一個demo,正好是我寫的,我授權給所有cmd100用戶,歡迎逆向,不追任何究法律責任..
源碼:http://www.cmd100.com/bbs/forum- ... 052-pid-173308.html
Apk文件: CMD100.demo.slipButton.rar (18.74 KB, 下載次數: 19)
方法:
既然是一個zip壓縮包,那就先把apk包解壓出來吧!
可以看到解壓出來的文件如下:
先處理xml 文件.. 你可能想直接打開xml文件,但其實xml文件被加密過了,打開只會是一堆你讀不懂的東西,這需要用工具解碼一下, 用到AXMLPrinter2.
打開CMD切換到AXMLPrinter2目錄.
命令: Java –jar axmlprinter2.jar [路徑]\AndroidManifest.xml >輸出文件名.xml
打開生成的這個文件,看看Manifest.xml是不是出來了?
反編譯結果:
-
<?xml version="1.0" encoding="utf-8"?>
-
<manifest
-
xmlns:android="http://schemas.android.com/apk/res/android"
-
android:versionCode="1"
-
android:versionName="1.0"
-
package="CMD100.demo.slipButton"
-
>
-
<application
-
android:label="@7F040001"
-
android:icon="@7F020000"
-
android:debuggable="true"
-
>
-
<activity
-
android:label="@7F040001"
-
android:name=".Main"
-
>
-
<intent-filter
-
>
-
<action
-
android:name="android.intent.action.MAIN"
-
>
-
</action>
-
<category
-
android:name="android.intent.category.LAUNCHER"
-
>
-
</category>
-
</intent-filter>
-
</activity>
-
</application>
-
<uses-sdk
-
android:minSdkVersion="4"
-
>
-
</uses-sdk>
- </manifest>
源文件:
-
<?xml version="1.0" encoding="utf-8"?>
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-
package="CMD100.demo.slipButton"
-
android:versionCode="1"
-
android:versionName="1.0">
-
<application android:icon="@drawable/icon" android:label="@string/app_name">
-
<activity android:name=".Main"
-
android:label="@string/app_name">
-
<intent-filter>
-
<action android:name="android.intent.action.MAIN" />
-
<category android:name="android.intent.category.LAUNCHER" />
-
</intent-filter>
-
</activity>
-
</application>
-
<uses-sdk android:minSdkVersion="4" />
- </manifest>
使用同樣的方法把res/layout/目錄下的佈局文件也解碼一下~在此我就不再贅述了.
接下來是dex文件的處理,需要用dex2jar工具處理轉換一下.
先把工具解壓出來,然後CMD切換到指定目錄,運行如下命令:
dex2jar.bat [目錄]\classes.dex
執行完畢後,classes.dex所在目錄下便生成了一個名爲classes.dex.dex2jar.jar的文件!
用jd-gui打開這個生成的jar試試!代碼就在裏面了有沒有?!
對比一下main.java吧.
反編譯:
-
public class Main extends Activity
-
implements OnChangedListener
-
{
-
public void OnChanged(boolean paramBoolean)
-
{
-
if (paramBoolean)
-
{
-
Toast.makeText(this, "打開了...", 0).show();
-
return;
-
}
-
Toast.makeText(this, "關閉了...", 0).show();
-
}
-
public void onCreate(Bundle paramBundle)
-
{
-
super.onCreate(paramBundle);
-
setContentView(2130903040);
-
((SlipButton)findViewById(2131034112)).SetOnChangedListener(this);
-
}
- }
源文件:
-
public class Main extends Activity implements OnChangedListener {
-
/** Called when the activity is first created. */
-
@Override
-
public void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.main);
-
-
SlipButton myBtn =(SlipButton) findViewById(R.id.slipBtn);//獲得指定控件
-
myBtn.SetOnChangedListener(this);//爲控件設置監聽器
-
}
-
@Override
-
public void OnChanged(boolean CheckState) {//當按鈕狀態被改變時
-
// TODO Auto-generated method stub
-
if(CheckState)
-
Toast.makeText(this,"打開了..." , Toast.LENGTH_SHORT).show();
-
else
-
Toast.makeText(this,"關閉了..." , Toast.LENGTH_SHORT).show();
-
}
- }
P.S.其實這樣獲得的源碼還是有一部分會出現錯誤啊~
=================分割線========================
將apk反編譯爲smali並插入自己的代碼
用到的工具:
1.apktool.jar (或smali-1.2.6.jar & baksmali-1.2.6.jar) Apktool.zip (2.01 MB, 下載次數: 27)
2.auto-sign. APK-sign.rar (1.66 MB, 下載次數: 33)
這些工具都是google的開源項目…
主要流程:
1.反編譯
2.插入代碼
3.重新打包
方法:
有了前面的鋪墊,我就不再囉嗦了.
命令:java -jar apktool.jar d 目標文件.apk
在apktool.jar所在目錄下就生成了這個apk反編譯後的文件夾,打開看看!
包括xml在內的文件都被解碼了!
不過我們關注的是smali文件夾,打開看看,裏面的目錄結構和源碼的目錄結構是一致的!
找到要修改的地方.在這個例子裏,就在Main.java(第一個載入的activity)的OnCreate方法裏插入一段代碼吧!
打開 Main.smali
-
.class public LCMD100/demo/slipButton/Main;
-
.super Landroid/app/Activity;
-
.source "Main.java"
-
# interfaces
-
.implements LCMD100/demo/slipButton/OnChangedListener;
-
-
# direct methods
-
.method public constructor <init>()V
-
.locals 0
-
.prologue
-
.line 14
-
invoke-direct {p0}, Landroid/app/Activity;-><init>()V
-
return-void
-
.end method
-
-
# virtual methods
-
.method public OnChanged(Z)V
-
.locals 2
-
.parameter "CheckState"
-
.prologue
-
const/4 v1, 0x0
-
.line 28
-
if-eqz p1, :cond_0
-
.line 29
-
const-string v0, "\u6253\u5f00\u4e86..."
-
invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
-
move-result-object v0
-
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
-
.line 32
-
:goto_0
-
return-void
-
.line 31
-
:cond_0
-
const-string v0, "\u5173\u95ed\u4e86..."
-
invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
-
move-result-object v0
-
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
-
goto :goto_0
-
.end method
-
.method public onCreate(Landroid/os/Bundle;)V
-
.locals 2
-
.parameter "savedInstanceState"
-
.prologue
-
.line 18
-
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
-
.line 19
-
const/high16 v1, 0x7f03
-
invoke-virtual {p0, v1}, LCMD100/demo/slipButton/Main;->setContentView(I)V
-
.line 21
-
const/high16 v1, 0x7f05
-
invoke-virtual {p0, v1}, LCMD100/demo/slipButton/Main;->findViewById(I)Landroid/view/View;
-
move-result-object v0
-
check-cast v0, LCMD100/demo/slipButton/SlipButton;
-
.line 22
-
.local v0, myBtn:LCMD100/demo/slipButton/SlipButton;
-
invoke-virtual {v0, p0}, LCMD100/demo/slipButton/SlipButton;->SetOnChangedListener(LCMD100/demo/slipButton/OnChangedListener;)V
-
.line 23
-
return-void
- .end method
你發現裏頭的代碼是見都沒見過的格式,這就是java的彙編代碼了…
學過80x86彙編的同學看着這些代碼是不是也覺得陌生?
沒事,我們可以對照前面介紹的那種方法查看源碼,然後尋找修改的位置!
找到這一行:
.method public onCreate(Landroid/os/Bundle;)V
這就是OnCreate方法的代碼起始了,在
.line 23
return-void
之前插入如下代碼: (效果是Toast彈出一句話.)
-
const-string v0, "Hey,dude.This program has been fucked!"
-
const/4 v1, 0x0
-
-
invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
-
-
move-result-object v0
- invoke-virtual {v0}, Landroid/widget/Toast;->show()V
爲什麼是這個,其實我也不懂smali,但是可以把自己要的功能寫出來,再反彙編…然後copy到這來…
好吧,我們來分析一下這段代碼,前面是類似申明瞭兩個變量,v0,v1,然後調用了Toast的makeText方法(列出了參數),再然後調用了其show方法…
看吧,其實我們是能大概看懂smali的內容,只是不懂語法而已!
好吧,廢話不多說.
現在改好了,用apktool重新打包~
命令: java -jar apktool.jar b 目標文件夾
執行完後,就在這個目錄裏生成了兩個目錄,分別是build,dist
Build下是中間文件,dist下則是apk文件(但是這個apk文件未簽名)
下面就是重新簽名了.
先解壓auto-sign
我們進入Build文件夾,複製apk文件夾到auto-sign文件夾下,然後執行命令:
sign_pack.bat apk
稍等片刻,你會發現文件夾下生成了對應的目錄,進入這個目錄,apk靜靜地躺在那…
趕緊,裝到手機上看看,是不是改成了?
成功彈出,哈哈...
至此,apk的反編譯和代碼插入就結束了.
藉此方法,我們可以輕鬆的對apk進行DIY...
歡迎轉載,但,轉載請註明出處!