安卓逆向入门笔记(一)——apk文件结构

查看 79|回复 5
作者:sigewangdaiduie   
最近在看正己大佬的安卓逆向教程,我顺便了解了些相关的基础知识,我就想把这些基础知识做个汇总,若有错误请大佬指正!
一、apk文件结构
APK是Android Package的缩写,即Android安装包。而apk文件其实就是一个压缩包,我们可以将apk文件的后缀改为.zip来观察apk中的文件。


image-20230416210158031.png (113.64 KB, 下载次数: 0)
下载附件
2023-5-3 22:47 上传

我们来了解当中一些常见的文件和文件夹:
assets文件夹
assets 这里存放的是静态资源文件(图片,视频等),这个文件夹下的资源文件不会被编译。不被编译的资源文件是指在编译过程中不会被转换成二进制代码的文件,而是直接被打包到最终的程序中。这些文件通常是一些静态资源,如图片、音频、文本文件等。
lib文件夹
lib:.so库(动态链接库)。APK文件中的动态链接库(Dynamic Link Library,简称DLL)是一种可重用的代码库,它包含在应用程序中,以便在运行时被调用。这些库通常包含许多常见的函数和程序,可以在多个应用程序中共享,从而提高了代码的复用性和效率。
META-INF文件夹
META-INF:在Android应用的APK文件中,META-INF文件夹是存放数字签名相关文件的文件夹,包含以下三个文件:
[ol]
  • MANIFEST.MF:MANIFEST.MF文件是一个摘要清单文件,它包含了apk文件中除自己以外所有文件的数字摘要。
  • CERT.SF:CERT.SF文件是用于存储通过私钥加密后得到的MANIFEST.MF文件的数字签名信息以及MANIFEST.MF文件中数字摘要的数字签名信息。
  • CERT.RSA:CERT.RSA文件包含了CERT.SF文件的数字签名和对文件签名时所使用的数字证书。
    [/ol]
    总之,META-INF文件夹中的文件是用于保护APK文件的完整性和真实性的重要文件,可以确保APK文件来自合法的开发者,并且没有被篡改过。
    现在看这些东西是不是有些不明白?什么是数字摘要、什么是数字签名、什么是数字证书什么的,没事,我们接下来讲解这些东西,让你搞明白。
    APK签名机制原理
    问:什么是数字摘要?
    答:数字摘要是一种数学算法,将任何长度的数据转换为固定长度的唯一字符串,而且不同的明文通过Hash算法转换成固定长度的密文,其结果总是不同的,而同样的明文其摘要必定一致。数字摘要通常用于数据完整性验证和加密技术中,以确保数据在传输或存储过程中没有被篡改或损坏。数字摘要算法是单向的,即无法通过数字摘要反推出原始数据。常见的数字摘要使用的Hash算法有MD5、SHA-1、SHA-256等。这里插一嘴,现在MD5在有的情况下已经不安全了,可能会出现不同的数据加密成相同的密文,因为明文的排列是有无数种可能的,而MD5所转换的密文长度是固定的128位,无限的数据对应有限的长度是不可能永远让不同的数据转换为不同的内容的。
    问:为什么会出现数字签名?
    答:要回答这个问题说来话长,我们要先从信息的传输开始讲起。
    对称加密:
    这天小红和小明在教室里通过纸条来传递信息,但小红和小明间隔甚远,需要经过其他同学帮助才能成功传输信息,在这个过程中是无法保证信息不被泄露的,那为了这个传输的信息不被泄露就需要对信息进行加密,而加密和解密是需要一个双方都知道的密钥来进行的,加密者用密钥对明文进行加密得到密文,解密者用密钥对密文进行解密得到明文,加解密都用同样的密钥,即为对称加密。所以双方该如何确定出一个同样的密钥呢?如果由一方生成密钥,再将密钥发送给对方,那么攻击者也可以获取到密钥,就会导致加解密没有了作用。
    那么什么办法可以解决这个问题呢?可以用非对称加密。
    非对称加密:
    在非对称加密中,密钥总是成对出现的,分别称之为公钥和私钥,私钥由自己安全保管不外泄,而公钥则可以发给网络中的任何人。用其中一把密钥加密的明文只能用另一把密钥进行解密,无法使用同一把密钥进行加解密,比如用公钥进行加密的明文只能用私钥进行解密,公钥自己没法解密。
    你可能还是会有疑问,如果一方将公钥发送给另一方,自己再用私钥对明文进行加密,再把加密的数据给另一方,那这不还是会导致加解密没有了作用?又或者一方将私钥发送给另一方,自己再用公钥对明文进行加密,再把加密的数据给另一方,这不还是会被攻击者获取到私钥从而解密数据?如果非对称加密这么使用确实会出现这种问题,但是非对称加密一般不这么用,而是下面这种操作:
    现在是服务器和浏览器之间的信息传输,它们之间是怎么做才能信息不外泄呢?
    第一步:服务器会将非对称加密中的公钥发送给浏览器,浏览器生成一串随机数字,而这串随机数字使用服务器发送过来的公钥进行加密。
    第二步:将通过公钥加密的随机数字发送给服务器,服务器接收后使用私钥进行解密,这样双方就都得到了一个同样的随机数字,而这个随机数字可以作为对称加密的密钥。
    第三步:使用随机数字作为密钥对真正需要传递的数据进行加密传输。
    这样就算是攻击者拦截到了服务器发送给浏览器的公钥,也只能无济于事,因为通过公钥加密的数据没法通过公钥进行解密。这套流程也被称之为SSL(安全套接字层)。
    这看似很美好,但是这真的无懈可击吗?不,因为服务器和浏览器之间无法得知接收的公钥或者数据来自于谁,这样攻击者可以先将服务器发送的公钥拦截下来替换成自己的公钥,浏览器接收到之后无法辨别这个公钥是来自于谁的,只会傻傻的使用这个公钥对生成的随机数字进行加密,然后返回给服务器,攻击者再将返回的内容拦截下来,通过自己的私钥进行解密,这样攻击者又获得了对称加密的密钥。
    所以想要解决这个问题,那么就需要知道接收到的信息是由谁发送的,这就引出了下一个概念——数字证书。
    数字证书:
    在讲数字证书之前,我们需要知道一个第三方机构——CA机构。CA机构是指数字证书认证机构(Certificate Authority),也称为证书颁发机构。它是一种可信第三方机构,负责颁发数字证书,用于证明数字身份、数字签名等安全通信和交易中的身份验证和数据保护。CA机构通过对证书申请者的身份进行认证,为其颁发数字证书,使得用户可以在网络上进行加密通信、数字签名、身份认证等安全操作,保障网络安全和数据隐私。
    我们来讲讲数字证书和CA机构在身份验证中是扮演一个什么样的角色:
    第一步、服务器会将自己的公钥、域名,还有自己所申请认证证书的CA机构,以及数字摘要的Hash算法、签名算法(用于生成数字签名的加密算法)、数字摘要、原始数据等信息打包在一起发送给自己申请的CA机构,该机构也有一对公私钥对,CA机构会用它的私钥对打包数据中的数字摘要进行加密,得到一个密文,而这个密文就是签名,数字签名生成后会被放在证书中发送给服务器的管理员,而这个证书就叫做TLS证书。
    第二步、服务器将CA机构发送过来的TLS证书代替原本要发送给浏览器的公钥发送给浏览器,浏览器拿到这个证书之后不会选择第一时间相信,而是拿CA机构公开的公钥对证书中的签名进行解密得到数字摘要,浏览器也会从证书中提取出原始数据和数字摘要的Hash算法进行转换,这样就可以获得原始数据的数字摘要,再将这两数字摘要一对比就知道数据在服务器发送过来的途中有没有被篡改了。
    第三步、如果解密后的数字摘要和由原始数据转换成的数字摘要一致,那么浏览器就会从证书中提取出公钥,从而可以安全的进行SSL。
    不过需要注意的是,上面的数字证书是https的验证流程,而apk文件和https在验证数字证书的过程中所用到的算法和流程也有所不同。
    HTTPS所用的数字证书通常需要经过CA机构的认证和颁发。而apk文件的数字证书包含了签名者的公钥、签名算法、签名时间等信息,在Android系统中使用的数字证书,是可以由开发者自行生成和使用。
    Android在安装APK时,会验证APK的数字签名是否合法。验证的过程包括以下几个步骤:
    [ol]
  • 提取APK文件中的数字证书。
  • 从数字证书中提取公钥。
  • 使用公钥对APK文件中的数字签名进行解密,得到数字摘要。
  • 对APK文件进行Hash运算,生成数字摘要。
  • 比较步骤3和步骤4中生成的数字摘要是否一致,如果一致则认为数字签名合法,否则认为数字签名不合法。
    [/ol]
    需要注意的是,数字证书中包含了数字签名的信息,包括签名者的公钥、签名算法、签名时间等。数字签名本身是对APK文件的数字摘要进行加密得到的,而不是对证书进行加密。APK文件中的数字证书通常存储在META-INF目录下的CERT.RSA文件中,在安装APK文件时,Android系统会提取CERT.RSA文件中的数字证书,并使用证书中的公钥对APK文件进行验证,以确保APK的真实性和完整性。如果数字证书无效或不匹配,则会提示安装失败或警告用户安装风险。
    MT管理器使用的签名工具是Android SDK中的apksigner工具。apksigner是一款官方提供的APK签名工具,可以对APK文件进行签名和验证。MT管理器在对APK文件进行修改后,会将修改后的文件打包成一个新的APK文件。然后,MT管理器会调用apksigner工具,对新的APK文件进行签名。签名过程中,apksigner会使用开发者提供的数字证书对APK文件进行签名,并生成新的META-INF目录和CERT.RSA文件。最后,MT管理器会将签名后的APK文件保存到指定位置。
    这里也有一点需要注意:MT管理器只能对已经进行过数字签名的APK文件进行修改和重新签名。因为MT管理器是通过调用Android SDK中的apksigner工具来进行APK签名的,而apksigner要求原本的APK文件必须进行了数字签名才能进行重新签名的操作。所以APK文件没有进行数字签名,apksigner无法对其进行签名操作,从而无法通过MT管理器进行修改和签名。
    AndroidManifest.xml配置文件
    AndroidManifest.xml是Android应用程序中最重要的文件之一,它包含了应用程序的基本信息,如应用程序的名称、图标、版本号、权限、组件(Activity、Service、BroadcastReceiver、Content Provider)等等。在应用程序运行时,系统会根据这个文件来管理应用程序的生命周期,启动和关闭应用程序,管理应用程序的组件等等。
    我们来了解一下AndroidManifest.xml文件的主要组成部分:
    [ol]
  • manifest标签
    [/ol]
    manifest标签是AndroidManifest.xml文件的根标签,它包含了应用程序的基本信息,如包名、版本号、SDK版本、应用程序的名称和图标等等。
  • application标签
    [/ol]
    application标签是应用程序的主要标签,它包含了应用程序的所有组件,如Activity(活动)、Service(服务)、Broadcast Receiver(广播接收器)、Content Provider(内容提供者)等等。在application标签中,也可以设置应用程序的全局属性,如主题、权限等等。
  • activity标签
    [/ol]
    activity标签定义了一个Activity组件,它包含了Activity的基本信息,如Activity的名称、图标、主题、启动模式等等。在activity标签中,还可以定义Activity的布局、Intent过滤器等等。
  • service标签
    [/ol]
    service标签定义了一个Service组件,它包含了Service的基本信息,如Service的名称、图标、启动模式等等。在service标签中,还可以定义Service的Intent过滤器等等。
  • receiver标签
    [/ol]
    receiver标签定义了一个BroadcastReceiver组件,它包含了BroadcastReceiver的基本信息,如BroadcastReceiver的名称、图标、权限等等。在receiver标签中,还可以定义BroadcastReceiver的Intent过滤器等等。
  • provider标签
    [/ol]
    provider标签定义了一个Content Provider组件,它包含了Content Provider的基本信息,如Content Provider的名称、图标、权限等等。在provider标签中,还可以定义Content Provider的URI和Mime Type等等。
  • uses-permission标签
    [/ol]
    uses-permission标签定义了应用程序需要的权限,如访问网络、读取SD卡等等。在应用程序安装时,系统会提示用户授权这些权限。
  • uses-feature标签
    [/ol]
    uses-feature标签定义了应用程序需要的硬件或软件特性,如摄像头、GPS等等。在应用程序安装时,系统会检查设备是否支持这些特性。
    以上是AndroidManifest.xml文件的主要组成部分,它们共同定义了应用程序的基本信息和组件,是应用程序的重要配置文件。现在如果看起来有点懵,没关系,后面实战会使用到它的,那时你或许会有一点对它的理解了。
    res文件夹
    res:资源文件目录,二进制格式。实际上,APK文件下的res文件夹并不是二进制格式,而是经过编译后的二进制资源文件。在Android应用程序开发中,资源文件通常是以XML格式存储的,如布局文件、字符串资源、颜色资源等。在编译时,Android编译器会将这些XML资源文件编译成二进制格式的资源文件,以提高应用程序的运行效率和安全性。虽然res文件夹下的二进制资源文件不能直接编辑和修改,但是开发者仍然可以通过Android提供的资源管理工具,如aapt、apktool等,来反编译和编辑这些资源文件的。
    在res文件夹中,主要包含以下子文件夹和文件:
    [ol]
  • drawable:该文件夹包含了应用程序中所有的图片资源,如icon、背景图等。
  • layout:该文件夹包含了应用程序中所有的布局文件,如activity布局、fragment布局等。
  • values:该文件夹包含了应用程序中所有的字符串、颜色、样式等资源,如strings.xml、colors.xml、styles.xml等。
  • anim:该文件夹包含了应用程序中所有的动画资源,如补间动画、逐帧动画等。
  • menu:该文件夹包含了应用程序中所有的菜单资源,如选项菜单、上下文菜单等。
  • xml:该文件夹包含了应用程序中所有的XML资源,如AndroidManifest.xml、preferences.xml等。
    [/ol]
    在Android应用程序中,res文件夹中的资源文件可以通过R类来访问和使用。R类是由Android编译器自动生成的一个类,它包含了应用程序中所有资源的ID值,可以通过这些ID值来访问和使用应用程序中的资源。
    那R类和res文件夹的关系是怎么样的呢?
    R类与res文件夹下的资源文件之间的关系如下:
    [ol]
  • R类的包名与应用程序的包名相同,即com.example.myapp。
  • R类中的子类与res文件夹下的子文件夹相对应,如R$drawable对应drawable文件夹,R$layout对应layout文件夹($前面的类名表示表示子类,$后面的类名表示父类)。
  • R类中的每个子类都包含了对应资源文件的ID值,如R$drawable中包含了所有drawable文件夹下的图片的ID值。
  • R类中的ID值是由Android编译器自动生成的,每个ID值都是唯一的,可以通过这些ID值来访问和使用对应的资源文件。
    [/ol]
    为了更好的理解这玩意实战中的作用,我们来进行次实战——将程序的默认启动activity改为我们自己的activity。
    我这里使用的是apktool。
    第一步:先把要反编译的apk文件放到apktool所在的文件夹
    第二步:在此文件夹中打开powershell并且输入cmd
    第三步:输入命令:apktool.bat d 要反编译的apk文件名


    image-20230420212109337.png (56.62 KB, 下载次数: 0)
    下载附件
    2023-5-3 22:49 上传

    完成上面步骤后在apktool文件夹中就会生成一个与要反编译的apk文件同名的文件夹,反编译的结果就在里面


    image-20230420214726321.png (29.09 KB, 下载次数: 0)
    下载附件
    2023-5-3 22:50 上传

    我们下一步需要通过反编译查看Java源码,这里使用的是dex2jar。
    第一步:将apk文件修改为.zip后缀后将.dex文件解压到dex2jar目录下
    第二步:在dex2jar目录下使用命令行中输入“d2j-dex2jar.bat ”命令运行dex2jar工具
    第三步:等待dex2jar工具完成转换。转换完成后,会在dex2jar目录下生成一个与.dex文件同名的.jar文件,这个就是源码了


    image-20230420215456022.png (109.72 KB, 下载次数: 0)
    下载附件
    2023-5-3 22:51 上传

    我们使用jd-gui打开刚才得到的源码,大概就是这个样子:


    image-20230421000701735.png (122.04 KB, 下载次数: 0)
    下载附件
    2023-5-3 22:52 上传

    这些工具在爱盘中都有存放,可以直接拿来使用。
    环境配置好,我们接下来就正式进行实战操作了:
    第一步:写一个简单的Activity和布局文件。
    Activity:
    .class public Lcom/zj/wuaipojie/ui/MyActivity;  // 定义一个公共类,类名为 MyActivity,包名为 com.zj.wuaipojie.ui。
    .super Landroidx/appcompat/app/AppCompatActivity;  // 继承自 AppCompatActivity 类。
    .source "MyActivity.java"  // 源代码文件名为 MyActivity.java。
    # direct methods  // 下面定义直接方法。
    .method public constructor ()V  // 构造函数,无参数,返回值为 void。
        .locals 0  // 声明本地变量个数为 0。
        .line 7  // 代码行号为 7。
        invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;->()V  // 调用父类的构造函数。
        return-void  // 返回 void 类型。
    .end method  // 定义结束。
    # virtual methods  // 下面定义虚方法。
    .method protected onCreate(Landroid/os/Bundle;)V  // onCreate 方法,参数类型为 Bundle,返回值为 void,是一个保护方法,子类可以访问。
        .locals 0  // 声明本地变量个数为 0。
        .line 11  // 代码行号为 11。
        invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V  // 调用父类的 onCreate 方法。
        const p1, 0x7f0b0040  // 将常量赋值给 p1。
        .line 12  // 代码行号为 12。
        invoke-virtual {p0, p1}, Lcom/zj/wuaipojie/ui/MyActivity;->setContentView(I)V  // 调用 setContentView 方法,设置布局文件。
        return-void  // 返回 void 类型。
    .end method  // 定义结束。
    布局文件:
       
       
       
    第二步:将Activity和布局文件放到反编译得到的文件夹中去,并定义好对应的资源ID。
    找Activity文件的位置我是使用MT管理器去查找一个Activity文件,得到该文件的路径,然后我就顺着路径找了过去,就这样我将我写的Activity放到了里头:


    image-20230421213758733.png (131.02 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:13 上传

    放好了Activity文件,那布局文件放在哪里呢?之前就提到了res/layout文件夹就包含了应用程序中所有的布局文件,那我们直接将布局文件丢res/layout文件夹里就行了,但到res文件夹中我看到了别的东西:


    image-20230421214139613.png (92.68 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:13 上传

    可以看到上面有好多layout-xx的文件夹,这是为什么呢?layout-xx是Android应用程序中用于支持不同屏幕方向和多语言的布局文件目录,比如:layout-land:用于存放横屏方向下的布局文件,当设备旋转为横屏时,系统会自动加载该目录下的布局文件。
    那我们直接将布局文件丢到layout文件夹中去:


    image-20230421214521117.png (119.55 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:15 上传

    我们添加了一个布局文件,之前说过每一个资源文件都有对应的ID值,我们可以通过这些ID值来访问和使用对应的资源文件。那我们需要去给我们这个布局文件添加资源ID,这怎么搞呢?别急,还记得之前说过R类和res的子文件夹之间的关系吗?我们在res/layout文件夹中添加了布局文件,那么我们需要到R$layout文件中去添加这个布局文件的资源ID:


    image-20230421215118805.png (100.99 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:16 上传

    能看出来规律吗?其实在最底下添加一个资源ID,而这个资源ID的值就是上一个加一。
    这里有个情况,当时我看到R$layout中记录的资源ID与res/layout中的布局文件数量不对等,其实这是因为R类只包含在编译时被引用的资源的ID,而不包含未被引用的资源的ID。
    具体来说,当你在代码中引用一个布局文件时,例如通过setContentView()方法设置Activity的布局,或者通过findViewById()方法获取布局中的控件,实际上是通过R.layout中对应的静态常量来访问该布局文件的ID。如果某个布局文件在代码中从未被引用,那么该布局文件的ID就不会被包含在R类中。
    那我们现在已经定义好了资源ID了吗?还没有,除了这里,我们还需要在一处地方定义我们布局文件的资源ID,那就是values\public.xml文件中。
    values\public.xml是一个用于指定资源ID的XML文件。该文件中包含了一系列的标签,每个标签定义了一个资源的名称、类型和ID。这些资源可以是应用程序内部使用的资源,也可以是外部库或框架中定义的资源。
    反编译后values和values-xx文件夹会在res文件夹下,实则values这些文件以及文件夹就是未反编译时的resources.arsc文件,这里应该是apktool反编译之后把它们放在了一起。。
    但我去那一看,发现一个问题:values\public.xml文件中定义的资源ID数量比R$layout中定义的资源ID多得多。


    image-20230422130538379.png (112.41 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:17 上传

    看这密密麻麻类型为layout的,还有好多类型为layout的没法截下来,可见数量之多,但这不应该呀!R$layout中定义的资源ID数量应该与public.xml文件中定义的资源ID数量一致呀!我找了会,我找到了这些:


    image-20230422125924993.png (106.75 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:21 上传



    image-20230422130010660.png (122.75 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:21 上传

    我发现除了com.zj.wuaipojie下的R类,在com下的其他包里也有R类,那么有没有可能public.xml中定义的资源ID数量是这些R类定义的资源ID数量之和。
    那么我们就先去public.xml文件给我们写的布局文件定义资源ID


    image-20230422153939439.png (128.17 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:22 上传

    开始还看错了,给了个0x7f0b003f,后面去修改R$layout.smali时才发现这个资源ID应该已经存在了,然后在这文本文件中一查确实已经存在,就赶忙修改成了0x7f0b007e。
    我们下一步需要将R$layout.smali中的资源ID和MyActivity中使用的资源ID给修改了。


    image-20230422154621025.png (97.35 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:22 上传



    image-20230422160224569.png (79.86 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:23 上传

    修改完成,我们就完成第二步了!我们的布局文件已经放好并且定义好了资源ID,但是我们的Activity只放到了反编译文件夹中却没有去声明它,那我们下一步就是去声明Activity并设为默认启动。
    第三步:声明Activity并设为默认启动
    我们来看一下配置信息:
    表示这个XML文件使用的XML版本是1.0,编码格式为UTF-8,依赖于外部文档 -->
    标签是清单文件的根标签,xmlns:android="http://schemas.android.com/apk/res/android"它定义了Android命名空间,命名空间用于标识 Android 框架定义的元素和属性,以及应用程序定义的元素和属性。而"http://schemas.android.com/apk/res/android"这个URL将作为Android命名空间用于存储XML元素和属性,并通过命名空间绑定和前缀来简化代码。如果不知道是什么意思,那就理解为这是一个导入库,当使用 Android 标签时,需要在标签前加上 android: 前缀。 -->
       
       
       
       
       
            
            
            
            
            
            
            
                
                   
                   
                

            
            
       
    我们看上面的代码,我们需要去声明我们的Activity并设为默认启动,那就需要将com.zj.wuaipojie.ui.MainActivity替换成我们的Activity,但这样会出现问题的,在《安卓逆向这档事》四、恭喜你获得广告&弹窗静默卡中提到过,一般在启动Activity的时候会预先加载一些数据,这样修改有很大概率会因为某些数据没有加载上从而导致应用出现闪退或者其他奇奇怪怪的问题。
    然后我想使用这个方法——Acitivity切换定位,修改Intent的Activity类名,可是我看到MainActivity没有人调用它,暂时只能是另寻他法了。


    image-20230422215342949.png (73.02 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:24 上传

    现在我能想到的方法就是将我们自己的Activity代替MainActivity的位置,再为MainActivity重新进行声明,我想或许正己大佬讲的预加载数据未加载完全的问题是因为将之后启动的Activity作为主Activity进行默认启动,这样有些之后才会加载的数据在启动时因为未被加载,而之后启动的Activity却先加载了,这样就导致有些数据没有被加载从而出现奇奇怪怪的问题。而我只是将我自己写的Activity进行默认启动,这样貌似没有数据加载不全一说呢!只不过我能力有限,也不知道我的猜想是否正确,但现在别无他法,只能硬着头皮试试看了。
       
       
       
          
             
                
                
             

          
          
          
          
          
          
          
       
    这是经过我修改后的配置文件,为什么要这么改呢?我来讲一下主activity:
         
            
            
         


  • android:exported="true":指定该 Activity 是否可以被其他应用程序调用。如果设置为 true,则表示该 Activity 可以被其他应用程序调用;如果设置为 false,则表示该 Activity 只能被当前应用程序调用。

  • android:label="@string/app_name":指定该 Activity 在应用程序中的显示名称。@string/app_name 表示引用了 strings.xml 文件中的一个字符串资源。

  • android:name="com.zj.wuaipojie.ui.MyActivity":指定该 Activity 的完整类名。

  • action android:name="android.intent.action.MAIN":表示activity作为一个什么动作启动,android.intent.action.MAIN表示作为主activity启动

  • category android:name="android.intent.category.LAUNCHER":表示这个activity为当前应用程序优先级最高的Activity

    现在对主Activity有了解了,但是你现在应该还有一个问题,那就是为什么将自己的Activity代替掉原先的主Activity,而原先的主Activity不需要重新进行声明呢?
    这是因为你将自己写的 Activity 设为主 Activity 启动且优先级最高,那么你只是将自己的 Activity 替换了 MainActivity 在 AndroidManifest.xml 文件中的位置。这样,当应用程序启动时,系统将启动 MyActivity,而不是 MainActivity,但是MainActivity仍然存在于 AndroidManifest.xml 文件中,可以在应用程序中使用。
    第四步:用apktool的打包功能重新打包反编译的apk文件
    在需要重新打包反编译的apk文件所处的文件夹中打开powershell并且输入cmd;
    输入命令:apktool.bat b 需要打包的文件夹 -o 重新打包反编译的apk文件存放的路径
    我输入命令后出现了一个报错:


    image-20230424092419763.png (63.26 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:24 上传

    我去查了一下,这个错误提示是由 APKTOOL 处理 APK 时出现的,提示资源目录名无效。具体原因可能是因为你的资源目录名包含了非法字符,比如空格或其他特殊字符,导致 APKTOOL 无法处理它们。
    这个错误信息中显示了res文件夹下的一个资源目录名为“navigation”,可能是导致错误的原因之一,我们去看看该文件夹:


    image-20230424095021226.png (35.99 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:25 上传

    但是这个文件没法删除,因为R类中有子类对应着这个资源文件夹,我不管怎么改文件名字都出了问题,我只能另寻他法,我查到除了资源文件夹名称无效还有可能是由以下原因导致的:
    [ol]
  • 目录不存在:请检查命令中指定的资源目录路径是否正确,如果路径不正确请修改为正确的路径。如果路径正确但目录不存在,请创建该目录。
  • 目录为空:请检查命令中指定的资源目录中是否包含有效的资源文件。如果目录为空,请将需要的资源文件放入该目录。
  • 权限问题:请确保您具有足够的权限访问命令中指定的目录。如果您不确定是否具有足够的权限,请使用管理员权限运行命令。
  • 其他原因:
    [/ol]
  • 重新安装或更新apktool:如果您的apktool版本过旧或者出现了其他问题,可以尝试重新安装或更新apktool。
  • 使用其他工具进行反编译和回编译:如果apktool无法解决问题,您可以尝试使用其他工具进行反编译和回编译,例如dex2jar和jd-gui等。

    我对以上原因进行检查,排除掉了第一、第二、第三和apktool版本过旧这些原因,现在只剩下了使用其他工具。
    我这里出了问题就不往下搞了,如果想试试可以自己动动手,如果有大佬知道怎么解决,还请麻烦大佬指点一下!
    第五步:重新签名
    重新签名的步骤如下:
    [ol]

  • 首先,需要在电脑上安装Java JDK和Android SDK。

  • 生成一个keystore文件。keystore文件可以用来对应用程序进行签名,以确保应用程序的完整性和安全性。可以使用keytool命令生成keystore文件,步骤如下:
    [ol]

  • 打开命令行窗口。

  • 输入以下命令,生成一个新的keystore文件:
    keytool -genkey -v -keystore  -alias  -keyalg RSA -keysize 2048 -validity 10000
    其中,是你想要保存keystore文件的路径和文件名,是你想要为该keystore设置的别名。
    例如:
    keytool -genkey -v -keystore C:\Users\yourname\keystore.jks -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
    这个命令会生成一个名为“keystore.jks”的keystore文件,并设置一个名为“alias_name”的别名。

  • 你需要输入以下信息来生成证书:
  • 姓名:输入你的名字或公司名。
  • 组织名称:输入你的组织名称或公司名称。
  • 城市或区域名称:输入你所在的城市或区域名称。
  • 省/市/自治区名称:输入你所在的省/市/自治区名称。
  • 国家/地区代码:输入你所在的国家/地区代码,例如US、CN等。

  • 输入一个密码来保护keystore文件,并再次输入以确认密码。
    请注意,这个密码非常重要,因为它将用于保护你的keystore文件。请确保你选择了一个强密码,并将其保管在安全的地方。

  • 生成keystore文件后,你可以使用它来对应用程序进行签名。在使用keystore文件进行签名之前,请确保你已经备份了它,并且保管在安全的地方。
    [/ol]

  • 下载并安装Apktool,它是一个可以反编译APK文件的工具。可以从官方网站下载最新的版本。

  • 打开命令行窗口,进入Apktool所在的文件夹。

  • 在命令行窗口中输入以下命令,反编译APK文件:
    apktool d
    其中,是你要反编译的APK文件路径。
    例如:
    apktool d C:\Users\yourname\test.apk
    这个命令会将名为“test.apk”的文件反编译到当前目录中的一个文件夹中。

  • 在反编译后的文件夹中找到“META-INF”文件夹,长按并选择“删除”。

  • 在文件夹中找到“build.gradle”文件,用文本编辑器打开该文件,将以下代码添加到文件末尾:
    signingConfigs {
       release {
           storeFile file("")
           storePassword ""
           keyAlias ""
           keyPassword ""
       }
    }
    buildTypes {
       release {
           signingConfig signingConfigs.release
       }
    }
    其中,是你的keystore文件的路径,是你的keystore密码,是你在keystore中设置的别名。
    例如:
    signingConfigs {
       release {
           storeFile file("C:\\Users\\yourname\\keystore.jks")
           storePassword "yourpassword"
           keyAlias "alias_name"
           keyPassword "yourpassword"
       }
    }
    buildTypes {
       release {
           signingConfig signingConfigs.release
       }
    }
    这个代码块会告诉Gradle使用你的keystore文件对应用程序进行签名。

  • 在命令行窗口中输入以下命令,重新打包APK文件:
    apktool b
    其中,是你反编译后的文件夹路径。
    例如:
    apktool b C:\Users\yourname\test
    这个命令会将名为“test”的文件夹重新打包成一个APK文件。

  • 在命令行窗口中输入以下命令,使用jarsigner对APK文件进行签名:
    jarsigner -verbose -keystore  -storepass   
    其中,是你的keystore文件的路径,是你的keystore密码,是你要签名的APK文件的路径,是你在keystore中设置的别名。
    例如:
    jarsigner -verbose -keystore C:\Users\yourname\keystore.jks -storepass yourpassword C:\Users\yourname\test\dist\test.apk alias_name
    这个命令会使用名为“alias_name”的别名,对名为“test.apk”的文件进行签名。你需要替换这些参数为你自己的路径、密码和别名。

  • 在命令行窗口中输入以下命令,使用zipalign对APK文件进行优化:
    [/ol]
    zipalign -v 4  
    其中,是你签名后的APK文件路径,是你要生成的优化后的APK文件路径。
    例如:
    zipalign -v 4 C:\Users\yourname\test\dist\test.apk C:\Users\yourname\test\dist\test-aligned.apk
    这个命令会对名为“test.apk”的文件进行优化,并将优化后的文件保存为“test-aligned.apk”。你需要替换这些参数为你自己的路径和文件名。
  • 重新打包完成后,将优化后的APK文件复制到手机中,即可安装和使用。
    [/ol]
    需要注意的是,在进行签名操作之前,需要先生成一个keystore文件,并设置好密码和别名。同时,也需要注意保护好keystore文件和密码,以确保应用程序的安全性。
    重新签名的操作均为我从网上查询所得,如若回编译成功,可以自行试试该方法,当然,你可以去网上另寻他法。如若本篇文章出现错误,请大佬帮忙指错、解惑,谢谢!
    重新签名原理简述:
    当需要对已经签名的apk文件进行重新签名时,需要先将原先的签名文件删除,然后使用keytool和jarsigner等工具生成一个新的签名文件,并将新的签名文件应用到apk文件中。还有一点需要注意,那就是重新签名后的apk文件可能会失去原先签名文件的一些权限,如无法更新原先的应用、无法与其他应用进行交互等。因此,建议在进行重新签名前,先备份原先的签名文件,以便在需要时进行恢复。
    classes.dex文件
    classes.dex文件是应用程序的可执行文件,它是一个被编译过的DEX(Dalvik Executable)文件,是Dalvik虚拟机的格式,用于在Android设备上运行Java应用程序。Dalvik 是 google 专门为 Android 操作系统设计的一个虚拟机,虽然 Android 上的程序是使用 java 来开发的,但是 Dalvik 和标准的 java 虚拟机 JVM 还是两回事,Dalvik VM是基于寄存器的,而 JVM 是基于栈的。
    当Java源码编译后,会生成Java字节码文件,但这些文件并不是classes.dex文件。在Android开发中,Java源码需要通过Android SDK提供的工具链进行编译,并且会被转换成Dalvik虚拟机可以执行的DEX格式,生成classes.dex文件。这个文件包含了应用程序的所有Java类和方法,可以在Android设备上运行。
    APK运行的主要逻辑是由classes.dex文件中的Java代码实现的。这些代码被编译成Dalvik虚拟机可以理解的二进制格式,并且被打包成一个DEX文件。当用户安装应用程序时,系统会将classes.dex文件解压并加载到Dalvik虚拟机中,以执行应用程序的Java代码。
    总之,classes.dex文件是Android应用程序的核心组件之一,包含了应用程序的所有Java代码和资源文件,可以在Android设备上运行。APK运行的主要逻辑是由classes.dex文件中的Java代码实现的,这些代码被编译成Dalvik虚拟机可以理解的格式,并且被打包成一个DEX文件。
    resources.arsc文件
    resources.arsc是Android应用程序的资源文件,是一个二进制文件,包含了应用程序的所有资源信息,例如布局文件、字符串、图片等。它是在应用程序编译过程中生成的,被打包进APK文件中,用于在应用程序运行时加载和使用资源。
    resources.arsc文件可以看作是一个映射表,将资源文件名、类型、值等信息映射到一个唯一的整数ID上。这个ID在R文件中定义,并且可以通过代码中的R类来引用。例如,R.layout.main表示布局文件main.xml对应的ID,R.string.app_name表示字符串资源app_name对应的ID。
    当应用程序运行时,系统会根据R类中的ID来查找对应的资源,并将其加载到内存中,供应用程序使用。这个过程是通过解析resources.arsc文件和R类实现的。通过这种方式,应用程序可以方便地访问和使用资源,而不需要手动处理资源文件的位置和命名等问题。
    看到这你肯定会好奇res文件夹和R类以及resources.arsc文件和R类之间的联系有何不同?
    resources.arsc文件和R类之间的联系和res文件夹和R类之间的联系都是通过ID实现的,但是两者的作用和实现方式有所不同。
    resources.arsc文件是一个二进制文件,包含了应用程序的所有资源信息,例如布局文件、字符串、图片等,以及它们对应的ID。当应用程序运行时,系统会根据R类中的ID来查找对应的资源,并将其加载到内存中,供应用程序使用。这个过程是通过解析resources.arsc文件和R类实现的。
    与res文件夹和R类不同的是,resources.arsc文件和R类之间的联系是在编译时建立的,而不是在运行时。在应用程序编译过程中,资源文件会被转换成二进制格式,并且生成一个对应的ID。这个ID会被写入到resources.arsc文件中,同时也会生成一个对应的常量和资源类型的枚举类,即R类。开发者可以通过R类中的常量来访问和使用资源,而不需要手动处理资源文件的位置和命名等问题。
    总之,res文件夹和R类以及resources.arsc文件和R类之间的联系都是通过ID实现的,但是它们的作用和实现方式有所不同。res文件夹和R类之间的联系是在运行时建立的,通过R类中的ID来访问和使用资源。而resources.arsc文件和R类之间的联系是在编译时建立的,通过R类中的常量来访问和使用资源。
    到这里apk的结构总算讲完了,我们现在讲讲额外的知识点——十六进制状态下的apk文件
    为什么要讲这个呢?因为我闲逛时看到了这篇帖子——[原创]基于APK文件格式的反编译对抗机制-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com),我觉得甚是有趣,就想借着讲apk文件结构顺便把apk文件格式讲了。
    编译后生成的apk文件实质上就是一个.zip的压缩包,是可以直接通过解压缩工具打开和解压,我们先来详细了解一下ZIP文件结构。
    ZIP文件结构
    ZIP格式压缩包主要由三个部分组成:数据区、中央目录记录区和中央目录记录尾部区。
    ZIP文件格式通过中央目录记录尾部区来获取到中央目录区的相对偏移地址。每个中央目录区记录文件的相关信息,包括文件名、文件的压缩方法、未压缩大小、压缩后大小、CRC校验值等等,并记录了数据区的相对偏移地址和大小。数据区中的每个文件被分为一个或多个压缩块,每个压缩块都有本地文件头、文件数据和数据描述段三个部分。本地文件头记录了该文件的一些元数据信息(对数据的描述信息),如是否加密、压缩方法等,文件数据是经过压缩处理的实际数据,数据描述段部分记录的则是该块的大小和CRC校验值等信息。
    看不懂不要紧,这就进行讲解:
    中央目录记录尾部区
    中央目录记录尾部区主要作用是获取到中央目录区的相对偏移地址。


    image-20230426212211248.png (160.96 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:26 上传

    上图是中央目录记录尾部区的字段信息,每个字段的详细解释如下:
    [ol]
  • 签名(4字节):标识该区域的开始,固定值为0x06054b50。
  • 磁盘编号(2字节):指定中央目录记录所在的磁盘编号,如果ZIP文件只有一个磁盘,则该值为0。
  • 中央目录记录起始磁盘编号(2字节):指定中央目录记录的起始磁盘编号,如果ZIP文件只有一个磁盘,则该值为0。
  • 中央目录记录数量(2字节):指定ZIP文件中的中央目录记录数量。
  • 中央目录记录总数(2字节):指定ZIP文件中的中央目录记录总数。
  • 中央目录大小(4字节):指定ZIP文件中的中央目录大小。
  • 中央目录偏移量(4字节):指定ZIP文件中的中央目录相对于ZIP文件起始位置的偏移量。
  • 注释长度(2字节):指定ZIP文件的注释长度,如果没有注释,则该值为0。
  • 注释(可变长度):ZIP文件的注释内容,长度由注释长度字段指定。
    [/ol]


    image-20230426212834993.png (44.23 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:27 上传

    上图中所划的区域就是该ZIP文件的中央目录记录尾部区,我们可以得到中央目录记录区的相对偏移地址为03221000,中央目录记录区的总大小为00028097,中央目录数量为085F。得到了这些信息,我们这就去中央目录记录区一探究竟。
    中央目录记录区
    中央目录记录区是ZIP文件格式中的一个区域,用于存储ZIP文件中的每个被压缩文件的元数据信息。


    image-20230217195619489.png (68.1 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:29 上传

    上图是中央目录记录区的字段信息,每个字段的详细解释如下:
    [ol]
  • 签名(4字节):标识该记录的开始,固定值为0x02014b50。
  • 版本号(2字节):指定ZIP规范的版本号。
  • 版本需要(2字节):指定进行解压缩所需的最低版本号。
  • 通用标志位(2字节):指定一些通用属性,如是否加密、是否压缩、是否有数据描述等。
  • 压缩方法(2字节):指定文件的压缩方法,如存储、缩小、最大压缩等。
  • 文件修改时间(2字节):指定文件的最后修改时间。
  • 文件修改日期(2字节):指定文件的最后修改日期。
  • CRC-32校验值(4字节):指定文件的CRC-32校验值,用于验证文件的完整性。
  • 压缩前大小(4字节):指定文件压缩前的大小,即未压缩时的大小。
  • 压缩后大小(4字节):指定文件压缩后的大小,即压缩后的大小。
  • 文件名长度(2字节):指定文件名的长度。
  • 扩展字段长度(2字节):指定扩展字段的长度。
  • 文件注释长度(2字节):指定文件的注释长度。
  • 磁盘编号开始(2字节):指定该文件的起始磁盘编号。
  • 内部文件属性(2字节):指定该文件的内部属性。
  • 外部文件属性(4字节):指定该文件的外部属性。
  • 相对偏移量(4字节):指定该文件在ZIP文件中的相对偏移量。
  • 文件名(可变长度):指定文件名,长度由文件名长度字段指定。
  • 额外字段 (可变长度): 记录额外的元数据信息,例如文件的注释、扩展属性等。
    [/ol]
    这里再注重解释一下通用标志位字段中数据的含义:
    [ol]
  • 第0位:如果该位被设置为1,则说明该文件被加密。
  • 第1位:如果该位被设置为1,则说明该文件使用了强制压缩算法。
  • 第2位:如果该位被设置为1,则说明该文件使用了一种被废弃的压缩算法。
  • 第3位:如果该位被设置为1,则说明该文件有一个数据描述段。
  • 第4位:保留位。
  • 第5位:保留位。
  • 第6位:如果该位被设置为1,则说明该文件是由一个跨磁盘的文件组成的。
  • 第7位:如果该位被设置为1,则说明该文件是由一个压缩的数据流组成的。
  • 第8位:如果该位被设置为1,则说明该文件的压缩使用了压缩算法以外的其他技术来提高压缩效率。
  • 第9位:如果该位被设置为1,则说明该文件的压缩使用了压缩算法技术来提高压缩效率。
    [/ol]


    image-20230427000724537.png (58.23 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:30 上传

    上图所划区域为中央目录记录区中的第一个中央目录,可以看到它的起始位置为03221000,从中央目录记录尾部区中获取到中央目录记录区的相对偏移位置,跳转到这,这里由一个一个的中央记录目录区组成,每个中央目录记录区记录着一个文件的相关信息,我们拿着上面所说的字段去对应上图所划区域可以得到很多有用信息,但现在要去看看数据区,那就需要获取到中央目录记录区对应文件的相对偏移量,值为00000000,中央目录记录区中记录的文件数据大小通常是看压缩后的大小,该值为3D7C。
    数据区
    数据区是zip格式压缩包最重要的部分,它存储了被压缩的文件内容。在zip格式压缩包中,每个被压缩的文件都会被分成多个小块,并分别存储在数据区中,这些小块被称为压缩块(compressed block)。每个压缩块都有一个头部,用于标识该块的大小、压缩方式以及解压后的大小等信息。
    本地文件头


    image-20230216150923348.png (89.43 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:31 上传

    下面是本地文件头每个字段的详解:
    [ol]
  • 本地文件头标识 (4字节): 记录数据区本地文件头的标识符,固定为 0x04034B50。
  • 解压所需的最低版本号 (2字节): 记录解压该文件所需的最低版本号。如果解压工具版本低于该值,则无法解压该文件。
  • 通用标志位 (2字节): 用于记录一些标志位,例如是否加密、是否压缩、是否有数据描述符等。
  • 压缩算法 (2字节): 记录文件压缩使用的算法,例如Deflate、LZMA、BZIP2等。
  • 文件最后修改时间 (2字节): 记录文件的最后修改时间,以 MS-DOS 格式存储。
  • 文件最后修改日期 (2字节): 记录文件的最后修改日期,以 MS-DOS 格式存储。
  • CRC-32 校验值 (4字节): 记录文件内容的 CRC 校验值,用于验证文件的完整性。
  • 压缩后的文件大小 (4字节): 记录文件压缩后的大小,以字节为单位。
  • 未压缩的文件大小 (4字节): 记录文件未压缩时的大小,以字节为单位。
  • 文件名长度 (2字节): 记录文件名的长度,以字节为单位。
  • 额外字段长度 (2字节): 记录额外字段的长度,以字节为单位。
  • 文件名 (可变长度): 记录文件名,以UTF-8编码格式存储。
  • 额外字段 (可变长度): 记录额外的元数据信息,例如文件的注释、扩展属性等。
    [/ol]


    image-20230427205550785.png (91.45 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:32 上传

    本地文件头记录了该文件的基本属性和元数据信息。
    文件数据
    文件数据紧跟在本地文件头之后,文件数据是被压缩的数据,它们存储在Compressed Data中。Compressed Data的大小是根据文件的实际情况动态计算的,因此文件数据的大小是不固定的。在解压缩时,解压工具会读取Compressed Data中的数据,根据压缩算法和数据进行解压缩,从而还原出原始文件的数据。
    数据描述段
    ZIP文件中的数据描述段是可选的,仅在通用标志位的第 3 位被设置为1时才存在,它紧跟在文件数据的最后一个字节之后。
    数据描述段由三个部分组成:CRC-32校验值、压缩后的大小和压缩前的大小。其中,CRC-32校验值是对文件数据进行校验的一种方法,它可以检测文件数据是否被修改或损坏。
    需要注意的是,ZIP文件的数据描述段是可选的,因此并不是所有的ZIP文件都包含数据描述段。在解压缩时,解压工具会根据数据描述段的存在与否,确定文件数据的压缩前后大小和CRC-32校验值。如果数据描述段不存在,解压工具也可以通过其他方式计算文件数据的压缩前后大小和CRC-32校验值。
    看到这,你可能会好奇中央目录记录区和本地文件头都有字段记录了文件的压缩前后大小、CRC-32校验值等信息,为什么还需要数据描述段?
    因为中央目录记录区和本地文件头中确实包含了文件的压缩前后大小、CRC-32校验值等信息,但这些信息并不是必须的,一些ZIP文件可能不包含数据描述段,或者数据描述段中的信息不完整或不准确。
    具体来说,数据描述段用于存储文件的压缩前后大小和CRC-32校验值等信息,它通常包含在数据区和中央目录记录区中。当解压缩工具读取ZIP文件时,它会首先查找数据区中的数据描述段,如果数据区中没有数据描述段,则会查找中央目录记录区中的数据描述段。如果ZIP文件中都没有数据描述段,则解压缩工具将使用其他方法来计算文件的压缩前后大小和CRC-32校验值。
    因此,中央目录记录区和本地文件头中记录文件的压缩前后大小、CRC-32校验值等信息是非常必要的,它们可以确保ZIP文件可以正确地被读取和解压缩,即使ZIP文件中不包含数据描述段也可以正常解压缩。
    到这里就讲完了ZIP文件结构,我们接下来就开始实战了,下面实战中所用到的工具是WinHex。
    基于ZIP文件格式的反编译对抗
    通用标志位
    我们先来玩玩通用标志位字段,这次使用的测试对象为Smali语法查询_1.0.0.apk文件,我们要做的就是将它修改成一个连我们自己都不知道密码的加密文件。
    我们先来看一下正常的解压和安装文件:


    image-20230429154015283.png (32.01 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:32 上传



    image-20230429154114497.png (367.55 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:33 上传

    我们通过ctrl+f将数据区和中央目录记录区所有记录的通用标志位的第零位换成了1。
    数据区:


    image-20230429172728539.png (148.64 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:33 上传

    中央目录记录区:


    image-20230429172858589.png (116.87 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:34 上传

    我们保存后看看效果:
    解压的时候果然出现没有设置密码要我们输入密码的情况


    image-20230429173237582.png (104.26 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:35 上传

    但是安装该apk文件时是没有任何问题的


    image-20230429173404701.png (370.66 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:35 上传

    而且我使用jadx-jui反编译该文件也是无法反编译的


    image-20230429173729760.png (105.3 KB, 下载次数: 0)
    下载附件
    2023-5-3 23:35 上传

    其他字段的玩法我这里就不演示了,如果对这个感兴趣的话可以去看原文,自己去玩一下、动动手,或许会有新的收获。
    这篇文章到此结束了,可能长度有些长,其他内容只能另开一篇帖子了。我才刚玩安卓逆向,作为安卓逆向的新手,还请给位大佬不吝赐教!

    文件, 应用程序

  • sigewangdaiduie
    OP
      

    审核大大,在细致分区时没有看到安卓原创区,如果是因为分区错误那麻烦改一下分区
    ylsw   

    技术贴!!!!!
    a5546120   

    这么多东西,记不住
    Arcticlyc   

    内容很丰富。太长了,看得头晕
    cnct2021   

    感谢分享,似懂非懂
    您需要登录后才可以回帖 登录 | 立即注册