返回 登录
0

Andriod逆向

阅读1772

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

评论