文章目錄
- 前言
- AS配置C語言環境
- 撰寫登錄app,使用C語言實作驗證功能
- 程式原始碼
- 驗證
- 逆向破解
- 參考
前言
??課程內容: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
??本博客-移動安全技術專欄文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/286419.html
標籤:其他
上一篇:Android中的執行緒(一)
