大家好,又见面了,我是你们的朋友全栈君
反编译目的
反编译apk:1
对apk应用进行激活成功教程并重新打包,反编译就是逆向的过程。 Android apk是用高级语言源代码,通常是Java,对apk的逆向智能转换成汇编语言,即Smali。 这次反编译的目的是为了学习apk的软件安全,了解apk的编译过程。
现有一个apk的开启界面如下(夜神模拟器打开):
代码语言:javascript复制实现:
1. 屏蔽"服务器地址"的文本框,让用户无法选中文本框。
2. 为该apk添加开机启动。
需要的环境和工具
工具
- apktool 对apk进行解包和打包操作。 解包:提取apk的资源文件 打包:对apk的资源文件重新打包 注:打包后的apk是未签名状态 官网下载地址:https://ibotpeaches.github.io/Apktool/
- dex2jar 提供jar转dex、dex转jar、dex转smali等等工具。 官网下载地址:https://sourceforge.net/projects/dex2jar/
- jd-gui 反编译器,将jar文件解析为Java文件。 官网下载地址:http://java-decompiler.github.io/
- autosign Android签名工具,是专为安卓系统开发的打包签名工具。 百度来源地址:http://www.ddooo.com/softdown/76655.htm
- android_nixiang 一款针对安卓平台的强大逆向辅助软件。 百度来源地址:https://www.zdfans.com/html/17408.html
以上工具资源均已存网盘:https://pan.baidu.com/s/1z7R2w9_vCxspI5FNSUM2GQ 提取码:keu8
- 夜神模拟器 官网下载地址:https://www.yeshen.com/
注:夜神模拟器的安装目录下有自带的adb.exe,本案例将使用adb.exe模拟apk的安装,
建议把adb.exe添加到环境变量里,方便运行
环境
- Java
Android逆向工程基本都要用到Java语言,并且
jar
文件的运行依赖于Java环境,所以需要安装Java的运行时环境。 通常用到的Java分为两种,运行时环境JRE
和开发工具JDK
,在官网可下载。 这里要明确需要哪种环境,如果需要运行Java程序,只需安装JRE
就可以了。如果需要编写Java程序,需要安装JDK
。 本案例只需要Java的运行时环境JRE
,安装完成后需要手动给JRE
目录添加到环境变量。 配置环境变量参考:https://blog.csdn.net/iiiiiilikangshuai/article/details/80289268 Java环境介绍:https://www.cnblogs.com/lsw9/p/8685623.html - Eclipse
Eclipse是编写Java的编辑器(IDE),本案例使用Eclipse IDE来修改
Smali
代码片段 官网下载地址:https://www.eclipse.org/downloads/packages/ Eclipse支持多种编程语言,用的Java语言就下载Java EE IDE
反编译流程
apk反编译大致过程如下:
代码语言:javascript复制 1. 用apktool对apk进行解包,解包后的文件夹更名为test,文件夹导入Eclipse
2. test.apk用WinRAR打开,提取classes.dex文件到dex2jar文件夹
3. 当前目录下打开cmd,执行d2j-dex2jar.bat classes.dex -o test.jar 得到test.jar
4. 使用jd-gui打开test.jar, File -> Save All Sources 重命名test.src.zip,导出源文件
5. 解压test.src.zip,将test.src文件夹导入Eclipse
6. Eclipse对应 test(Smali汇编码) 和 test.src(Java源代码) , 修改Smali片段实现Android开机自启
7. apktool对test重新打包,使用autosign工具或android_nixiang工具对test.apk进行签名
8. 打开夜神模拟器测试安装test_sign.apk
9. 使用adb.exe模拟发送Android开机的广播报文测试开机自启
apktool解包
将test.apk复制到apktool目录下执行cmd命令
代码语言:javascript复制apktool.bat d test.apk -o test
代码语言:javascript复制解析:apktool.bat d:解包 test.apk:需要解包的apk文件 -o:新建目录 test:目录名称
导入到Eclipse File -> Open Projects from File System
加壳或混淆过的apk提取出来的目录结构跟本案例的不同,本案例用的是没有加壳也没有混淆的apk。 本案例提取后的目录结构:(目录结构不完全相同,看apk的结构)
代码语言:javascript复制——— test
|———— lib
|———— original
|———— res
|———— smali
|———— unknown
|———— AndroidManifest.xml
|———— apktool.yml
lib:
存放.so
后缀的库文件
original:
存放软件的签名信息,保证apk包的完整性,META-INF/CERT.RSA
文件存放apk的数字签名信息。
res: 存放apk的所有静态资源,如图片、xml等。
smali: 存放apk反编译后的汇编语言文件。修改apk的内容可直接在这里边修改。
unknown: 存放一些txt文本文件和没有编译过的源文件等。
AndroidManifest.xml: 项目的总配置文件,也是项目的入口文件,记录应用中所使用的各种组件。
apktool.yml: 记录apk的版本号、文件名、资源文件数量等等信息。
导出apk的源代码
test.apk用WinRAR打开,提取里边的classes.dex文件到dex2jar目录,执行cmd命令
代码语言:javascript复制d2j-dex2jar.bat classes.dex -o test.jar
代码语言:javascript复制解析: d2j-dex2jar.bat classes.dex:需要转换的文件 -o:新建文件 test.jar:文件名称
jd-gui打开test.jar
File -> Save All Sources
重命名test.src.zip,导出源文件
解压test.src.zip并导入到Eclipse (图片省略)
修改Smali代码
打开Eclipse,test.src
是apk的源代码,test
是apk编译后的源代码。
首先打开test目录的AndroidManifest.xml
,找到以下代码片段,就是apk的入口文件。
<activity android:label="@string/app_name" android:name="com.test.ui.LoginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
android:name
字段的值就是该apk的入口文件
在Eclipse里按Ctrl H
查找LoginActivity
, 选择File Search
模式查找。
Eclipse分屏打开.java
和.smali
的文件, 双击文件隐藏Project Explorer
。
无法选中文本框
让用户无法选中指定的文本框,我用的方法是在xml文件里找到对应的控件里添加android:focusable="false"
属性。
apk的界面文件通常放在res/layout
文件夹里。
通过全局查找"服务器地址"
找到对应的<string name="server_address">服务器地址</string>
标签。
再全局查找server_address
字段,找到xml文件里对应的EditText
控件。
<LinearLayout android:layout_gravity="center_horizontal" android:orientation="horizontal" android:layout_width="600.0dip" android:layout_height="wrap_content" android:layout_marginTop="20.0dip">
<TextView android:textSize="23.0dip" android:textStyle="bold" android:textColor="@color/white" android:gravity="right" android:id="@id/hosturl_textview" android:layout_width="150.0dip" android:layout_height="wrap_content" android:text="@string/server_address" />
<EditText android:textSize="23.0sp" android:textColor="@color/white" android:id="@id/hosturl_edittext" android:background="@color/color_666666" android:padding="5.0dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="10.0dip" />
</LinearLayout>
其中android:text="@string/server_address"
就是EditText
控件引用了<string name="server_address">服务器地址</string>
标签的值。
在EditText
控件标签的最后添加android:focusable="false"
属性,即可实现无法选中该文本框。
添加开机自启
当Android启动时,会发出一个系统广播,内容为ACTION_BOOT_COMPLETED
,它的字符串常量表示为android.intent.action.BOOT_COMPLETED
。只要在程序中“捕捉”到这个消息,再启动之即可。记住,Android框架说:Don’t call me, I’ll call you back。我们要做的是等到接收这个消息,而实现的手段就是实现一个BroadcastReceiver
。
实现BroadcastReveiver
需要根据Java源码去分析Smali源码,并在合适的位置添加相应的Smali源码,实现开机自启。
首先在test的UI层,即LoginActivity
所在的目录。添加StartBroadcastReceiver.smali
和StartBroadcastReceiver$1.smali
两个文件,源码如下:
Smali源码
StartBroadcastReceiver.smali
.class public Lcom/test/ui/StartBroadcastReceiver;
.super Landroid/content/BroadcastReceiver;
.source "StartBroadcastReceiver.java"
# instance fields
.field private mHandler:Landroid/os/Handler;
# direct methods
.method public constructor <init>()V
.locals 2
.prologue
.line 17
invoke-direct {
p0}, Landroid/content/BroadcastReceiver;-><init>()V
.line 21
new-instance v0, Landroid/os/Handler;
invoke-static {
}, Landroid/os/Looper;->getMainLooper()Landroid/os/Looper;
move-result-object v1
invoke-direct {
v0, v1}, Landroid/os/Handler;-><init>(Landroid/os/Looper;)V
iput-object v0, p0, Lcom/test/ui/StartBroadcastReceiver;->mHandler:Landroid/os/Handler;
return-void
.end method
# virtual methods
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
.locals 6
.param p1, "context" # Landroid/content/Context;
.param p2, "intent" # Landroid/content/Intent;
.prologue
const/4 v3, 0x0
.line 26
invoke-virtual {
p2}, Landroid/content/Intent;->getAction()Ljava/lang/String;
move-result-object v2
const-string v3, "android.intent.action.BOOT_COMPLETED"
invoke-virtual {
v2, v3}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v2
if-eqz v2, :cond_0
.line 27
iget-object v2, p0, Lcom/test/ui/StartBroadcastReceiver;->mHandler:Landroid/os/Handler;
new-instance v3, Lcom/test/ui/StartBroadcastReceiver$1;
invoke-direct {
v3, p0, p1}, Lcom/test/ui/StartBroadcastReceiver$1;-><init>(Lcom/test/ui/StartBroadcastReceiver;Landroid/content/Context;)V
const-wide/16 v4, 0x2710
invoke-virtual {
v2, v3, v4, v5}, Landroid/os/Handler;->postDelayed(Ljava/lang/Runnable;J)Z
.line 36
:cond_0
return-void
.end method
StartBroadcastReceiver$1.smali
.class Lcom/test/ui/StartBroadcastReceiver$1;
.super Ljava/lang/Object;
.source "StartBroadcastReceiver.java"
# interfaces
.implements Ljava/lang/Runnable;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/test/ui/StartBroadcastReceiver;->onReceive(Landroid/content/Context;Landroid/content/Intent;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Lcom/test/ui/StartBroadcastReceiver;
.field final synthetic val$context:Landroid/content/Context;
# direct methods
.method constructor <init>(Lcom/test/ui/StartBroadcastReceiver;Landroid/content/Context;)V
.locals 0
.param p1, "this$0" # Lcom/test/ui/StartBroadcastReceiver;
.prologue
.line 31
iput-object p1, p0, Lcom/test/ui/StartBroadcastReceiver$1;->this$0:Lcom/test/ui/StartBroadcastReceiver;
iput-object p2, p0, Lcom/test/ui/StartBroadcastReceiver$1;->val$context:Landroid/content/Context;
invoke-direct {
p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public run()V
.locals 3
.prologue
.line 34
new-instance v0, Landroid/content/Intent;
iget-object v1, p0, Lcom/test/ui/StartBroadcastReceiver$1;->val$context:Landroid/content/Context;
const-class v2, Lcom/test/ui/LoginActivity;
invoke-direct {
v0, v1, v2}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
.line 35
.local v0, "mBootIntent":Landroid/content/Intent;
const/high16 v1, 0x10000000
invoke-virtual {
v0, v1}, Landroid/content/Intent;->setFlags(I)Landroid/content/Intent;
.line 36
iget-object v1, p0, Lcom/test/ui/StartBroadcastReceiver$1;->val$context:Landroid/content/Context;
invoke-virtual {
v1, v0}, Landroid/content/Context;->startActivity(Landroid/content/Intent;)V
.line 37
return-void
.end method
Java源码
StartBroadcastReceiver.java
package com.test.ui;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
public class StartBroadcastReceiver extends BroadcastReceiver
{
private Handler mHandler = new Handler(Looper.getMainLooper());
public void onReceive(Context paramContext, Intent paramIntent)
{
if (paramIntent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
this.mHandler.postDelayed(new Runnable(paramContext)
{
public void run()
{
Intent localIntent = new Intent(this.val$context, LoginActivity.class);
localIntent.setFlags(268435456);
this.val$context.startActivity(localIntent);
}
}
, 10000L);
}
}
}
/* Location: E:apk反编译jd-guitest.src.jar * Qualified Name: com.test.ui.StartBroadcastReceiver * JD-Core Version: 0.6.0 */
apktool打包
添加好Smali
代码后,使用apktool对test重新打包
apktool b test
代码语言:javascript复制解析: apktool b:打包 test:需要打包的文件夹名称
打包之后会在test/dist
目录下生成test.apk (图片省略)
apk签名
本案例使用android_nixiang工具完成apk的签名
autosign工具的使用需要.keystore .pk8 .pem
三个文件,参考:https://blog.csdn.net/zhuweiming9202027/article/details/81501981
到这里就完成了apk的反编译,打包,签名过程了。。
模拟器安装apk
夜神模拟器参考命令如下
代码语言:javascript复制adb devices # 查看连接的模拟器设备
adb kill-server # 删除已连接的所有设备端口
adb connect 127.0.0.1:62001 # 使用62001端口连接模拟器设备
adb root # 获取模拟器设备root权限
adb push [本地文件路径] [模拟器文件路径] # 上传文件到模拟器设备
adb pull [模拟器文件路径] [本地文件路径] # 下载模拟器设备文件到本地
adb shell # 进入模拟器的shell
代码语言:javascript复制adb shell am broadcast -a android.intent.action.BOOT_COMPLETED # 模拟发送安卓的开机广播报文
验证apk
略
参考来源: Smali语法: https://www.cnblogs.com/lee0oo0/p/3728271.html apk反编译技巧: https://www.cnblogs.com/geeksongs/p/10864200.html apk反编译再打包: https://blog.csdn.net/sxk874890728/article/details/80486223 android开机自启: https://blog.csdn.net/u012611644/article/details/80542119 adb shell模拟发送开机广播: https://blog.csdn.net/mqdxiaoxiao/article/details/88854923
- 对apk应用进行激活成功教程并重新打包,反编译就是逆向的过程。 ↩︎
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/193083.html原文链接:https://javaforall.cn