Andriod逆向

xiaoxiao2021-02-28  26

Android软件逆向分析基础 2-1Dalvik虚拟机基本原理

一、DVM简介 1、DVM运行Dalvik字节码 2、Dalvik的的可执行文件是.dex,体积小于JVM的可执行文件.class 3、DVM基于寄存器,JVM基于栈 二、Dalvik汇编语言介绍 1、命名法,如果有3个局部变量和4个参数(包括一个this) v0,v1,v2(局部变量v打头),p0(this),p1,p2,p3(参数p打头) 2、类型描述符 V(void),Z(boolean),B(byte),S(short),C(char),I(int),J(long),F(float),D(double),L(java类),[(数组); DVM寄存器都是32bit,J,D类型需要两个寄存器; 对象类型:Ljava/lang/String;相当于java.lang.String; 一维数组[I=int[],二维数组[[I=int[][]; 对对象里面方法的调用为 Lpackage/name/ObjectName;->MethodName(III)Z,第一个L是指package/name/ObjectName这是一个java类的类型 后面跟的是对象的名称->后面跟的MethodName是方法名,(III)指的是方法有三个参数,都是int类型的,Z指的是方法函数的返回值是boolean 类型的; method(I[[Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String等价于String method(int,int[],int,String,Object[]) 对对象里面变量的调用为 Lpackage/name/ObjectName;->FieldName: Ljava/lang/String;冒号后面的Ljava/lang/String;指的是变量类型 三、程序编译与反编译 apk包由资源文件,dex文件AndroidManifest.xml布局文件三个打包构成,反编译dex文件生成smali文件,可以直接阅读。一般用baksmali

2-2Dalvik汇编语言

.class 后面是类名 .super 后面跟的是基类名 .method 后面跟的是方法 .registers 后面的数字指的是程序使用了几个寄存器 具体的Dalvik指令可以看《Addroid软件安全与逆向分解》第三章

Android控制台可以直接执行的文件格式就是dex。我的实验方法是

先写一个java文件,编译之后得到class文件,再用dx工具得到dex文件

我的java代码是 public class helloworld{ public static void main(String[] args){ System.out.println(“Helloworld!”); } }

得到的dex文件经过baksmali反编译后得到smali代码 .class public Lhelloworld; .super Ljava/lang/Object; .source “helloworld.java”

direct methods

.method public constructor ()V .registers 1

.prologue .line 1 invoke-direct {p0}, Ljava/lang/Object;-><init>()V return-void

.end method

.method public static main([Ljava/lang/String;)V .registers 3

.prologue .line 3 sget-object v0, Ljava/lang/System;->out: Ljava/io/PrintStream; const-string v1, "Helloworld!" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V .line 4 return-void

.end method

2-3Dalvik版的helloworld

编译smali文件,可以用ApkToolBox,同时这里面也有smali.jar文件通过指令编译为 java -jar smali.jar -o classes.dex(输出的可执行文件) Helloworld.smali(源文件)使用ApktoolBox的回编译dex功能也可以,但这时smali文件必须在一个同名的文件夹中,把文件夹拖入

ApkToolBox文件路径中,得到dex文件。

3-1静态分析的概念与定位关键代码

静态分析 1、定义:不运行代码的情况下,阅读反汇编代码来掌握程序功能的一种技术 2、两种方法:阅读Dalvik字节码(反编译dex文件生成的smali文件) 阅读java代码(通过dex2jar生成jar文件,再用jd-gui阅读jar),不过准确性不高

关键代码定位 常用步骤: 1、反编译apk,通常是反编译成smali文件 2、通过AndroidManifest.xml查找主类Activity 3、查看程序的入口函数:主Activity的OnCreat() 4、查看Application类(全局,早于其他类启动)的OnCreate()函数,该函数通常用作授权检测 常用方法: 信息反馈法:运行时信息 特征函数法:运行时行为 顺序查看法:执行流程 代码注入法:添加Log

.class public Lcom/example/administrator/helloworld/MainActivity; //类名 .super Landroid/support/v7/app/AppCompatActivity; //基类名,说明MainActivity是继承的AppCompatActivity .source “MainActivity.java” //源代码文件

instance fields //实例的成员变量,此处为空

direct methods //直接方法

.method public constructor ()V //构造函数(constructor),返回值为void .locals 0 //局部变量0个

.prologue .line 6 invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;-><init>()V //直接调用方法,p0存放this,当前对象 return-void

.end method

virtual methods

.method protected onCreate(Landroid/os/Bundle;)V .locals 1 .param p1, “savedInstanceState” # Landroid/os/Bundle;

.prologue .line 10 invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V .line 11 const v0, 0x7f040019 invoke-virtual {p0, v0}, Lcom/example/administrator/helloworld/MainActivity;->setContentView(I)V .line 12 return-void

.end method

smali文件 MainActivity[Math Processing Error]SNChecker.smali:成员内部类,SNChecker为类名 MainActivity.smali:外部类

3-2Smali文件格式与分析

内部类的表示 this[Math Processing Error]0不是父类的引用,是表示对内部类所在的外部类的引用。此处外部类和父类的概念是不同的) this$X型字段都被指定了synthetic(合成的)属性,表明他们是被编译器合成的,虚构的,非java代码指定的字段 构造函数执行步骤(后两步是任何一个类初始化都有的步骤,第一步只有内部类初始化才需要) 1、保存外部类的引用到本类的一个synthetic字段中 2、调用内部类的父类的构造函数 3、内部类自身初始化

从屏幕截图中可看到,在.class那行,类名是MainActivity$SNChecker,其中MainActivity是主类名,SNChecker是

内部类名,中间用[Math Processing Error]0,他是被编译器合成的虚构 的,不是我们自己写的,内部类SNChecker所在的外部类是MainActivity,所以this$0指向了MainActivity,存在寄存器 p0中。 smali语言中,类直接方法都是在#direct methods中,截图里面13-31行都是这个类的构造函数constructor, constructor是smali构造函数的标准函数名,后面一堆是参数类型和返回值类型。 .local指的是非参数寄存器个数,.param指的是参数寄存器,.param p2,”sn”意思就是变量sn是存在p2寄存器中的。 代码第20行对应上述步骤1,将对外部类的引用保存到本类的p1寄存器中(此处视频中说的是保存到寄存器p1中,但我还是有些疑问,如果是保存在p1中,p1就是非参寄存器,.local后面就不应该是0。还有个问题,就是这样操作之后p1和p0的值是不是就一样了,都指向对外部类的引用),23行对应步骤2,27行对应步骤3,是对内部类成员变量sn的初始化(此处视频课件有错误,严格意义上第27行的代码只是对内部类成员变量sn的初始化,并不算是 调用SNChecker自身的构造函数) Smali语法简单介绍如下: Davlik字节码中,寄存器都是32位的,能够支持任何类型,64位类型(Long/Double)用2个寄存器表示; Dalvik字节码有两种类型:原始类型;引用类型(包括对象和数组) 原始类型:v void 只能用于返回值类型 Z boolean B byte S short C char I int J long(64位) F float D double(64位) 对象类型:Lpackage/name/ObjectName; 相当于java中的package.name.ObjectName;解释如下: L:表示这是一个对象类型 package/name:该对象所在的包 ;:表示对象名称的结束 数组的表示形式: [I :表示一个整形的一维数组,相当于java的int[]; 对于多维数组,只要增加[ 就行了,[[I = int[][];注:每一维最多255个; 对象数组的表示形式: [Ljava/lang/String 表示一个String的对象数组;

方法的表示形式: Lpackage/name/ObjectName;——>methodName(III)Z 详解如下: Lpackage/name/ObjectName 表示类型 methodName 表示方法名 III 表示参数(这里表示为3个整型参数) 说明:方法的参数是一个接一个的,中间没有隔开; 字段的表示形式: Lpackage/name/ObjectName;——>FieldName: Ljava/lang/String; 即表示: 包名,字段名和各字段类型 有两种方式指定一个方法中有多少寄存器是可用的: .registers 指令指定了方法中寄存器的总数 .locals 指令表明了方法中非参寄存器的总数,出现在方法中的第一行 方法的传参: 当一个方法被调用的时候,方法的参数被置于最后N个寄存器中; 例如,一个方法有2个参数,5个寄存器(v0~v4) 那么,参数将置于最后2个寄存器(v3和v4) 非静态方法中的第一个参数总是调用该方法的对象; 说明:对于静态方法除了没有隐含的this参数外,其他都一样 寄存器的命名方式: V命名 P命名 第一个寄存器就是方法中的第一个参数寄存器 比较:使用P命名是为了防止以后如果在方法中增加寄存器,需要对参数寄存器重新进行编号的缺点 特别说明一下:Long和Double类型是64位的,需要2个寄存器 例如:对于非静态方法 LMyObject——>myMethod(IJZ)V; 有4个参数:LMyObject,int,long,bool; 需要5个寄存器来存储参数; P0 this P1 I (int) P2,P3 J (long) P4 Z(bool)

相关链接:http://bbs.ichunqiu.com/thread-9017-1-1.html?from=csdnJG

转载请注明原文地址: https://www.6miu.com/read-2400279.html

最新回复(0)