安卓逆向5.Android Studio JNI静态注册(C++和Java互操作)
1)JNI普通字段,静态字段互操作,获取普通字段的值,设置普通字段的值,获取静态字段的值,设置静态字段的值。
1.根据上一篇帖子使用Android Studio新建一个名字叫TestStaticReflection的项目,并在UI界面上添加一个TextView控件,ID为txtOutputDebug,用于输出调试信息。 上一篇帖子:安卓逆向4.Android Studio JNI静态注册(一个简单的JNI静态注册流程) https://www.cnblogs.com/fuhua/p/12695436.html
2.在MainActivity创建一个普通字段,一个静态字段和四个方法。分别用来获取普通字段的值,设置普通字段的值,获取静态字段的值,设置静态字段的值。如图
3.使用命令:javah -jni com.crackme.teststaticreflection.MainActivity生成MainActivity所对应的jni头文件,如图
4.创建TestStaticReflection.cpp文件,并实现头文件中的四个导出函数。cpp文件代码如下
#include "com_crackme_teststaticreflection_MainActivity.h" //获取普通字段的值 JNIEXPORT jstring JNICALL Java_com_crackme_teststaticreflection_MainActivity_GetTestField(JNIEnv * env, jobject obj) { //通过完全限定的名称com/crackme/teststaticreflection/MainActivity寻找到MainActivity这个类 jclass _jClass=env->FindClass("com/crackme/teststaticreflection/MainActivity"); //在MainActivity下寻找字段名为TestField,且字段类型为Ljava/lang/String的字段ID jfieldID _jfieldID=env->GetFieldID(_jClass,"TestField","Ljava/lang/String;"); //通过字段ID获取字段的值 jobject jstr=env->GetObjectField(obj,_jfieldID); //返回字段的值 return (jstring)jstr; } //获取静态字段的值 JNIEXPORT jstring JNICALL Java_com_crackme_teststaticreflection_MainActivity_GetTestStaticField(JNIEnv * env, jobject obj) { //通过完全限定的名称com/crackme/teststaticreflection/MainActivity寻找到MainActivity这个类 jclass _jClass=env->FindClass("com/crackme/teststaticreflection/MainActivity"); //在MainActivity下寻找字段名为TestStaticField,且字段类型为Ljava/lang/String的字段ID jfieldID _jfieldID=env->GetStaticFieldID(_jClass,"TestStaticField","Ljava/lang/String;"); //通过字段ID获取字段的值 jobject jstr=env->GetStaticObjectField(_jClass,_jfieldID); //返回字段的值 return (jstring)jstr; } //设置普通字段的值 JNIEXPORT void JNICALL Java_com_crackme_teststaticreflection_MainActivity_SetTestField(JNIEnv * env, jobject obj) { //通过完全限定的名称com/crackme/teststaticreflection/MainActivity寻找到MainActivity这个类 jclass _jClass=env->FindClass("com/crackme/teststaticreflection/MainActivity"); //在MainActivity下寻找字段名为TestField,且字段类型为Ljava/lang/String的字段ID jfieldID _jfieldID=env->GetFieldID(_jClass,"TestField","Ljava/lang/String;"); //调用SetObjectField方法重新给字段赋值 env->SetObjectField(obj,_jfieldID,env->NewStringUTF("我是重新设置的普通字段的值")); } //设置静态字段的值 JNIEXPORT void JNICALL Java_com_crackme_teststaticreflection_MainActivity_SetTestStaticField(JNIEnv * env, jobject obj) { //通过完全限定的名称com/crackme/teststaticreflection/MainActivity寻找到MainActivity这个类 jclass _jClass=env->FindClass("com/crackme/teststaticreflection/MainActivity"); //在MainActivity下寻找字段名为TestStaticField,且字段类型为Ljava/lang/String的字段ID jfieldID _jfieldID=env->GetStaticFieldID(_jClass,"TestStaticField","Ljava/lang/String;"); //通过字段ID获取字段的值 env->SetStaticObjectField(_jClass,_jfieldID,env->NewStringUTF("我是重新设置的静态字段的值")); }
5.使用ndk-build命令生成libTestStaticReflection.so
6.修改MainActivity类中的OnCreate方法代码如下:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView txtOutputDebug=(TextView) findViewById(R.id.txtOutputDebug); String strOutPut="------------------获取字段-----------------\r\n"; strOutPut+="TestField:"+GetTestField()+"\r\n"; strOutPut+="TestStaticField:"+GetTestStaticField()+"\r\n"; strOutPut+="------------------设置字段-----------------\r\n"; SetTestField(); SetTestStaticField(); strOutPut+="TestField:"+TestField+"\r\n"; strOutPut+="TestStaticField:"+TestStaticField+"\r\n"; txtOutputDebug.setText(strOutPut); }
7.模拟器测试运行
2)JNI普通方法,静态方法调用。
8.在MainActivity中新增如下代码并在onCreate方法中进行调用
9.此时MainActivity完整代码如下
package com.crackme.teststaticreflection;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import java.util.concurrent.Executor;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("TestStaticReflection");
}
//普通字段
public String TestField="我是普通字段";
//静态字段
public static String TestStaticField="我是静态字段";
//获取普通字段的值
public native String GetTestField();
//获取静态字段的值
public native String GetTestStaticField();
//设置普通字段的值
public native void SetTestField();
//设置静态字段的值
public native void SetTestStaticField();
//将strOutPut设置为全局变量
static String strOutPut=null;
//将会从native层调用的普通方法
public void TestMethod()
{
strOutPut+="\n------------------方法调用测试-----------------\n";
strOutPut+="普通方法被调用\n";
}
//将会从native层调用的静态方法
public static void TestStaticMethod(String arg)
{
strOutPut+="\n------------------方法调用测试-----------------\n";
strOutPut+="静态方法被调用"+" 参数:"+arg+"\n";
}
//调用普通方法
public native String CallTestMethod();
//调用静态方法
public native void CallTestStaticMethod(String arg);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView txtOutputDebug=(TextView) findViewById(R.id.txtOutputDebug);
strOutPut="------------------获取字段-----------------\n";
strOutPut+="TestField:"+GetTestField()+"\n";
strOutPut+="TestStaticField:"+GetTestStaticField()+"\n";
strOutPut+="\n------------------设置字段-----------------\n";
SetTestField();
SetTestStaticField();
strOutPut+="TestField:"+TestField+"\n";
strOutPut+="TestStaticField:"+TestStaticField+"\n";
CallTestMethod();
CallTestStaticMethod("我是参数");
txtOutputDebug.setText(strOutPut);
}
}
10.在cpp文件中实现新增的两个native方法
11.此时cpp文件完整代码如下
#include "com_crackme_teststaticreflection_MainActivity.h"
//获取普通字段的值 JNIEXPORT jstring JNICALL Java_com_crackme_teststaticreflection_MainActivity_GetTestField(JNIEnv * env, jobject obj) { //通过完全限定的名称com/crackme/teststaticreflection/MainActivity寻找到MainActivity这个类 jclass _jClass=env->FindClass("com/crackme/teststaticreflection/MainActivity"); //在MainActivity下寻找字段名为TestField,且字段类型为Ljava/lang/String的字段ID jfieldID _jfieldID=env->GetFieldID(_jClass,"TestField","Ljava/lang/String;"); //通过字段ID获取字段的值 jobject jstr=env->GetObjectField(obj,_jfieldID); //返回字段的值 return (jstring)jstr; } //获取静态字段的值 JNIEXPORT jstring JNICALL Java_com_crackme_teststaticreflection_MainActivity_GetTestStaticField(JNIEnv * env, jobject obj) { //通过完全限定的名称com/crackme/teststaticreflection/MainActivity寻找到MainActivity这个类 jclass _jClass=env->FindClass("com/crackme/teststaticreflection/MainActivity"); //在MainActivity下寻找字段名为TestStaticField,且字段类型为Ljava/lang/String的字段ID jfieldID _jfieldID=env->GetStaticFieldID(_jClass,"TestStaticField","Ljava/lang/String;"); //通过字段ID获取字段的值 jobject jstr=env->GetStaticObjectField(_jClass,_jfieldID); //返回字段的值 return (jstring)jstr; } //设置普通字段的值 JNIEXPORT void JNICALL Java_com_crackme_teststaticreflection_MainActivity_SetTestField(JNIEnv * env, jobject obj) { //通过完全限定的名称com/crackme/teststaticreflection/MainActivity寻找到MainActivity这个类 jclass _jClass=env->FindClass("com/crackme/teststaticreflection/MainActivity"); //在MainActivity下寻找字段名为TestField,且字段类型为Ljava/lang/String的字段ID jfieldID _jfieldID=env->GetFieldID(_jClass,"TestField","Ljava/lang/String;"); //调用SetObjectField方法重新给字段赋值 env->SetObjectField(obj,_jfieldID,env->NewStringUTF("我是重新设置的普通字段的值")); } //设置静态字段的值 JNIEXPORT void JNICALL Java_com_crackme_teststaticreflection_MainActivity_SetTestStaticField(JNIEnv * env, jobject obj) { //通过完全限定的名称com/crackme/teststaticreflection/MainActivity寻找到MainActivity这个类 jclass _jClass=env->FindClass("com/crackme/teststaticreflection/MainActivity"); //在MainActivity下寻找字段名为TestStaticField,且字段类型为Ljava/lang/String的字段ID jfieldID _jfieldID=env->GetStaticFieldID(_jClass,"TestStaticField","Ljava/lang/String;"); //通过字段ID获取字段的值 env->SetStaticObjectField(_jClass,_jfieldID,env->NewStringUTF("我是重新设置的静态字段的值")); } //调用java层普通方法 JNIEXPORT jstring JNICALL Java_com_crackme_teststaticreflection_MainActivity_CallTestMethod(JNIEnv * env, jobject obj) { jclass _jClass= env->FindClass("com/crackme/teststaticreflection/MainActivity"); jmethodID _jmethodID= env->GetMethodID(_jClass,"TestMethod","()V"); env->CallVoidMethod(obj,_jmethodID); return env->NewStringUTF("hahah"); } //调用java层静态方法 JNIEXPORT void JNICALL Java_com_crackme_teststaticreflection_MainActivity_CallTestStaticMethod(JNIEnv * env, jobject obj, jstring jstr) { jclass _jClass= env->FindClass("com/crackme/teststaticreflection/MainActivity"); jmethodID _jmethodID= env->GetStaticMethodID(_jClass,"TestStaticMethod","(Ljava/lang/String;)V"); env->CallStaticVoidMethod(_jClass,_jmethodID,jstr); }
12.运行测试是否调用成功
项目源文件下载:
链接:https://pan.baidu.com/s/1g_ct5DyDOi_6qY0E7c-aZA
提取码:zx2u