文章目录

  • 前言
  • 一、Smali简介
  • 二、Smali语法简介
    • 1.基本类型
    • 2.引用类型
    • 3.方法体定义
    • 4.关键字
    • 5.寄存器类别区分
    • 6.条件跳转
    • 7.Smali针对函数返回结果的操作
    • 8.Smali变量操作权限
  • 三、阅读部分
    • APK效果
    • 打包和反编译
    • 阅读
  • 四、实际操作部分
  • 总结

前言

本节介绍移动安全相关知识中的Smali语法,并自主动手完成一个小练习

一、Smali简介

Smali是Android虚拟机Davlik的寄存器语言,语法上和汇编语言类似. Davlik是基于寄存器的,就是说smali里的所有操作都必须经过寄存器来进行.
简单来说就是高级语言Java和机器语言的一个中间层代码语言,执行效率相比高级语言更加高效,更加贴近底层,通过我们用Apktool反编译APK出来的结果中便会含有Smali文件夹,文件夹下的内容就是Smali语言

本节主要针对基于Java编写的Android应用反编译出的Smali文件进行分析。

二、Smali语法简介

1.基本类型

B—byte
C—char
D—double
F—float
I—int
S—short
V—void
J—long
Z—boolean

2.引用类型

  • [XXX->X代表类型的数组
    例:
    [B -->Byte[]
    [I -->Int[]
  • Lxx/yyy -->Object对象
    例如:
    String str–>str Ljava/lang/String;
    subobjectName objectName->objectName LpackageaName/objectNamesubobjectName注:这里的subobjectName 注:这里的subobjectName注:这里的符号代表内部类,内部类的含义我就不用解释了吧

3.方法体定义

方法体格式:
Func-Name (Para-Type1Para-Type2Para-Type3…)Return-Type 注意: 参数之间没有任何分隔符,返回值在最后

例:
void hello() —> hello()V
boolean hello(int,int,int) —>hello(III)Z
String fun(boolean, int[], int[], String, long)
—>fun(Z[I[ILjava/lang/String,J)Ljava/lang/String

4.关键字

  • .field private isFlag:z 定义变量
  • .method 方法
  • .parameter 方法参数
  • .prologue 方法开始
  • .line123 此方法开始于123行
  • invoke-super 调用父函数
  • const/high16 v0,0x7fox 把0x7fox的值赋值给v0
  • invoke-direct 调用函数
  • return-void 函数返回void
  • .end method 函数结束
  • new-instance 创建实例
  • iput-object 对象赋值
  • iget-object 调用对象
  • invoke-static 调用静态函数
  • .class public Lcom/disney/WMW/WMWActivty; 类名
  • .super Lcom/XXX/XXX/XXX; 父类名
  • .source “XXX.java” 源文件名
  • .implements Lcom/XXX/XXX/XXX; 实现了接口
  • .annotation 内部类

5.寄存器类别区分

  • 寄存器v,本地寄存器 (local register, 非参寄存器)
    常用v开头数字结尾的符号表示 v0,v1,v2…

    可以看到这里的locals后面的参数为2,表明使用两个v开头的本地寄存器,若修改数量为1,可以编译通过,但是运行时,会发生错误

  • 寄存器p,参数寄存器 (parameter regisgter)
    常用p开头数字结尾的符号来表示 p0,p1,p2,p3…

# direct methods
.method public constructor <init>()V.locals 0.line 18invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()Vreturn-void
.end method

p0为非静态方法自动创建的寄存器,存储着this,也就是该方法所属类的实例本身,例如这段函数中,一个Activity invoke-direct调用其父类AppCompatActivity的init()方法,传入的参数是这个实例本身的this

6.条件跳转

  • if-eq vA,vB, :cond_** 如果vA等于vB,则跳转到:cond_**
  • if-ne vA,vB, :cond_** 如果vA不等于vB,则跳转到:cond_**
  • if-lt vA,vB, :cond_** 如果vA小于vB,则跳转到:cond_**
  • if-ge vA,vB, :cond_** 如果vA大于等于vB,则跳转到:cond_**
  • if-gt vA,vB, :cond_** 如果vA大于vB,则跳转到:cond_**
  • if-le vA,vB, :cond_** 如果vA小于等于vB,则跳转到:cond_**
  • if-eqz vA, :cond_** 如果vA等于0,则跳转到:cond_**
  • if-nez vA, :cond_** 如果vA不等于0,则跳转到:cond_**
  • if-ltz vA, :cond_** 如果vA小于0,则跳转到:cond_**
  • if-gez vA, :cond_** 如果vA大于等于0,则跳转到:cond_**
  • if-gtz vA, :cond_** 如果vA大于0,则跳转到:cond_**
  • if-lez vA, :cond_** 如果vA小于等于0,则跳转到:cond_**

7.Smali针对函数返回结果的操作

在Java代码中调用函数和返回函数结果可以只用一条语句来表示,如:

 A=getPoint();

但在Smali里则需要分开完成,在使用上述指令后,如果调用的函数返回非void, 那么还需要用到move-result(返回基本函数类型)和move-result-object(返回对象指令);

例:

 const-string v0,"Eric"invoke-static {v0},Lcmb/pbi;->t(Ljava/lang/String)LJava/lang/String;move-result-object v2

此时v2保存的就是调用t方法得到的String字符串

8.Smali变量操作权限

字段操作指令表示对对象字段进行设值和取值操作,就像是你在代码中长些的set和get方法.基本指令是iput-type,iget-type,sput-type,sget-type.type表示数据类型.

普通字段读写操作
前缀是i的iput-type和iget-type指令用于字段的读写操作.

指令 描述

  • iget-object vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id对象的引用值给vBB寄存器
  • iget-boolean vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器
  • iget-wide vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器
  • iget vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器
  • iput-object vAA,vBB,filed_id 把vAA寄存器指向的对象的引用赋值给vBB寄存器中的filed_id对象
  • iput-boolean vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的boolean类型
  • iput-wide vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的wide类型
  • iput vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的int类型

静态字段读写操作
前缀是s的sput-type和sget-type指令用于静态字段的读写操作

指令 描述

  • sget-object vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id对象的引用值给vBB寄存器
  • sget-boolean vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器
  • sget-wide vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器
  • sget vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器
  • sput-object vAA,vBB,filed_id 把vAA寄存器指向的对象的引用赋值给vBB寄存器中的filed_id对象
  • sput-boolean vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的boolean类型
  • sput-wide vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的wide类型
  • sput vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的int类型

三、阅读部分

我们这里采取自己动手打包一个登录验证的APK进行阅读和练习

APK效果

登录界面

登陆后的界面

打包和反编译

打包用AS一键打包
反编译用APKTool对APK进行反编译出相关Smali代码



点击Smali用VS Code工具进行阅读

阅读

MainActivity.smali

.class public Lcom/example/androidsafetest01/MainActivity;//包名+类名
.super Landroidx/appcompat/app/AppCompatActivity;//父类名称
.source "MainActivity.java"//.source 源文件名称# instance fields
.field private btn:Landroid/widget/Button;.field private editText:Landroid/widget/EditText;//实例变量 变量名称:包名# direct methods
.method public constructor <init>()V//方法开始.locals 0.line 12//这个方法对应Java代码中的12行invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()V//调用父类中的构造函数,返回值为空return-void
.end method//方法结束.method static synthetic access$000(Lcom/example/androidsafetest01/MainActivity;)Landroid/widget/EditText;.locals 0.line 12iget-object p0, p0, Lcom/example/androidsafetest01/MainActivity;->editText:Landroid/widget/EditText;//将MainActivity的id值送给EditText,初步猜测是在给权限return-object p0
.end method.method private initEvent()V.locals 2//使用了两个寄存器.line 26iget-object v0, p0, Lcom/example/androidsafetest01/MainActivity;->btn:Landroid/widget/Button;new-instance v1, Lcom/example/androidsafetest01/MainActivity$1;invoke-direct {v1, p0}, Lcom/example/androidsafetest01/MainActivity$1;-><init>(Lcom/example/androidsafetest01/MainActivity;)Vinvoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V//调用实例的虚方法return-void
.end method.method private initView()V.locals 1const v0, 0x7f08008f.line 44invoke-virtual {p0, v0}, Lcom/example/androidsafetest01/MainActivity;->findViewById(I)Landroid/view/View;move-result-object v0check-cast v0, Landroid/widget/EditText;iput-object v0, p0, Lcom/example/androidsafetest01/MainActivity;->editText:Landroid/widget/EditText;const v0, 0x7f080057.line 45invoke-virtual {p0, v0}, Lcom/example/androidsafetest01/MainActivity;->findViewById(I)Landroid/view/View;move-result-object v0check-cast v0, Landroid/widget/Button;iput-object v0, p0, Lcom/example/androidsafetest01/MainActivity;->btn:Landroid/widget/Button;return-void
.end method# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V.locals 0.annotation system Ldalvik/annotation/MethodParameters;accessFlags = {0x0}names = {"savedInstanceState"}.end annotation.line 19invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)Vconst p1, 0x7f0b001d.line 20invoke-virtual {p0, p1}, Lcom/example/androidsafetest01/MainActivity;->setContentView(I)V.line 21invoke-direct {p0}, Lcom/example/androidsafetest01/MainActivity;->initView()V.line 22invoke-direct {p0}, Lcom/example/androidsafetest01/MainActivity;->initEvent()Vreturn-void
.end method

MainActivity$1.smali

.class Lcom/example/androidsafetest01/MainActivity$1;
.super Ljava/lang/Object;
.source "MainActivity.java"# interfaces
.implements Landroid/view/View$OnClickListener;# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;value = Lcom/example/androidsafetest01/MainActivity;->initEvent()V
.end annotation.annotation system Ldalvik/annotation/InnerClass;accessFlags = 0x0name = null
.end annotation# instance fields
.field final synthetic this$0:Lcom/example/androidsafetest01/MainActivity;# direct methods
.method constructor <init>(Lcom/example/androidsafetest01/MainActivity;)V.locals 0.annotation system Ldalvik/annotation/MethodParameters;accessFlags = {0x8010}names = {"this$0"}.end annotation.line 26iput-object p1, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity;invoke-direct {p0}, Ljava/lang/Object;-><init>()Vreturn-void
.end method# virtual methods
.method public onClick(Landroid/view/View;)V.locals 2.annotation system Ldalvik/annotation/MethodParameters;accessFlags = {0x0}names = {"view"}.end annotation.line 29iget-object p1, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity;invoke-static {p1}, Lcom/example/androidsafetest01/MainActivity;->access$000(Lcom/example/androidsafetest01/MainActivity;)Landroid/widget/EditText;move-result-object p1invoke-virtual {p1}, Landroid/widget/EditText;->getText()Landroid/text/Editable;move-result-object p1invoke-virtual {p1}, Ljava/lang/Object;->toString()Ljava/lang/String;move-result-object p1if-eqz p1, :cond_0.line 30invoke-virtual {p1}, Ljava/lang/String;->length()Imove-result v0if-eqz v0, :cond_0const-string v0, "123456".line 31invoke-virtual {p1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Zmove-result p1if-eqz p1, :cond_1.line 32new-instance p1, Landroid/content/Intent;iget-object v0, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity;invoke-virtual {v0}, Lcom/example/androidsafetest01/MainActivity;->getApplicationContext()Landroid/content/Context;move-result-object v0const-class v1, Lcom/example/androidsafetest01/EndActivity;invoke-direct {p1, v0, v1}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V.line 33iget-object v0, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity;invoke-virtual {v0, p1}, Lcom/example/androidsafetest01/MainActivity;->startActivity(Landroid/content/Intent;)Vgoto :goto_0.line 36:cond_0iget-object p1, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity;invoke-virtual {p1}, Lcom/example/androidsafetest01/MainActivity;->getApplicationContext()Landroid/content/Context;move-result-object p1const/4 v0, 0x0const-string v1, "\u8f93\u5165\u5bc6\u7801\u6709\u8bef"//这里Smali采用的是Unicode编码invoke-static {p1, v1, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;move-result-object p1invoke-virtual {p1}, Landroid/widget/Toast;->show()V:cond_1:goto_0return-void
.end method

四、实际操作部分

这里通过修改其中的明文密码判定部分,改变其登录逻辑为,密码等于123456789时,进行登录行为

改变后

再次打包APK,进行重签名发送到手机上进行安装

重签名,这里的签名方式采用的是Java中的jarsigner命令,jarsigner命令只可以针对V1的签名方式进行签名,后期应该会进行更改签名方式

jarsigner -verbose -keystore D:\2022\Names\AndroidSafeSign.jks D:\2022\移动安全\apks\release\AndroidSafeTest02.apk -signedjar D:\2022\移动安全\apks\AfterRenamed\AndroidSafeTest01.apk key0

执行效果:

修改过后的视频播放地址

但是这种修改Smali的方法基于静态调试,实际反编译APK过程中基本不会有打静态补丁的机会,这里也是仅供练习使用。

总结

以上是Smali语法学习部分,欢迎大家指正

移动安全:Smali语法学习示例与实践相关推荐

  1. Android逆向入门7——Smali语法学习(1)

    这一节我们一起探讨smali语法和smali在Android逆向中的应用,它是Android逆向世界中不可或缺的一部分. 简单的来说,Dex反编译的结果就是Smali,Smali和dex之间的关系,我 ...

  2. Smali语法学习三

    寄存器与变量 Java中的变量都是放在内存中的,安卓为了提高性能,变量都是放在寄存器中的.寄存器为32位,可以支持任何类型.其中long和double这种64为的类型需要两个寄存器保存.寄存器采用v和 ...

  3. Smali语法学习五

    #算数运算 Java代码: public void num(int b){int a = b;boolean b1 = true;Log.d("MainActivity",&quo ...

  4. notepad++ smali语法高亮模板分享

    某论坛也有,但是太难看了, 前面介绍了一些工具可以反编译dex文件为smali文件,在Android程序逆向分析中,阅读smali代码已然是十分重要的,但各种代码编辑器都无法较好的支持smali文件的 ...

  5. smali语法中文版

           这是学习Smali重中之中,不过现在有些反编译的软件已经存在相应的插件,可以直接看到这些操作码名称的中文解释(如:Android killer),但是对其进行学习还是非常有必要的.以下是 ...

  6. 《0基础学安卓逆向》第2集:初始apk文件和smali语法

    1.APK文件 apk=android Application PacKage=APKapk文件是什么:是安卓app的安装文件本质:(apk文件其实就是个)zip压缩包 意味着可以用解压缩工具把apk ...

  7. jsx 调用php,JavaScript_JavaScript的React框架中的JSX语法学习入门教程,什么是JSX? 在用React写组件的 - phpStudy...

    JavaScript的React框架中的JSX语法学习入门教程 什么是JSX? 在用React写组件的时候,通常会用到JSX语法,粗看上去,像是在Javascript代码里直接写起了XML标签,实质上 ...

  8. MySQL语法学习笔记

    MySQL语法学习笔记 学习之道,非尽心竭力者不能进也!我是小七黛,欢迎查看我的笔记,有问题欢迎交流探讨. SQL是一种结构查询语言,用于查询关系数据库的标准语言,包括若干关键字和一致的语法,便于数据 ...

  9. Markdown语法学习|精简版

    markdown语法学习|精简版 文章开头 点击这里回到下方介绍 页面跳转 的阅读位置 点击这里回到下方介绍 toc 的阅读位置 此笔记学习摘抄自Markdown语法大全(超级版),并根据笔者的使用不 ...

  10. 搜索引擎系统学习与开发实践总结

    导读: 搜索引擎系统学习与开发实践总结 2006-07-23 20:14 一.搜索引擎概述 搜索引擎的发展历史 在互联网发展初期,网站相对较少,信息查找比较容易.然而伴随互联网爆炸性的发展,普通网络用 ...

最新文章

  1. Leangoo敏捷工具,scrum看板工具截止时间变化~
  2. P3225 [HNOI2012]矿场搭建
  3. 127. Word Ladder 单词接龙
  4. java 验证码 添加背景图_java登陆界面怎么加背景图 会的我加你
  5. 【Web前端开发最佳实践系列】前端代码推荐和建议
  6. 阿里云、腾讯云和华为云618活动细节对比
  7. webpack 安装vue(两种代码模式compiler 和runtime)
  8. Linux复习-shell程序设计
  9. Waveform Audio 驱动(Wavedev2)之:WAV API模拟 1
  10. Matlab实现Compow协议,optisystem和matlab协同仿真
  11. 计算机数据结构模拟试题,十套计算机数据结构试题及答案.doc
  12. rfid破解 BLE Hacking
  13. 理解Mybatis一级缓存,以及如何真正使用到一级缓存
  14. win定时关机_windows如何设置定时关机?
  15. 前端1——html笔记
  16. onclick和onfocus的区别
  17. js实现页面指定区域局部刷新
  18. 【数据库系统】第一部分 数据库基础(4) 数据库安全性
  19. 遍历HashMap中元素的三种方法
  20. freopen函数使用

热门文章

  1. 在office2003中打开office2007文件的补丁(.docx文件,pptx文件打开方法)
  2. 解决U盘快捷方式木马
  3. SQL Server 2008 R2安装步骤示例
  4. Android静默安装实现方案,仿360手机助手秒装和智能安装功能
  5. 在ubuntu9.10下 安装nvidia GT130M最新驱动190.42版本
  6. win10打开蓝牙_联想笔记本win10无法连接蓝牙音箱的解决方法
  7. android 关闭进程 后台进程还在,为何有些安卓后台程序就是关不掉呢?
  8. 基于QT的IM(jabber)库和客户端
  9. 玩qq游戏提示计算机内存不足,win10系统玩游戏提示“计算机内存不足”怎么办...
  10. 镜像翻转_《蒙娜丽莎》镜像翻转后,暗藏神秘的第二张脸?网友:笑容消失了...