SSSL Lab1 : Android逆向

SSSL Lab1 : Android逆向,第1张

概述Lab1:Android逆向文章目录Lab1:Android逆向1.1AndroidProgramming1.1.1任务描述1.1.2BroadcastReceiver1.1.3Service1.1.4AppCompatActivity1.1.5线程中的更改UI1.1.6私有成员变量、函数的访问1.1.7生成应用程序签名1.1.8其它1.2Java2Smali1.2.1任务描 Lab1 : AndroID逆向

文章目录Lab1 : Android逆向1.1 Android Programming1.1.1 任务描述1.1.2 BroadcastReceiver1.1.3 Service1.1.4 AppCompatActivity1.1.5 线程中的更改UI1.1.6 私有成员变量、函数的访问1.1.7 生成应用程序签名1.1.8 其它@L_404_11@1.2.1 任务描述1.2.2 smali选择排序Smali文件结构基本类型对象数组方法声明及调用1.2.3 smali获取主机ip1.3 Smali2Java1.3.1 任务描述1.3.2 step11.3.3 step21.4 Reversing and Repacking1.4.1 任务描述1.4.2 Task 1 Knock the door1.4.3 Task 2 Give me your token1.4.4 Task 3 Call to the NPC1.5 实验难点/反思1.6. 参考资料

1.1 AndroID Programming1.1.1 任务描述​ 创建一个安卓项目,在com.smali.secretchallenge包中实现SecretBootReceiver类,使得这个应用程序能在安卓开机时自动运行,并且自动启动一个后台程序。

​ 在com.smali.secretchallenge中实现SecretService类,这个被SecretBootReceiver启动。这个类的功能包括:获取设备的GPS位置,每3秒显示把位置的经纬度显示到屏幕上。

​ 在应用程序运行时前,需要获得位置权限。在com.smali.secretchallenge包的MainActivity类中需要实现权限获取的请求。

​ 更改线程中的UI。(不允许在另一个线程中更改UI,只能在主线程中更改它。)

需要在单击按钮时创建一个对话框,并显示刚才在文本中输入的内容。

关键字private的目的是保护文件或方法不被类外访问。但由于Java Reflection,这并不一定有效。

实现以下 *** 作:在包classes.jar的PoRELab类中访问私有成员变量curStr;调用私有成员函数privateMethod。

生成应用程序签名。

1.1.2 broadcastReceiver

​ 实验中的SecretBootReceiver继承了androID.content.broadcastReceiver。broadcastReceiver是安卓四大组件之一,用以接受广播信息,并启动相应处理机制。broadcastReceiver需要重写onReceive方法来接收以Intent对象为参数的消息。实验中创建了一个Intent(context, MainActivity.class)并通过context.startActivity来启动MainActivity。

​ 记得在AndroIDManifest.xml中注册receiver:

<receiver androID:name=".SecretBootReceiver">    <intent-filter>        <action androID:name="androID.intent.action.BOOT_COMPLETED" />        <category androID:name="androID.intent.category.LAUNCHER" />    </intent-filter></receiver>
1.1.3 Service

​ Service是一个后台运行的组件,执行长时间运行且不需要用户交互的任务。

​ Service包括两种状态:Started、Bound。通过startService()启动了服务,则Service处于Started状态。一旦启动,Service可以在后台无限期运行,即使启动它的组件已经被销毁。当AndroID的应用程序组件通过bindService()绑定了Service,则Service是Bound状态。Bound状态的服务提供了一个客户服务器接口来允许组件与服务进行交互,如发送请求,获取结果,甚至通过IPC来进行跨进程通信。

​ Service的生命周期:

​ 程序中SecretService继承Service类,重写了onStartCommand方法。onStartCommand中开启了一个新线程,线程执行一个死循环,循环内部调用locationUpdates函数获取GPS信息并输出,然后线程陷入3秒睡眠。于是该应用程序可以实现每3s一次的GPS信息输出。

locationUpdates中使用了androID.location中的方法获取经纬度。通过androID.Widget.Toast将位置信息输出到屏幕上。

这边暂时Toast使用不了,用<uses-permission androID:name="androID.permission.RECEIVE_BOOT_COMPLETED" />开启了权限也不行。

​ 睡了一觉,Toast就可以了。【挠头】:

​ 记得在AndroIDManifest.xml中注册service:

<service    androID:name=".SecretService"    androID:enabled="true"    androID:exported="true" ></service>
1.1.4 AppCompatActivity

​ Activity代表了一个具有用户界面的单一屏幕,如 Java 的窗口或者帧。

​ AndroID 系统初始化它的程序是通过Activity中的 onCreate() 回调的调用开始的。

​ Activity的生命周期如下图:

​ 实验中MainActivity类继承了AppCompatActivity这个类,并重写onCreateonRequestPermissionsResult函数。

onCreate中先调用父类onCreate,然后获取位置权限。获取权限后,开启一个Intent,通过startService启动SecretService这个类。

1.1.5 线程中的更改UI

​ AndroID UI机制:UI *** 作只有一个主线程,app只有这个线程可以处理UI;长时间的代码需要放后台,不能阻塞UI。

​ 可以使用Handler来完成子线程对主线程UI的更改。

Handler:很多功能或 *** 作是不能都放在Activity当中,否则会出现长时间没响应,甚至会出现ANR之类的错误(即5秒内没响应)。把那些费时费力的 *** 作放在另外一个线程 *** 作当中,这样就能够和主线程(UI)线程同步 *** 作,不会出现长时间等待或没响应的 *** 作,使得用户体验大大提高。Handler就是实现上面的功能的一个东西,它接受子线程发送来的数据,并用此数据配合主线程更新UI。

Looper:“循环者”,它被设计用来使一个普通线程变成Looper线程,即不断循环。

AlertDialog:d窗。通过AlertDialog.Builder创建一个d窗。

​ 通过以上三者,并使用Handler.post进行消息传递。

​ 结果如下:

1.1.6 私有成员变量、函数的访问

​ Java的反射机制:Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。在程序运行时动态加载类并获取类的详细信息,从而 *** 作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

​ 导入jar包:将classes.jar包拷贝到app/src/main/libs中,这时候还未导入,需要在这个jar上右键,然后单机add as library,成功导入后如图:

​ 可以看到这个jar包内有BuildConfig和PoRELab两个类,包名是com.pore.mylibrary。通过Class.forname("com.pore.mylibrary.PoRELab")创建一个Class对象,然后写入以下代码:

Method method = c.getDeclaredMethod("privateMethod", String.class, String.class);method.setAccessible(true);FIEld tag = c.getDeclaredFIEld("curStr");tag.setAccessible(true);Object obj = c.newInstance();method.invoke(obj, "hello", tag.get(obj));

​ 即可访问curStr变量,以及调用privateMethod函数(参数是“”hello“)。最终结果可以在Logcat中看到:

1.1.7 生成应用程序签名

​ 为什么要生成签名?

​ AndroID系统要求每一个AndroID应用程序必须要经过数字签名才能够安装到系统中,也就是说如果一个AndroID应用程序没有经过数字签名,是没有办法安装到系统中的!AndroID通过数字签名来标识应用程序的作者和在应用程序之间建立信任关系,不是用来决定最终用户可以安装哪些应用程序。这个数字签名由应用程序的作者完成,并不需要权威的数字证书签名机构认证,它只是用来让应用程序包自我认证的。

​ 主要看了这篇博文生成签名:https://blog.csdn.net/YuEOrange/article/details/86018718。

​ Event Log如下:

1.1.8 其它
1. 调试问题:目前采用输出调试的方法。调用`androID.util.Log`将调试信息写入log中,可以在logcat中通过设置filter来观察调试结果。
 Log.d("deBUG", "information");
1.2 Java2Smali1.2.1 任务描述使用smali写一个选择排序的程序。使用smali写一个获得主机IP的程序。1.2.2 smali选择排序

Smali是用于Dalvik(AndroID虚拟机)的反汇编程序实现。汇编工具(将Smali代码汇编为dex文件)为smali.jar,与之对应的baksmali.jar则是反汇编程序。

smali、dex、java、class的关系:

Smali文件结构

一个Smali文件对应的是一个Java的类,更准确的说是一个.class文件,如果有内部类,需要写成Classname$InnerClassAClassname$InnerClassB…这样的形式

基本类型
类型关键字对应Java中的类型说明
VvoID,只能用于返回类型
Zboolean
Bbyte
Sshort
Cchar
Iint
Jlong (64 bits)
Ffloat
Ddouble (64 bits)
对象

Object类型,即引用类型的对象,在引用时,使用L开头,后面紧接着的是完整的包名,比如:java.lang.String对应的Smali语法则是Ljava/lang/String

数组

一维数组在类型的左边加一个方括号,比如:[I等同于Java的int[]

方法声明及调用

官方Wiki中给出的Smali引用方法的模板如下:

Lpackage/name/Objectname;->Methodname(III)Z

.method和.end method 类似Java大括号{}

.locals 指定方法中非参寄存器总数,出现在方法第一行

.registers 指定方法中寄存器总数

.prologue 表示代码开始

.line 表示java源码行号,用于调试

Dalvik字节码手册

首先写一个Java版本的选择排序:

public static voID select_sort(int[] a) {	for(int i=0;i<a.length;i++) {		int minIndex = i;		for(int j=0;j<a.length;j++) {			if(num[j] < num[minIndex])	{				minIndex = j;			}		}		int temp = num[i];		num[i] = num[minIndex];		num[minIndex] = temp;	}}

翻译成smali:

.method public static select_sort([I)V	.register 	.prologue	array-length v0, p0	const/4 v1, 0x1 #常量赋值	if-ge v1,v0:cond_1	const 	

smali和dex的相互转换需要smali-2.5.2.jarbaksmali-2.5.2.jar这两个包。下载地址。

smali转dex:

java -jar .\smali-2.5.2.jar a Select.smali -o sean_Select.dex

进入安卓系统:

adb shell

创建目录:

mkdir /data/local/tmp/selectSort

回到windows终端,将sean_Select.dex发送给到安卓系统/data/local/tmp/selectSort路径上:

PS D:\YC\study\系统软件安全\lab1> adb push sean_Select.dex /data/local/tmp/selectSortsean_Select.dex: 1 file pushed, 0 skipped. 0.1 MB/s (1048 bytes in 0.014s)

在安卓系统终端运行Select.dex:

dalvikvm -cp sean_Select.dex Select 3 4 1

结果如下:

1.2.3 smali获取主机ip

Java的获取IP的程序:

import java.net.InetAddress;import java.net.UnkNownHostException;public class GetIP{	public static voID main(String args[]) {		StringBuffer res = null;		try {			res = foo(args[0]);		} catch (UnkNownHostException e) {			e.printstacktrace();		}		System.out.println(res);	}	public static StringBuffer foo(String name) throws UnkNownHostException {		StringBuffer res = new StringBuffer();		InetAddress address = InetAddress.getByname(name);		String hostname = address.getHostname();		String hostAddress = address.getHostAddress();		res.append(hostname).append("=").append(hostAddress);		return res;	}}

翻译成smali程序。因为太懒了,没有自己翻。上网找了下java转smali的方式:java->class->dex->smali。

javac GetIP.javajava -jar dx.jar --dex --output=GetIP.dex GetIP.classjava -jar baksmali.jar GetIP.dex

其中dx.jarandroID-sdk\build-tools.0.1\lib里面,输入上述命令后会生成一个out目录,目录里面的就是翻译好的GetIP.smali

.class public LGetIP;.super Ljava/lang/Object;.source "GetIP.java"# direct methods.method public constructor <init>()V    .registers 1    .prologue    .line 4    invoke-direct {p0}, Ljava/lang/Object;-><init>()V    return-voID.end method.method public static foo(Ljava/lang/String;)Ljava/lang/StringBuffer;    .registers 5    .annotation system Ldalvik/annotation/Throws;        value = {            Ljava/net/UnkNownHostException;        }    .end annotation    .prologue    .line 15    new-instance v0, Ljava/lang/StringBuffer;    invoke-direct {v0}, Ljava/lang/StringBuffer;-><init>()V    .line 16    invoke-static {p0}, Ljava/net/InetAddress;->getByname(Ljava/lang/String;)Ljava/net/InetAddress;    move-result-object v1    .line 17    invoke-virtual {v1}, Ljava/net/InetAddress;->getHostname()Ljava/lang/String;    move-result-object v2    .line 18    invoke-virtual {v1}, Ljava/net/InetAddress;->getHostAddress()Ljava/lang/String;    move-result-object v1    .line 19    invoke-virtual {v0, v2}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer;    move-result-object v2    const-string v3, "="    invoke-virtual {v2, v3}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer;    move-result-object v2    invoke-virtual {v2, v1}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer;    .line 20    return-object v0.end method.method public static main([Ljava/lang/String;)V    .registers 3    .prologue    .line 6    const/4 v0, 0x0    .line 8    const/4 v1, 0x0    :try_start_2    aget-object v1, p0, v1    invoke-static {v1}, LGetIP;->foo(Ljava/lang/String;)Ljava/lang/StringBuffer;    :try_end_7    .catch Ljava/net/UnkNownHostException; {:try_start_2 .. :try_end_7} :catch_e    move-result-object v0    .line 12    :goto_8    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V    .line 13    return-voID    .line 9    :catch_e    move-exception v1    .line 10    invoke-virtual {v1}, Ljava/net/UnkNownHostException;->printstacktrace()V    goto :goto_8.end method

windows终端:

java -jar .\smali-2.5.2.jar a GetIP.smali -o sean_GetIP.dexadb push sean_GetIP.dex /data/local/tmp/GetIP

安卓终端:

dalvikvm -cp sean_GetIP.dex GetIP weibo.com

结果如下:

1.3 Smali2Java1.3.1 任务描述将smali文件夹中的文件汇编为Box.dex,然后运行。阅读Checker.smali代码,看懂它的意思。然后写一个能实现其功能的java代码。运行Box.dex,输入StudentID。然后得到一个Encode msg,再跑一遍Box.dex,输入StudentID,会返回True。阅读并理解Encoder.smali代码,然后写一个能实现其功能的java代码。1.3.2 step1

windows终端:

java -jar .\smali-2.5.2.jar a smali -o Box.dexadb push Box.dex /data/local/tmp/Box

安卓终端:

阅读checker.smali,一边读一遍翻译成java:

public class Checker {    private String secret;    public Checker(){secret="key";};    private boolean checkStr1(String S1) {        char[] c1 = S1.tochararray();        int sum = 0, first = 0, second = 0;        for(int i = 0;i < c1.length;i++) {            if(c1[i] != 0x78)                continue;            sum ++;            if(sum == 1)                first = i;            if(sum == 2)                second = i;        }        if(sum != 2 || second-first != 4 || c1[0] != 0x30 || c1[c1.length-1] != 0x39)            return false;        String S2 = S1.substring(0, first);        if(S2.contains(this.secret))            return true;        return false;    }    private int count(String S1) {        char[] c1 = S1.tochararray();        int sum = 0;        for(int i = 0;i < c1.length;i++) {            if(c1[i] == 0x31)                sum ++;        }        return sum;    }    private int func(int n)    {        if(n<=1) return 1;        else return func(n-1)*n;    }    public boolean check(String S1) {        if(S1.length() < 0xc || S1.length() > 0x10)            return false;        String S2 = S1.substring(0,0xa);        String S3 = S1.substring(0xa,S1.length());        int x2 = this.count(S3);        int x3 = this.func(x2);        if(x2 != x3 || this.checkStr1(S2) == false)            return false;        return true;    }}

看懂了它的意思,部分注释已经写在代码上了:返回为true的串由长度由S1和S2组成,S1=“0keyx???x9”,其中"?"可为任何非"x"的字符,S2中应包含2个"1"且S2长度不大于6。

测试结果:

1.3.3 step2

先看看跑Box.dex的效果:

然后阅读Encode.smali,一边理解一边写java:

public class Encoder{    private String algorithm;    private String charSet;    private final String[] hexDigits;    Encoder() {        String[] S1 = new String[0x10];        for(int i = 0;i < 16;i++) {            S1[i] = Integer.toHexString(i);        }        hexDigits = S1;        algorithm = "MD5";        charSet = "utf-8";    }    private String byteArrayToHexString(byte[] B1)    {        StringBuffer ans = new StringBuffer();        for(int i = 0;i < B1.length;i++) {            ans.append(bytetoHexString(B1[i]));        }        return ans.toString();    }    private String bytetoHexString(byte B1) {        int B = B1;        if(B1 < 0)            B &= 0xff;        StringBuilder ans = new StringBuilder();        ans.append(hexDigits[B / 0x10]).append(hexDigits[B % 0x10]);        return ans.toString();    }    private String getSalt() {        StringBuilder ans = new StringBuilder(0x10);        for(int i = 0; i < 16; i++) {            if(new Random().nextBoolean())                ans.append("1");            else                ans.append("0");        }        return ans.toString();    }    public boolean check(String S1, String S2) {        char[] C1 = new char[0x20];        char[] C2 = new char[0x10];        if(S2.length() != 0x30)            return false;        for(int i = 0;i < 0x30;i += 0x3) {            C1[i / 0x3 * 0x2] = S2.charat(i);            C1[i / 0x3 * 0x2 + 1] = S2.charat(i + 0x2);            C2[i / 0x3] =  S2.charat(i + 0x1);        }        String S3 = new String(C2);        StringBuilder S4 = new StringBuilder();        S4.append(S1).append(S3);        String S5 = S4.toString();        try {            MessageDigest dig = MessageDigest.getInstance(algorithm);            StringBuilder str2 = new StringBuilder();            str2.append("");            str2.append(byteArrayToHexString(dig.digest(S5.getBytes(charSet))));            String str1 = new String(C1);            return str1.equals(str2.toString());        } catch(Exception e) {            e.printstacktrace();        }        return false;    }    public String enCoding(String S1) {        String S2 = getSalt();        String S6 = null;        String ans = null;        StringBuilder S3 = new StringBuilder();        S3.append(S1).append(S2);        String S4 = S3.toString();        try{            MessageDigest dig = MessageDigest.getInstance(algorithm);            StringBuilder S5 = new StringBuilder();            S5 = S5.append("");            S5.append(byteArrayToHexString(dig.digest(S4.getBytes(charSet))));            S6 = S5.toString();        }catch(Exception e) {            e.printstacktrace();        }		try{            char[] C1 = new char[0x30];            for(int i = 0;i < 0x30;i += 3) {                C1[i] = S6.charat(i / 0x3 * 0x2);                C1[i + 1] = S2.charat(i / 0x3);                C1[i + 2] = S6.charat(i / 0x3 * 0x2 + 1);            }            ans = new String(C1);        }catch(Exception e) {        	ans = S6;            e.printstacktrace();        }    }}

运行结果:

1.4 reversing and Repacking1.4.1 任务描述

​ 通过apk解包、反编译、重新打包、apk签名完成安卓逆向。

​ 各种工具的下载地址

1.4.2 Task 1 Knock the door

​ 首先下载解包工具apktool_2.4.1.jar,然后命令行输入java -jar apktool_2.4.1.jar d lab.apk解包。

​ 解包之后可以看到文件的组织吧,但主程序是smali格式,是比较难看懂的:

​ 反编译成java需要Jeb工具,Jeb工具要在jdk1.8环境下才能工作,所以jdk环境也要配置好。

​ Jeb我下载的是破解版的jeb-2.2.7.201608151620_crack_qtfreet00,用记事本打开jeb_wincon.bat,加上一句set JAVA_HOME=C:\Program files\Java\jdk1.8.0_121就配置好了。

​ 用Jeb直接打开lab.apk

​ 点击Bytecode,查看Bytecode/HIErarchy,可以看到主程序。选择要看的程序,右键->DecomplIE即可查看其反汇编的java代码。主要的方法是这两个:

public MainActivity() {    super();    this.l0 = 0;    this.l1 = 999999;}public voID buttonClick(VIEw arg5) {    int v5 = this.l0;    if(v5 != this.l1) {        ++v5;        this.l0 = v5;        this.t2.setText(String.format("%d / %d", Integer.valueOf(v5), Integer.valueOf(this.l1)));    }    else {        this.t2.setText(2131427372);        this.t3.setText(PlayGame.getFlag(this.te.getText().toString(), this.ctx));    }}

​ 意思大概是点击button 1000000次才能运行PlayGame。要攻击的话,把对应的smali文件中buttonClick方法if-eq改为if-ne即可。

​ 然后回编译java -jar apktool_2.4.1.jar b lab,报了个错:

error: No resource IDentifIEr found for attribute 'compileSdkVersion' in package 'androID'

​ 不知道这是什么错。最后用java -jar apktool_2.4.1.jar b lab -p framework -o lab.apk强制回编译了QAQ。参考文章。

​ 然后是安装openssl。官网下载地址。装好了之后把bin路径添加到环境变量里面。

​ 然后是给apk签名:

openssl genrsa -3 -out testkey.pem 2048openssl req -new -x509 -key testkey.pem -out testkey.x509.pem -days 10000openssl pkcs8 -in testkey.pem -topk8 -outform DER -out testkey.pk8 -nocrypt

​ 把lab.apk, apksigner.jar, testkey.pk8, testkey.x509.pem,testkey.pem放到同一目录,打包成签好名的lab_signed.apk:

java -jar apksigner.jar sign --cert testkey.x509.pem --key testkey.pk8 --in lab.apk --out lab_signed.apk

然后把新的apk传到安卓设备上:adb install lab_signed.apk,运行:

​ 只需要点击1次button就成功啦~~~

1.4.3 Task 2 Give me your token

​ Task2写在PlayGame这个类里面:

public static String getFlag(String arg8, Context arg9) {        StringBuilder v9 = new StringBuilder("pore");        StringBuilder v1 = new StringBuilder("pore");        StringBuilder v2 = new StringBuilder("pore");        StringBuilder v3 = new StringBuilder("pore");        v9.setCharat(0, ((char)(v9.charat(0) - 4)));        v9.setCharat(1, ((char)v9.charat(1)));        v9.setCharat(2, ((char)(v9.charat(2) + 5)));        v9.setCharat(3, ((char)(v9.charat(3) - 1)));        v1.setCharat(0, ((char)(v1.charat(0) + 4)));        v1.setCharat(1, ((char)(v1.charat(1) + 10)));        v1.setCharat(2, ((char)(v1.charat(2) - 13)));        v1.setCharat(3, ((char)(v1.charat(3) + 7)));        v2.setCharat(0, ((char)(v2.charat(0) - 4)));        v2.setCharat(1, ((char)(v2.charat(1) - 6)));        v2.setCharat(2, ((char)(v2.charat(2) - 11)));        v2.setCharat(3, ((char)(v2.charat(3) + 3)));        v3.setCharat(0, ((char)(v3.charat(0) + 2)));        v3.setCharat(1, ((char)(v3.charat(1) - 10)));        v3.setCharat(2, ((char)(v3.charat(2) + 1)));        v3.setCharat(3, ((char)(v3.charat(3) + 14)));        if(arg8.equals("".concat(v2.toString()).concat(v1.toString()).concat(v9.toString()).concat(v3.toString()))) {            return "You got it! Task2 finished.\nTry to call sth here";        }        return "Welcome to task2";    }

​ 翻译以下,Flag是lightyellowdress~~淡黄的长裙哈哈哈哈。

​ 验证一下:

1.4.4 Task 3 Call to the NPC

​ Task2中给的hint:Try to call sth here。应该是要我们调用下面这个函数:

public static native String skdaga(String arg0) {}

​ 在PlayGame.smali的return前面加两行:

invoke-static {p1}, Lcom/pore/play4fun/PlayGame;->skdaga(Ljava/lang/String;)Ljava/lang/String;move-result-objext p0

​ 然后再次打包QAQ…

​ 成功拿到Flag啦啊啊啊泪目。。。

​ Flag是flag{SmalIISCoolll}哈哈。

1.5 实验难点/反思安卓虚拟机搞了半天。和我机子上的linux系统冲突了。重装了2次自动好了》。。安卓开发并没有真正学会,都是照着样例代码打的。只能说大概了解了各组件的生命周期以及一些安卓的语法。。。不知道安卓怎么调试…只学会了用log输出调试逆向那边感觉还行,都可以用工具来编译or反编译or回编译。回编译那里出了一点问题,目前是用暴力的方法回编译的,并没能真正解决问题。不知道smali怎么调试,就硬跑…还没有在真正理解反射那部分的原理…(自己也是才学Java还没有真正理解最后那个native函数的调用。1.6. 参考资料

[1] AndroidStudio怎样导入jar包

[2] 一篇文章帮你搞定Android中java、class、dex、smali、jar、apk之间的转换关系

[3] Smali基础知识

[4] Dalvik 字节码

[5] 教我兄弟学Android逆向番外02 jeb工具的使用

总结

以上是内存溢出为你收集整理的SSSL Lab1 : Android逆向全部内容,希望文章能够帮你解决SSSL Lab1 : Android逆向所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/1018526.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-23
下一篇2022-05-23

发表评论

登录后才能评论

评论列表(0条)

    保存