android-smali记录

Posted 蝶泳奈何桥.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android-smali记录相关的知识,希望对你有一定的参考价值。


title: android-smali记录
categories: Android
tags: [android, 加壳, smali]
date: 2022-09-29 14:33:53
comments: false
mathjax: true
toc: true

android-smali记录


前篇

  • Android逆向基础:Smali语法 - https://www.jianshu.com/p/9931a1e77066
  • SMALI语法入门教程 - https://www.cnblogs.com/bluestorm/p/12272942.html

现在 as 中安装 java2smali 插件, 方便由 java 生成 smali 文件对比


Dalvik字节码

Dalvik是google专门为Android操作系统设计的一个虚拟机,经过深度的优化。虽然Android上的程序是使用java来开发的,但是Dalvik和标准的java虚拟机JVM还是两回事。Dalvik VM是基于寄存器的,而JVM是基于栈的;Dalvik有专属的文件执行格式dex(dalvik executable),而JVM则执行的是java字节码。Dalvik VM比JVM速度更快,占用空间更少。

通过Dalvik的字节码我们不能直接看到原来的逻辑代码,这时需要借助如Apktool或dex2jar+jd-gui工具来帮助查看。但是,注意的是最终我们修改APK需要操作的文件是.smali文件,而不是导出来的Java文件重新编译(况且这基本上不可能)。


Smali是什么

Smali是Android虚拟机的反汇编语言。
我们都知道,Android代码一般是用java编写的,执行java程序一般需要用到java虚拟机,在Android平台上也不例外,但是出于性能上的考虑,并没有使用标准的JVM,而是使用专门的Android虚拟机(5.0以下为Dalvik,5.0以上为ART)。Android虚拟机的可执行文件并不是普通的class文件,而是再重新整合打包后生成的dex文件。dex文件反编译之后就是Smali代码,所以说,Smali语言是Android虚拟机的反汇编语言。


掌握Smali有哪些好处

1、动态调试APK,通常静态分析APK是不够的,如果需要彻底分析APK的执行逻辑,需要通过动态调试来进行。
具体教程参考:http://blog.csdn.net/hanchaohao2012/article/details/63253725
2、修改APK运行逻辑,通过修改Smali代码,再重新编译打包成新的APK,是Android逆向的基本操作。


Smali基本语法

数据类型

SmaliJava备注
vvoid只能用于返回值类型
Zboolean
Bbyte
Sshort
Cchar
Iint
Jlong
Ffloat
Ddouble
Lpackage/name;对象类型L表示这是一个对象类型,package表示该对象所在的包,;表示对象名称的结束
[类型数组[I表示一个int型数组,[Ljava/lang/String 表示一个String的对象数组

语法关键词

关键词说明
.class定义java类名
.super定义父类名
.source定义Java源文件名
.filed定义字段
.method定义方法开始
.end method定义方法结束
.annotation定义注解开始
.end annotation定义注解结束
.implements定义接口指令
.local指定了方法内局部变量的个数
.registers指定方法内使用寄存器的总数
.prologue表示方法中代码的开始处
.line表示java源文件中指定行
.paramter指定了方法的参数
.param和.paramter含义一致,但是表达格式不同

寄存器

Java中变量都是存放在内存中的,Android为了提高性能,变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型。
为什么寄存器比内存快,可以参考这篇文章:http://www.ruanyifeng.com/blog/2013/10/register.html

寄存器分为如下两类:
1、本地寄存器
用v开头数字结尾的符号来表示,v0, v1, v2,…
2、参数寄存器
用p开头数字结尾的符号来表示,p0,p1,p2,…
注意:
在非static方法中,p0代指this,p1为方法的第一个参数。
在static方法中,p0为方法的第一个参数。

Smali代码示例:

const/4 v0, 0x1 //把值0x1存到v0本地寄存器
iput-boolean v0,p0,Lcom/aaa;->IsRegisterd:Z //把v0中的值赋给com.aaa.IsRegistered,p0代表this,相当于this.Isregistered=true

成员变量

成员变量定义格式为:
.field public/private [static][final] varName:<类型>

获取指令
iget, sget, iget-boolean, sget-boolean, iget-object, sget-object

操作指令
iput, sput, iput-boolean, sput-boolean, iput-object, sput-object
array的操作是aget和aput

指令解析
sget-object v0,Lcom/aaa;->ID:Ljava/lang/String;
获取ID这个String类型的成员变量并放到v0这个寄存器中
iget-object v0,p0,Lcom/aaa;->view:Lcom/aaa/view;
iget-object比sget-object多一个参数p0,这个参数代表变量所在类的实例。这里p0就是this

Smali代码示例1:

const/4 v3, 0x0
sput-object v3, Lcom/aaa;->timer:Lcom/aaa/timer;

相当于java代码:this.timer = null;

Smali代码示例2:

.local v0, args:Landroid/os/Message;
const/4 v1, 0x12
iput v1,v0,Landroid/os/Message;->what:I

相当于java代码:args.what = 18;
其中args为Message的实例


函数

函数定义格式为:
.method public/private [static][final] methodName()<类型>
.end method

函数的定义一般为:

Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type**

注意参数与参数之间没有任何分隔符,同样举几个例子就容易明白了:

  1. foo ()V

​ 没错,这就是void foo()。

  1. foo (III)Z

​ 这个则是boolean foo(int, int, int)。

  1. foo (Z[I[ILjava/lang/String;J)Ljava/lang/String;

​ 看出来这是String foo (boolean, int[], int[], String, long) 了吗?

Smali代码示例:

.method private ifRegistered()Z
    .locals 2            // 本地寄存器的个数
    .prologue
    const/4 v0, 0x1      //v0赋值为1
    if-eqz v0, :cond_0   //判断v0是否等于0,等于0则跳到cond_0执行
    const/4 v1, 0x1      //符合条件分支
    :goto_0              //标签
    return v1            //返回v1的值
    :cond_0              //标签
    const/4 v1, 0x0      //cond_0分支
    goto :goto_0         //跳到goto_0执行
.end method

函数分为两类:direct method和virtual method
direct method就是private方法,virtual method就是指其余的方法。

调用指令:
invoke-direct
invoke-virtual
invoke-static
invoke-super
invoke-interface

调用格式:
invoke-指令类型 参数1, 参数2,…, L类名;->方法名
如果不是是静态方法,参数1代表调用该方法的实例。

Smali代码示例:

const-string v0, "NDKLIB"
invoke-static v0, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

相当于java代码:System.loadLibrary(“NDKLIB”)

函数返回结果
Smali需要用指令move-result或move-result-object来保存函数返回的结果

Smali代码示例:

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

表示将方法t返回的String对象保存到v2中。


以上是关于android-smali记录的主要内容,如果未能解决你的问题,请参考以下文章

Android-smali语法学习

测试指令元素时未定义父级

GetOrgChart:尚未定义父节点的节点

具有自定义父级的 Spring Boot 父级 pom

在 wpf C# 中禁用自定义父项时启用子控件

如何在 BeautifulSoup ISO 标签中转义父属性实际上命名为 <parent>?