だから、混乱したファイル
混乱の最初に、目的
JNIが形成javahはコスト関数名類似java_com_XXこのフォームに対応する現像工程において使用し、容易に逆転することによって求めることができる場合に輸出のリストIDAそう逆
次のように:私たちの目的は、この機能は簡単に推測の難易度を高め、IDAに見つけることができないようにすることです。
第二に、混乱方法
1.原理
我々はSystem.loadLibraryのを呼び出すと(のJavaにXXXメソッド)をロードするには、仮想マシンを教えてくれるときlibxxx.soリンクライブラリを。VMは、最初の関数は、ローカルレベルへのJava層からいくつかの初期化作業を行うJNI_OnLoadを実行するので、ライブラリをロードします。また、この機能でJava層でネイティブメソッドを登録し、最終的にRegisterNativesをメソッドは、特定の方法に従うことなく、形式に名前を付けながら、C / C ++の暗黙的なストライキJavaでネイティブメソッドの方法に私たちを助けることができます呼び出します。
。JavaのJNI従来の方法:1のJavaクラスは、ネイティブメソッドを用いて調製し; ---> javahはを使用してコマンド・ファイルを生成する2 .Hヘッダ、ヘッダファイルに実装3符号化方式--->このような「公式。 「プロセス、我々はこれが不利益をもたらすことを認識し、そう簡単には逆で検出されたjava_com_xxxx
だから我々はRegisterNativesをメソッド呼び出しJNIは、JVMにネイティブを登録するための動的な方法を提供しているJNIネイティブメソッド機能を混乱させる
動的登録の手順:
LのJNI_OnLoadはカスタム関数、registerNativeMethodsによって()関数は、ネイティブ関数ポインタとヘッダファイルを交換します。
Lは、対応する置き換えネイティブ関数の機能を実現します。
隠れ= -fvisibility = L隠れシンボル・テーブルは、ファイルAndroid.mk LOCAL_CFLAGSここでの追加します
2.実装
(C ++例えば、わずかな変化構文Cを必要とします)
1) JNIで任意のフォルダのCPPファイル名を作成します。
2) 次のコードをコピー
//
// Created by libb on 2019/5/8.
//
#include<jni.h>
#include <stdio.h>
#include <log.h>
#include <assert.h>
#include "com_limushan_decomplieso_JniTest.h"
#define JNIREG_CLASS "com/limushan/decomplieso/JniTest"//指定要注册的类
jobject getApplication1(JNIEnv* env) {
jclass localClass = (env)->FindClass("android/app/ActivityThread");
if (localClass != NULL) {
// LOGI("class have find");
jmethodID getapplication = env->GetStaticMethodID(localClass, "currentApplication",
"()Landroid/app/Application;");
if (getapplication != NULL) {
jobject application = (env)->CallStaticObjectMethod(localClass, getapplication);
return application;
}
return NULL;
}
return NULL;
}
extern "C"
__attribute__((section (".mytext"))) JNICALL jobject _xxx_yyy1(JNIEnv *env, jclass obj) {
return getApplication1(env);
}
extern "C"
__attribute__((section (".mytext"))) JNICALL void _xxx_yyy2(JNIEnv *env, jclass obj,jint flag) {
jclass temp_clazz = NULL;
jmethodID mid_static_method;
// 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
temp_clazz = env->FindClass("java/lang/System");
mid_static_method = env->GetStaticMethodID(temp_clazz, "exit", "(I)V");
(env)->CallStaticVoidMethod( temp_clazz, mid_static_method, flag);
(env)->DeleteLocalRef(temp_clazz);
}
extern "C"
__attribute__((section (".mytext"))) JNICALL jstring _xxx_yyy3(JNIEnv *env, jclass obj) {
jobject context = getApplication1(env);
jclass class_system = (env)->FindClass( "java/lang/System");
if (class_system == NULL) {
LOGD("class system is null");
}
jmethodID method_get_property = (env)->GetStaticMethodID(class_system, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
if (method_get_property != NULL) {
LOGD("method is found...");
} else {
LOGD("method not found...");
}
jstring host = (env)->NewStringUTF("http.proxyHost");
jstring port = (env)->NewStringUTF("http.proxyPort");
jstring hostIp = (jstring)(env)->CallStaticObjectMethod(class_system, method_get_property, host);
jstring hostPort = (jstring)(env)->CallStaticObjectMethod(class_system, method_get_property, port);
if (hostIp != NULL || hostPort != NULL) {
LOGD("有代理,好危险!");
} else {
LOGD("环境正常,可以操作");
}
return hostPort;
}
/**
* Table of methods associated with a single class.
*/
//绑定,注意,V,Z签名的返回值不能有分号“;”
//这里就是把JAVA层的getStringFromC()函数绑定到Native层的getStringc()函数,就无需使用原生的Java_com_xx_xx_classname_methodname这种恶心的函数命名方式了
static JNINativeMethod gMethods[] = {
{ "getApplication", "()Ljava/lang/Object;", (void*)_xxx_yyy1},
{ "exitApplication", "(I)V", (void*)_xxx_yyy2},
{ "checkProxyExist", "()Ljava/lang/String;", (void*)_xxx_yyy3},
};
/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = (env)->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
if ((env)->RegisterNatives(clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
sizeof(gMethods) / sizeof(gMethods[0])))
return JNI_FALSE;
return JNI_TRUE;
}
/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
if ((vm)->GetEnv( (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL);
if (!registerNatives(env)) {//注册
return -1;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
return result;
我々RegisterNativesをは地元の動的メソッドを取得します
3) 変形法対応表
/**
* Table of methods associated with a single class.
*/
//绑定,注意,V,Z签名的返回值不能有分号“;”
//这里就是把JAVA层的getApplication函数绑定到Native层的_xxx_yyy1函数,
//就无需使用原生的Java_com_xx_xx_classname_methodname这种恶心的函数命名方式了
static JNINativeMethod gMethods[] = {
{ "getApplication", "()Ljava/lang/Object;", (void*)_xxx_yyy1},
{ "exitApplication", "(I)V", (void*)_xxx_yyy2},
{ "checkProxyExist", "()Ljava/lang/String;", (void*)_xxx_yyy3},
};
これは、配列、Javaのネイティブメソッドと私たちの地元の機能間のこの対応マッピングです。各関数は、特定表しJNINativeMethod
構造は、以下の公式定義を:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
- 最初の名前は、Java関数内の変数の名前です。
- 第二の可変署名、文字列は、Java関数のパラメータと戻り値に記載されています
- FnPtr第三の変数は、ネイティブ関数への関数ポインタです。フロントは、(void *型)に接続する必要があります
- 最初のパラメータは、主に2番目の引数がより複雑であり、我々は、書き込み方法であり、第三のメソッド内部.hファイルである。パラメータは、戻り値を示した後にブラケットがブラケットで、種類を示します。
「()」の戻り値は、バックを表し、文字パラメータを示します。例えば:
"()V")は、(無効XXXを言います。
"(I)V" ボイドXXXを(A INT)を表し;
"(II)I" 表示しますXXX(あなたなら、あなたB)。
"()Ljava /ラング/文字列;" 表示文字列XXX()。
パラメータおよびこれらのタイプの文字の機能マップは次のよう:
?????
Vボイドが無効
ブールjboolean Zを
I int型のJINT
J jlongロング
D jdoubleダブル
F. Jfloatフロート
B jbyteバイト
文字jchar C
S jshort短い
配列は、「[」スタートを使用していますが、 "[[[D"は"ダブル[] [] []")であり、同じように"[" 2つの文字のn次元アレイは、番号の前にある表し
、[ I jintArray INT []
[F. jfloatArrayフロートを[]
[B jbyteArrayバイト[]
[C jcharArrayのchar []
[S jshortArrayショート[]
[jdoubleArrayダブルD []
[J jlongArrayロング[]
[Z jbooleanArrayブール[]
参照タイプは:と、「L」で始まる「」中間で終了し、「/」分離します。「;」クラス名は、複数のセパレータである
Ljava /ラング/文字、文字列JSTRING
Ljava /ラング/オブジェクト、オブジェクトjオブジェクト
···
4) 実施ネイティブ関数に対応する機能を置き換え
例としては、次のとおりです:名前は任意にここで撮影することができ、独自の実装を実現するために交換する必要があります
extern "C"
__attribute__((section (".mytext"))) JNICALL void _xxx_yyy2(JNIEnv *env, jclass obj,jint flag) {
jclass temp_clazz = NULL;
jmethodID mid_static_method;
// 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
temp_clazz = env->FindClass("java/lang/System");
mid_static_method = env->GetStaticMethodID(temp_clazz, "exit", "(I)V");
(env)->CallStaticVoidMethod( temp_clazz, mid_static_method, flag);
(env)->DeleteLocalRef(temp_clazz);
}
我々はJavaの層を持っていないので、属性を持つ関数((セクション(「.mytext 『)))では、このような場合は、この関数の翻訳は、カスタムの内部という名前の』 .mytext」セクションにコンパイルされますこの機能は、したがって、内部のカスタムセクションを定義するために書き込まれます
5) 文が登録するカテゴリ
???
の#define JNIREG_CLASS "COM / limushan / decomplieso / JNITest" //登録したいクラスを指定
???
6) = -fvisibility =隠されたシンボルテーブルを隠す一のLOCAL_CFLAGS文書Android.mkを添加しました
7) 他のステップは、一貫性のあるJNI開発します
8) ので、ビルドファイルをビルドNDK
次のように具体的な結果は、メソッド名の関数名は、インデックステーブルの呼び出しで見つからないれます。唯一の解決するために次のステップへの自己定義された断面積を見つけます