我一直在尝试拦截Android内核中的读取系统调用(针对maguro的3.0.72)。我正在使用内核模块用于此目的。一个例子如下:
#include <linux/module.h>
#include <linux/unistd.h>
MODULE_LICENSE ("Dual BSD/GPL");
asmlinkage long
(*orig_call_open) (const char __user * filename, int flags, int mode);
asmlinkage long
(*orig_call_read) (unsigned int fd, char __user * buf, size_t count);
#define SYS_CALL_TABLE_ADDR 0xc0058828
void **sys_call_table;
asmlinkage long
new_sys_open (const char __user * filename, int flags, int mode)
{
printk ("Calling my open\n");
return orig_call_open (filename, flags, mode);
}
asmlinkage long
new_sys_read (unsigned int fd, char __user * buf, size_t count)
{
printk ("Calling my read\n");
return orig_call_read (fd, buf, count);
}
/* Module initialization and cleanup functions */
int
init_module ()
{
sys_call_table = (void *) SYS_CALL_TABLE_ADDR;
// save original function ptrs
orig_call_open = (void *) sys_call_table[__NR_open];
orig_call_read = (void*) sys_call_table[__NR_read];
// replace existing functions with ours
sys_call_table[__NR_open] = (unsigned long *) new_sys_open;
sys_call_table[__NR_read] = (unsigned long *) new_sys_read;
printk ("Initializing.\n");
return 0;
}
void
cleanup_module ()
{
sys_call_table[__NR_open] = (unsigned long *) orig_call_open;
sys_call_table[__NR_read] = (unsigned long *) orig_call_read;
printk ("Cleaning up.\n");
}
我通常可以使用insmod插入模块。但是,当我尝试删除它(使用rmmod)时,内核会中断,设备会重新启动。
[...]
[ 80.512054] Unable to handle kernel paging request at virtual address bf000040
[ 80.512145] pgd = c6d98000
[ 80.512237] [bf000040] *pgd=85edc811, *pte=00000000, *ppte=00000000
[ 80.512634] Internal error: Oops: 80000007 [#1] PREEMPT SMP
[ 80.512725] Modules linked in: [last unloaded: privacy_capsules]
[ 80.513061] CPU: 0 Not tainted (3.0.72-gfb3c9ac-dirty #4)
[ 80.513214] PC is at 0xbf000040
[ 80.513336] LR is at sys_read+0x6c/0x78
[ 80.513427] pc : [<bf000040>] lr : [<c01533ec>] psr: 200f0013
[...]
我还测试了其他系统调用(例如,仅用于sys_open和sys_write - 并且没有sys_read)并且它正常工作(insmod和rmmod)。但是,问题似乎只发生在sys_read上。
有什么想法吗?非常感谢提前!
编辑:
这些是函数指针的地址:
orig_call_read : 0xc0153380
new_sys_read : 0xbf000000
我从模块代码中获取了一段汇编代码:
00000000 <new_sys_read>:
0: e1a0c00d mov ip, sp
4: e92dd878 push {r3, r4, r5, r6, fp, ip, lr, pc}
8: e24cb004 sub fp, ip, #4
c: e1a04000 mov r4, r0
10: e3000000 movw r0, #0
14: e3400000 movt r0, #0
18: e1a06001 mov r6, r1
1c: e1a05002 mov r5, r2
20: ebfffffe bl 0 <printk>
24: e3003000 movw r3, #0
28: e3403000 movt r3, #0
2c: e1a00004 mov r0, r4
30: e1a01006 mov r1, r6
34: e5933000 ldr r3, [r3]
38: e1a02005 mov r2, r5
3c: e12fff33 blx r3
40: e89da878 ldm sp, {r3, r4, r5, r6, fp, sp, pc}
所以,正如@ChrisStratton建议的那样,一个被阻塞的read()返回(在这种情况下,在blx r3之后),但是找不到下一个地址(0xbf000040
)。
答案 0 :(得分:1)
这确实看起来像是一个阻塞或其他延迟的读取调用,试图在卸载后返回代码。
我认为您在地址报告中交换了两个功能的地址。
当原始版本尝试在[<bf000040>]
处返回替换的最后一行时发生故障,但由于您的模块已卸载,因此不再在内存中。我预计像这样的系统很容易会有很多长时间阻塞的读取呼叫。
您可能需要在sysfs或类似程序中实现一个接口,而不是卸载模块,您可以使用它来禁用新的重定向,同时将其保留在内存中。
另一个选择是看看它是否可以跳过&#34;跳跃&#34;而不是&#34;呼叫&#34;原来,原来的回程会跳过你并直接回到你的来电者那里。在ARM中,这将是一个没有链接的分支。查看代码,看起来你必须首先清理你的本地堆栈,在代码开始时将寄存器恢复到它们的状态,然后进行跳转。