#include
#include
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
int kmem;
void read_kmem2(unsigned char *buf, off_t off, int sz)
{
off_t offset; ssize_t bread;
offset = lseek(kmem, off, SEEK_SET);
bread = read(kmem, buf, sz);
return;
}
void write_kmem2(unsigned char *buf, off_t off, int sz) {
off_t offset; ssize_t written;
offset = lseek(kmem, off, SEEK_SET);
if (written = write(kmem, buf, sz) == -1) { perror("Write error");
exit(0);
}
return;
}
int main(int argc, char *argv[]) {
off_t sys_call_table;
unsigned int addr_ptr, sys_call_number;
if (argc
return 0;
}
kmem=open("/dev/kmem",O_RDWR);
if(kmem
perror("Error opening kmem"); return 0;
}
sscanf(argv[1], "%x", &sys_call_table); sscanf(argv[2], "%d", &sys_call_number);
sscanf(argv[3], "%x", &addr_ptr); char buf[256];
memset (buf, 0, 256); read_kmem2(buf,sys_call_table+(sys_call_number*4),4);
printf("Original value: %02x%02x%02x%02x\n", buf[3], buf[2], buf[1], buf[0]);
write_kmem2((void*)&addr_ptr,sys_call_table+(sys_call_number*4),4);
read_kmem2(buf,sys_call_table+(sys_call_number*4),4);
printf("New value: %02x%02x%02x%02x\n", buf[3], buf[2], buf[1], buf[0]);
close(kmem);
return 0;
}
使用前期准备的工具链编译kmem_util.c并将它拷贝至设备中。需要注意的是,从Android Lollipop开始,所有的可执行文件都必须在PIE选项下编译生成。
$ /tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc -pie -fpie -o kmem_util kmem_util.c
$ adb push kmem_util /data/local/tmp/
$ adb shell chmod 755 /data/local/tmp/kmem_util
在修改内核内存空间前,我们需要知道系统调用表中的正确偏移量。我们可以在内核源代码的unistd.h文件中找到openat系统调用的定义:
$ grep -r "__NR_openat" arch/arm/include/asm/unistd.h
#define __NR_openat (__NR_SYSCALL_BASE+322)
接下来要找到我们要替换的openat的地址。我们同样可以在/proc/kallsyms中获取该地址:
$ adb shell cat /proc/kallsyms | grep new_openat
bf000000 t new_openat [kernel_hook]
现在我们已经准备好覆盖sys_call_table条目所需的一切信息了。Kmem_util的用法为:
./kmem_util
以下命令可以修改openat系统调用表以指向我们的自定义函数:
berndt@osboxes:~/Host/Research/SoftToken/Android/Kernel/msm$ adb shell su -c /data/local/tmp/kmem_util c000f984 322 bf000000
Original value: c017a390
New value: bf000000
一切顺利的话,现在/bin/cat命令应该“看不见“我们之前创建的文件了。
berndt@osboxes:~/Desktop/Module$ adb shell su -c cat /data/local/tmp/nowyouseeme
tmp-mksh: cat: /data/local/tmp/nowyouseeme: No such file or directory
如上所示,文件“nowyouseeme“已经在所有用户进程的视图中消失了。为了完美隐藏该文件,你还需要对stat()、access()等其他系统调用进行hook。
文件隐藏只是的冰山一角,通过修改内核,你还可以完成很多事情,比如绕过许多root检测方法、完整性检查以及实现反调试功能等。
总结
Hook系统调用对Android逆向工程师而言非常有用。你需要使用自定义内核编译自己的逆向工程沙箱。本文介绍了如何在运行Lollipop的Nexus 5上执行上述操作,其他AOSP兼容设备上的过程应该与此类似。