Smail语法(1)
【情景分析】Android apk,反编译之后,我们能阅读到的代码是 dalvik字节码 - smali 。有时候,工作需要,必须破解apk里面的一些协议或者方法。以此,借鉴经验,来开发自己的项目。
【官方语法链接】 http://www.blogjava.net/midea0978/archive/2012/01/04/367847.html
【语法】
一. 数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 原始类型: V void ,只能用于返回值类型 Z boolean B byte S short C char I int J long ( 64 位) F float D double ( 64 位) 引用类型: 对象 和 数组 |
Smail表现形式
1 2 3 4 5 6 7 | 原始类型:用大写字母代替即可,用法无异<br> 引用类型: 对象:<strong> L + 包名.对象 +</strong> ; 对象的表示则以L作为开头,格式是LpackageName/objectName;(注意必须有个分号跟在最后),例如String对象在smali中为:Ljava/lang/String;,其中java/lang对应java.lang包,String就是定义在该包中的一个对象。 <br> 数组:<strong>[ + 数据类型</strong> 数组的表示方式是:在基本类型前加上前中括号“[”,例如 int 数组和 float 数组分别表示为:[I、[F<br> <br> [I——表示一个整型一维数组,相当于java中的 int []。<br> 对于多维数组,只要增加[就行了。[[I相当于 int [][],[[[I相当于 int [][][]。注意每一维的最多 255 个。<br> 对象数组的表示:[Ljava/lang/String;表示一个String对象数组。<br> |
二. 方法
方法定义:
1 2 3 | 表示形式:Lpackage/name/ObjectName;->MethodName(III)Z Lpackage/name/ObjectName;表示类型,MethodName是方法名。III为参数(在此是 3 个整型参数),Z是返回类型(bool型)。 方法的参数是一个接一个的,中间没有隔开。<br><br>一个更复杂的例子:<br><br>method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;<br>在java中则为:<br>String method( int , int [][], int , String, Object[]) |
内部类:
1 | 既然类是用LpackageName/objectName;来表示,那类里面的内部类又如何在smali中引用呢?答案是:LpackageName/objectName$subObjectName;。也就是在内部类前加“$”符号 |
字段:
1 | 表示形式: <br>Lpackage/name/ObjectName;->FieldName:Ljava/lang/String; 即包名,字段名和各字段类型。 |
标记说明:
1 2 3 4 5 | # static fields 定义静态变量的标记 # instance fields 定义实例变量的标记 # direct methods 定义静态方法的标记 # virtual methods 定义非静态方法的标记 构造函数的返回类型为V,名字为<init>。 |
语法:If语句
1 2 3 4 5 6 7 8 9 10 11 12 | if -eq p1, v0, :cond_8 表示如果p1和v0相等,则执行cond_8的流程: :cond_8 invoke-direct {p0}, Lcom/paul/test/a;->d()V 调用com.paul.test.a的d()方法<br> if -ne p1, v0, :cond_b 表示不相等则执行cond_b的流程: :cond_b const / 4 v0, 0x0 invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V invoke- super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z move-result v0 大概意思就是调用com.paul.test.a的setPressed方法,然后再调用父类View的onKeyUp方法,最后 return v0 |
三. 寄存器(重点)
概念:
1 2 | 在dalvik字节码中,寄存器都是 32 位的,能够支持任何类型。 64 位类型(Long和Double型)用 2 个寄存器表示。 有两种方式指定一个方法中有多少寄存器是可用的。<br><br> .registers指令指定了方法中寄存器的总数。 [注意:一个方法内,不允许超过 15 个;如果超过 15 个,需要做特殊处理,处理方法找google大神,度娘]<br> .locals指令表明了方法中非参寄存器的数量。 |
命名方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 有两种方式——V命名方式和P命名方式。P命名方式中的第一个寄存器就是方法中的第一个参数寄存器。在下表中我们用这两种命名方式来表示上一个例子中有 5 个寄存器和 3 个参数的方法。 v0 第一个local register v1 第二个local register v2 p0 第一个parameter register v3 p1 第二个parameter register v4 p2 第三个parameter register 你可以用任何一种方式来引用参数寄存器——他们没有任何差别。 注意:baksmali默认对参数寄存器使用P命名方式。如果想使用V命名方式,可以使用-pl—no-parameter-registers选项。 使用P命名方式是为了防止以后如果要在方法中增加寄存器,需要对参数寄存器重新进行编号的缺点。 <br>Long/Double值 Long和 double 类型是 64 位的,需要 2 个寄存器(切记切记)。 例如,对于非静态方法LMyObject;->MyMethod(IJZ)V,参数分别是LMyObject;, int , long ,bool。故该方法需要 5 个寄存器来存储参数。 p0 this p1 I p2,p3 J p4 Z |
下篇文章继续。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· C# 中比较实用的关键字,基础高频面试题!
· .NET 10 Preview 2 增强了 Blazor 和.NET MAUI
· Ollama系列05:Ollama API 使用指南
· 为什么AI教师难以实现
· 如何让低于1B参数的小型语言模型实现 100% 的准确率