移动安全技术-Java调用C函数_JNI

Posted hunpi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了移动安全技术-Java调用C函数_JNI相关的知识,希望对你有一定的参考价值。


前言

  课程内容:Jni、Ndk、so、Ida。

  使用Jni实现java程序调用其它开发语言的函数。

  环境:NDK,CMake。

  实验:用java调用C函数。

AS配置C语言环境

  通过科学上网方式,下载安装 NDKCmake
位置: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的主要内容,如果未能解决你的问题,请参考以下文章

在windows下 如何使用java jni调用so文件

01_JNI是什么,为什么使用,怎么用JNI,Cygwin环境变量配置,NDK案例(使用Java调用C代码),javah命令使用

JNI基础

Android在C ++ JNI代码中从另一个活动类调用Java函数

JNI调用C语言

Android JNI编程—JNI基础