gpt4 book ai didi

java - 如何使用 native 代码以编程方式查找 Java 局部变量的内存地址?

转载 作者:太空宇宙 更新时间:2023-11-04 03:33:05 25 4
gpt4 key购买 nike

虽然也有类似的问题(比如 1 , 2 , 3 ),但是他们的回答并没有解决我的问题。

我正在使用 Android NDK 和 Android Studio 1.5.1,目标是 Android API 18(在 Android KitKat 4.4 之前,所以我处理的是 Dalvik,而不是 ART 运行时)。

我知道原始 Java 局部变量应该在 Dalvik 解释器堆栈上,但我找不到它。

我使用以下代码在 Java 代码中声明了一个 Java 本地整数魔数(Magic Number) (0x23420023) 并使用 native 代码(C 代码)搜索它。

我将 Java 代码的进程 ID (pid) 和线程 ID (tid) 传递给 C 代码,因此我可以搜索声明该魔数(Magic Number)变量的 Java 方法占用的虚拟地址空间。

在 C 代码中,我通过读取和解析文件/proc/pid/task/tid/maps 来获取 Java 代码的内存区域

问题是什么?

当我扫描内存区域时(从文件/proc/pid/task/tid/maps 中提取):

ad5b1000-ad7d7000 r--p 00000000 1f:01 756/data/dalvik-cache/data@app@com.example.magicnumber2-1.apk@classes.dex

我可以立即找到魔数(Magic Number),但问题是内存区域被应用程序目标文件占用,而不是 Dalvik 堆栈。您可以通过取消注释标记为“//1-dex:”的第一个 if 语句并注释掉标记为“//2-permission:”和“//3-inode”的第二个和第三个 if 语句来确认这一点C 代码中的两个 while 循环。

但是,当我搜索其他剩余的内存区域(从文件/proc/pid/task/tid/maps 中提取)时,它们具有读取、写入和私有(private)权限“rw-p”(因为 Dalvik 堆栈应该具有读/写/私有(private)权限),我收到段错误。您可以通过注释掉标记为“//1-dex:”的第一个 if 语句并取消注释标记为“//2-permission:”和“//3-inode”的第二个和第三个 if 语句来确认这一点C 代码中的两个 while 循环。

Java代码:

public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("MyLibrary");
}

public native boolean findMagicNumber(int pid, int tid);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int magicNumber = 0x23420023 ;
int pid = android.os.Process.myPid();
int tid = android.os.Process.myTid();
findMagicNumber(pid, tid);
System.out.println("********** magicNumber = " + magicNumber + " PID=" + pid + " TID=" + tid);
}
}

C代码:

#include "com_example_magicnumber2_MainActivity.h"
#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include <string.h>


JNIEXPORT jboolean JNICALL Java_com_example_magicnumber2_MainActivity_findMagicNumber(JNIEnv *env, jobject obj, jint pid, jint tid) {

long long startaddr, endaddr, size, offset, inode;
char permissions[8], device[8], filename[200], line[250];
char *start, *end, *candidate;
char filepath[100];

//pid is the process id and tid is the thread id of the Java calling method from the Java code
sprintf(filepath,"/proc/%d/task/%d/maps", pid, tid);
FILE* file = fopen(filepath, "r");

while (fgets(line, sizeof(line), file)) {
memset( filename, '\0', sizeof(filename) );
sscanf(line,"%llx-%llx %s %llx %s %llx %s", &startaddr, &endaddr, permissions, &offset, device, &inode, filename);

//1-dex: examine only the memory region mapped to the app dex file
if ((strstr(filename,".dex"))==NULL) continue;

//2-permission: examine only read, write, and private memory regions
//if (((strstr(permissions, "rw-p")))==NULL) continue;

//3-inode: examine only the memory region that is not mapped to a file or device
//if (inode !=0) continue;

__android_log_print(ANDROID_LOG_DEBUG,":", "%llx-%llx %s %llx %s %llx %s",
startaddr, endaddr, permissions, offset, device, inode, filename);
start = startaddr;
end = endaddr;
candidate = memchr( start, 0x14, (end-start));
while( candidate !=0){
if ((candidate[2]== 0x23) &&
(candidate[3] == 0x00) &&
(candidate[4] == 0x42) &&
(candidate[5] == 0x23)){
__android_log_print(ANDROID_LOG_DEBUG,"@@@@@@@@@@","The magic number is found at %p", candidate);
break;
}
else
candidate = memchr(candidate+1, 0x14, (end-candidate));
}
}
}

最佳答案

JNI 提供了一种访问 native 代码中的 java 变量的机制,此处对此进行了描述:http://www.math.uni-hamburg.de/doc/java/tutorial/native1.1/implementing/field.html

然后你可以使用

  &x; // gets the address of x

获取变量的地址

另一种方法是使用汇编程序,即下面的代码打印堆栈的开始(通过打印堆栈指针和基指针的地址)

#include <stdio.h>

unsigned long get_sp(){
__asm__("mov %rsp, %rax ");
}

unsigned long get_bp(){
__asm__("mov %rbp, %rax ");
}

int main(int argc, char **argv)
{
int n;
printf("SP 0x%x\n", get_sp());
printf("BP 0x%x\n", get_bp());
return 0;
}

关于java - 如何使用 native 代码以编程方式查找 Java 局部变量的内存地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34626536/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com