MT管理器 论坛:https://bbs.binmt.cc/
使用技巧系列教程:https://www.52pojie.cn/thread-1259872-1-1.html
MT管理器 使用手册
- :https://mt2.cn/guide/
- :https://www.bookstack.cn/read/mt-manual/80b8084f6be128c0.md
- :https://binmt.cc/doc/index.php?s=/1&page_id=1
MT管理器 永久VIP版 v2.15.0 安卓版:https://www.kxdw.com/android/98900.html
1、MT管理器
介绍
MT 管理器是安卓平台上的老牌经典神器,是一款功能强大的工具软件,拥有独具特色的双窗口文件管理和强大的 APK 编辑功能,让你可以在手机上高效地进行各种文件操作以及修改安卓软件。
- 文件复制、移动、创建软链接、重命名、删除、创建文件(夹),文件批量操作。获取 Root 权限后可访问系统目录,挂载文件系统为读写,修改文件权限和所有者。
- 像 WinRAR 那样打开 ZIP 格式文件,可以对 ZIP 内的文件进行删除、重命名、移动,添加/替换外部文件到 ZIP 中,无需解压后再重新打包,同时支持单独解压 ZIP 内的部分文件。
- 自带强大的文本编辑器,可以流畅编辑大文本文件,支持设置是否显示行号、开关自动换行、双指缩放字体大小、自动识别编码、代码语法高亮、自动缩进、正则搜索替换。
- 拥有图片查看、音乐播放、字体预览、执行脚本、文本对比等功能,在侧拉栏中可方便地查看存储设备、FTP连接、书签、后台、工具等。
- APK 编辑功能,主要有 DEX 编辑,ARSC 编辑,XML 编辑,APK 签名、APK 优化、APK 共存、去除签名校验、RES 资源混淆、RES 反资源混淆、翻译模式等。
MT 管理器中的部分功能需要登录后才能使用,部分高级功能需要开通 VIP 会员后才能使用。
登录才能使用的功能
- XML 反编译,但相比 VIP 会员,反编译速度慢,反编译的源码最多 200 行。
- 翻译模式中的自动翻译,普通用户只能使用一个字典,联网翻译引擎只有百度翻译。
会员才能使用的功能
- XML 反编译无任何限制
- XML 资源值智能编辑功能
- Smali 代码转成 Java 代码
- 翻译模式中更多的联网翻译引擎
- 翻译模式中无限字典个数
- APK 共存时自定义包名
- Dex 修复功能
- 导入自定义签名
- Arsc 资源查询功能
- 去除 APK 签名校验
- RES 反资源混淆
每个功能的具体介绍请查阅前面的文档,更多的 VIP 功能还在不断添加中。
基础操作
双窗口操作
打开 MT 管理器后第一眼看到的就是它的左右两个操作窗口,该设计已经是 MT 的标志之一,与之对应的是双窗口操作模式。
MT 没有粘贴文件这个功能,当你进行复制、移动、解压等操作时,是一步完成的。
例如当你复制左边窗口的文件时,那么它将会被直接复制到右边窗口中
辅助操作
- 同步:下方工具栏的第四个按钮,点击后,另一个窗口的路径和文件位置将会和当前窗口同步。如果是在压缩文件中同步,则会跳转到压缩文件所在位置。
- 后退、前进、返回上级:下方工具栏的第一、二、五个按钮,注意后退和返回上级时完全不同的概念,一个是返回到上一个路径,一个是返回到上级目录。
- 存储、书签:打开侧拉栏,可以看到存储器和书签。点击相应存储器可快速进入根目录、内部存储、外置存储等。书签需要自己添加,注意只有当你添加了书签后,才会在侧拉栏中看到书签分组。
文件多选
左右滑动任意一个文件即可选中它,并进入多选状态,然后通过单次点击来选中更多。
进入多选状态后,下方的工具栏会进行相应的变化,从左到右的功能分别变为全选、反选、取消、类选、连选。
- 全选和反选相信大家都懂不多介绍。
- 类选,即按类型选择,例如你选中了一个 txt 文件,点击类选后,当前目录下所有的 txt 文件都会被选中。
- 连选,即连续选择,我们在最新版本中已经简化了操作,你只需要滑动选择第一个文件,再滑动选择第二个文件,就会自动选择它们之间全部文件。你现在点击该按钮只显示操作提示。
文件管理
ROOT 相关
MT 支持以 root 权限身份去管理文件,但这并不意味着使用 MT 一定需要 root 权限,只有当你需要访问 /data 目录,挂载 /system 读写等操作时,才需要 root 权限。
开启获取 root 权限后,MT 会在启动时尝试获取 root 权限。如果您的手机没有 root 或者您拒绝给 MT 授予 root 权限,通过关闭该设置可以提高启动速度。更改该设置后需要重启 MT 才能生效。
要判断 MT 是否已经获取到 root 权限,可以通过以下方式:
- 访问 /data 目录,目录有内容说明有 root 权限。
- 挂载根目录或者 /system 为读写,挂载成功说明有 root 权限。如果上面的方式中,第一个成功但第二个失败,那么可能是您的手机厂商对 root 权限进行了阉割,即 root 不完整,解决方法请根据机型自行上网搜索。
挂载读写
- 有些分区默认是只读的,例如根目录和 /system,我们无法直接修改上面的文件,需要先将它挂载为读写,挂载读写一定需要 root 权限。内置存储是读写的,基本都不支持挂载。挂载的方式是先进入要挂载的目录,然后点击 MT 右上角的菜单,再选择挂载读写/只读。
压缩文件
MT 支持各种 ZIP 的增删改操作和解压 RAR 文件,但目前均不支持加密的压缩文件。另外 ZIP 格式的文件后缀有 .zip .jar .apk。APK 文件实际上也是个 ZIP 格式的文件,点击 APK 后先会显示该应用的相关信息,点击查看后,就可以浏览 APK 的内部文件了。另外有些损坏的 APK 点击后显示打开失败,你可以通过 长按 - 打开方式 - ZIP查看 来浏览它的内部文件。
- 由于 API 限制的原因,操作压缩文件(指打开压缩文件、解压、添加等操作)的内部流程无法走 root 权限的路线,所以当操作压缩文件时,有没有 root 权限时没区别的。
当提示权限不足:
-
解压文件时,不要直接解压到系统目录,而是解压到内部存储中,否则容易遇到权限不足问题。如果一定需要将该文件复制到系统目录,那就先解压到内部存储,再从内部存储复制到系统目录。
-
不要在系统目录中操作压缩文件,不然也容易遇到权限不足问题。有许多新手用户会直接在 /data/app 目录中操作 apk 文件,这是个十分错误的做法,正确的方式是先将 apk 复制到内部存储后再修改,修改完再签名安装。
可以使用 MT 直接往 ZIP 中添加/替换文件,比起传统的全部解压 - 添加/替换 - 重新压缩方式更加高效。
添加文件前有两个可选项,分别是压缩级别和更新方式,其中压缩级别当从 ZIP 往 ZIP 添加文件时是隐藏的,因为添加时是直接复制压缩过的数据,不需要再次压缩。
压缩级别有 7 个选项,最好级别压缩率最高,最快级别压缩率最低,存储则不压缩直接打包,APK 模式则根据被添加的文件类型自动选择压缩级别,在往 APK 中添加文件时,建议选择 APK 模式。
更新方式有 3 个选项
- 全部替换:添加的文件会直接替换掉 ZIP 中已存在的文件
- 更新替换:当添加的文件的修改日期大于 ZIP 中已存在的文件的修改日期时,进行替换,否则跳过。
- 全部跳过:不会替换 ZIP 中已存在的文件,直接跳过。
外置存储
外置存储指用户插入的 SD 卡或者通过 OTG 方式连接的 U 盘,当你的手机连接了外置存储后,可以在 MT 的侧拉栏的存储分组看到它。
文件搜索
可以在本地文件和 ZIP 中进行文件搜索,点击右上角的三个点弹出菜单,再点击搜索即可打开搜索对话框。
填入要搜索的文件名表达式,* 代表匹配 0 或 N 个任意字符,?代表匹配 1 个任意字符。
另外除了搜索指定后缀,MT 在搜索前会对表达式首尾补上 *,不然当你搜索 bcd 时,只能搜索到文件名为 bcd 的文件,而不能搜索到文件名为 abcde 的文件。如果你要搜索指定后缀的文件,则输入 .后缀名,如 .apk
例子
abc 可以搜索到 1abc.txt
ab*c 可以搜索到 1abc.txt 和 1abxxxc.txt
ab?c 可以搜索到1abxc.txt,不能搜索到 1abc.txt 和 1abxxxc.txt
*.apk 可以搜索到 123.apk,不能搜索到 123.apka
- 搜索子目录:勾选后会对子目录进行搜索,否则只搜索当前目录。
- 按文件大小过滤:指定文件大小的范围,不指定时两边都选择无限制,指定之后将不会搜索到文件夹。
- 文件中包含内容:指定文件中包含的内容,可以选择是否区分大小写,不指定时请留空,指定之后将不会搜索到文件夹。
- 查看搜索结果:完成一次搜索后,点击右上角的三个点弹出菜单,再点击搜索结果即可查看上次的搜索结果。
文本编辑
MT 的文本编辑器拥有十分流畅的体验和符合直觉的操作方式。
- 快捷搜索:你可以先选中一段文本,然后点击菜单中的搜索,被选中的文本会自动填到查找内容中,如果已开启了正则表达式搜索,还会提前对文本中的特殊符号进行转义处理。
- 正则替换:当你开启了正则表达式进行文本替换时,替换可以用 $0 表示整个搜索到的文本,$1 - $9 表示子匹配文本。
- 双指缩放:在编辑文本时你可以随时使用两根手指对字体进行放大缩小,可以在设置中关闭该操作。
- 编码切换:打开文件后文本编辑器会自动识别文件编码(目前不支持手动选择),你可以在菜单中切换编码,不过只是影响到保存文件时的编码。
- 编辑大文本:你可以用 MT 编辑无限大小的文本文件,当然前提是可用内存要足够大。当你打开一个大文本文件后,基本可以秒进(具体受手机性能影响),但你可能会看到屏幕上方还有一个无进度条在滑动,说明此时排版还未完成,你只能查看不能编辑,等到无进度条消失后才可以进行编辑,如果你关闭了自动换行,则排版时间会大大减少。当检测到文本字数过多时,还会自动开启流畅模式,你也可以手动在菜单中开启。开启流畅模式后,可以解决编辑大文本时输入法十分卡顿的问题,但也会导致输入法的复制剪切等功能无法使用(自带菜单的功能不受影响)。
文本对比
文本对比是 MT 中藏得比较深的一个功能,采用仿 GitHub 风格的差异对比界面,可以快速找出两个文本文件中改动过的部分。
- 开启方法:注意只支持对本地目录中的文件进行文本对比,不支持压缩文件和 FTP 中的文件。
- 同窗口:滑动选中第一个要对比的文件,再单击选中另一个要对比的文件,然后长按弹出菜单,可看到”文本对比”。
- 双窗口:在一个窗口中滑动选中要对比的文件,再在另一个窗口中滑动选中要对比的文件,然后长按弹出菜单,可看到”文本对比”。
- 双窗口简单版:滑动选中第一个要对比的文件,再长按另一个窗口中要对比的文件,在弹出的菜单中即可看到”文本对比”。
逆向功能
APK介绍
APK 文件是安卓平台的应用安装包,它实际上是一个 ZIP 格式的压缩文件,MT 对 ZIP 压缩文件在各种操作上的支持,为修改 APK 打下了良好的基础。通常一个 APK 文件中包含着以下文件:
- AndroidManifest.xml:应用清单文件,版本号、版本名称、权限、应用名称、应用图标、活动、服务、广播等配置信息,均在这个文件中。
- classes.dex:安卓代码文件,在开发安卓应用时,开发者编写的 Java 代码会先编译成 N 个 class 文件,最后再将它们合并成 classes.dex 文件,所以应用 Java 层的代码基本都在该文件中,有些比较大的应用甚至还有 classes1.dex、classes2.dex…
- resources.arsc:资源配置文件,包含着字符串、主题、图片文件索引、布局文件索引等信息。
- res/:资源文件夹,包含着图片、布局、菜单等文件,resources.arsc 中索引的文件均存放在该目录中(进行过资源混淆的除外)。
- assets/:副资源文件夹,不是每个 APK 中都有它,里面的文件也不会在 resources.arsc 中进行索引。
- lib/:存放 so 文件,该类文件通常由 C / C++ 进行编写,MT 目前不支持修改 so 文件。
- META-INF/:存放签名相关的文件,通常没有什么用。
资源索引
用两个例子来说明资源索引的过程和原理,下面 resources.arsc 统称 arsc 文件,classes.dex 统称 dex 文件。
- 应用名称:APK介绍中提到应用名称定义在 AndroidManifest.xml 文件中,其具体是在 application 标签的 label 属性中,但一般它的值只是一个资源 ID,而具体的值在 arsc 文件中。为什么这样设计呢?主要是为了多国语言支持。然后我们可以根据这个 ID 去 arsc 文件中查找它的具体值。在下图中,应用名称指定为 @7f0e0032,若在中文简体的系统,应用名称是 MT管理器,若在其它语言系统,应用名称是 MT Manager。
- 布局文件:在 dex 文件中,我们查看某个 Activity 的代码,一般它是通过 setContentView(ID) 来加载布局文件,我们同样可以用上面的办法通过这个 ID 拿到具体的值,不过我们通过这个 ID 在 arsc 文件中找到的值应该是像 res/layout/activity_main.xml 这样的路径,可以看出布局资源在 arsc 存储的只是文件路径,具体的内容我们还需要去 APK 中找到这个文件并打开。
除了布局文件,图片文件、菜单文件等也是同样的情况,均在 arsc 文件中存储资源文件路径。
XML编辑
这里提到的 xml 并不是常见的文本格式的文件,而是在 APK 中的 xml 文件,它是二进制格式,如果你将它当成文本文件打开,那么将看到一堆乱码。使用 MT 打开一个 xml 文件时,它将会弹出打开方式菜单,可以选择反编译或者字符常量池,字符常量池只能编辑 xml 中的字符串常量。
通过 MT 管理器的反编译,可以将单个 xml 文件反编译成文本格式,并且 MT 还支持修改后将它编译回去。(反编译 xml 是一个半收费功能,免费版限制了反编译速度、源码行数,无 ID 转名称,无资源值智能编辑。)反编译后至于 xml 该怎么改,改什么,如果你了解安卓开发,自然就知道如何修改。
资源 ID 转名称 - VIP 功能
资源值智能编辑 - VIP 功能
DEX编辑
一个 Android 应用的绝大部分代码(使用 Java 编写)都会编译到 dex 文件中。当你使用 MT 打开一个 dex 文件时,它将会弹出打开方式菜单,你可以选择 Dex 编辑器、Dex 编辑器++、Dex 修复、翻译模式。
Dex 编辑器和 Dex 编辑器++ 均可以修改 dex 文件内的代码,两者均使用了开源项目 JesusFreke/smali 来实现,但 Dex 编辑器用的是 dexlib,已经在多年前停止了维护更新,而 Dex 编辑器++ 使用的是最新版的 dexlib2,和 smali 项目保持同步。推荐使用 Dex 编辑器++
当你遇到某个 dex 文件无法正常打开时,你可以尝试使用 Dex 修复功能。注意必须把 dex 文件解压后才能使用该功能,不能在压缩包内进行修复。使用该功能需要开通 VIP。
- 浏览界面采用树形方式进行包名和类的浏览
- 最近界面记录最近打开的文件和被修改过的文件
- 搜索界面可进行搜索以及显示搜索结果你可以把看到的类都当成一个个 smali 文件,点击进去之后看到的也是这个类对应的 Smali 代码。
- 如果开通了 VIP,还可以在菜单中选择将 Smali 转成 Java 代码,并且 MT 提供了多个 Java 反编译引擎,当你发现 Java 中某个方法反编译失败时,可以尝试切换反编译引擎。
注意反编译出来的 Java 代码只是用作参考,无法修改。要修改的话只能去修改 Smali 代码,然后再重新反编译成 Java 代码,对照查看修改是否正确。做完修改后,你就可以回到编辑器主界面,点击菜单中的编译,生成新的 dex 文件。
DEX 工程
在 Dex 编辑器++ 中,MT 引入了工程这个概念。如果你是使用 Dex 编辑器,每当你修改完退出时,要么选择不保存,要么选择编译成新的 dex 文件,但不论如何,你添加的注释、哪些是新加的类、哪些类被修改了,这些记录都会丢失。
但是我们在修改 dex 文件时,一般不是一遍就能修改完的,需要多次修改和测试,保留上面所说的这些记录就十分有用,而现在,Dex 编辑器++ 都能做到这些。
创建工程
首先要使用 Dex 编辑器++ 打开一个 dex 文件时,此时MT自动为我们创建了一个临时Dex工程。临时工程在退出后是会被删除的,所以你需要点击左上角的菜单,选择保存为工程。
保存完之后,当你在 Dex 编辑器++ 的主界面时,都可以放心地退出,不用担心丢失任何数据,更不用每次退出前还需要手动保存。
打开工程
在 MT 主界面打开侧拉栏,就可以看到你保存的所有工程了。点击就可以打开该工程并进入 Dex 编辑器++。注意,一定要从侧拉栏中打开工程,而不是打开之前的 dex 文件,直接打开 dex 文件是创建临时工程。
编译 Dex
修改完成之后,在 Dex 编辑器++ 的主界面,点击菜单中的编译即可生成新的 dex 文件。
如果你是在临时工程中编译,那么编译后会替换掉原来的 dex 文件。
如果你是在正式工程中编译,那么编译后的 dex 文件会放在工程目录下,你需要手动把 dex 替换到 apk 中。
工程目录
所有工程均放在 内部存储/MT2/projects 文件夹中,不能移动。
侧拉栏中长按工程即可快速进入工程目录。
进入工程目录后可以看到 data 和 smali 两个文件夹。(2.5.0 版本开始支持多dex编辑,新增了 config、build 和 _dex 文件夹)
- _dex 存放编译后的dex文件
- build 存放进行编译时产生的一些文件,可提高下一次编译的速度
- conifg 存放工程配置文件,建议不要自己修改
- data 存放原dex文件和代码缓存,缓存可以提高搜索代码的速度
- smali 存放各个文件夹用于对应不同的dex,每个文件夹存放编辑过的类和自己添加的类我们还可以在工程目录中自行放其它文件,比如可以放apk文件,以方便打包dex。
删除和重命名
所有工程均放在 内部存储/MT2/projects 文件夹中,首先你要进入这个文件夹(可以先快速进入一个工程目录,再返回上级),如果你要删除工程,那么就删掉和工程名字一样的文件夹,同理如果你要重命名工程,那么就重命名对应的文件夹。
初始化时,每个类都是根据它的类名和包名进行存放,当我们在 smali 代码中修改了一个类的类名或包名时,它的位置和名称并不会改变,实际还是以 smali 代码中的定义为准。
举个例子,浏览界面中打开 com/android/example 中的 ClassA,在 smali 第一行定义了它的完整类名 Lcom/android/example/ClassA;,将它改成 Lcom/android/ClassB; 并保存后,你可能以为它会移动到 com/android 中,并且名称变成 ClassB,其实不会,你依旧需要在 com/android/example 中的 ClassA 打开它。
总的来说,smali 的文件名不需要与该文件中定义的类名一样,smali 文件所在的目录不需要与该文件中定义的包名对应,一切以 smali 文件内容中的定义为准。
Dex编辑器++支持搜索代码、类名、方法名、字段名、字符串、整数,可指定搜索路径、是否搜索子目录、是否区分大小写,支持正则表达式,支持在当前搜索结果中搜索,支持撤销搜索。
发起搜索的方式有两种,
- 一是切换到搜索界面,直接点击对应选项,
- 二是在浏览界面长按文件夹,点击弹出菜单中的搜索。
搜索字符串和代码的区别
- 字符串包含于代码。代码就是 smali 代码,而字符串是 smali 代码中的 “xxxxxx”,即引号中的那部分内容。
如何添加外部 smali 文件到工程中?
- 进入工程目录,打开 smali 文件夹,进入某个dex对应的文件夹,把你要添加的 smali 文件复制进去,再次打开工程即可看到添加的文件。
怎么修改 Java 代码?
- 反编译出来的 Java 代码只是用作参考,无法修改。要修改的话只能去修改 Smali 代码,然后再重新反编译成 Java 代码,对照查看修改是否正确。
怎么快速跳转到另一个类?
- 在编辑 smali 代码时,完整选中一个类名,类名以 L 开头 ; 结尾,例如 Lcom/aaa/bbb/ccc;,然后你就可以在弹出菜单中看到跳转,点击后,如果该类存在于当前 dex,就可以直接跳转到它到 smali 代码中。
字符常量池功能在哪?
- 暂时没有该功能,如果需要请使用旧版 Dex 编辑器。
如何往现有工程添加新的dex
- MT管理器从2.5.0开始支持多dex编辑,如果要往现有工程添加新的dex,只需将欲添加的文件重命名去掉 “.dex” 后缀,然后复制到 “工程目录/data/dex” 文件夹内。
ARSC编辑
一个 Android 应用的绝大部分资源配置,例如字符串、主题、图片文件索引、布局文件索引等信息,都保存在 arsc 文件中。当你使用 MT 打开一个 arsc 文件时,它将会弹出打开方式菜单,你可以选择 Arsc 编辑器、翻译模式、资源查询。
Arsc 编辑器功能可以对 arsc 文件中的任意内容进行添加、删除、修改,本章内容会进行详细说明。arsc 的结构,从外层到内层依次是:
- 包(Package)
- 类型(Type)
- 配置(Config)
- 条目(Entry)
- 值(Value)
一般一个 arsc 文件只有一个包,进入 Arsc 编辑器后,在 ID 搜索资源下面的项就是该文件的包。
进入包之后,看到的列表就是类型,其中最左边是包 ID + 类型 ID ,例如 7F01,紧接着的是类型名称,例如 attr、string、style 等。
至于各个类型分别代表什么意思,其实只要你做过 Android 开发,就会发现它和你在 res 目录中定义的资源基本一致。例如 strings.xml 中的字符串数据都可以在 string 类型里面找到,在 drawable 中放置的图片也可以在 drawable 类型里面找到,不过 drawable 类型里面存储的是图片的路径。
进入配置之后,看到的列表就是条目,其中最左边是条目 ID ,例如 0000,紧接着的是资源名称,还可能显示资源值。
补充:一个完整的资源 ID 就是包 ID + 类型 ID + 条目 ID ,例如 7F010000。
翻译模式
翻译模式是专门为翻译应用而开发的一套功能,分别有 Arsc 翻译模式、Xml 翻译模式、Dex 翻译模式,这三大翻译模式基本覆盖了绝大部分 APP 的全部文本。
在翻译一个应用时,要遵循一套准则,优先翻译 arsc,其次翻译 xml,最后再选择性翻译 dex。
- Arsc 翻译模式,首先你要打开待翻译的 apk 里面的 resources.arsc 文件,选择翻译模式,然后就能看到可以翻译的语言包,[DEFAULT] 代表默认语言,zh-rCN代表简体中文。左边显示待翻译的文本,右边显示翻译后的文本。翻译时你可以选择手动翻译、联网翻译、字典翻译,具体会在下面进行说明。在 Arsc 翻译模式的主界面,点击右上角的设置按钮,就可以看到“保存时写出本次翻译数据到 arsc 文件”的选项。
-
Xml 翻译模式:一些应用的部分文字可能不在 arsc 文件,而是在 apk 里面的某些 xml 文件中,而一个 apk 有非常多个 xml 文件,要一个个去查找和翻译显然不方便,而 MT 就可以自动帮你遍历所有 xml 文件,找出所有可以进行翻译的文本。要使用 Xml 翻译模式,首先你要找到并点击需要翻译的 apk,点击功能,就可以在弹出菜单中看到 XML 翻译模式,进入后就可以进入翻译界面。
-
Dex 翻译模式:点击 dex 文件就可以看到翻译模式了,再次点击即可进入。记住 dex 中的文本不要直接去翻译,而是当你做完 Arsc 翻译 和 Xml 翻译时,先测试你翻译完成的应用,如果你看到某个未翻译的文本,去 Dex 文件中搜索它,如果可以找到,再单独地修改它,其它文本不要动,不然很可能造成无法预料的错误。
应用签名
应用签名的主要作用有两个
- 第一个是检验安装包是否被修改,
- 第二个是用于确认签名者的身份。
签名时需要一个密钥文件,同一个密钥文件签名出来的 apk,它的签名身份信息是一样的,使用不同的密钥文件的话,签名身份信息自然不一样。并且除非你能拿到开发者的密钥文件,不然只靠签名信息文件,你是很难在修改过的 apk 文件上伪造出原签名身份信息的。
当修改了一个 apk 后,需要重新签名才能安装(除非你修改了系统),否则系统拒绝安装。
在第一次安装 apk 时,系统压根不知道这个应用的作者是谁,所以它只能检验安装包是否被修改。但是,如果系统已经安装了这个应用,当你覆盖安装时,系统会把已安装和正在安装的 apk 的签名者信息进行对比,如果不一致,也会拒绝安装。
要解决这个问题很简单,把已安装的应用卸载了,然后就可以安装我们重新签名的应用了。
假设你做了一个十分流行的软件,但被别人修改了并植入木马,造成了非常大的影响,如果警察找上门怎么办?很简单,只要把官方版和木马版的签名身份进行对比,就可以证明你的清白了。
MT 进行签名:
- MT 对 apk 进行签名。其实很简单,点击要签名的 apk,点功能,就可以看到 APK 签名,点击后选择你要使用的签名密钥,就可以开始签名了。
导入签名
- 一般签名 apk 需要一个密钥文件,这个文件的后缀是 .jks 或者 .keystore,你可以网上搜索专门的软件来生成它。在使用密钥文件进行签名时,需要正确输入主密码、别名、别名密码后才能签名。但使用 MT 签名的话不需要这么麻烦,MT 中自带了一个默认密钥,你可以直接用它进行签名,不需要输入密码。当然你也可以导入自己的密钥文件,不过需要开通 VIP 会员。使用 MT 直接点击 .jks 或者 .keystore 文件,然后在弹出的对话框中正确输入主密码、别名、别名密码,就可以导入到 MT 的密钥库中,下次签名时就可以看到你导入的密钥了。
在 APK 信息的对话框中,点击功能后弹出菜单,除了前面介绍过的 APK 签名和 XML 翻译模式外,还可以看到 APK 优化、APK 共存、RES 资源混淆、RES 反资源混淆、去除签名校验,后面两个功能需要开通 VIP 才能使用。
- APK 优化:该功能对安装包内不规范的文件以 APK 模式进行重新打包并 Zipalign 对齐优化,优化后安装包可能会增大。
-
APK 共存:在安卓系统中,包名是每个应用的身份 ID,应用更新后名字、图片、界面都可以变化,唯独包名不能变。对于不同的应用,它们的包名不能一样,否则会被认为是同个应用。通过这个原理,只需要改变应用的包名,就可以在手机多次安装同一个应用,而不会出现覆盖安装了。APK 共存功能正是帮你自动完成包名的修改。
由于程序的复杂多变,很难有一种方法可以保证应用在修改完包名后还能正常运行,MT 提供了两种方案进行修改,我称它们为新版方案和旧版方案。两者没有优劣之分,只是修改方法不同,在一种方案失败了之后应该尝试下另一种方案。
新版方案
- 新版共存方案由 MT 独创,它通过修改 AndroidManifest.xml 中的包名以及其它一些关键信息,还有修改 resources.arsc 中的包名来实现共存,不会修改 dex 和 so 文件,对 apk 的改动最小,成功率也比较高。如果使用该方案生成的 apk 安装后无法运行,并且你有一定的技术经验的话,可以用 getPackageName 为关键字搜索代码,找出导致出错的地方手动修复。
旧版方案
- 旧版共存方案使用传统方式制作共存,它会把 apk 所有的包含包名的数据全部替换成新的包名,包括 arsc、dex、xml、so 文件中的数据。如果使用该方案在处理 dex 文件时报错,可以先进行 dex 修复并打包回去,最后再进行共存。
去除签名校验
- 有些应用会对 apk 的签名身份信息进行校验,以防止被修改。它的实现原理是对 PackageManager 的 getPackageInfo() 方法进行 hook,修改其返回的 signatures 数据,所以仅适用于通过该方式来进行签名校验的应用,如果是通过其它方式进行签名校验则无效。MT 会从 META-INF/XXX.RSA (DSA) 文件中获取原始签名数据,所以在使用该功能前请确保被处理的 apk 中的 RSA/DSA 签名信息文件是未经过修改的。如果当前处理的文件不是原版 apk,请先将原版安装包中的 META-INF/XXX.RSA (DSA) 文件添加当前 apk 中。
简单实战
编写的一个简单小软件,安全无毒,可以点击这里下载。
安装这个 APP 后打开,会先进入一个欢迎页面,等待两秒后才会跳到主界面,而且它的界面上都是英文。如果你联网了,再等一会后它还会弹出更新提示。
在主界面中可以看到有两个按钮,第一个按钮需要你输入正确密码后才能给你看好东西,第二个按钮会显示你点击了多少次。
现在使用 MT 对它做点事情,
- 首先是汉化这个应用,
- 然后去掉烦人的启动页面和更新提示,
- 接着破解掉密码,
- 最后改软件名称、图标。
去除签名校验
在修改任何一个 APP 前,建议先检查下它有没有做防修改保护。步骤非常简单,首先卸载掉已安装的版本,然后直接对 MTestApp.apk 进行签名,处理完成后,安装生成的 MTestApp_sign.apk。再次打开发现用不了,就是用了签名校验保护。
打开后会发现一切正常,成功去除签名检验了。当然这个功能也不是百分百对所有应用有效,具体原因去看它的原理说明
汉化应用
打开 MTestApp_kill.apk 点击查看进入安装包内,点击 resources.arsc 文件,选择翻译模式,打开后发现有好多的语言包,拥有强迫症的我决定删掉没用的语言包,只保留默认和简体中文。
要精简语言包的话,需要使用 Arsc 编辑器。退出翻译模式,再次点击 resources.arsc 文件,选择 Arsc 编辑器,进入 cc.binmt.mtestapp。
字符串资源一般存在于 string、array、plurals 三个类型中,在这边我们只看到 string 类型,所以我们只需要精简 string 里面的配置就行了。
点击 string 进入配置列表,因为我们只保留默认和简体中文,所以把除了 string 和 string-zh-rCN 之外的配置都删掉。
- 如果你在汉化其它 app 时没有找到 string-zh-rCN,你可以自己新建一个,或者干脆把默认语言包内的文本都翻译成中文。
看到这边你可能会问,明明有 string-zh-rCN 这个简体中文语言包,为什么这个 app 的界面还是英文的?
我们来找找原因吧,进入默认语言包往下拉,可以看到从 001F 到 0029 的文本,基本都是主界面上显示的那些文字,但进入 zh-rCN 后却找不到 001F 到 0029。也就是主界面上的那些文字只存在于默认语言包,而在简体中文语言包中没有对应的条目。
所以我们在 string-zh-rCN 中点击添加菜单,选择 string 来源,把 001F 到 0029 的条目添加进来。
现在,我们完成了语言包的精简,并且把简体中文语言包中缺少的词条添加进去了。点击菜单保存文件,退出 Arsc 编辑器。返回主界面后 MT 会提示你更新文件,点击确定。
开始汉化
再次点击 resources.arsc 文件,选择翻译模式,这次只看到 [DEFAULT] 和 zh-rCN 了,即默认语言和简体中文。如果你还看到其它语言包选项,那么可能你还需要去 array 和 plurals 类型中删除配置。选择 zh-rCN 进入,我们需要翻译的是这几个文本:
使用谷歌自动翻译后:
有些地方翻译得不太正确,另外有个十分隐秘的错误,仔细看你会发现上图左右两边的 % 长得不太一样,右边的 % 被谷歌翻译整成全角符号了,这会导致格式控制符失效。不知道什么是格式控制符的话去看前面关于翻译模式的文档。
修正翻译结果:
点击菜单保存翻译结果,返回后再点击菜单保存文件,退出翻译模式。(注意两次保存)
效果测试
更新完文件后,返回上级,对 MTestApp_kill.apk 进行签名,然后安装生成的 MTestApp_kill_sign.apk。
打开后你会发现,大部分已经完成汉化,并且点击下面的按钮,显示的数字会不断增加,更新提示中会显示“新版本:1100”,如果这两个地方显示不正确,那就是你破坏了格式控制符。
欢迎页面的 Welcome!、输入框的 Password、第一个按钮的 OK,这三处文本没有完成汉化,我们要去其它地方找找。
XML 翻译
再次打开 MT,点击 MTestApp_kill.apk 选择 XML 翻译模式功能,可以找到我们刚刚没翻译的那三个词条了,直接进行翻译并保存。
效果测试
保存完后退出翻译模式,对 MTestApp_kill.apk 进行签名,然后安装生成的 MTestApp_kill_sign.apk。
这次没问题了,已经完成了所有的文字汉化,所以下面不需要去使用 Dex 翻译模式了。
去除启动页
打开 APP 都要看着启动页 2 秒,很烦人,既然如此我们把它去掉吧。
学过 Android 开发的都知道,APP 的每个界面都是一个 Activity,然后你点击桌面上的图标之后,其实是启动了这个 APP 的入口 Activity。现在我们这个 APP 的入口 Activity 就是启动页,启动页打开 2 秒后,它就会自动关掉,然后跳转到主界面。
既然我们知道了这个流程,那么要修改它就很容易,我们只要让主界面成为 APP 的入口 Activity,不就可以跳过启动页了。
定位主界面
第一步是确定主界面的 Activity 名称是什么,打开 MT 侧拉栏工具中的 Activity 记录,根据提示启动服务,如果启动成功,返回 MT 后你会看到:
现在返回桌面,启动 APP,等它跳转到主界面后,回到 MT 中。
从上图中可以看到,我们启动 APP 后,它是先跳转到 WelcomeActivity,然后再跳转到 MainActivity,所以 MainActivity 就是我们要找的主界面了。
修改入口
Activity 的配置保存在 apk 里面的 AndroidManifest.xml 文件中,使用 MT 反编译这个文件。
查找入口 Activity 我们只需要搜索 android.intent.action.MAIN 或者 android.intent.category.LAUNCHER 就能快速定位。
<activity
android:theme="@7f0c011a"
android:name="cc.binmt.mtestapp.WelcomeActivity"
android:launchMode="singleTop">
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
可以看到当前入口 Activity 是 WelcomeActivity,其中 intent-filter 包裹着的那 6 行代码的作用就是让这个 Activity 成为入口并显示在桌面上,所以我们把它去掉。
<activity
android:theme="@7f0c011a"
android:name="cc.binmt.mtestapp.WelcomeActivity"
android:launchMode="singleTop">
</activity>
然后我们要让 MainActivity 成为入口,就给它加上刚刚那段 intent-filter。
<activity
android:name="cc.binmt.mtestapp.MainActivity" />
去掉末尾的 /> 换成 >,并加上 </activity>,然后在它们中间插入 intent-filter,最后如下。
<activity
android:name="cc.binmt.mtestapp.MainActivity" >
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
最终修改结果:
修改完成后点击菜单编译并退出,更新文件到 apk 中后,返回上级对 MTestApp_kill.apk 进行签名,安装生成的 MTestApp_kill_sign.apk。
如果你的修改步骤没错,再次打开 APP 后你会直接进入主界面,不再显示启动页。
去更新提示
去掉了烦人了启动页后,还有一个更新提示依旧很烦人。
我们查看 apk 信息时可以看到它当前的版本号是 1,而这边的更新提示显示最新版本号是 1100。当然一般应用的更新提示都不会告诉你版本号,而是告诉你版本名称和更新内容,我这边为了方便直接显示出来。
注意,应用判断是否更新时,基本都是通过版本号进行判断,而不是版本名称。
方法一:修改 AndroidManifest.xml
反编译 apk 中的 AndroidManifest.xml 文件查看应用的版本号和版本名称。
其中 versionCode 就是版本号,versionName 就是版本名称,我们把 versionCode 改成 9999(大于 1100) 然后编译保存,重新签名后安装测试,发现还是有更新提示,看来这个 APP 使用方法一无效。(只是对当前 APP 无效,其它 APP 还是可能有效的。)
方法二:搜索版本号
既然方法一无效,那么很大的可能是版本号写死在 dex 中,而不是运行时从 AndroidManifest.xml 里面获取,所以我们尝试去 dex 文件中搜索版本号。
所以我们用 Dex 编辑器++ 打开 apk 中的 classes.dex 文件,切换到搜索页,发起新搜索,内容输入 1,搜索类型选择整数,不要勾选十六进制,点击确认后,发现我们搜索到了 554 个结果,有点太多了。
搜索到这么多结果的主要原因是 1 这个数字出现的概率太大了,这么多结果我们不好一个一个去看,所以暂时先放弃方法二。
如果你在去除其它 APP 的更新提示时,使用该方法搜索到了很少的几个结果,只需要在代码中把对应的数字修改成大于最新版本的数字就行了。另外代码中的数字一般以十六进制显示,所以在代码中进行文本搜索时还需要手动转换一下版本号。
方法三:搜索关键字
尝试这个方法前先把 apk 备份一下,待会给方法四使用。
一般 APP 会从一个网址中读取最新版本信息,而网址是 http 开头,所以我们搜索 http,然后根据整个网址来判断它是否是我们要找的。
与更新有关的英语单词有:version、update、ver,如果你找到的网址包含其中一个,那么很可能就是它了。
如果在你搜到的网址中都找不到这几个单词,那你可以尝试使用 Dex 编辑器++,搜索类型选择代码,分别搜索上面的三个单词。
这边我尝试使用搜索网址的方式,为了查找方便,我是用 Dex 编辑器(没有++)打开 classes.dex 文件,进入字符常量池,菜单中选择过滤,输入 http。
可以看到 http://binmt.cc/test/version.txt 就包含着关键字 version,我们把它随便改成一个无效的网址,例如 http://127.0.0.1 ,修改完成后然后保存 dex 文件。
老操作,退出 Dex 编辑器,更新完后重新签名安装,打开 APP 后更新提示果然不见了。
方法四:还是搜索关键字
再补充一个方法,这边使用方法三中备份的 apk 进行修改,因为方法三已经成功去掉更新提示
对话框标题中的发现新版本应该是固定的,直接在 dex 中搜索发现新版本搜不到内容,那这个字符串应该在 arsc 文件中。
我们使用 Arsc 编辑器打开 resources.arsc 文件,搜一下字符串发现新版本:
上图中第二个是在汉化应用时遗留下来的数据,不用管它,我们长按第一个,选择复制 ID,这边我们复制的 ID 是 7F0B0029。
然后我们用 Dex 编辑器++ 打开 apk 中的 classes.dex 文件,切换到搜索页,发起新搜索,内容输入 7F0B0029,搜索类型选择整数,勾选十六进制,点击确定。
进入 MainActivity$2$1,菜单中选择转成 Java。
可以看到 run() 方法用于显示一个对话框,猜得没错的话应该就是更新提示的对话框,我们返回到 smali 代码中,把 run() 方法中的代码删掉。
然后保存代码并编译 dex,退出 Dex 编辑器++,更新完后重新签名安装,打开 APP 同样不会出现更新提示。
总结
使用上面的方法定位到关键位置后,你可以用三个思路去掉更新提示,第一个是把版本号改大,方法一和二就是如此;第二个是让 APP 获取不到最新版本号,方法三用的就是这个思路;第三个是不让它显示更新对话框,把显示对话框的代码删掉,方法四用的就是这个思路。
爆破 密码
APP 要求我们输入正确的密码后才能看美女,可惜我们不知道密码,点击确定后它提示了“密码错误!!”,我们就从这个提示入手。
通过前面的修改,我们知道字符串“密码错误!!”在 arsc 文件中,去 arsc 文件中搜一下,复制资源 ID。
然后用 Dex编辑器++ 打开 dex 文件,以十六进制整数搜索刚刚复制的 ID。
进入 MainActivity,菜单中选择转成 Java 。
在 Java 代码中再次搜索资源 ID,可以定位到上图中的关键代码。可以看到它是先计算我们输入的密码的 hashCode,判断它是否等于 0x075bcd15,是则启动一个 Activity,不是则弹出密码错误的提示。
由于不好算出哪个字符串的 hashCode 是 0x075bcd15,所以我们直接改判断,把等于改成不等于就行了。
先补充下 smali 的条件跳转分支语法知识,其实网上一搜就有了。
if-eq vA, vB, :cond_** 如果vA等于vB则跳转到:cond_**
if-ne vA, vB, :cond_** 如果vA不等于vB则跳转到:cond_**
if-lt vA, vB, :cond_** 如果vA小于vB则跳转到:cond_**
if-ge vA, vB, :cond_** 如果vA大于等于vB则跳转到:cond_**
if-gt vA, vB, :cond_** 如果vA大于vB则跳转到:cond_**
if-le vA, vB, :cond_** 如果vA小于等于vB则跳转到:cond_**
if-eqz vA, :cond_** 如果vA等于0则跳转到:cond_**
if-nez vA, :cond_** 如果vA不等于0则跳转到:cond_**
if-ltz vA, :cond_** 如果vA小于0则跳转到:cond_**
if-gez vA, :cond_** 如果vA大于等于0则跳转到:cond_**
if-gtz vA, :cond_** 如果vA大于0则跳转到:cond_**
if-lez vA, :cond_** 如果vA小于等于0则跳转到:cond_**
回到 smali 代码中,搜索资源 ID,定位到 139 行。
可以看到 138 行是一个位置标签 :cond_43,由于我们搜索的资源 ID 代表的是密码错误,所以当密码错误时,它才会跳转到这里,于是我们往上找 :cond_43,看它是从哪里跳过来的。
可以在 126 行看到:if-ne v0, v1, :cond_43
它表示如果 v0 不等于 v1 就跳转到提示密码错误的代码,否则继续往下执行。也就是说,v0 不等于 v1 时,密码错误;v0 等于 v1 时,密码正确。所以我们把代码改成:if-eq v0, v1, :cond_43
这样当我们输入错误的密码时,它反而会判断成密码正确了。
为了验证我们修改的正确性,再次点击菜单中的转成 Java ,此时显示的仍是上次的反编译结果,需要点击菜单中的重新加载再次进行反编译。你会看到 41 行原本的 == 变成 != 了,修改结果和我们预期的一样。
最后我们保存代码并编译 dex,退出 Dex 编辑器++,更新完后重新签名安装,打开 APP 随便输入密码点击确定,就可以看到美女啦!
修改 软件名、图标
APP 的名称定义在 AndroidManifest.xml 文件中,具体在 application 标签的 android:label 属性中,该属性的值可以直接是一个字符串,或者是字符串资源引用。
例如上图中 APP 名定义为 @7f0b001f,这是一个字符串资源引用,你可以去 arsc 文件中搜索这个 ID。
改这边的值就可以修改软件名了,另外你也可以直接在 AndroidManifest.xml 把 @7f0b001f 改成你想要的软件名,但这样软件名就被写死了,不会根据语言环境自动切换。
在第一张图中我们可以看到入口 Activity 的标签只有 android:name 属性,前面我介绍过它会以图标形式显示在桌面上,你也可以给 Activity 添加 android:label 属性,不然它将默认使用 application 标签的 android:label 属性。
修改图标
APP 的图标定义在 AndroidManifest.xml 文件中,具体在 application 标签的 android:icon 属性中。例如我们这个 APP 的图标定义为 @7f0a0000,复制这个 ID 去 arsc 文件中搜索。
可以看到这个 apk 一共有 5 个图标,其实这些图标都一样,只是分辨率不一样。如果你要修改图标,提前准备好图片资源,把 apk 中对应的文件替换掉就行了。
如果你觉得一次要准备 5 个不同分辨率的图标进行替换的话不方便,你也可以只替换其中一个,然后在 arsc 中把其它四个配置删掉,同时 apk 中对应的图标也删掉。
例如你准备的图标的分辨率和 apk 中 hdpi 的图标分辨率最接近,那么你可以只替换 hdpi 所对应路径的图标,然后把 mdpi、xhdpi、xxhdpi、xxxhdpi 四个配置都删掉。这样做完全没问题,即使你的分辨率是 xxxhdpi,系统找不到最佳分辨率图标时就会去使用 hdpi 的图标,顶多显示时图标比较不清晰。