一、创建项目 myapplication
我的项目文件大致是这样,这是我制作之后的全部文件:
二、设计UI界面布局
在\res\layout\activity_main.xml文件中添加两个TextView元素作为文字提示,一个EditText元素实现输入精度值,两个Button元素,分别实现计算和清空结果功能。
activity_main.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:gravity="center_horizontal"
android:orientation="vertical"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="171dp">
<TextView
android:id="@+id/vText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_columnSpan="4"
android:layout_margin="5dp"
android:paddingLeft="12dp"
android:gravity="left"
android:text="Approximated value of Pi:"
android:textSize="17dp"
/>
<TextView
android:id="@+id/showText"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_columnSpan="4"
android:layout_margin="5dp"
android:paddingTop="5dp"
android:paddingLeft="12dp"
android:gravity="left"
android:text="Showing Result.. "
android:textSize="17dp"
app:layout_constraintTop_toBottomOf="@id/countButton" />
<EditText
android:id="@+id/inText"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginStart="10dp"
android:hint="Please enter a number."
android:inputType="numberDecimal" />
<Button
android:id="@+id/countButton"
android:layout_width="150dp"
android:layout_height="55dp"
android:layout_marginTop="25dp"
android:layout_marginRight="80dp"
android:text="calculate" />
<Button
android:id="@+id/DeleteButton"
android:layout_width="150dp"
android:layout_height="55dp"
android:layout_marginLeft="80dp"
android:layout_marginTop="-55dp"
android:text="delete" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
布局展示:
三、使用C语言实现莱布尼茨公式求 π 的近似值;
在cpp/native-lib.cpp文件中编写实现pi的近似值计算的程序代码,代码如下图:
#include <jni.h>
#include <string>
#include <stdio.h>
#include <cmath>
using namespace std;
#define PI 3.1415926535
extern "C" JNIEXPORT jdouble JNICALL
Java_com_example_myapplication_JNI_1N_calculationPI(
JNIEnv* env,
jclass /* this */, jdouble precision) {
double pi = 0.0;
double term = 1.0;
int sign = 1;
while(fabs(pi*4-PI)> precision)
{
pi += sign * (1.0 / term);
term += 2.0;
sign *= -1;
}
return 4.0 * pi;
}
四、在自定的apps开放平台里设计并实现模块的封装及接口定义;
①java实现布局中各元素的事件处理
在\Java\com.example.myapplication\MainActivity.java文件中定义MainActivity类,继承自AppCompatActivity,并实现OnClickListener接口。这一步的目的是为两个Button元素定义单独的事件处理程序。在这个类中,将实现用户点击计算Button进行计算pi近似值和清除Button进行清空结果。
MainActivity.java代码展示:
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import static com.example.myapplication.JNI_N.calculationPI;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("application");
}
@Override
protected void onCreate(Bundle SaveInstanceState) {
super.onCreate(SaveInstanceState);
setContentView(R.layout.activity_main);
//声明并初始化
TextView tv=findViewById(R.id.showText);
Button cButton=findViewById(R.id.countButton);
Button delButton=findViewById(R.id.DeleteButton);
EditText InText=findViewById(R.id.inText);
//通过JNI_N.calculationPI(precision)来结合c++实现点击计算的按钮进行计算并展示结果
cButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cButton.setOnClickListener(this);
String input = InText.getText().toString();
if (!input.isEmpty()) {
double precision = Double.parseDouble(InText.getText().toString());
double pi = JNI_N.calculationPI(precision);
tv.setText(" " + pi);
}
else
{
tv.setText("Please enter a number.");
}
} });
//清除结果
delButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
delButton.setOnClickListener(this);
tv.setText(" ");
}
});
}
}
上面代码中,double pi = JNI_N.calculationPI(precision); 是调用c语言代码接口。而这个接口声明定义我是在新建的另一个JNI_N.java文件中声明的,代码如下图:
package com.example.myapplication;
public class JNI_N {
// static {System.loadLibrary("pi");}
public static native double calculationPI(double precision);
}
我对MainActivity.java代码简单解释一下哈:
计算Button点击事件实现代码是上面MainActivity.java代码中的:
清除结果Button点击事件实现代码是上面MainActivity.java代码中的:
注意:求π 的近似值的c语言代码必须在Java_com_example_myapplication_JNI_1N_calculationPI(JNIEnv* env,jclass /* this */, jdouble precision){}方法内实现。JNI_1N就是JNI_N.java中的JNI_N类名,calculationPI就是接口名。
五、CMakeLists.txt文件中也要添加项目名字:
然后编译程序(Make Project),试着运行(Run)看看能不能成功,编译成功后会生成xxx.so文件,如下图:
六、在自制简单demo工程里调用模块实现输入精度值(不少于5组精度值),输出 π 值;
运行demo工程可以在手机中显示的一个计算pi近似值app界面,输入精度值,点击calculate得出结果,点击delete清除结果。实现效果如下图:
七、设置 Obfuscator-LLVM 的代码混淆参数并对封装后的模块编译生成库文件;
混淆前先使用的反汇编工具是IDA 进行查看libapplication.so的反汇编代码。直接将Andriod Studio的工程文件中的cpp\jniLibs\x86文件下的libapplication.so拖进去IDA界面中。回到Andriod Studio就可以看到cpp\jniLibs\x86下多了几个libapplication.so.xxx。
以下是使用IDA查看.so文件步骤(直接将Andriod Studio的工程文件中的cpp\jniLibs\x86文件下的libapplication.so拖进去IDA界面中):
(1)混淆前先做环境配置工作准备,分别下载并安装好Obfuscator-LLVM、cmake、Mingw。
我下载的是obfuscator-llvm-9.0.1版。
(2)cmd进入命令窗口,进入obfuscator-llvm-9.0.1目录下,新建一个build目录文件:mkdir build ,obfuscator-llvm-9.0.1目录下就会出来一个空的build 文件夹 。
(3)然后进入build目录文件中执行以下操作:
①初始化MakeFIle,输入命令:cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DLLVM_INCLUDE_TESTS=OFF ../../obfuscator-llvm-9.0.1
②开始编译,编译时间>=30min,电脑配置好的话可能会短些。输入命令:mingw32-make.exe -j8
(4)编译完成后,build文件中就会生成很多文件,然后我将obfuscator-llvm-9.0.1\build\bin下的 clang、clang-format、clang++ 三个文件复制替换到我存放Andriod studio用的ndk文件夹D:\solft\appgalley\ndk\21.4.7075529\toolchains\llvm\prebuilt\windows-x86_64\bin(这个ndk文件是看你之前安装An下的ndk存放的位置。这里面的这三个文件最好复制一份保存到别的地方,以防替换不成功还可以恢复)中。
(5)接着我将obfuscator-llvm-9.0.1\build\lib\clang\9.0.1\include下的__stddef_max_align_t.h 、stdarg.h 、stddef.h三个文件复制替换到我存放Andriod studio用的ndk文件夹D:\solft\appgalley\ndk\21.4.7075529\toolchains\llvm\prebuilt\windows-x86_64\sysroot\usr\include下。
(6)设置环境变量:系统变量中Path中添加cmake,mingw64的环境变量
(7)设置参数修改 CMakeLists.txt
(8)然后clean project再编译程序make project,成功就可以了。
八、再把新的.so文件拖到IDA中查看,对比混淆代码前后的库文件,反汇编的结果;
下面是我的demo工程文件生成.so文件在IDA中的原本样子展示以及源代码(20行)展示:
混淆后框框变多了,代码变复杂了,代码原本只有20行,变成了31行,效果图展示如下: