亂改人家的 APP yay - APK 反編譯與 Smali 基礎 Coding (上)

前言

Leko 今天 (2020-08-26) 在 Twitter 上看到一篇值得分享的好消息,想分享到 FB 上

剛好想起之前人家介紹的 Tuigram 還有 Twiger 可以把 tweet 變成圖片

用了才發現,兩個軟體居然都只支援分享到 Instagram 上 (Leko 不是很喜歡 IG :(

所以就想說改一下 APP 讓他們支援分享到任意 App 上 yay

值得分享的好消息

會用到的東西

  • APK 檔
  • apktool
  • JADX
  • Android SDK
     

本文

Tuigram (入門級)

我們的目標很簡單,把原本的分享到 Instagram 的按鈕改成可以隨意分享

 

1. 反編譯

> apktool.bat d '.\Tuigram Share tweets on instagram_v1.1.7_apkpure.com.apk' -r

在原地會看到一個新生出來的資料夾

 

2. 看 Code

用 JADX 開啟 APK

按放大鏡把 Text search 叫出來 (順便等他 Decompile 完)

想著總之先搜尋 instagram 吧,沒想到一搜就中,yay

 

要代換的程式碼

看一下官方 Doc,可以看到我們需要的 Code

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
shareIntent.setType("image/jpeg");
startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));

JADX 搜尋出來的 Code 如下

public boolean b(String str, String str2) {
    Intent intent = new Intent("com.instagram.share.ADD_TO_STORY");
    Uri a2 = FileProvider.a(this, "com.vcoud.fileprovider", new File(str2));
    intent.setType(str);
    intent.putExtra("interactive_asset_uri", a2);
    grantUriPermission("com.instagram.android", a2, 1);
    if (getPackageManager().resolveActivity(intent, 0) == null) {
        return false;
    }
    startActivityForResult(intent, 0);
    return true;
}

// 中間省略

public void a(String str, String str2) {
    Intent intent = new Intent("android.intent.action.SEND");
    intent.setType(str);
    Uri a2 = FileProvider.a(this, "com.vcoud.fileprovider", new File(str2));
    intent.addFlags(1);
    intent.putExtra("android.intent.extra.STREAM", a2);
    intent.setComponent(new ComponentName("com.instagram.android", "com.instagram.share.handleractivity.ShareHandlerActivity"));
    startActivity(intent);
}

可以明顯的看出 b 是分享到 IG 限動,a 是普通的 IG 貼文

a 跟我們的目標最像,所以我們改 a (差別只在 a:7setComponent 還有範例 Code 的 Intent.createChooser )

 

3. 改 Code

我們打開步驟 1 生出的資料夾,在 smali/com/vcoud/tuigram/MainActivity.smali 找到我們的 target

首先我們要先把 setComponent 刪掉 (很顯然的就是 .line 11 的部分,全部註解掉)

接著加上 Intent.createChooser 的部分

startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));

// 事實上相當於
String title = getResources().getText(R.string.send_to);
Intent chooser = Intent.createChooser(shareIntent, title);
startActivity(chooser)

所以我們寫

# String title = "分享至"
# 這個是上面的 getResources().getText(R.string.send_to)
# 會作為分享畫面的標題
const-string v1, "分享至"

# 在 .line 5 可以看到 new-instance v0, Landroid/content/Intent;
# 也就是 Intent
# v1 則是我們的 string
# 接受一個 Intent 和一個 CharSequence 作為參數,回傳一個 Intent
# 其中 createChooser 是一個 static method
invoke-static {v0, v1}, Landroid/content/Intent;->createChooser(Landroid/content/Intent;Ljava/lang/CharSequence;)Landroid/content/Intent;

# 把上一步驟的結果 (chooser) 移到 v1 裡 (v1 是不會再用到的 string 所以不用擔心)
move-result-object v1

# 接著我們 startActivity
# 注意到 class method 的第一個參數是 class instance,類似 python 裡的 Class function 第一個參數總是 self
# 原本他 call 的是 {p0, v0},其中 v0 是原本的 Intent
# 現在我們把 v0 換成我們剛剛新建立的 chooser,也就是 v1 
invoke-virtual {p0, v1}, Landroid/content/Context;->startActivity(Landroid/content/Intent;)V

結果長得像這樣

    # ...

    .line 11
    # new-instance p1, Landroid/content/ComponentName;

    # const-string p2, "com.instagram.android"

    # const-string v1, "com.instagram.share.handleractivity.ShareHandlerActivity"

    # invoke-direct {p1, p2, v1}, Landroid/content/ComponentName;->(Ljava/lang/String;Ljava/lang/String;)V

    # invoke-virtual {v0, p1}, Landroid/content/Intent;->setComponent(Landroid/content/ComponentName;)Landroid/content/Intent;

    .line 12
    const-string v1, "分享至"

    invoke-static {v0, v1}, Landroid/content/Intent;->createChooser(Landroid/content/Intent;Ljava/lang/CharSequence;)Landroid/content/Intent;

    move-result-object v1

    invoke-virtual {p0, v1}, Landroid/content/Context;->startActivity(Landroid/content/Intent;)V

    return-void
.end method

# ...

儲存。

 

4. 打包回去

> apktool.bat b '.\Tuigram Share tweets on instagram_v1.1.7_apkpure.com\'

結果會在 .\Tuigram Share tweets on instagram_v1.1.7_apkpure.com\dist\ 裡面找到
build 好的 APK,簽名後裝進手機裡就大功告成辣 owo

 

4.1 簽名

首先建立 Keystore

> keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

keytool 在 JDK 裡面有附

 

接著簽名

> %ANDROID_SDK%\build-tools\%VERSION%\apksigner.bat sign --ks %KEYSTORE% %APK_PATH%

%ANDROID_SDK%, %VERSION%, %KEYSTORE%, %APK_PATH% 換掉就可以簽名了

 

yay
按讚

發佈留言

電子郵件地址不會被公開。必填項已用 * 標註