目录
1.准备工作
1.1下载好smali的jar这里使用smali-2.4.0.jar (PS: 执行命令为 java -jar assemble xxx.smali -o xxx.dex)
1.2 root的真机或者模拟器
1.3 安装好JaDex方便自己看看大概写出来的东西是个什么样子,用其它工具也行,不过这个很方便。
2.编写smali文件
.class public Lcom/test/smali/Programmer;
.super Ljava/lang/Object;
.source "Programmer.java"
#变量
.field private name:Ljava/lang/String;#名称
.field private age:I#年龄
.field private sex:I#性别 1男 0女
.field private partnerName:Ljava/lang/String;
#构造函数 PS:如果只有一个无参构造函数不用自己写g构造函数,否则new的时候会死循环
.method public constructor <init>(Ljava/lang/String;)V
.locals 1
invoke-direct {p0}, Lcom/test/smali/Programmer;-><init>()V
.param p1,"name"
if-eqz p1,:cound_0
iput-object p1,p0,Lcom/test/smali/Programmer;->name:Ljava/lang/String;
:cound_0
return-void
.end method
#get\set函数
#getName函数
.method public getName()Ljava/lang/String;
.locals 1
.prologue
iget-object v0,p0,Lcom/test/smali/Programmer;->name:Ljava/lang/String;
return-object v0
.end method
#setName函数
.method public setName(Ljava/lang/String;)V
.locals 1
.prologue
.local p1, "name":Ljava/lang/String;
if-eqz p1,:cound_0
#move-object name,p1 #这么写是错的,操作field要用iput
iput-object p1,p0,Lcom/test/smali/Programmer;->name:Ljava/lang/String;
:cound_0
return-void
.end method
#getAge函数
.method public getAge()I
.locals 1
.prologue
iget v0,p0,Lcom/test/smali/Programmer;->age:I
return v0
.end method
#setAge函数
.method public setAge(I)V
.locals 1
.prologue
.local p1, "age":I
if-lez p1,:cound_0
iput p1,p0,Lcom/test/smali/Programmer;->age:I
:cound_0
return-void
.end method
#getSex函数
.method public getSex()I
.locals 1
.prologue
iget v0,p0,Lcom/test/smali/Programmer;->sex:I
return v0
.end method
#setSex函数
.method public setSex(I)V
.locals 1
.local p1,"sex":I
iput p1,p0,Lcom/test/smali/Programmer;->sex:I
return-void
.end method
#getPartnerName函数
.method public getPartnerName()Ljava/lang/String;
.locals 1
.prologue
iget-object v0,p0,Lcom/test/smali/Programmer;->partnerName:Ljava/lang/String;
return-object v0
.end method
#setPartnerName函数
.method public setPartnerName(Ljava/lang/String;)V
.locals 1
.local p1,"name":Ljava/lang/String;
if-eqz p1,:cound_0
iput-object p1,p0,Lcom/test/smali/Programmer;->partnerName:Ljava/lang/String;
:cound_0
return-void
.end method
#toString函数
.method public toString()Ljava/lang/String;
.locals 14
.prologue
#创建一个StringBuilder用来拼接字符串
new-instance v0,Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
#给v0寄存器所持有的StringBuilder的实例一个为"sb"名称
.local v0,"sb":Ljava/lang/StringBuilder;
iget-object v1,p0,Lcom/test/smali/Programmer;->name:Ljava/lang/String;
.local v1,"name":Ljava/lang/String;
iget v2,p0,Lcom/test/smali/Programmer;->age:I
.local v2,"age":I
iget v3,p0,Lcom/test/smali/Programmer;->sex:I
.local v3,"sex":I
iget-object v4,p0,Lcom/test/smali/Programmer;->partnerName:Ljava/lang/String;
.local v4,"partnerName":Ljava/lang/String;
const-string v5,"这是一个默默无闻的程序员"
const-string v6,"年龄:"
const-string v7,"对象是"
const-string v8,"是条单身狗!"
const-string v9,"性别"
const-string v10,"男"
const-string v11,"女"
#对属性的值进行判断
if-eqz v1,:cound_0
#if(name!=null)
invoke-virtual {v0,v1},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
:cound_0
if-nez v1,:cound_1
#if(name==null)
invoke-virtual{v0,v5},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
:cound_1
invoke-virtual{v0,v6},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual{v0,v2},Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
invoke-virtual{v0,v9},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
if-eqz v3,:cound_2
#if(sex!=0)
invoke-virtual{v0,v10},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
:cound_2
if-nez v3,:cound_3
#if(sex == 0)
invoke-virtual{v0,v11},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
:cound_3
if-eqz v4,:cound_4
invoke-virtual{v0,v7},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual{v0,v4},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
:cound_4
if-nez v4,:cound_5
invoke-virtual{v0,v8},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
:cound_5
invoke-virtual {v0},Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v12
sget-object v13,Ljava/lang/System;->out:Ljava/io/PrintStream;
invoke-virtual {v13,v12},Ljava/io/PrintStream;->println(Ljava/lang/String;)V
.end local v0
#调用父类的toString方法
invoke-super {p0}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v0
return-object v0
.end method
#main函数
.method public static main([Ljava/lang/String;)V
.locals 6
.local p0,"strs":[Ljava/lang/String;
.prologue
const-string v0,"张三"
.local v0,"name":Ljava/lang/String;
const/16 v1,0x12
.local v1,"age":I
const/16 v2,0x1
.local v2,"sex":I
const-string v3,"李四"
.local v3,"partnerName":Ljava/lang/String;
new-instance v4,Lcom/test/smali/Programmer;
invoke-direct {v4},Lcom/test/smali/Programmer;-><init>()V
invoke-virtual {v4,v0},Lcom/test/smali/Programmer;->setName(Ljava/lang/String;)V
invoke-virtual {v4,v1},Lcom/test/smali/Programmer;->setAge(I)V
invoke-virtual {v4,v2},Lcom/test/smali/Programmer;->setSex(I)V
#注释之后打印出该程序猿/媛是个单生狗
#invoke-virtual {v4,v3},Lcom/test/smali/Programmer;->setPartnerName(Ljava/lang/String;)V
invoke-virtual {v4},Lcom/test/smali/Programmer;->toString()Ljava/lang/String;
return-void
.end method
3.编译smali文件
自己写的一个smali.bat,为了少打几个字!
开始编译
4.检查并运行
JaDex查看:
package com.test.smali;
public class Programmer {
private int age;
private String name;
private String partnerName;
private int sex;
public Programmer(String name) {
if (name != null) {
this.name = name;
}
}
public static void main(String[] strArr) {
String partnerName = "李四";
Programmer programmer = new Programmer();
programmer.setName("张三");
programmer.setAge(18);
programmer.setSex(1);
programmer.toString();
}
public int getAge() {
return this.age;
}
public String getName() {
return this.name;
}
public String getPartnerName() {
return this.partnerName;
}
public int getSex() {
return this.sex;
}
public void setAge(int age) {
if (age > 0) {
this.age = age;
}
}
public void setName(String name) {
if (name != null) {
this.name = name;
}
}
public void setPartnerName(String name) {
if (name != null) {
this.partnerName = name;
}
}
public void setSex(int sex) {
this.sex = sex;
}
public String toString() {
StringBuilder sb = new StringBuilder();
String name = this.name;
int age = this.age;
int sex = this.sex;
String partnerName = this.partnerName;
String str = "这是一个默默无闻的程序员";
String str2 = "年龄:";
String str3 = "对象是";
String str4 = "是条单身狗!";
String str5 = "性别";
String str6 = "男";
String str7 = "女";
if (name != null) {
sb.append(name);
}
if (name == null) {
sb.append(str);
}
sb.append(str2);
sb.append(age);
sb.append(str5);
if (sex != 0) {
sb.append(str6);
}
if (sex == 0) {
sb.append(str7);
}
if (partnerName != null) {
sb.append(str3);
sb.append(partnerName);
}
if (partnerName == null) {
sb.append(str4);
}
System.out.println(sb.toString());
return super.toString();
}
}
模拟器运行:
5.遇到问题
1.定义全局变量出现错误
错误写法:.field private name:Ljava/lang/String; = "",根据错误提示的字面意思理解,应该是"只有静态的域才能够指定初始值。"
正确写法:.field private name:Ljava/lang/String;
编译后Jadex查看如下:
2.创建setName方法时move指令与iput混淆
错误写法:move-object p1,p0,Lcom/test/smali/Programmer;->name:Ljava/lang/String;
正确写法:iput-object p1,p0,Lcom/test/smali/Programmer;->name:Ljava/lang/String;
编译后JaDex查看如下:
3.创建方法提示寄存器数量定义问题
创建方法时没有指明寄存器数量,加上.locals "函数用到的寄存器数量" 即可。如: .locals 5
4.new-instance 死循环
由于模仿反编译出来的smali文件写了无参构造函数,结果在编译时出现构造函数死循环。
正确方法:不写构造函数,或者写一个有参的的构造函数。如下:
.method public constructor<init>(Ljava/lang/String;)V
.locals 1
.prologue
.param p1,"name"
invoke-direct {p0},Lcom/test/smali/Programmer;-><init>()V
if-eqz p1,:cound_0
iput-object p1,p0,Lcom/test/smali/Programmer;->name:Ljava/lang/String;
:cound_0
return-void
.end method