smali修改Textview+smali常用语法
来源:互联网 发布:淘宝充值米币靠谱吗 编辑:程序博客网 时间:2024/05/29 02:41
Smali语言其实就是Davlik的寄存器语言;Smali语言就是android的应用程序.apk通过apktool反编译出来的都有一个smali文件夹,里面都是以.smali结尾的文件的展示语言,我们可以通过分析修改Smali程序达到修改源程序的目的。
下面给出修改一个android工程其中Textview的教程。
如图,下面是android工程listedittest的目录:
通过apktool反编译出来的Smali文件夹里面的目录
先打开一个主类MainActivity.smali文件,先来浏览一下里面的语言,再来说说smali的语法规则:
.class public Lcom/myandroid/listedittest/MainActivity;.super Landroid/app/Activity;.source "MainActivity.java"# static fields.field static str:[Ljava/lang/String;# instance fields.field private bt_cancel:Landroid/widget/Button;.field private bt_confirmdelete:Landroid/widget/Button;.field private bt_deselectall:Landroid/widget/Button;.field private bt_selectall:Landroid/widget/Button;.field private checkNum:I.field private list:Ljava/util/ArrayList; .annotation system Ldalvik/annotation/Signature; value = { "Ljava/util/ArrayList", "<", "Ljava/util/HashMap", "<", "Ljava/lang/String;", "Ljava/lang/String;", ">;>;" } .end annotation.end field.field private lv:Landroid/widget/ListView;.field private mAdapter:Lcom/myandroid/listedittest/MyAdapter;.field private tv_show:Landroid/widget/TextView;# direct methods.method static constructor <clinit>()V .locals 3 .prologue .line 30 const/16 v0, 0xd new-array v0, v0, [Ljava/lang/String; const/4 v1, 0x0 const-string v2, "data1" aput-object v2, v0, v1 const/4 v1, 0x1 const-string v2, "data2" aput-object v2, v0, v1 const/4 v1, 0x2 const-string v2, "data3" aput-object v2, v0, v1 const/4 v1, 0x3 const-string v2, "data4" aput-object v2, v0, v1 const/4 v1, 0x4 const-string v2, "data5" aput-object v2, v0, v1 const/4 v1, 0x5 const-string v2, "data6" aput-object v2, v0, v1 const/4 v1, 0x6 const-string v2, "7" aput-object v2, v0, v1 const/4 v1, 0x7 const-string v2, "data8" aput-object v2, v0, v1 const/16 v1, 0x8 const-string v2, "data9" aput-object v2, v0, v1 const/16 v1, 0x9 const-string v2, "data10" aput-object v2, v0, v1 const/16 v1, 0xa const-string v2, "data11" aput-object v2, v0, v1 const/16 v1, 0xb const-string v2, "data12" aput-object v2, v0, v1 const/16 v1, 0xc const-string v2, "data13" aput-object v2, v0, v1 sput-object v0, Lcom/myandroid/listedittest/MainActivity;->str:[Ljava/lang/String; return-void.end method.method public constructor <init>()V .locals 0 .prologue .line 20 invoke-direct {p0}, Landroid/app/Activity;-><init>()V return-void.end method.method static synthetic access$000(Lcom/myandroid/listedittest/MainActivity;)Ljava/util/ArrayList; .locals 1 .parameter "x0" .prologue .line 20 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->list:Ljava/util/ArrayList; return-object v0.end method.method static synthetic access$100(Lcom/myandroid/listedittest/MainActivity;)I .locals 1 .parameter "x0" .prologue .line 20 iget v0, p0, Lcom/myandroid/listedittest/MainActivity;->checkNum:I return v0.end method.method static synthetic access$102(Lcom/myandroid/listedittest/MainActivity;I)I .locals 0 .parameter "x0" .parameter "x1" .prologue .line 20 iput p1, p0, Lcom/myandroid/listedittest/MainActivity;->checkNum:I return p1.end method.method static synthetic access$108(Lcom/myandroid/listedittest/MainActivity;)I .locals 2 .parameter "x0" .prologue .line 20 iget v0, p0, Lcom/myandroid/listedittest/MainActivity;->checkNum:I add-int/lit8 v1, v0, 0x1 iput v1, p0, Lcom/myandroid/listedittest/MainActivity;->checkNum:I return v0.end method.method static synthetic access$110(Lcom/myandroid/listedittest/MainActivity;)I .locals 2 .parameter "x0" .prologue .line 20 iget v0, p0, Lcom/myandroid/listedittest/MainActivity;->checkNum:I add-int/lit8 v1, v0, -0x1 iput v1, p0, Lcom/myandroid/listedittest/MainActivity;->checkNum:I return v0.end method.method static synthetic access$200(Lcom/myandroid/listedittest/MainActivity;)V .locals 0 .parameter "x0" .prologue .line 20 invoke-direct {p0}, Lcom/myandroid/listedittest/MainActivity;->dataChanged()V return-void.end method.method static synthetic access$300(Lcom/myandroid/listedittest/MainActivity;)Landroid/widget/TextView; .locals 1 .parameter "x0" .prologue .line 20 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->tv_show:Landroid/widget/TextView; return-object v0.end method.method private dataChanged()V .locals 3 .prologue .line 157 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->mAdapter:Lcom/myandroid/listedittest/MyAdapter; invoke-virtual {v0}, Lcom/myandroid/listedittest/MyAdapter;->notifyDataSetChanged()V .line 159 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->tv_show:Landroid/widget/TextView; new-instance v1, Ljava/lang/StringBuilder; invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V const-string v2, "\ufffd\ufffd\u0461\ufffd\ufffd" invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v1 iget v2, p0, Lcom/myandroid/listedittest/MainActivity;->checkNum:I invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; move-result-object v1 const-string v2, "\ufffd\ufffd" invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v1 invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v1 invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V .line 160 return-void.end method.method private initDate()V .locals 4 .prologue .line 146 const/4 v0, 0x0 .local v0, i:I :goto_0 sget-object v2, Lcom/myandroid/listedittest/MainActivity;->str:[Ljava/lang/String; array-length v2, v2 if-ge v0, v2, :cond_0 .line 147 new-instance v1, Ljava/util/HashMap; invoke-direct {v1}, Ljava/util/HashMap;-><init>()V .line 148 .local v1, map:Ljava/util/HashMap;,"Ljava/util/HashMap<Ljava/lang/String;Ljava/lang/String;>;" const-string v2, "content" sget-object v3, Lcom/myandroid/listedittest/MainActivity;->str:[Ljava/lang/String; aget-object v3, v3, v0 invoke-virtual {v1, v2, v3}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; .line 149 const-string v2, "flag" const-string v3, "false" invoke-virtual {v1, v2, v3}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; .line 150 iget-object v2, p0, Lcom/myandroid/listedittest/MainActivity;->list:Ljava/util/ArrayList; invoke-virtual {v2, v1}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z .line 146 add-int/lit8 v0, v0, 0x1 goto :goto_0 .line 152 .end local v1 #map:Ljava/util/HashMap;,"Ljava/util/HashMap<Ljava/lang/String;Ljava/lang/String;>;" :cond_0 return-void.end method# virtual methods.method public onCreate(Landroid/os/Bundle;)V .locals 2 .parameter "savedInstanceState" .prologue .line 36 invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V .line 37 const v0, 0x7f030001 invoke-virtual {p0, v0}, Lcom/myandroid/listedittest/MainActivity;->setContentView(I)V .line 39 const v0, 0x7f080007 invoke-virtual {p0, v0}, Lcom/myandroid/listedittest/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/ListView; iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->lv:Landroid/widget/ListView; .line 40 const v0, 0x7f080003 invoke-virtual {p0, v0}, Lcom/myandroid/listedittest/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->bt_selectall:Landroid/widget/Button; .line 41 const v0, 0x7f080005 invoke-virtual {p0, v0}, Lcom/myandroid/listedittest/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->bt_cancel:Landroid/widget/Button; .line 42 const v0, 0x7f080004 invoke-virtual {p0, v0}, Lcom/myandroid/listedittest/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->bt_deselectall:Landroid/widget/Button; .line 43 const v0, 0x7f080008 invoke-virtual {p0, v0}, Lcom/myandroid/listedittest/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->bt_confirmdelete:Landroid/widget/Button; .line 44 const v0, 0x7f080006 invoke-virtual {p0, v0}, Lcom/myandroid/listedittest/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/TextView; iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->tv_show:Landroid/widget/TextView; .line 45 new-instance v0, Ljava/util/ArrayList; invoke-direct {v0}, Ljava/util/ArrayList;-><init>()V iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->list:Ljava/util/ArrayList; .line 47 invoke-direct {p0}, Lcom/myandroid/listedittest/MainActivity;->initDate()V .line 49 new-instance v0, Lcom/myandroid/listedittest/MyAdapter; iget-object v1, p0, Lcom/myandroid/listedittest/MainActivity;->list:Ljava/util/ArrayList; invoke-direct {v0, v1, p0}, Lcom/myandroid/listedittest/MyAdapter;-><init>(Ljava/util/ArrayList;Landroid/content/Context;)V iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->mAdapter:Lcom/myandroid/listedittest/MyAdapter; .line 51 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->lv:Landroid/widget/ListView; iget-object v1, p0, Lcom/myandroid/listedittest/MainActivity;->mAdapter:Lcom/myandroid/listedittest/MyAdapter; invoke-virtual {v0, v1}, Landroid/widget/ListView;->setAdapter(Landroid/widget/ListAdapter;)V .line 53 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->bt_selectall:Landroid/widget/Button; new-instance v1, Lcom/myandroid/listedittest/MainActivity$1; invoke-direct {v1, p0}, Lcom/myandroid/listedittest/MainActivity$1;-><init>(Lcom/myandroid/listedittest/MainActivity;)V invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V .line 67 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->bt_cancel:Landroid/widget/Button; new-instance v1, Lcom/myandroid/listedittest/MainActivity$2; invoke-direct {v1, p0}, Lcom/myandroid/listedittest/MainActivity$2;-><init>(Lcom/myandroid/listedittest/MainActivity;)V invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V .line 82 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->bt_deselectall:Landroid/widget/Button; new-instance v1, Lcom/myandroid/listedittest/MainActivity$3; invoke-direct {v1, p0}, Lcom/myandroid/listedittest/MainActivity$3;-><init>(Lcom/myandroid/listedittest/MainActivity;)V invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V .line 101 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->bt_confirmdelete:Landroid/widget/Button; new-instance v1, Lcom/myandroid/listedittest/MainActivity$4; invoke-direct {v1, p0}, Lcom/myandroid/listedittest/MainActivity$4;-><init>(Lcom/myandroid/listedittest/MainActivity;)V invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V .line 119 iget-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->lv:Landroid/widget/ListView; new-instance v1, Lcom/myandroid/listedittest/MainActivity$5; invoke-direct {v1, p0}, Lcom/myandroid/listedittest/MainActivity$5;-><init>(Lcom/myandroid/listedittest/MainActivity;)V invoke-virtual {v0, v1}, Landroid/widget/ListView;->setOnItemClickListener(Landroid/widget/AdapterView$OnItemClickListener;)V .line 142 return-void.end method
上面的smali语言对应的java类就是Mainactivity.java类如下:
package com.myandroid.listedittest;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import com.myandroid.listedittest.MyAdapter.ViewHolder;public class MainActivity extends Activity { private ListView lv; private MyAdapter mAdapter; private ArrayList<HashMap<String, String>> list; private Button bt_selectall; private Button bt_cancel; private Button bt_deselectall; private Button bt_confirmdelete; private int checkNum; // 记录选中的条目数量 private TextView tv_show;// 用于显示选中的条目数量 static String str[] = { "data1", "data2", "data3", "data4", "data5", "data6", "7", "data8", "data9", "data10", "data11", "data12", "data13" }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); /* 实例化各个控件 */ lv = (ListView) findViewById(R.id.lv); bt_selectall = (Button) findViewById(R.id.bt_selectall); bt_cancel = (Button) findViewById(R.id.bt_cancelselectall); bt_deselectall = (Button) findViewById(R.id.bt_deselectall); bt_confirmdelete = (Button) findViewById(R.id.bt_confirmdelete); tv_show = (TextView) findViewById(R.id.tv); list = new ArrayList<HashMap<String, String>>(); // 为Adapter准备数据 initDate(); // 实例化自定义的MyAdapter mAdapter = new MyAdapter(list, this); // 绑定Adapter lv.setAdapter(mAdapter); // 全选按钮的回调接口 bt_selectall.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 遍历list的长度,将MyAdapter中的map值全部设为true for (int i = 0; i < list.size(); i++) { list.get(i).put("flag", "true"); } // 数量设为list的长度 checkNum = list.size(); // 刷新listview和TextView的显示 dataChanged(); } }); // 取消按钮的回调接口 bt_cancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 遍历list的长度,将已选的按钮设为未选 for (int i = 0; i < list.size(); i++) { if (list.get(i).get("flag").equals("true")) { list.get(i).put("flag", "false"); checkNum--;// 数量减1 } } // 刷新listview和TextView的显示 dataChanged(); } }); // 反选按钮的回调接口 bt_deselectall.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 遍历list的长度,将已选的设为未选,未选的设为已选 for (int i = 0; i < list.size(); i++) { if (list.get(i).get("flag").equals("true")) { list.get(i).put("flag", "false"); checkNum--; } else { list.get(i).put("flag", "true"); checkNum++; } } // 刷新listview和TextView的显示 dataChanged(); } }); // 确认删除的回调接口 bt_confirmdelete.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Iterator<HashMap<String, String>> iterator = list.iterator(); while (iterator.hasNext()) { HashMap<String, String> temp = iterator.next(); if (temp.get("flag").equals("true")) { iterator.remove(); } } checkNum = 0; // 通知列表数据修改 dataChanged(); } }); // 绑定listView的监听器 lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Toast.makeText(MainActivity.this, "当前位置:" + arg2, Toast.LENGTH_SHORT); // 取得ViewHolder对象,这样就省去了通过层层的findViewById去实例化我们需要的cb实例的步骤 ViewHolder holder = (ViewHolder) arg1.getTag(); // 改变CheckBox的状态 holder.cb.toggle(); // 将CheckBox的选中状况记录下来 // 调整选定条目 if (holder.cb.isChecked() == true) { list.get(arg2).put("flag", "true"); checkNum++; } else { list.get(arg2).put("flag", "false"); checkNum--; } // 用TextView显示 tv_show.setText("已选中" + checkNum + "项"); } }); } // 初始化数据 private void initDate() { for (int i = 0; i < str.length; i++) { HashMap<String, String> map = new HashMap<String, String>(); map.put("content", str[i]); map.put("flag", "false"); list.add(map); } } // 刷新listview和TextView的显示 private void dataChanged() { // 通知listView刷新 mAdapter.notifyDataSetChanged(); // TextView显示最新的选中数目 tv_show.setText("已选中" + checkNum + "项"); }}
通过对比发现基本的方法名称没有改变,多了一个.method public constructor <init>()V表示该类的不带参数缺省的构造方法,onCreate()方法是以.method public onCreate(Landroid/os/Bundle;)V开始,.end method结束;方法的表示形式就是这个样子的。
下面介绍一下Smali代码注入,原理:在已有APK或JAR包中插入一些Dalvik虚拟机的指令,从而改变原有程序的路径和行为。
如果想修改以下Textview的值,我们可以在smali文件里搜索“tv_show"。
对应
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
对应
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
对应
由以上分析可得
第44行执行初始化工作,并且在smali文件的第407行把参数p0的内容打入到寄存器v0。于是我们可以通过修改p0来修改textview的值。
iput-object v0, p0, Lcom/myandroid/listedittest/MainActivity;->tv_show:Landroid/widget/TextView;
修改为
iput-object v0, "我是修改后的内容", Lcom/myandroid/listedittest/MainActivity;->tv_show:Landroid/widget/TextView;
再通过apktool b 需要打包回去的文件
打包回去就在反编译后的Mainactivity文件里生成一个dist文件夹,里面就有打包的Mainactivity.apk。如图
注意:要直接安装到手机或模拟器是不行的,需要签名,可以通过APKSign_gr这个签名软件来签名,也可以通过其他方式签名,在签名的时候如果一开始在eclipse里运行生成的apk是使用了ADB的debug权限签名,如果使用APKSign_gr这个签名,需要在手机或模拟器中把原来的apk卸载掉,在安装新的apk,就ok了,这个是解决安装apk时“INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES”这个错误的。
Smali语法简单介绍如下:
Davlik字节码中,寄存器都是32位的,能够支持任何类型,64位类型(Long/Double)用2个寄存器表示;
Dalvik字节码有两种类型:原始类型;引用类型(包括对象和数组)
原始类型:v void 只能用于返回值类型
Z boolean
B byte
S short
C char
I int
J long(64位)
F float
D double(64位)
对象类型:Lpackage/name/ObjectName; 相当于java中的package.name.ObjectName;解释如下:
L:表示这是一个对象类型
package/name:该对象所在的包
;:表示对象名称的结束
数组的表示形式:
[I :表示一个整形的一维数组,相当于java的int[];
对于多维数组,只要增加[ 就行了,[[I = int[][];注:每一维最多255个;
对象数组的表示形式:
[Ljava/lang/String 表示一个String的对象数组;
方法的表示形式:
Lpackage/name/ObjectName;——>methodName(III)Z 详解如下:
Lpackage/name/ObjectName 表示类型
methodName 表示方法名
III 表示参数(这里表示为3个整型参数)
说明:方法的参数是一个接一个的,中间没有隔开;
字段的表示形式:
Lpackage/name/ObjectName;——>FieldName:Ljava/lang/String;
即表示: 包名,字段名和各字段类型
有两种方式指定一个方法中有多少寄存器是可用的:
.registers 指令指定了方法中寄存器的总数
.locals 指令表明了方法中非参寄存器的总数,出现在方法中的第一行
方法的传参:
当一个方法被调用的时候,方法的参数被置于最后N个寄存器中;
例如,一个方法有2个参数,5个寄存器(v0~v4)
那么,参数将置于最后2个寄存器(v3和v4)
非静态方法中的第一个参数总是调用该方法的对象;
说明:对于静态方法除了没有隐含的this参数外,其他都一样
寄存器的命名方式:
V命名
P命名 第一个寄存器就是方法中的第一个参数寄存器
比较:使用P命名是为了防止以后如果在方法中增加寄存器,需要对参数寄存器重新进行编号的缺点
特别说明一下:Long和Double类型是64位的,需要2个寄存器
例如:对于非静态方法
LMyObject——>myMethod(IJZ)V;
有4个参数:LMyObject,int,long,bool; 需要5个寄存器来存储参数;
P0 this
P1 I (int)
P2,P3 J (long)
P4 Z(bool)
- smali修改Textview+smali常用语法
- Smali常用语法
- SMALI语法
- smali语法
- smali语法
- smali语法
- smali语法
- Smali语法
- Smali语法
- smali语法
- smali语法
- smali语法
- smali语法
- Smali语法
- smali语法
- smali语法
- smali语法
- SMALI
- NSTimer
- 昨天晚上被 Android 手机上的广告程序折磨了。
- Webdriver实现原理
- Cocos2d-x 屏幕适配解决方案
- NodeJS优缺点及适用场景讨论
- smali修改Textview+smali常用语法
- 安卓文件读取
- 深入同步语法
- Linux 自旋锁
- 每日一思
- 减少GC回收
- bitmap两篇文章
- Java IO流学习总结
- Hadoop 2.0 – HA功能中ZKFC对NN状态的控制