Lab1 : Android逆向
文章目录
1.1 Android Programming
1.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
这个类,并重写onCreate
,onRequestPermissionsResult
函数。
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
:弹窗。通过AlertDialog.Builder
创建一个弹窗。
通过以上三者,并使用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如下: