android hook api
android安全可以从三个层面考虑,一次是java虚拟机层,nativec层,还有linux kernel层,本次hook api是属于nativec层的。
hook api之后就可以使得程序对原有系统函数的调用改为对我们自己编写的函数的调用,这既可以作为一种攻击手段,又可以在维持程序运行的情况下更新程序等等。下面谈谈思路以及实例(以打电话进程com.android.phone为例,项目保密起见,我修改了相关函数的名称,但是思路绝对不假,这事我验证过的)
1.向目标进程注入代码(注入so,并调用该so里的一个函数)。首先调用ptrace函数,调试com.android.browser进程,在这里我们需要遍历该进程加载的libc.so,这里有我们需要的dlopen,dlsym等函数的地址,我们先中断com.android.phone,修改其寄存器,压入参数如我们的so路径,并将之前找到的dlopen地址压入寄存器,直接操作blx,就可以让目标进程调用dlopen加载我们的so,同理dlsym调用我们的so里的函数。这个已经有大牛写出来了,
下面就是我做的工作,重定向函数实现hook
2.com.android.phone程序打电话等网络连接时调用了xxx.so,该so维护了一个got表和rel.plt表。其中rel.plt表存放了外部依赖函数的地址,而got表里存放的就是本so定义的函数的地址。在上文被注入的so已经和com.android.phone处于一个进程空间,并且可以执行一段我们设定的代码。我们的代码应该这么做。我们也加载xxx.so,这里不会真正的加载,应该已经加载过了,但是我们可以获得xxx.so的句柄,然后查找到rel.plt表中的dial函数表项。然后加载我们写的一个myxxx.so,该so里有我们自己定义的mydial函数,注意两个函数的签名必须一致。同理我们找到mydial函数加载后的地址,然后将之前xxx.so的dial表项的函数地址替换为我们的mydial函数的地址。注意在地址替换时需要先调用mprotect函数来突破so内存空间的写保护。 在mydial函数里,我们copy了dial函数的全部代码,但是有一个改变。就是将目标电话号码修改为我们指定的号码。
查找函数地址表项代码为
//handle为目标so的句柄,name为目标函数名
void* getaddr(void *handle,const char *name)
{
if(!handle)
return;
Soinfo *si = (Soinfo*)handle;
Elf32_Sym *symtab = si->symtab;
const char *strtab = si->strtab;
Elf32_Rel *rel = si->plt_rel;
unsigned count = si->plt_rel_count;
unsigned idx;
for(idx=0; idx<count; idx++) //外部依赖函数在rel_plt中
{
unsigned type = ELF32_R_TYPE(rel->r_info);
unsigned sym = ELF32_R_SYM(rel->r_info);
unsigned reloc = (unsigned)(rel->r_offset + si->base);
char *sym_name = (char *)(strtab + symtab[sym].st_name);
if(strcmp(sym_name, name)==0)
{
printf("\"plt_rel\" idx:%2d type:%2d sym:%2d sym_name:%-30s addr:%0x\n",idx,type,sym,sym_name,*((unsigned*)reloc));
return (void *)*((unsigned*)reloc);
}
rel++;
}
for(idx=0;idx<si->nchain;idx++) //自定义函数在symtab中
{
unsigned type = ELF32_R_TYPE(symtab[idx].st_info);
unsigned sym = ELF32_R_SYM(symtab[idx].st_info);
char *sym_name = (char *)(strtab + symtab[idx].st_name);
if(strcmp(sym_name, name)==0)
{
printf("\"got\" idx:%2d sym_name:%-30s st_value:%0x base: %0x\n",idx,sym_name,symtab[idx].st_value,si->base);
return (void *)(symtab[idx].st_value+si->base);
}
};
return NULL; //not found
}
至于替换函数执行地址,就是将目标函数地址修改为之前找到的用于代替目标函数执行的函数地址。注意got表中时相对so的base的值,需要加减两个so的base差值。而rel.plt表中则是绝对地址。
从安全的角度入手,我们可以hook关键函数,实现权限操作限制。
补充:移动开发 , Android ,