初めに
・初記事になります。拙い文章ですが、暖かい目で見て頂けると幸いです。
用意するもの
・フッキング用ライブラリ
今回はCydia SubstrateのMSHookFunctionを使用させて頂きました。
・普通のAndroid端末
・ApkEditer
#注意
この記事は解説記事ではなく、あくまでやってみたよ~という紹介の記事になります。
ですので、自分なりの解釈と間違っている知識を披露している、説明を省いているなどの場合がありますが、ご了承ください。
方法
対象アプリに攻撃用ライブラリを埋め込んでフックする
①対象アプリを作る
・流石に他の方が作ったアプリをフックする訳には行かないので、今回は自分で対象のアプリを作ります。
対象アプリのファイル構成はこんな感じです。
package xxxxxx.vtable_victim;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Start();//nativeメゾットの呼び出し
}
native void Start();//nativeメゾット
}
#include <jni.h>
#include <string>
#include <thread>
#include <pthread.h>
#include <unistd.h>
#include <dlfcn.h>
#define println(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "VTEST Victim", __VA_ARGS__))
struct Target {
void TargetHello();
void Update();
};
void Target::TargetHello() {
printB("TargetHello");
}
void Target::Update() {
printB("Update");
}
extern "C"
JNIEXPORT void JNICALL
Java_xxxxxx_vtable_1victim_MainActivity_Start(JNIEnv *env, jobject thiz) {
Target target;
target.TargetHello();//TargetHello呼び出し
}
javaとcppファイルもこんな感じでセットアップします。
②攻撃用アプリを作る
攻撃用アプリは新しいプロジェクトを作成してcppファイルだけセットアップします。
#include <jni.h>
#include <string>
#include "Substrate/CydiaSubstrate.h"
#include "android/log.h"
#define println(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "VTEST Attacker", __VA_ARGS__))
__attribute__((constructor))//System.loadLibraryで読み込まれた時に起動
void OnLoad(){
void* handle = dlopen("libnative-lib.so",RTLD_LAZY);//ライブラリのハンドル
MSHookFunction(NULL,NULL,NULL);//↓
}
フック用ライブラリの関数、MSHookFunctionから見ていきます。
void MSHookFunction(void * symbol,void * hook,void ** old);
引用元:http://www.cydiasubstrate.com/api/c/MSHookFunction/
・symbol
The address of code to instrument with replacement code. This is normally, but need not be, a function.
・hook
The address of an ABI-compatible replacement for the code at the address referenced by symbol.
・old
A pointer to a function pointer that will be filled in with a stub which may be used to call the original implementation. This can be NULL if you do not proceed to the original.
それぞれの引数の説明がありました。うーん...なんだこれ...
要約すると
symbolはターゲットの関数のアドレスが入って
hookの所にはターゲットと置き換えたい関数のアドレスが入って
oldの所には置き換えられた元の関数ポインタへのポインタが入る
...のかな?
間違っていたらご指摘お願いいたします。m(__)m
ほんじゃこれに沿って...
#include <jni.h>
#include <string>
#include "Substrate/CydiaSubstrate.h"
#include "android/log.h"
#define println(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "VTEST Attacker", __VA_ARGS__))
void (*Target_TargetHello_origin)(void*);//元の関数の関数ポインタ
void Target_TargetHello_hook(void* thiz){//置き換えたい処理
println("Hook -> Target::TargetHello Called");
}
__attribute__((constructor))//System.loadLibraryで読み込まれた時に起動
void OnLoad(){
void* handle = dlopen("libnative-lib.so",RTLD_LAZY);
void* funcaddr = dlsym(handle,"_ZN6Target11TargetHelloEv");//フックする関数のアドレス
MSHookFunction(funcaddr,(void*)Target_TargetHello_hook,(void**)Target_TargetHello_origin);
dlclose(handle);
}
こんな感じになりました。
これをlibattack-lib.soにコンパイルします。
③早速フックしてみる
準備が出来たので早速フックしてみようと思います...が。
今回はInjectとか他のアプリからフックするみたいな方法ではなく、
対象アプリに直接埋め込んでフックするという手法を取ります。
何故なら、今回使用しているAndroidの端末はroot化していないからです。
さて、対象アプリに埋め込む作業ですが、次の二つの手順を踏んでいきます。
❶コンパイルしたlibattack-lib.soを対象アプリlibフォルダに入れる
❷System.loadLibraryでlibattack-lib.soを読み込ませる
❶は簡単にできますが、❷はjavaをsmailにデコンパイルして、それを編集しなければいけません。
❶からやっていきます。
といっても、簡単な作業ですので、ファイル構成だけ載せていきます。
============APKの中身=============
assert
res
lib
┗armeabi-v7a
┣libnative-lib.so
┗libattack-lib.so ←移植
AndroidManifest.xml
...
=================================
libattack-lib.soを移植しましたら❷に行きます
❷はsmaliファイルを編集するのですが、少し注意点があります。
・対象ライブラリが読み込まれてからフックする
・対象ライブラリ内でメゾットが読み込まれる前にフックする
・MainActivity.smaliに埋め込み用コードを挿入する
const-string v0, "attack-lib"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
先ほどの注意点を踏まえて編集していきます。
上記埋め込み用コードですが、MainActivity.javaのsetContentViewメゾットの後に挿入します。
MainActivity.javaをsmaliに変換して....
.class public Lxxxxxx/vtable_victim/MainActivity;
.super Landroidx/appcompat/app/AppCompatActivity;
.source "MainActivity.java"
# direct methods
.method static constructor <clinit>()V
.registers 1
const-string v0, "native-lib"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
return-void
.end method
.method public constructor <init>()V
.registers 1
invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()V
return-void
.end method
# virtual methods
.method native Start()V
.end method
.method protected onCreate(Landroid/os/Bundle;)V
.registers 3
invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
const v0, 0x7f0b001c
invoke-virtual {p0, v0}, Lxxxxxx/vtable_victim/MainActivity;->setContentView(I)V
こ↑こ↓
invoke-virtual {p0}, Lxxxxxx/vtable_victim/MainActivity;->Start()V
return-void
.end method
こ↑こ↓と書かれている部分に挿入します。
.method protected onCreate(Landroid/os/Bundle;)V
.registers 3
invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
const v0, 0x7f0b001c
invoke-virtual {p0, v0}, Lxxxxxx/vtable_victim/MainActivity;->setContentView(I)V
const-string v0, "attack-lib"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
invoke-virtual {p0}, Lxxxxxx/vtable_victim/MainActivity;->Start()V
return-void
.end method
これでOKです。
そしたらApk EditerでApkを組み上げまして....
完成です!
④試運転
それでは起動して動作を確認してみます。
・フック前
・フック後
これでフックが出来ました。おしまい。
。
ではなく、これには__重大な問題__が残っています。それは....
元の関数が呼び出せてないという問題です。
これでは元々あった処理が呼び出されず、危険です。
というわけで、元の関数を呼び出していきましょう。
⑤元の関数を呼び出してみる
MsHookFunctionの三番目の引数に入っていた謎の関数ポインタ君がカギです。
元の関数の関数ポインタを関数として呼び出すことによって、元の関数を呼び出すことが出来ます。
#include <jni.h>
#include <string>
#include "Substrate/CydiaSubstrate.h"
#include "android/log.h"
#define println(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "VTEST Attacker", __VA_ARGS__))
void (*Target_TargetHello_origin)(void*);//元の関数の関数ポインタ
void Target_TargetHello_hook(void* thiz){//置き換えたい処理
println("Hook -> Target::TargetHello Called");
Target_TargetHello_origin(thiz);//元の関数を呼び出す
}
__attribute__((constructor))//System.loadLibraryで読み込まれた時に起動
void OnLoad(){
void* handle = dlopen("libnative-lib.so",RTLD_LAZY);
void* funcaddr = dlsym(handle,"_ZN6Target11TargetHelloEv");//フックする関数のアドレス
MSHookFunction(funcaddr,(void*)Target_TargetHello_hook,(void**)Target_TargetHello_origin);
dlclose(handle);
}
⑥最後に
まだ試したいことや、もっと幅広くできることもありますので、また時間があれば書きたいと思います。
読みにくい私の記事を読んでいただいてありがとうございました。
それでは~