如何使用本机代码以编程方式查找Java本地变量的内存地址
How to find the memory address of a Java local variable programmatically using a native code?
尽管有类似的问题(如1、2、3),但它们的答案并不能解决我的问题。
我使用Android NDK和Android Studio 1.5.1,目标是Android API 18(在Android KitKat 4.4之前,所以我处理的是Dalvik,而不是ART运行时)。
我知道一个原始Java本地变量应该在Dalvik解释器堆栈上,但我找不到它
我使用以下代码在Java代码中声明了一个Java本地整数幻数(0x23420023),并使用本地代码(C代码)进行搜索。
我将Java代码的进程id(pid)和线程id(tid)传递给C代码,这样我就可以搜索声明该幻数变量的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
我可以立即找到神奇的数字,但问题是内存区域被应用程序对象文件占用,而不是Dalvik堆栈。您可以通过取消注释标记为"//1-dex:"的第一个if语句,并注释掉C代码中两个while循环之间标记为"//2-permission:"answers"//3-inode"的第二个和第三个if语句来确认这一点。
然而,当我搜索其他具有读、写和私有权限"rw-p"(因为Dalvik堆栈应该具有读/写/私有权限)的剩余内存区域(从文件/proc/pid/task/tid/maps中提取)时,我得到了一个分段错误。您可以通过注释掉C代码中两个while循环之间标记为"//1-dex:"的第一个if语句,并取消注释标记为"//2-permission:"answers"//3-inode"的第二个和第三个if语句来确认这一点。
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, ' ', 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提供了一种访问本地代码中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%xn", get_sp());
printf("BP 0x%xn", get_bp());
return 0;
}
- 附加调试器并以编程方式获取变量地址 Visual Studio
- 变量地址的运算符[]是如何工作的
- C 给出了一个字符串列表,如何从类中获取各个变量地址
- 从函数返回变量地址时如何修复"与局部变量关联的堆栈内存地址"?
- 获取封装在命名空间中的静态变量地址
- 为什么分配的变量地址之间相差 16 个字节?
- 为什么在循环中定义的变量地址在每次迭代中都保持不变
- 是否可以使用指向语句中声明的变量地址的指针"if"
- 字符串从变量(&变量)地址的长度 - 嵌入式C
- 汇编:C++堆栈变量地址不同/错误?
- x 在变量地址中的意义是什么?
- 在哪里放置 HW BP 以捕获全局变量地址损坏
- C++变量地址不匹配
- 重载 std::ostream 运算符<<未调用,stream 获取变量地址而不是对象
- std矢量包含指针和变量地址.清理
- 注册变量地址
- 使用内联程序集获取变量地址
- 如果用调试信息编译,则通过其名称获取全局变量地址
- 如何在Visual Studio中复制变量地址
- 当堆栈内存中的变量地址分配给数据段或堆内存中的指针时,是否有任何错误?