吾爱破解安卓逆向入门教程学习
00x1 ELF
ELF 文件是Linux 和 Android 系统中最常见的二进制文件格式,全称是“可执行与可链接格式”(Executable and Linkable Format)。它就像程序的“包装盒”,里面装着代码、数据以及告诉操作系统如何运行程序的信息,无论是直接运行的软件、动态库还是编译中间文件,大多都采用这种格式
ELF 文件是 Linux 和 Android 系统里最常用的程序文件格式,用来存可执行程序、库文件和编译中间文件 。
在 Android 应用运行时 , ELF 文件的大部分内容 , 会被 映射到内存中 ; 这就意味着 Android 应用内存中的很多数据 , 会遵循 ELF 文件格式的规范
ELF 文件格式最常见的形式就是 .so 动态库 ;
文件扩展名:可能没有扩展名,也可能是 .elf、.o、.so 等,具体取决于文件用途 。
ELF 文件的特点 :ELF 文件是以7F 45 4C 46开头 , 其中 7F 是一个二进制标志 , 45 4C 46 是 ELF 字符对应的 ASCII 码 ;
ELF文件类型有
可执行文件(Executable File)加载后可以直接运行的二进制机器直接执行
可执行文件(ELF格式)被操作系统加载器加载进内存后,CPU可以直接执行它里面的二进制机器码(原生代码)。
- 可执行文件是包含程序代码的ELF文件,经过编译和链接后可以直接执行。它通常包含程序的入口点,操作系统加载它后便开始执行。
- 这类文件可以通过命令行直接运行。例如,执行一个ls命令的二进制文件就是一个可执行的ELF文件。
- 文件的类型标识通常是ET_EXEC。
目标文件(Object File)
也就是翻译成机器码的c语言,需要靠外部的库才能执行。.o
翻译成机器码:编译器自己就能搞定
“依赖外部”发生在翻译完之后(链接阶段)
问题出在,你写的 C 代码几乎不可能只靠自己完成所有事。
只要你调用了一个外部函数,比如 printf:
```c
#include <stdio.h>
void sayHello() {
printf("Hello");
}
```
编译器把 sayHello 翻译成机器码后,这个目标文件里会留下一个“坑”:
· “此处需要调用 printf 函数,但 printf 的机器码不在我这里,请后续帮我填上它的真实地址。”
这个“填坑”的动作,就叫链接(Linking)。
它必须依赖外部的库(如 libc.so),因为 printf 的真实机器码在那里。
- 目标文件是源代码编译后生成的中间文件,它包含了程序的机器代码,但还没有完全链接。目标文件通常不能单独运行,需要与其他目标文件或者库文件一起链接,生成可执行文件。
- 文件的类型标识通常是ET_REL(Relocatable)。
- 目标文件会包含符号表、重定位信息和调试信息,供链接器使用。
共享库文件(Shared Library)共享库(环境空间)
也就是他就是单纯的依赖然后存储在一个文件
共享库文件(.so)就是:
1. 单纯的依赖:它本身只是一堆被编译好的函数(如 printf、strcpy),静静地等着别的程序来调用自己。
2. 存储在一个文件中:这些函数被打包在一个独立的二进制文件里,方便管理和共享。
它自己不做任何“汇聚”的动作,只是一个被动的代码仓库。真正把依赖关系“连接”起来,让程序能调用到它的,是动态链接器(Linker),就像你之前理解的“引用的包”,最终由 ART 虚拟机去加载和解析一样。
4.核心转储文件(Core Dump)
程序崩溃时生成的内存快照,用于调试。
- 共享库文件是一种可以被多个程序同时使用的动态链接库(.so文件)。它包含了供多个程序共享的函数和代码,通常用于提供一些常见功能的共享实现。
- 当一个程序需要某些功能时,它会在运行时加载共享库,而不是在编译时将这些功能静态链接进程序。共享库有助于节省内存和磁盘空间。
- 文件的类型标识通常是ET_DYN(Dynamic)。
静态库文件(Static Archive File)
目标文件打包是吧?.a
这是一个归档文件,包含多个目标文件(.o文件),用于静态链接。链接器会将静态库中的代码复制到最终的可执行文件中。
参考
【Android 逆向】ELF 文件格式 ( ELF 文件头 | ELF 文件头标志 | ELF 文件位数 | ELF 文件大小端格式 )-腾讯云开发者社区-腾讯云
【Linux篇】ELF文件及其加载与动态链接机制-腾讯云开发者社区-腾讯云
elf文件详解_.elf-CSDN博客
elf文件详解_.elf-CSDN博客
00x2 NDK开发
NDK开发是Android应用开发中的一项重要技术,它允许开发者使用C和C++语言进行高性能、安全、可移植的代码编写。本文将带您了解NDK开发的基本概念、应用场景、优势以及实践方法,帮助您更好地掌握NDK开发技术。
在Android平台上,虽然Java是主要的开发语言,但对于一些需要高性能的应用逻辑,C和C++无疑是更好的选择。这时候,我们就需要用到Android NDK(Native Development Kit)这个工具了。
NDK是Android平台提供的一套原生开发工具集,它允许开发者使用C和C++编写应用中的一部分代码,并将其编译为动态链接库(.so文件)。这些库可以在Android应用中通过Java Native Interface(JNI)进行调用,实现Java与C/C++的交互。
可以与java代码连接
参考
深入浅出:NDK开发全解析
【NDK开发】Android NDK 原生构建:ndk-build 与 CMake-CSDN博客
安卓开发
1.src:
该目录是放置所有Java代码的地方,在这里的含义和 普通Java项目下的src目录是完全一样的,在src目录中 可以创建多个包,每个包中可以存放不同的文件或者 Activity。
2.gen:
该目录是自动生成的,主要有一个R.java文件,在项目中添加的任何资源文件都会在其中生成一个相应的资源Id,这个文件一定不要手动修改,当res资源文件修改时, R.java文件都会重新编译。
3.Android 8.0.0:
该目录中存放的是当前工程使用的Android SDK,从图中可以看出当前应用程序引用的是Android SDK 8.0.0,不同版本的SDK文件的名称也不同。
4.assets:
该目录用于存放一些随程序打包的文件,通常放置一些项目中用到的多媒体资源。当Android程序打包时它会原封不动地一起打包,安装时会直接解压到对应的assets 目录中。
5.bin:
该目录不需要过多的关心,它主要包含了一些在编译时自动产生的文件,其中会有一个当前项目编译好的安装包,展开bin目录会看到HelloWorld程序的安装包HelloWorld.apk,把这个文件复制到手机上就可以直接安装了。但是不能作为发布版本使用。
6.libs:
如果项目中用到了第三方的Jar包,就需要把这些Jar包都放在libs目录下,放 在这个目录下的Jar包都会被添加到构建路径中去。
7.res:
该目录中放置的是Android要用到的各种程序资源,如图片、布局、字符串等。(可以分为以下几层)
8.res/drawable:
存放png、jpg 等图标文件。其中,drawable目录分为不同的文件夹:drawable-hdpi、drawable-ldpi、drawable-mdpi、 drawable-xhdpi、drawable-xxhdpi,这些文件夹中存放的图片分别对应不同的手机屏幕大小,以便做屏幕适配。
9.res/layout:
存放xml 界面文件,xml 界面文件和HTML 文件一样,主要用于显示用户操作界面。
10.res/values:
存放应用使用到的各种类型数据。不同类型的数据存放在不同的文件中,其中strings.xml 定义字符串和数值,colors.xml 定义颜色和颜色字串数值,dimens.xml 定义尺寸数据,styles.xml 定义样式。
11.res/anim:
存放自定义动画的XML 文件。
12.res/raw:
该目录用于存放应用使用到的原始文件,如音效文件等。编译软件时,这些数据不会被编译,它们被直接加入到程序安装包里。
13.res/xml:
XML资源文件。
14.AndroidManifest.xml:
该文件是整个项目的配置文件,在程序中定义的四大组件都需要在这个文件里注册,另外还可以在这个文件中给应用程序添加权限声明,也可以重新 指定创建项目时程序最低兼容的版本和最高版本。清单文件配置的信息会配置到Android系统中,当程序运行时,系统会先找到清单文件中配置的信息,然后根据设置的信息打开相应的组件。
15.proguard-project.txt:
该文件是Android提供的混淆代码工具Proguard的配置文件,通过该文件可以混淆应用程序中的代码,防止应用程序被反编译出源码。
16.project.properties:
该文件记录了 Android项目运打时的环境,并通过一行代码指定了编译程序时所使用的SDK版本,这个版本可以手动更改,但必须是已下载的版本
app/src/main/java/com/example/ndkdamo/MainActivity.java:31
在这个java文件里面,所见到的Activity就是在第一章认识的Android四大组件之一。这个java文件主要配置了Activity获得页面主要加载的界面文件activity_main.xml。
MainActivity.java是 Android 应用程序中主活动(Main Activity)的 Java 源代码文件。它是大多数 Android 应用的入口点,负责管理用户界面的显示和交互逻辑。
package com.example.ndkdamo; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import com.example.ndkdamo.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { // Used to load the 'ndkdamo' library on application startup. //加载一次ndkdamo //· Android 上会查找 libndkdamo.so。 //· Linux 上查找 libndkdamo.so。 // · Windows 上查找 ndkdamo.dll。 static { System.loadLibrary("ndkdamo"); } private ActivityMainBinding binding; //布局绑定 @Override protected void onCreate(Bundle savedInstanceState) { //必须执行,表示一个窗口正在生成 super.onCreate(savedInstanceState); //也就是这个activity main就是自动绑定activity_main.xml然后创建一个对象是吧? binding = ActivityMainBinding.inflate(getLayoutInflater()); //获取外层视图并显示 setContentView(binding.getRoot()); // Example of a call to a native method //获取示例文本 TextView tv = binding.sampleText; //文本控件赋值 tv.setText(stringFromJNI()); } /** * A native method that is implemented by the 'ndkdamo' native library, * which is packaged with this application. */ //native,so层实现方法,如下 public native String stringFromJNI();?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"> <TextView android:id="@+id/sample_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>Ctrl shift a
app/src/main/cpp/CMakeLists.txt:20
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html. # For more examples on how to use CMake, see https://github.com/android/ndk-samples. # Sets the minimum CMake version required for this project. cmake_minimum_required(VERSION 3.22.1) # Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, # Since this is the top level CMakeLists.txt, the project name is also accessible # with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level # build script scope). project("ndkdamo") # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. # # In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define # the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME} # is preferred for the same purpose. # # In order to load a library into your app from Java/Kotlin, you must call # System.loadLibrary() and pass the name of the library defined here; # for GameActivity/NativeActivity derived applications, the same library name must be # used in the AndroidManifest.xml file. add_library(${CMAKE_PROJECT_NAME} SHARED # List C/C++ source files with relative paths to this CMakeLists.txt. native-lib.cpp) # Specifies libraries CMake should link to your target library. You # can link libraries from various origins, such as libraries defined in this # build script, prebuilt third-party libraries, or Android system libraries. target_link_libraries(${CMAKE_PROJECT_NAME} # List libraries link to the target library android log)函数名规则
Java_com_example_ndkdamo_MainActivity_stringFromJNI
· 格式固定:Java_ + 包名(点换成下划线) + _ + 类名 + _ + 方法名。
· 这里表示:包名 com.example.ndkdamo,类名 MainActivity,方法名 stringFromJNI。
· Java 层必须对应声明一个 public native String stringFromJNI();。
std 是什么?
· std 是 C++ 标准库命名空间(standard namespace)的缩写。
· C++ 标准库中的所有组件(如 string、vector、cout、sort 等)都定义在 std 命名空间中,以避免与用户自定义的标识符冲突。
· 整个函数(包括声明和函数体)都是 C++ 代码,并不是“外面是 Java 可解析的东西,里面是 C++”这种分割。
· 但是,函数名(Java_com_example_ndkdamo_MainActivity_stringFromJNI)和修饰符(extern "C"、JNIEXPORT、JNICALL)是为了遵循 JNI 的命名与链接规范,让 Java 虚拟机在加载动态库后,能够根据这个固定名称找到函数的入口地址。
· 一旦 Java 虚拟机找到了并调用这个函数,函数内部的代码(比如 std::string hello = ...)就完全是 C++ 的执行逻辑。
外面的声明就相当于一个翻译的意思,一个连接的桥梁。
也就是说找到是一码事显示又是一码事。
1. 外面的桥梁只管“找到函数”
· extern "C":保证 C++ 函数名不被修饰,让 JVM 能按名字找到这个函数。
· JNIEXPORT:保证函数符号被导出到动态库中,让 JVM 能加载到。
· 特殊函数名:告诉 JVM 这个函数对应 Java 的哪个 native 方法。
这些只解决了“定位函数入口”的问题,不涉及参数和返回值如何在两种语言之间转换。
---
2. 数据类型转换必须手动完成
Java 和 C/C++ 对数据的内存表示完全不同:
· Java 的 String:是一个对象(UTF-16 内部表示,有垃圾回收)。
· C++ 的 std::string:是一个类(通常存储字节数组,不兼容 Java)。
· C 的 char*:只是一个指针,指向字节。
JVM 无法自动知道你想把 C++ 的 std::string 转成 Java 的 String,所以你必须显式调用 JNI 提供的转换函数,比如:
· NewStringUTF(const char*):把 C 字符串转成 Java String。
· GetStringUTFChars(jstring, ...):反过来,把 Java String 转成 C 字符串。
· 外部声明(extern "C" 等)→ 让 JVM 找到你。
· JNI 转换函数(NewStringUTF 等)→ 让你手动把 C++ 数据变成 Java 能接受的形式。
这里
#include <jni.h>//导入jni头文件,提供jni函数及数据类型定义 #include <string>//导入c++标准库 //声明jni函数,会被java代码调用 //extern "C" c语音的方式编译该函数,可以被java虚拟机按名字找到 //也就是兼容的作用,让Java的虚拟机可以找到原生函数,方便链接 //JNIEXPORT 宏,一般是另外一个的地址,C++地库地址方便Java寻找。 //jstring 返回类型是宏 extern "C" JNIEXPORT jstring JNICALL //包名 com.example.ndkdamo,类名 MainActivity,方法名 stringFromJNI Java_com_example_ndkdamo_MainActivity_stringFromJNI( //JNIEnv Java Native Interface Environment 的缩写,即“Java 本地接口环境”。它是一个结构体(或说接口表),包含了大量函数指针,用于在原生代码中操作 Java 对象、类、方法、字段、字符串、数组等。 //表示“指向 JNIEnv 结构体的指针 JNIEnv* env, //调用该原生方法的 Java 对象实例,实例方法 jobject /* this */) { //string字符串 std::string hello = "Hello from C++"; //hello.c_str()转化c //NewStringUTF 是 JNI(Java Native Interface)中用于将 Modified UTF-8 编码的 C/C++ 字符串转换为 Java java.lang.String 对象的函数,返回 jstring,由 JVM 自动管理内存。 //返回 return env->NewStringUTF(hello.c_str()); }参考
HelloWorld,我的第一趟旅程出发点-腾讯云开发者社区-腾讯云
gradle/gradle-daemon-jvm.properties:13
网络超时
C:\Users\jc\AndroidStudioProjects\ndkdamo>gradlew.bat assembleDebug Downloading https://services.gradle.org/distributions/gradle-9.4.1-bin.zip Exception in thread "main" java.io.IOException: Downloading from https://services.gradle.org/distributions/gradle-9.4.1-bin.zip failed: timeout (10000ms) at org.gradle.wrapper.Install.forceFetch(SourceFile:4) at org.gradle.wrapper.Install$1.call(SourceFile:8) at org.gradle.wrapper.GradleWrapperMain.main(SourceFile:67) Caused by: java.net.SocketTimeoutException: Read timed out at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:288) at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:314) at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:355) at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:808) at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966) at java.base/sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:484) at java.base/sun.security.ssl.SSLSocketInputRecord.readHeader(SSLSocketInputRecord.java:478) at java.base/sun.security.ssl.SSLSocketInputRecord.bytesInCompletePacket(SSLSocketInputRecord.java:70) at java.base/sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1465) at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:1069) at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:244) at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:284) at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:343) at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:826) at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:761) at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1740) at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1641) at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224) at org.gradle.wrapper.Install.forceFetch(SourceFile:2) ... 2 moregradle/gradle-daemon-jvm.properties:13
· 文件头的注释 #This file is generated by updateDaemonJvm 说明它是由 Gradle 的 Daemon JVM 自动更新机制 生成的。
· 当你项目里声明了需要某个特定版本的 JDK(例如 JDK 21),但本地没有时,Gradle 就会生成或读取这样一份“工具链配置”,告诉它去哪里下载对应平台的 JDK。
#This file is generated by updateDaemonJvm toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect toolchainVersion=21解决方法,国内链接
gradle/wrapper/gradle-wrapper.properties:9
#Sat Jun 06 01:00:57 CST 2026 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-9.5.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists
00x3 jni
JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。
这种机制使得Java程序能够调用本地应用程序或库中的函数,这些本地方法通常用于执行与硬件直接交互、性能要求较高的任务,如图形处理、音频处理等。同时也允许本地代码调用Java层的函数,从而增强了Java程序的灵活性和扩展性。
刚刚上面的Java就是jni注册。
这个也是
// 定义方法数组 JNINativeMethod methods[] = { {"nativeGetStringFromJNI", "(Ljava/lang/String;)V", (void*)Java_com_example_ndkdemo_MainActivity_nativeGetStringFromJNI} }; // 获取类 jclass clazz = env->FindClass("com/example/ndkdemo/MainActivity"); // 手动注册 env->RegisterNatives(clazz, methods, 1);参考
Android JNI机制概述-腾讯云开发者社区-腾讯云
00x4 ida
lib:lib目录下的子目录存放的是一些与手机CPU架构对应的C/C++代码编译生成的so文件,一般用于JNI开发。
原生把一些注册代码以及渲染放在so文件下面
So里面就是注册具体实现的东西,里面可能有Java注册的逻辑。
__int64 __fastcall Java_com_example_ndkdamo_MainActivity_stringFromJNI(_JNIEnv *a1) { const char *v1; // rsi __int64 v3; // [rsp+18h] [rbp-48h] char v4[24]; // [rsp+40h] [rbp-20h] BYREF unsigned __int64 v5; // [rsp+58h] [rbp-8h] v5 = __readfsqword(0x28u); std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::basic_string[abi:ne190000]<0>( v4, "Hello from C++"); v1 = (const char *)sub_200B0(v4); v3 = _JNIEnv::NewStringUTF(a1, v1); std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::~basic_string(v4); if ( __readfsqword(0x28u) != v5 ) JUMPOUT(0x20001LL); return v3; }public Java_com_example_ndkdamo_MainActivity_stringFromJNI Java_com_example_ndkdamo_MainActivity_stringFromJNI proc near var_60= qword ptr -60h var_58= qword ptr -58h var_50= qword ptr -50h var_48= qword ptr -48h var_3C= dword ptr -3Ch var_38= qword ptr -38h var_30= qword ptr -30h var_28= qword ptr -28h var_20= byte ptr -20h var_8= qword ptr -8 ; __unwind { // __gxx_personality_v0 push rbp mov rbp, rsp sub rsp, 60h mov rax, fs:28h mov [rbp+var_8], rax mov [rbp+var_28], rdi mov [rbp+var_30], rsi lea rsi, aHelloFromC ; "Hello from C++" lea rdi, [rbp+var_20] mov [rbp+var_58], rdi call __ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2B8ne190000ILi0EEEPKc ; std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::basic_string<0>(char const*) mov rdi, [rbp+var_58] mov rax, [rbp+var_28] mov [rbp+var_50], rax call sub_200B0 mov rdi, [rbp+var_50] ; this mov rsi, rax ; char * ; try { call __ZN7_JNIEnv12NewStringUTFEPKc ; _JNIEnv::NewStringUTF(char const*) ; } // starts at 1FF89 mov [rbp+var_48], rax jmp $+5他后面讲的改,我以后再改的试试吧,具体就是要么是汇编修改,要么是二进制修改,然后把注册的内容覆盖实现修改。
