随着 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,领域涵盖爬虫、深度学习、服务研发和对象存储等。团队非正亦非邪,只作认为对的事情,请你们当心。