smali中使用#來表明註釋一行
例如:
# const-string v0, "aaa" #這句不會被執行java
V void,只能用於返回值類型
Z boolean
B byte
S short
C char
I int
J long(64位)
F float
D double(64位)linux
lit四、lit八、lit1六、lit3二、lit64表示字面值(直接賦值),數字是值所佔用位的長度android
long和double的值佔用兩個寄存器、例:一個在v0寄存器的double值實際佔用v0,v1兩個寄存器windows
boolean值的存儲實際是1和0,1位真、0爲假;boolean型的值實際是轉成int型的值進行操做數組
對象的表示則以L做爲開頭,格式是LpackageName/objectName;(注意必須有個分號跟在最後)app
例如String對象在smali中爲:Ljava/lang/String;,ide
其中java/lang對應java.lang包,String就是定義在該包中的一個對象。函數
那類裏面的內部類又如何在smali中引用呢?ui
答案是:LpackageName/objectName$subObjectName;。也就是在內部類前加「$」符號。this
數組的表示方式是:在數據類型前加上前中括號「[」,
[I 表示一個整型一維數組,至關於java中的int[]。
對於多維數組,只要增長[就好了。[[I至關於int[][],[[[I至關於int[][][]。注意每一維的最多255個。
對象數組的表示:[Ljava/lang/String;表示一個String對象數組String[]。
表示形式:Lpackage/name/ObjectName;->MethodName(III)Z
Lpackage/name/ObjectName;表示類型,MethodName是方法名。III爲參數(在此是3個整型參數),Z是返回類型(bool型)。
方法的參數是一個接一個的,中間沒有隔開。
foo ()V ->沒錯,這就是void foo()。
foo (III)Z ->這個則是boolean foo(int, int, int)。
foo (Z[I[ILjava/lang/String;J)Ljava/lang/String; ->看出來這是String foo (boolean, int[], int[], String, long) 了嗎?
表示形式:Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
即包名,字段名和各字段類型
在smali裏的全部操做都必須通過寄存器來進行:
本地寄存器用v開頭數字結尾的符號來表示,如v0、v一、v二、...
參數寄存器則使用p開頭數字結尾的符號來表示,如p0、p一、p二、...
特別注意的是,p0不必定是函數中的第一個參數,在非static函數中,p0代指「this」,p1表示函數的第一個參數,p2表明函數中的第二個參數…
而在static函數中p0纔對應第一個參數(由於Java的static方法中沒有this方法)
本地寄存器沒有限制,理論上是能夠任意使用的
vx vy vz表示某個寄存器 ,根據不一樣的指令能夠訪問1六、25六、64k寄存器
return vx
返回在vx寄存器的值。
0F00 - return v0
返回v0寄存器中的值。
10
return-wide vx
返回在vx,vx+1寄存器的double/long值。
1000 - return-wide v0
返回v0,v1寄存器中的double/long值。
11
return-object vx
返回在vx寄存器的對象引用。
1100 - return-object v0
返回v0寄存器中的對象引用。
12
const/4 vx, lit4
存入4位常量到vx。
1221 - const/4 v1, #int 2
存入int型常量2到v1。目的寄存器在第二個字節的低4位,常量2在更高的4位。
13
const/16 vx, lit16
存入16位常量到vx。
1300 0A00 - const/16 v0, #int 10
存入int型常量10到v0。
14
const vx, lit32
存入int 型常量到vx。
1400 4E61 BC00 - const v0, #12345678 // #00BC614E
存入常量12345678到v0。
15
const/high16 v0, lit16
存入16位常量到最高位寄存器,用於初始化float值。
1500 2041 - const/high16 v0, #float 10.0 // #41200000
存入float常量10.0到v0。該指令最高支持16位浮點數。
16
const-wide/16 vx, lit16
存入int常量到vx,vx+1寄存器,擴展int型常量爲long常量。
1600 0A00 - const-wide/16 v0, #long 10
存入long常量10到v0,v1寄存器。
17
const-wide/32 vx, lit32
存入32位常量到vx,vx+1寄存器,擴展int型常量到long常量。
1702 4e61 bc00 - const-wide/32 v2, #long 12345678 // #00bc614e
存入long常量12345678到v2,v3寄存器。
18
const-wide vx, lit64
存入64位常量到vx,vx+1寄存器。
1802 874b 6b5d 54dc 2b00- const-wide v2, #long 12345678901234567 // #002bdc545d6b4b87
存入long常量12345678901234567到v2,v3寄存器。
19
const-wide/high16 vx, lit16
存入16位常量到最高16位的vx,vx+1寄存器,用於初始化double 值。
1900 2440 - const-wide/high16 v0, #double 10.0 // #402400000
存入double常量10.0到v0,v1。
1A
const-string vx, 字符串ID
存入字符串常量引用到vx,經過字符串ID或字符串。
1A08 0000 - const-string v8, "" // string@0000
存入string@0000(字符串表#0條目)的引用到v8。
1B
const-string-jumbo
未知注4
1C
const-class vx, 類型ID
存入類對象常量到vx,經過類型ID或類型(如Object.class)。
1C00 0100 - const-class v0, Test3 // type@0001
存入Test3.class(類型ID表#1條目)的引用到v0。
1D
monitor-enter vx
得到vx寄存器中的對象引用的監視器。
1D03 - monitor-enter v3
得到v3寄存器中的對象引用的監視器。
add-type 加法指令
sub-type 減法指令
mul-type 乘法指令
div-type 除法指令
rem-type 取餘
neg-type 取反
and-type 與運算指令
or-type 或運算指令
xor-type 異或元算指令
shl-type 有符號左移指令
shr-type 有符號右移指令
ushr-type 無符號右移指令
int-to-long 整形轉爲長整型
float-to-int 單精度浮點型轉爲整形
int-to-byte 整形轉爲字節類型
neg-int 求補指令,對整數求補
not-int 求反指令,對整數求反
cmpl-float vAA,vBB,vCC 比較兩個單精度的浮點數.若是vBB寄存器中的值大於vCC寄存器的值,則返回-1到vAA中,相等則返回0,小於返回1
cmpg-float vAA,vBB,vCC 比較兩個單精度的浮點數,若是vBB寄存器中的值大於vCC的值,則返回1,相等返回0,小於返回-1
cmpl-double vAA,vBB,vCC 比較兩個雙精度浮點數,若是vBB寄存器中的值大於vCC的值,則返回-1,相等返回0,小於則返回1
cmpg-double vAA,vBB,vCC 比較雙精度浮點數,和cmpl-float的語意一致
cmp-double vAA,vBB,vCC 等價與cmpg-double vAA,vBB,vCC指令
if-eq vA,vB,target vA,vB寄存器中的相等,等價於java中的if(a==b),好比if-eq v3,v10,002c表示若是條件成立,則跳轉到current position+002c處.其他的相似
if-ne vA,vB,target 等價與java中的if(a!=b)
if-lt vA,vB,target vA寄存器中的值小於vB,等價於java中的if(a<b)
if-gt vA,vB,target 等價於java中的if(a>b)
if-ge vA,vB,target 等價於java中的if(a>=b)
if-le vA,vB,target 等價於java中的if(a<=b)
除了以上指令以外,Davilk還提供可一個零值條件指令,該指令用於和0比較,能夠理解爲將上面指令中的vB寄存器的值固定爲0.
if-eqz vAA,target 等價於java中的if(a==0)或者if(!a)
if-nez vAA,target 等價於java中的if(a!=0)或者if(a)
if-ltz vAA,target 等價於java中的if(a<0)
if-gtz vAA,target 等價於java中的if(a>0)
if-lez vAA,target 等價於java中的if(a<=0)
if-gtz vAA,target 等價於java中的if(a>=0)
move vA,vB 將vB寄存器的值賦值給vA寄存器,vA和vB寄存器都是4位
move/from16 vAA,VBBBB 將vBBBB寄存器(16位)的值賦值給vAA寄存器(7位),from16表示源寄存器vBBBB是16位的
move/16 vAAAA,vBBBB 將寄存器vBBBB的值賦值給vAAAA寄存器,16表示源寄存器vBBBB和目標寄存器vAAAA都是16位
move-object vA,vB 將vB寄存器中的對象引用賦值給vA寄存器,vA寄存器和vB寄存器都是4位
move-result vAA 將上一個invoke指令(方法調用)操做的單字(32位)非對象結果賦值給vAA寄存器
move-result-wide vAA 將上一個invoke指令操做的雙字(64位)非對象結果賦值給vAA寄存器
mvoe-result-object vAA 將上一個invoke指令操做的對象結果賦值給vAA寄存器
move-exception vAA 保存上一個運行時發生的異常到vAA寄存器
new-array vA,vB,type@CCCC 建立指定類型與指定大小(vB寄存器指定)的數組,並將其賦值給vA寄存器
fill-array-data vAA,+BBBBBBBB 用指定的數據填充數組,vAA表明數組的引用(數組第一個元素的地址)
new-instance vAA,type@BBBB 構造一個指定類型的對象將器引用賦值給vAA寄存器.此處不包含數組對象
instance-of vA,vB,type@CCCC 判斷vB寄存器中對象的引用是不是指定類型,若是是,將v1賦值爲1,不然賦值爲0
check-cast vAA,type@BBBB 將vAA寄存器中對象的引用轉成指定類型,成功則將結果賦值給vAA,不然拋出ClassCastException異常.
1.普通字段讀寫操做
iget-byte vX,vY,filed_id 讀取vY寄存器中的對象中的filed_id字段值賦值給vX寄存器
iput-byte vX,vY,filed_id 設置vY寄存器中的對象中filed_id字段的值爲vX寄存器的值
iget-boolean vX,vY,filed_id
iput-boolean vX,vY,filed_id
iget-long vX,vY,filed_id
iput-long vX,vY,filed_id
2.靜態字段讀寫操做
sget-byte vX,vY,filed_id
sput-byte vX,vY,filed_id
sget-boolean vX,vY,filed_id
sput-boolean vX,vY,filed_id
sget-long vX,vY,filed_id
sput-long vX,vY,filed_id
invoke-direct{parameters},methodtocall 調用實例的直接方法,即private修飾的方法.此時須要注意{}中的第一個元素表明的是當前實例對象,即this,後面接下來的纔是真正的參數.好比指令invoke-virtual {v3,v1,v4},Test2.method5:(II)V中,v3表示Test2當前實例對象,而v1,v4纔是方法參數
invoke-static{parameters},methodtocall 調用實例的靜態方法,此時{}中的都是方法參數
invoke-super{parameters},methodtocall 調用父類方法
invoke-virtual{parameters},methodtocall 調用實例的虛方法,即public和protected修飾修飾的方法
invoke-interface{parameters},methodtocall 調用接口方法
invoke-direct/range,
invoke-static/range,
invoke-super/range,
invoke-virtual/range,
invoke-interface/range指令
該類型指令和以上指令惟一的區別
就是後者能夠設置方法參數,可使用的寄存器的範圍,
在參數多於四個時候使用.
return-void 什麼也不返回
return vAA 返回一個32位非對象類型的值
return-wide vAA 返回一個64位非對象類型的值
return-object vAA 反會一個對象類型的引用
指令 說明
monitor-enter vAA 爲指定對象獲取鎖操做
monitor-exit vAA 爲指定對象釋放鎖操做
throw vAA 拋出vAA寄存器中指定類型的異常
goto +AA 無條件跳轉到指定偏移處(AA即偏移量)
packed-switch vAA,+BBBBBBBB 分支跳轉指令.vAA寄存器中的值是switch分支中須要判斷的,BBBBBBBB則是偏移表(packed-switch-payload)中的索引值,
spare-switch vAA,+BBBBBBBB 分支跳轉指令,和packed-switch相似,只不過BBBBBBBB偏移表(spare-switch-payload)中的索引值
if-test vA,vB,+CCCC 條件跳轉指令,用於比較vA和vB寄存器中的值,若是條件知足則跳轉到指定偏移處(CCCC即偏移量),test表明比較規則,能夠是eq.lt等.
關鍵詞 說明
.filed 定義字段
.method…end method 定義方法
.annotation…end annotation 定義註解
.implements 定義接口指令
.local 指定了方法內局部變量的個數
.registers 指定方法內使用寄存器的總數
.prologue 表示方法中代碼的開始處
.line 表示java源文件中指定行
.paramter 指定了方法的參數
.param 和.param
.class public Lcom/disney/WMW/WMWActivity;
.super Lcom/disney/common/BaseActivity;
.source "WMWActivity.java"
# interfaces
.implements Lcom/burstly/lib/ui/IBurstlyAdListener;
它是com.disney.WMW這個package下的一個類
繼承自com.disney.common.BaseActivity
這是一個由WMWActivity.java編譯獲得的smali文件
WMWActivity實現了一個com.burstly.lib.ui這個package下的IBurstyAdListener接口
public class WMWActivity extends BaseActivity implements IBurstlyAdListener
{
}
.class public Lcom/example/test/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"
它是com.example.test這個package下的一個類
繼承自android.app.Activity
這是一個由MainActivity.java編譯獲得的smali文件
public class MainActivity extends Activity
{
}
.class public Lcom/example/utils/PhoneUtil;
.super Ljava/lang/Object;
.source "PhoneUtil.java"
它是com.example.utils這個package下的一個類
這是一個由PhoneUtil.java編譯獲得的smali文件
public class PhoneUtil
{
}
#interfaces
.implements <接口名稱>
# interfaces
.implements Landroid/view/View$OnClickListener;
普通字段
此處非權限修飾符則但是final,volidate,transient.
#instance fields
.field <訪問權限修飾符> [非權限修飾符] <字段名>:<字段類型>
# instance fields
.field private TAG:Ljava/lang/String;
靜態字段
smali文件還爲靜態字段,普通字段分別添加#static field和#instan filed註釋.
#static fields
.field <訪問權限> static [修飾詞] <字段名>:<字段類型>
# static fields
.field private static final pi:F = 3.14f
# annotations
.annotation system Ldalvik/annotation/MemberClasses;
value = {
Lcom/disney/WMW/WMWActivity$MessageHandler;,
Lcom/disney/WMW/WMWActivity$FinishActivityArgs;
}
.end annotation
它有兩個成員內部類——MessageHandler和FinishActivityArgs
.annotation build Landroid/annotation/SuppressLint;
value = {
"SimpleDateFormat"
}
.end annotation
屏蔽android lint錯誤
@SuppressLint("SimpleDateFormat")
public static String getCallHistoryList(Context context, ContentResolver cr){
}
# annotations
.annotation system Ldalvik/annotation/MemberClasses;
value = {
Lcom/example/test/R$attr;,
Lcom/example/test/R$dimen;,
Lcom/example/test/R$drawable;,
Lcom/example/test/R$id;,
Lcom/example/test/R$layout;,
Lcom/example/test/R$menu;,
Lcom/example/test/R$string;,
Lcom/example/test/R$style;
}
.end annotation
內部類能夠分爲成員內部類、靜態嵌套類、方法內部類、匿名內部類。
內部類做爲一個獨立的類,它也擁有本身獨立的smali文件,只是內部類的文件名形式爲 "[外部類]$[內部類].smali"
parameter的個數和方法參數的數量相對應,即有幾個參數便有幾個.parameter,默認從1開始,即p1,p2,p2….
該類型的方法有個默認的參數指向當前對象,在smali中,方法的默認對象參數用p0表示.
直接方法即所謂的direct methods,Davilk中方法調用指令invoke-direct
#direct methods
.method <訪問權限修飾符> [非訪問權限修飾符] <方法原型>
<.locals>
[.parameter]
[.prologue]
[.line]
<代碼邏輯>
.end
# direct methods
.method public constructor <init>()V
.registers 2
.prologue
.line 8
invoke-direct {p0}, Landroid/app/Activity;-><init>()V
.line 10
const-string v0, "MainActivity"
iput-object v0, p0, Lcom/social_touch/demo/MainActivity;->TAG:Ljava/lang/String;
.line 13
const/4 v0, 0x0
iput-boolean v0, p0, Lcom/social_touch/demo/MainActivity;->running:Z
return-void
.end method
虛方法的定義會和直接方法惟一的不一樣就是註釋不一樣:#virtual methods
#virtual methods
.method <訪問權限> [修飾關鍵詞] <方法原想>
<.locals>
[.parameter1]
[.parameter2]
[.prologue]
[.line]
<代碼邏輯>
.end
Android上的so(elf)與linux上的99%的類似,結構是通用的
Linux下使用比較方便,但ndk也提供了readelf能夠在windows下使用
NDK目錄\toolchains\arm-linux-androideabi-4.6\prebuilt\windows\bin
arm-linux-androideabi-readelf.exe -a xx.so > f:\1.txt
一、-h或者--file-header
顯示在ELF文件頭裏包含的全部信息
二、-l或者--program-headers或者--segments
顯示程序頭表信息,包擴有幾個段,每一個段的屬性,以及每一個段中包含有哪幾個節(Section)
三、-S或者--section-headers或者--sections
顯示節區表內的全部信息,包括每一個節的屬性,注意這裏是用的是大寫的「S」
四、-t或者--section-details
用來顯示全部節的詳細信息,感受上但從信息量上來講,和前面的「-S」沒有什麼大的不一樣
五、-e或者--headers
顯示全部頭的信息,包括ELF文件頭、程序頭和節頭,也就是「-h -l -S」的組合。
六、-s或者--syms或者--symbols
顯示符號表的信息,包含靜態符號表(.symtab)和動態符號表(.dynsym)
若是隻關心動態符號表,能夠直接使用「--dyn-syms」。
七、-r或者--relocs
顯示全部重定位入口的信息
八、-d或者--dynamic
顯示動態節區的內容
九、-x或者--hex-dump=<number|name>
顯示某個節區的二進制碼,具體哪一個節能夠用該節的編號或者名字來指定,例如「-x .text」:
結構定義;
unsigned :無符號
char: 1個字節
short: 2個字節
int: 4個字節
typedef unsigned short __u16;
typedef int __s32;
typedef unsigned int __u32;
typedef __u32 Elf32_Addr;
typedef __u16 Elf32_Half;
typedef __u32 Elf32_Off;
typedef __s32 Elf32_Sword;
typedef __u32 Elf32_Word;
/* 32-bit ELF base types. */
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
/* 64-bit ELF base types. */
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef int16_t Elf64_SHalf;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
#define EI_NIDENT 16
typedef struct elf32_hdr{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point */
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf32_phdr{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
adb connect 127.0.0.1:62001
請求支付,計費id:30000916146302
package com.lotuseed.android;
import java.util.HashMap;
import java.util.Map;
public class LSGAVirtualCurrency
{
public static void onChargeRequest(String paramString1, String paramString2, double paramDouble1, String paramString3, double paramDouble2, String paramString4)
{
HashMap localHashMap = new HashMap();
localHashMap.put("i", paramString1);
if ((paramString2 != null) && (paramString2.length() > 0)) {
localHashMap.put("f", paramString2);
}
localHashMap.put("a", Double.toString(paramDouble1));
if ((paramString3 != null) && (paramString3.length() > 0) && (!paramString3.equalsIgnoreCase("CNY"))) {
localHashMap.put("t", paramString3);
}
if (paramDouble2 > 0.0D) {
localHashMap.put("v", Double.toString(paramDouble2));
}
if ((paramString4 != null) && (paramString4.length() > 0)) {
localHashMap.put("c", paramString4);
}
g.onEvent("^pr", localHashMap, true);
}
public static void onChargeSuccess(String paramString)
{
g.onEvent("^ps", paramString, true);
}
public static void onReward(double paramDouble, String paramString)
{
HashMap localHashMap = new HashMap();
localHashMap.put("r", paramString);
localHashMap.put("v", Double.toString(paramDouble));
g.onEvent("^v", localHashMap, true);
}
}
Ljava/lang/String;
.method public static onResult(II)V
.locals 2
.param p0, "id" # I
.param p1, "success" # I
.prologue
.line 369
if-nez p1, :cond_0
.line 370
sget-object v0, Lorg/cocos2dx/cpp/AppActivity;->context:Lorg/cocos2dx/cpp/AppActivity;
iget-object v0, v0, Lorg/cocos2dx/cpp/AppActivity;->mOrderID:Ljava/lang/String;
invoke-static {v0}, Lcom/lotuseed/android/LSGAVirtualCurrency;->onChargeSuccess(Ljava/lang/String;)V
.line 372
:cond_0
sget-object v0, Lorg/cocos2dx/cpp/AppActivity;->context:Lorg/cocos2dx/cpp/AppActivity;
new-instance v1, Lorg/cocos2dx/cpp/AppActivity$2;
invoke-direct {v1, p0, p1}, Lorg/cocos2dx/cpp/AppActivity$2;-><init>(II)V
invoke-virtual {v0, v1}, Lorg/cocos2dx/cpp/AppActivity;->runOnGLThread(Ljava/lang/Runnable;)V
.line 378
return-void
.end method
public static void onResult(int paramInt1, final int paramInt2)
{
Int paramInt2 = 0;
if (paramInt2 == 0) {
LSGAVirtualCurrency.onChargeSuccess(context.mOrderID);
}
context.runOnGLThread(new Runnable()
{
public void run()
{
AppActivity.onResultNative(this.val$id, paramInt2);
}
});
}
const/4 p1, 0x0