隨着 Android 移動安全的高速發展,不論是爲了執行效率仍是程序的安全性等,關鍵代碼下沉 native 層已成爲基本操做。 native 層的開發就是通指的 JNI/NDK 開發,經過 JNI 能夠實現 java 層和 native 層(主要是 C/C++ )的相互調用,native 層經編譯後產生 so 動態連接庫,so 文件具備可移植性廣,執行效率高,保密性強等優勢。 那麼問題來了,如何調用 so 文件顯得異常重要,固然你也能夠直接分析 so 文件的僞代碼,利用強悍的編程功底直接模擬關鍵操做,可是我想對於普通人來講頭髮仍是比較重要的。
當前調用 so 文件的主流操做應該是:
1,基於 Unicorn 的各類實現(還在學習中,暫且不表)
2,Android 服務器的搭建,在 App 內起 http 服務完成調用 so 的需求(固然前提是過了 so 的效驗等操做) 至於爲何選用 AndServer,好吧,不爲何,只是由於搜索到了它
爲何結合 Service,在學習 Android 開發的時候瞭解到了 Service 的生命週期,我的理解用 Service 去建立 Http 服務比較好。
固然也有 Application 的簡單使用,由於在正式環境中,大多數 so 文件的邏輯中都有 context 的一些包名了,簽名了的效驗等,自定義 Application 的話獲取 context 傳參就行了。java
這是我編譯好的一個 so 文件,就是根據入參作下簡單的字符串拼接(如下是 native 層編譯前的 c 代碼)android
extern "C"
JNIEXPORT jstring JNICALL
Java_com_fw_myapplication_ndktest_NdkTest_stringFromUTF(JNIEnv *env, jobject instance, jstring str_) {
jclass String_clazz = env->FindClass("java/lang/String");
jmethodID concat_methodID = env->GetMethodID(String_clazz, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
jstring str = env->NewStringUTF(" from so --[NightTeam夜幕]");
jobject str1 = env->CallObjectMethod(str_, concat_methodID, str);
const char *chars = env->GetStringUTFChars((jstring)str1, 0);
return env->NewStringUTF(chars);
}
複製代碼
這部分代碼仍是有必要貼一下的,簡單的靜態註冊使用了反射的思想,反射在逆向中相當重要 接下來是 java 代碼,定義了 native 函數編程
package com.fw.myapplication.ndktest;
public class NdkTest {
public static native String stringFromUTF(String str);
static {
System.loadLibrary("yemu");
}
}
複製代碼
若是到這裏有點懵逼的同窗可能須要去補下 Android 開發基礎了json
先說下個人環境,由於這個環境影響太大了
1,AndroidStudio 3.4
2,手機 Android 6 架構 armeabi-v7a
打開 AndroidStudio 新建 project
瀏覽器
AndServer 官方文檔:yanzhenjie.com/AndServer/
打開官方文檔,看看人家的入門介紹,新建 java 文件
安全
package com.nightteam.httpso;
import android.app.Application;
public class MyApp extends Application {
private static MyApp myApp;
public static MyApp getInstance() {
return myApp;
}
@Override
public void onCreate() {
super.onCreate();
myApp = this;
}
}
複製代碼
而後在 manifest 文件中指定要啓動的 Application
bash
我們這裏用按鈕的點擊事件啓動 Service,故在 activity_main.xml 中添加一個 button 並指定點擊事件
服務器
package com.nightteam.httpso.Service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.nightteam.httpso.ServerManager;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class MyService extends Service {
private static final String TAG = "NigthTeam";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: MyService");
new Thread() {
@Override
public void run() {
super.run();
InetAddress inetAddress = null;
try {
inetAddress = InetAddress.getByName("0.0.0.0");
Log.d(TAG, "onCreate: " + inetAddress.getHostAddress());
ServerManager serverManager = new ServerManager(getApplicationContext(), inetAddress, 8005);
serverManager.startServer();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
複製代碼
打上了幾個 log,在子線程中啓動 AndServer 的服務(什麼時候使用 UI 線程和子線程是 Android 基礎,這裏就不贅述了)
注意一下,這裏從 0.0.0.0 獲取 inetAddress,可不要寫錯了,localhost 和 0.0.0.0 的區別請移步搜索引擎
而後就是向 ServerManager 的構造函數傳遞 context,inetAddress,port 用來 new 對象,隨後開啓服務 最後注意檢查下 manifest 文件中 Service 的聲明
網絡
回到咱們的 MainActivity.java 的 operate( button 的點擊事件)編寫啓動 Service 代碼架構
public void operate(View view) {
switch (view.getId()){
case R.id.id_bt_index:
//啓動服務:建立-->啓動-->銷燬
//若是服務已經建立了,後續重複啓動,操做的都是同一個服務,不會再從新建立了,除非你先銷燬它
Intent it1 = new Intent(this, MyService.class);
Log.d(TAG, "operate: button");
startService(it1);
((Button) view).setText("服務已開啓");
break;
}
}
複製代碼
到這裏咱們的服務基本搭建好了,可是爲了方便起見,我想把我們的本機 ip 顯示在 App 上,這樣咱們就不用去設置再查看了
我在網上找到了一個獲取 ip 地址的一個工具類,源碼以下:
package com.nightteam.httpso;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.regex.Pattern;
public class NetUtils {
private static final Pattern IPV4_PATTERN = Pattern.compile("^(" +
"([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" +
"([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
private static boolean isIPv4Address(String input) {
return IPV4_PATTERN.matcher(input).matches();
}
//獲取本機IP地址
public static InetAddress getLocalIPAddress() {
Enumeration<NetworkInterface> enumeration = null;
try {
enumeration = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
e.printStackTrace();
}
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
NetworkInterface nif = enumeration.nextElement();
Enumeration<InetAddress> inetAddresses = nif.getInetAddresses();
if (inetAddresses != null)
while (inetAddresses.hasMoreElements()) {
InetAddress inetAddress = inetAddresses.nextElement();
if (!inetAddress.isLoopbackAddress() && isIPv4Address(inetAddress.getHostAddress())) {
return inetAddress;
}
}
}
}
return null;
}
}
複製代碼
把工具類 copy 到咱們的 Android 項目中,繼續在 MainActivity.java 中編碼
最後一步就是爲 app 申請網絡權限了
好了,上面就是利用 AndServer 打造 Android 服務器調 so 文件的總體思路和流程,若是你懶得看的話,直接用我寫好的 App 修修補補也是能夠的,只須要發送消息【AndServer搭建Web服務調so】到公衆號【NightTeam】便可。
文章做者:「夜幕團隊 NightTeam 」- 妄爲
夜幕團隊成立於 2019 年,團隊成員包括崔慶才、周子淇、陳祥安、唐軼飛、馮威、蔡晉、戴煌金、張冶青和韋世東。
涉獵的主要編程語言爲 Python、Rust、C++、Go,領域涵蓋爬蟲、深度學習、服務研發和對象存儲等。團隊非正亦非邪,只作認爲對的事情,請你們當心。