Android Mod 教程(1)初识Mod、Java生成smali环境准备(以不破坏原结构制作app共...
本帖最后由 小木曾雪菜 于 2020-1-10 22:31 编辑# Android Mod 教程(1)初识Mod、Java生成smali环境准备(以不破坏原结构制作app共存为例)
## 0. 前言
目前看到制作共存大多是修改包名然后替换所有包名相关的字符串,这种方式很容易出问题,比如说有些遗漏的字符串没有替换,.so中调用了相关的包名(动态绑定情况,静态可以修改IAT替换,但是很容易出错)。所以一种比较好的方法制作共存是,修改包名且修改程序入口(不修改原来的包名),在新的入口处`extends`原来的入口,或是`startActivity`。此帖和我在隔壁发布内容一样,原理虽然不难,但是写了好长时间,希望大家给点个赞。其实这篇教程主要目的还是java生成smali的尝试,以制作共存为例,抛砖引玉,这种Java上生成smali字节码的方法可以推广到mod制作。
1月10日更新:
今天修改了一下标题,因为我成功尝试了修改app为原生层添加ASF外置sd卡写操作支持,这个过程涉及到了elf的修改,ndk jni编译so hoo .got表以及java层注入smali相配合。
感觉是一次挺有意思的尝试,其中也有很多坑(修改so直接闪退,无法调试,也没有报错信息;java内部匿名类序号不同,手动修改特别容易出错),
之后整理完成会陆续发布,可以算是对安卓制作mod的参考。
## 1. 准备工具
* android.jar // (https://androidsdkmanager.azurewebsites.net/SDKPlatform)
* apktool.jar //decompile and recompile apk
* javac // java -> class
* dx.jar// class -> dex
* baksmali.jar //dex -> smali
* dex-tools//dex -> jar
当然除了apktool其他知识为了用java编写,习惯后直接编写smali也是可以的。
## 2. 修改package名和入口Activity
先用apktool反编译源程序
*(apktool出错的注意检查java环境,必须是64位,oracle的javapath可能默认是32位)*
```
java -jar apktool_2.4.0.jar d "%~1" -o "%~dpn1
```
`AndroidManifest.xml`开头处`package=""`即为包名,下例为修改后的包名
```xml
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="cn.natdon.onscripterv2yuri">
```
`<intent-filter>`中`"android.intent.action.MAIN"`极为程序入口,修改后入口class为`cn.natdon.onscripterv2yuri.start2`
**注意修改包名后所有的`activity`缺省包名都要修改。**
```xml
<activity android:label="@string/app_name" android:launchMode="singleInstance" android:name=".start2" android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
```
## 3. 配置Java生成Smali(可选)
### 3.1 命令行java编译为smali
通常情况下可以用Android Studio中的java2smali插件,但是我不想安装这么臃肿的软件。介绍一种比较轻便的生成smali方法,结合vscode自动补全功能非常好用。此方法非常小巧,所用工具不到50mb。
!(https://attach.52pojie.cn//forum/201912/16/230801jgprv544gxoespsu.png)
原理很简单,javac将.java编译为编译.class,之后用dx.jar将.class整合为classes.dex文件,再用baksmali.jar反编译.dex文件得到需要的smali。这个步骤需要`android.jar` 库函数还有原来程序的`classes.dex`转为`classes.jar`(为了extends继承), 极为javac -cp中的依赖项。
写成的批处理脚本为:
> make_smali.bat
```bash
@echo off
set jarlib=android_api21.jar;classes.jar
set dx=dx_r29.0.2.jar
set baksmali=baksmali-2.3.4.jar
for /f %%i in ('dir /s /b "%~f1"') do (
::echo %%i
if %%~xi EQU .java (
echo processing %%~fi
javac -cp%jarlib% "%%~fi")
)
java -jar %dx% --dex --output="%~dp1classes.dex" "%~f1"
java -jar %baksmali% d "%~dp1classes.dex"
pause
```
### 3.2 vscode
先放一张vscode的效果图吧:
!(https://attach.52pojie.cn//forum/201912/16/230709c1oo11suricxo0iu.png)
在vscode中 ctrl+shift+p `Java: Create Java Project`创建java环境,配置`.classpath`的dependencis(要`Java: Refresh`才能更新),之后即可类似于Android Studio的自动补全了。配置`Build Task`可以实现自动化。
> .classpath
```xml
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
<classpathentry kind="lib" path="MiNE3.v1.5_classes.jar"/>
<classpathentry kind="lib" path="D:\\AppExtend\\ReverseToolAndroid\\scripts\\android_api21.jar"/>
</classpath>
```
> tasks.json
```json
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "MakeSmali",
"type": "shell",
"command": ".\\make_smali.cmd src",
"group": {
"kind": "build",
"isDefault": true}}]}
```
## 4. 编写新的入口smali
### 方法一:extends原来程序的入口class
> start.java
```java
package cn.natdon.onscripterv2yuri;
import android.os.Bundle;
public class start extends cn.natdon.onscripterv2.start {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
```
> start.smali
```java
.class public Lcn/natdon/onscripterv2yuri/start;
.super Lcn/natdon/onscripterv2/start;
.source "start.java"
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 4
invoke-direct {p0}, Lcn/natdon/onscripterv2/start;-><init>()V
return-void
.end method
# virtual methods
.method public onCreate(Landroid/os/Bundle;)V
.registers 2
.prologue
.line 6
invoke-super {p0, p1}, Lcn/natdon/onscripterv2/start;->onCreate(Landroid/os/Bundle;)V
.line 7
return-void
.end method
```
### 方法二:startActivity调用原入口Activity
> start2.java
```java
package cn.natdon.onscripterv2yuri;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import cn.natdon.onscripterv2.start;
public class start2 extends Activity{
public void onCreate(Bundle savedInstanceState){
Intent intent = new Intent(this, start.class);
startActivity(intent);
}
}
```
> start2.smali
```java
.class public Lcn/natdon/onscripterv2yuri/start2;
.super Landroid/app/Activity;
.source "start2.java"
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 7
invoke-direct {p0}, Landroid/app/Activity;-><init>()V
return-void
.end method
# virtual methods
.method public onCreate(Landroid/os/Bundle;)V
.registers 4
.prologue
.line 9
new-instance v0, Landroid/content/Intent;
const-class v1, Lcn/natdon/onscripterv2/start;
invoke-direct {v0, p0, v1}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
.line 10
invoke-virtual {p0, v0}, Lcn/natdon/onscripterv2yuri/start2;->startActivity(Landroid/content/Intent;)V
.line 11
return-void
.end method
```
## 5. 将修改完的app编译并签名
```shell
keytool -genkey -alias abc.keystore -keyalg RSA -validity 20000 -keystore abc.keystore
java -jar apktool_2.4.0.jar b "%~1" -o "%~1_rebuild.apk"
jarsigner -verbose -keystore abc.keystore -signedjar "%~1_rebuild_signed.apk" "%~1_rebuild.apk" -storepass "password"abc.keystore
```
编译好的apk即可安装,只要原app没有校验基本上重编译的都能运行。 感谢楼主分享{:1_893:} DDFer 发表于 2019-12-17 09:03
大佬说的好!
不过我仍旧选择bin大的一键共存。。
毕竟这样共存完了,也没精力去弄别的了
bin大一键共存是什么? 我查阅的资料除了虚拟化,基本上都是批量替换类名相关字符串,遇到jni的可能会出问题。其实这篇教程主要目的还是java生成smali的尝试,以制作共存为例,这种方法可以推广到mod制作。 支持一下 前排支持 做个工具给我们白嫖党用用呗:lol 这个我理解是保持签名不变?如果对比修改前后的apk包的MD5或者SHA,还是不一样的吧。 来个工具吧,小白不会用,谢谢大神 majia4075669072 发表于 2019-12-17 00:16
这个我理解是保持签名不变?如果对比修改前后的apk包的MD5或者SHA,还是不一样的吧。
重签名肯定会变,这里指的结构式原来的包名相同。主要应对的是有so调用java的成员,这个是通过包名来寻找。 倘若1 发表于 2019-12-17 00:18
来个工具吧,小白不会用,谢谢大神
我感觉已经说的很清楚了,哪里不会? 2370177068 发表于 2019-12-17 00:01
做个工具给我们白嫖党用用呗
我感觉原理说的已经很清楚了,文中的方法依赖项很小,连android studio都不需要。熟悉smali可以不用java,直接写smali extends 原包里的类。 更加 有意思