移动安全技术-Java调用C函数_JNI
Posted hunpi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了移动安全技术-Java调用C函数_JNI相关的知识,希望对你有一定的参考价值。
前言
课程内容:Jni、Ndk、so、Ida。
使用Jni实现java程序调用其它开发语言的函数。
环境:NDK,CMake。
实验:用java调用C函数。
AS配置C语言环境
通过科学上网方式,下载安装 NDK
和 Cmake
。
位置:File -> Settings -> Appearance -> System Settings -> android SDK。
创建C++项目
查看CMakeLists.txt文件的内容:
查看MainActivity.java,可以看到加载了native-lib
库,并且声明了相关的native方法 stringFromJNI()
:
查看native-lib.cpp,可以看到stringFromJNI
方法,作用是通过C++返回一个string数据:
编写登录app,使用C语言实现验证功能
程序源码
(1)MainActivity.java
package com.example.hellojni;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import android.text.InputType;
public class MainActivity extends AppCompatActivity {
//final String username = "xiaoshen";
//final String passwd = "nihaoya";
final String right = "恭喜小沈通过验证!";
final String wrong = "验证失败,加油!";
String input_username = "";
String input_passwd = "";
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et1 = (EditText) findViewById(R.id.input_username);
final EditText et2 = (EditText) findViewById(R.id.password);
Button mybutton_1 = (Button) findViewById(R.id.login_in);
mybutton_1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 点击按钮弹出文本
input_username = et1.getText().toString();
input_passwd = et2.getText().toString();
//Toast.makeText(MainActivity.this, "点击成功", Toast.LENGTH_SHORT).show();
Verify();
}
}
);
Button mybutton_2 = (Button) findViewById(R.id.login_out);
mybutton_2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 点击按钮弹出文本
//input_passwd = et2.getText().toString();
Toast.makeText(MainActivity.this, "请进行登陆验证", Toast.LENGTH_SHORT).show();
}
}
);
}
public void Verify() {
if (checkNameAndPasswd(input_username, input_passwd)==1) {
Toast.makeText(MainActivity.this, right, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, wrong, Toast.LENGTH_SHORT).show();
}
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native int checkNameAndPasswd(String uname, String passwd);
}
(2)string.xml
<resources>
<string name="app_name">HelloJni</string>
<string name="xitong">网络准入认证系统</string>
<string name="username">小沈</string>
<string name="passwd">加油!</string>
<string name="in">登录</string>
<string name="out">注销</string>
<string name="input1">用户名</string>
<string name="input2">密码</string>
</resources>
(3)colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorAccent">#D81B60</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="blue">#ff00ff</color>
<color name="red">#ff0000</color>
</resources>
(4)activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/textView4"
android:text="@string/input1"
android:layout_width="70dp"
android:layout_height="52dp"
android:textSize="20dp"
android:layout_marginTop="285dp"
android:layout_marginLeft="20dp"
tools:text="@string/input1" />
<EditText
android:id="@+id/input_username"
android:layout_width="300dp"
android:layout_height="52dp"
android:hint="@string/username"
android:layout_marginTop="280dp"
android:inputType="text" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:layout_width="260dp"
android:layout_height="50dp"
android:text="@string/xitong"
android:layout_marginTop="200dp"
android:layout_gravity="center"
android:textSize="30sp"
android:textColor="#000000"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/in_pass"
android:text="@string/input2"
android:layout_width="70dp"
android:layout_height="52dp"
android:textSize="20dp"
android:layout_marginTop="402dp"
android:layout_marginLeft="20dp"
tools:text="@string/input2" />
<EditText
android:id="@+id/password"
android:layout_width="280dp"
android:layout_height="52dp"
android:ems="10"
android:hint="@string/passwd"
android:gravity="center_vertical"
android:layout_marginTop="400dp"
android:textSize="17sp"
android:inputType="textPassword" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:layout_editor_absoluteX="411dp">
<Button
android:id="@+id/login_in"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_marginTop="480dp"
android:layout_marginLeft="80dp"
android:background="@color/blue"
android:text="@string/in" />
<Button
android:id="@+id/login_out"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_marginLeft="50dp"
android:layout_marginTop="480dp"
android:background="@color/red"
android:text="@string/out" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
(5)C语言验证程序native-lib.cpp
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jint JNICALL
Java_com_example_hellojni_MainActivity_checkNameAndPasswd(
JNIEnv* env,
jobject thiz, jstring uname, jstring passwd) {
// 获取 uname 和 passwd
//const char *real_uname = "xianshen233";
//const char *real_passwd = "61happy";
char real_uname[20] = "xiaoshen233";
char real_passwd[20] = "61happy";
// 接收变量:用户名uname、口令passwd。赋值给指针unameC、passwdC。
const char *unameC = (char *)(env->GetStringUTFChars(uname, JNI_FALSE));
const char *passwdC = (char *)(env->GetStringUTFChars(passwd, JNI_FALSE));
// 将接收的变量,分别赋值给对应的数组,unameCC和passwdCC。
int len_uname = strlen(unameC);
int len_passwd = strlen(passwdC);
char unameCC[len_uname];
char passwdCC[len_passwd];
strcpy(unameCC, unameC);
strcpy(passwdCC, passwdC);
// 对两队数组进行验证,strcmp()相等时返回0。
if((strcmp(real_uname, unameCC)==0) && (strcmp(real_passwd, passwdCC)==0)){
return 1;
}
else{
return 0;
}
}
验证
输入正确的用户名、以及错误的口令,验证失败。
输入正确的用户名、以及正确的口令,验证成功!
把项目打包成APK文件:
工具栏点击“Build”,在下拉栏选择“Generate Signed Bundle /APK”,在弹出的对话框中选择APK。在弹框中任意填写信息,此处口令填写为123456。Build Variants选择release,勾选V2,点击Finish完成。
逆向破解
使用IDA对上一位同学的app进行破解,未成功。
参考
《NDK开发-ReleaseStringUTFChars调用的坑》
https://segmentfault.com/a/1190000005859213
本博客-移动安全技术专栏文章
以上是关于移动安全技术-Java调用C函数_JNI的主要内容,如果未能解决你的问题,请参考以下文章
01_JNI是什么,为什么使用,怎么用JNI,Cygwin环境变量配置,NDK案例(使用Java调用C代码),javah命令使用