【
本文分三篇。本篇提供一个最小的修改案例。更详细的修改请参考篇三:
http://blog.csdn.net/aimingoo/article/details/7939132
】
(前三节有关背景介绍请至:http://blog.csdn.net/aimingoo/article/details/7939093)
4、修改前的准备工作
=======
这里介绍一些Android上的逆向工程的基础。首先,我们要操作Phone.apk,它其实也就是一个.zip文件,其中包括四个主要信息:
- 资源文件:res\*.*和resources.arsc
- 代码文件:classes.dex
- 应用描述:AndroidManifest.xml
- 签名信息:META-INF\*.*
apktool这个工具可以处理前三种数据,而签名信息则必须使用一个signapk.jar(有些工具包称为AutoSign)。
1)解包(缺省至Phone目录)
apktool d -f Phone.apk
注意我们接下来的修改都不会动到资源,所以事实上也可以不解开其中的资源文件。可以这样使用命令行:
apktool d -f -r Phone.apk
这样在编译回去的时候会快一点,而且也可以避免一些错误。——但很多时候的修改需要对照着资源文件来看,所以你也可以解一份有资源文件的版本放在旁边作参照。
2) 编译回.apk(指定从Phone目录)
apktool b -f Phone Phone2.apk
3) 对Phone2.apk加签名
java -jar signapk.jar platform.x509.pem platform.pk8 Phone2.apk Phone2_signed.apk
注意这时使用的签名文件为platform.x509.pem和platform.pk8,而不是我们平常用的testkey*.*。这是很关键的一处:Phone.apk必须使用platform.*来签名。
5、修改:初步
=======
我们将Phone.apk解到Phone目录之后。可以找到如下子目录:
Phone\smali\com\android\phone\
我们接下来主要修改两个文件:
CallCard.smali
InCallScreen.smali
注意这里的*.smali是另一种格式的源代码,它反编译自Dalvik虚拟机中执行码(opcode)。基本上,你可以认为这*.smali就是汇编代码(基于寄存器的虚拟机引擎)。好吧,但我们既然要“原生的”,那么就只好来改改这些汇编代码了。:(
1)对InCallScreen.smali只需要做一处修改
---------
找到:
.field private mMainFrame:Landroid/view/ViewGroup;
.field public mMainFrame:Landroid/view/ViewGroup;
.method private updateDisplayForPerson(Lcom/android/internal/telephony/CallerInfo; ...
invoke-static {v0, v1}, Lcom/android/phone/CallCard;->showCachedImage(Landroid/widget/ImageView;Lcom/android/internal/telephony/CallerInfo;)Z move-result v4 if-nez v4, :cond_2
if-nez v4, :cond_2
## ===》》》 if-eqz v4, :cond_20 move-object/from16 v0, p0 move-object/from16 v5, p4 invoke-virtual {v0, v1, v5}, Lcom/android/phone/CallCard;->showCachedBackground(Lcom/android/internal/telephony/CallerInfo;Lcom/android/internal/telephony/Call;)Z move-result v4 goto :cond_2 :cond_20 ## end fix.
goto :cond_2
invoke-static {v9, v3}, Lcom/android/phone/CallCard;->showCachedImage(Landroid/widget/ImageView;Lcom/android/internal/telephony/CallerInfo;)Z move-result v9 if-nez v9, :cond_2 ## 《《《《===修改此处
## ===》》》 if-eqz v9, :cond_20 move-object/from16 v5, p1 invoke-virtual {p0, v3, v5}, Lcom/android/phone/CallCard;->showCachedBackground(Lcom/android/internal/telephony/CallerInfo;Lcom/android/internal/telephony/Call;)Z move-result v9 goto :cond_2 :cond_20 ## end fix.
## ## 【主函数:更新全屏大头贴】 ## .method public showCachedBackground(Lcom/android/internal/telephony/CallerInfo;Lcom/android/internal/telephony/Call;)Z .locals 6 .parameter "ci" .parameter "call" .prologue invoke-virtual {p2}, Lcom/android/internal/telephony/Call;->getState()Lcom/android/internal/telephony/Call$State; move-result-object v0 invoke-virtual {v0}, Lcom/android/internal/telephony/Call$State;->isAlive()Z move-result v0 if-nez v0, :cond_0 :goto_0 return v0 :cond_0 if-nez p1, :cond_1 :goto_1 const/4 v0, 0x0 goto :goto_0 :cond_1 iget-boolean v2, p1, Lcom/android/internal/telephony/CallerInfo;->isCachedPhotoCurrent:Z if-eqz v2, :goto_1 iget-object v2, p1, Lcom/android/internal/telephony/CallerInfo;->cachedPhoto:Landroid/graphics/drawable/Drawable; if-eqz v2, :goto_1 iget-object v3, p0, Lcom/android/phone/CallCard;->mInCallScreen:Lcom/android/phone/InCallScreen; const/16 v4, 0xF0 invoke-virtual {v2}, Landroid/graphics/drawable/Drawable;->getIntrinsicWidth()I move-result v5 if-lt v5, v4, :goto_1 const/16 v4, 0xF0 invoke-virtual {v2}, Landroid/graphics/drawable/Drawable;->getIntrinsicHeight()I move-result v5 if-lt v5, v4, :goto_1 iget-object v3, v3, Lcom/android/phone/InCallScreen;->mMainFrame:Landroid/view/ViewGroup; if-eqz v3, :goto_1 invoke-virtual {v3, v2}, Landroid/view/ViewGroup;->setBackgroundDrawable(Landroid/graphics/drawable/Drawable;)V const/16 v2, 0x8 iget-object v3, p0, Lcom/android/phone/CallCard;->mPhoto:Landroid/widget/ImageView; invoke-virtual {v3, v2}, Landroid/widget/ImageView;->setVisibility(I)V ## const/16 v2, 0x0 ## invoke-virtual {p0, v2}, Lcom/android/phone/CallCard;->setPersonInfoStyle(Z)V goto :goto_0 .end method
CallCard.InCallScreen.mMainFrame成员。而该成员在InCallScreen类中被声明为private,所以需要在第1步中把InCallScreen中的该声明改成public。
public boolean showCachedBackground(CallerInfo paramCallerInfo, Call paramCall) { // 电话是在用状态(来电或呼出或接通) boolean bool = paramCall.getState().isAlive(); // paramCallerInfo.isCachedPhotoCurrent有效 bool = bool && (paramCallerInfo != null) && paramCallerInfo.isCachedPhotoCurrent; if (bool) { Drawable localDrawable = paramCallerInfo.cachedPhoto; if ((localDrawable.getIntrinsicWidth() < 240) || (localDrawable.getIntrinsicHeight() < 240)) { bool = false } else { // 置mMainFrame的背景 this.mInCallScreen.mMainFrame.setBackgroundDrawable(localDrawable); // 使mPhoto不显示(原来的头像就不必显示了嘛) this.mPhoto.setVisibility(8); // 修改作个人信息的显示风格(备用,后文解释) // setPersonInfoStyle(false); } } return bool; }