【发布时间】:2016-01-06 05:55:31
【问题描述】:
虽然有类似的问题(如1、2、3),但他们的回答并没有解决我的问题。
我正在使用面向 Android API 18 的 Android Studio 1.5.1 的 Android NDK(在 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 语句并注释掉标记为“//2-permission:”和“//3-inode”之间的第二个和第三个 if 语句来确认这一点C 代码中的两个 while 循环。
但是,当我搜索具有读、写和私有权限“rw-p”的其他剩余内存区域(从文件 /proc/pid/task/tid/maps 中提取)时(因为 Dalvik 堆栈应该具有读/写/私有权限),我得到一个分段错误错误。您可以通过注释掉标记为“//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));
}
}
}
【问题讨论】:
-
在虚拟机中,无法保证局部变量可能在哪里(如果有的话)。笔记;即使您找到冷代码的位置,如果代码升温,它也可能会改变(尽管 Android 不倾向于这样做)
-
int magicNumber = 0x23420023 ;不需要在任何地方分配,编译器可以(并且很可能会)将其作为常量省略
标签: java android c++ c android-ndk