AndServer+Service 打造 Android 服务器实现 so 文件调用

640?wx_fmt=png"NightTeam",一个值得加星标640?wx_fmt=png的公众号。

640?wx_fmt=jpeg

正文共:5623 字 26 图

预计阅读时间:15 分钟

作者:  妄为

so 文件调用

随着 Android 移动安全的高速发展,不管是为了执行效率还是程序的安全性等,关键代码下沉 native 层已成为基本操作。

libyemu.so 简介

这是我编译好的一个 so 文件,就是根据入参做下简单的字符串拼接(以下是 native 层编译前的 c 代码)

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);
}

这部分代码还是有必要贴一下的,简单的静态注册使用了反射的思想,反射在逆向中至关重要

package com.fw.myapplication.ndktest;

public class NdkTest {
    public static native String stringFromUTF(String str);

    static {
        System.loadLibrary("yemu");
    }
}

如果到这里有点懵逼的同学可能需要去补下 Android 开发基础了

Android 项目测试 so

先说下我的环境,因为这个环境影响太大了  

640?wx_fmt=png

在 module 的 build 中加这么一句,然后 sync  
640?wx_fmt=png

把编译好的 so 文件复制到 libs 文件夹下(和刚才的 jniLibs.srcDirs 对应)  
640?wx_fmt=png

把 so 对应的 java 代码也 copy 过来,注意包名类名的一致性  
640?wx_fmt=png

打开 activity_main.xml 文件为 TextView 添加 id  
640?wx_fmt=png

打开 MainActiviy.java 开始编码  
640?wx_fmt=png

这两行的意思就是,先从布局中找到对应 id 的 TextView,然后为其设置 Text(调用 native 函数的返回值)  
下面测试一下咱们的 so 调用情况  
640?wx_fmt=png

可以看到咱们的 so 文件调用成功(这里咱们的 so 没有效验,只是测试 app 是否可以正常调用)

AndServer 代码编写

AndServer 官方文档:https://yanzhenjie.com/AndServer/  

640?wx_fmt=png

如图经典 MVC 的 C 就写好了,定义了一个 nightteam_sign 接口,请求方式为 get,请求参数为 sign,调用 native 函数,然后返回 json,但是这里我想利用 Application 获取下 context 对象,取下包名,接下来自定义 Applictaion

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  

640?wx_fmt=png

然后修改 MyController.java 的代码  
640?wx_fmt=png

接下来把官方文档-服务器的代码 copy 下来  
导入一些包,修改部分代码如下  
640?wx_fmt=png

新版本的 AndServer.serverBuilder 已经需要传递 context 了,这里把网络地址和端口号也修改为从构造参数中获取,到这里 AndServer 的东西基本完了,实际上咱们就搭建一个调 so 的接口,并没有过多的业务逻辑,所以代码就是使用的最简单的

Service 代码编写

咱们这里用按钮的点击事件启动 Service,故在 activity_main.xml 中添加一个 button 并指定点击事件  

640?wx_fmt=png

640?wx_fmt=png

接下来编写自定义 Service 代码

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 基础,这里就不赘述了)  

640?wx_fmt=png

开启 Service,并获取本机 ip

回到我们的 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 上,这样我们就不用去设置再查看了  

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 中编码  

640?wx_fmt=png

获取了一下本机地址和 Android SDK 版本( Android 8 之后启动 Service 方式不一样)

申请权限,启动 App

最后一步就是为 app 申请网络权限了  

640?wx_fmt=png

随后连接我们的手机,运行项目,测试一下,点击开启服务  
640?wx_fmt=png

看下 AndroidStudio 日志  
640?wx_fmt=png

好像一切正常,在浏览器访问下试试( ip 就是 App 中显示的 ip 地址)  
640?wx_fmt=png

如图正常访问到了我们想要的内容
回过头来说下 Service,打开我们手机的设置,找到应用程序管理-运行中的服务(手机不同,方式不同)
640?wx_fmt=png

可以看到我们的程序,运行了一个服务,这个服务就是咱们编码的 MyService
640?wx_fmt=png

接下来杀掉该 App进程,再次查看运行中的服务
640?wx_fmt=png

我这里在权限管理设置了自动运行,可以保持服务的运行。(这个地方还是根据系统有大小差异)
至此使用 App 起 http 服务调 so 就完成了


好了,上面就是利用 AndServer 打造 Android 服务器调 so 文件的整体思路和流程,如果你懒得看的话,直接用我写好的 App 修修补补也是可以的,只需要发送消息【AndServer搭建Web服务调so】到公众号【NightTeam】即可。


文章作者:「夜幕团队 NightTeam 」- 妄为

夜幕团队成立于 2019 年,团队成员包括崔庆才、周子淇、陈祥安、唐轶飞、冯威、蔡晋、戴煌金、张冶青和韦世东。

涉猎的主要编程语言为 Python、Rust、C++、Go,领域涵盖爬虫、深度学习、服务研发和对象存储等。团队非正亦非邪,只做认为对的事情,请大家小心。

640?wx_fmt=jpeg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值