尝试规避"FORTIFY_SOURCE: FD_SET: file descriptor >= FD_SETSIZE"

    Android 5.0及以上,select调用会检查fd大小,是否超过1024,如果超过就会提示:

FORTIFY_SOURCE: FD_SET: file descriptor >= FD_SETSIZE. Calling abort().

然后崩溃,检查的代码在:

/bionic/libc/bionic/__FD_chk.cpp


extern "C" int __FD_ISSET_chk(int fd, fd_set* set, size_t set_size) {
  if (__predict_false(fd < 0)) {
    __fortify_chk_fail("FD_ISSET: file descriptor < 0", 0);
  }
  if (__predict_false(fd >= FD_SETSIZE)) {
    __fortify_chk_fail("FD_ISSET: file descriptor >= FD_SETSIZE", 0);
  }
  if (__predict_false(set_size < sizeof(fd_set))) {
    __fortify_chk_fail("FD_ISSET: set is too small", 0);
  }
  return FD_ISSET(fd, set);
}

如果是因为自己的代码调用select提示fd超标,可以通过编译时覆盖__FD_ISSET_chk函数的方式,略过检查,

但是如果是从其它第三方库调到select,或者libc.so自己调用select,编译覆盖的方法就行不通。

尝试了一下直接修改汇编指令的方法,把1024调到4096,步骤如下:


readelf -s libc.so | grep __FD_ISSET_chk

// 找到__FD_ISSET_chk在libc.so中的地址,我的手机上为 0004d3d9


objdump -d libc.so > output

// 把so dump出来,查看汇编代码,定位到地址为0004d3d9,发现了__FD_ISSET_chk的函数体,明显能看到一行:


4d3e4:       f5b0 6f80       cmp.w   r0, #1024       ; 0x400

// 这里就是比较fd和1024的地方,所以只要这条指令中的1024改为更大的数字就可以了

// 在这里我偷了个懒,本来需要查找cmp.w指令格式,再修改立即数1024,再构造一条指令的,我是通过查找cmp.w r0的方法,

发现了一条指令相同,立即数更大的指令:


4e606:       f5b0 5f80       cmp.w   r0, #4096       ; 0x1000

// 完全相同,只是6f变成5f,数字就变成了4096,最终的修改目标就是,找到"6f"的地址,修改为"5f"


修改方法如下:

使用hex编译器,例如vi的:%!xxd,定位到地址为4d3e0 这一行,从左到右就是4c3e0, 4c3e1, 4c3e2, ...每一个地址对应一个字节,

4c3e7就是"6f"的地址

然后,借助mprotect系统调用,把4c3e7对应Page的权限修改为PROT_WRITE | PROT_EXEC | PROT_READ,就可以直接修改了。

在这里发现把权限修改为PROT_WRITE | PROT_EXEC或PROT_EXEC会出现permission denied错误。


最后测试一下,dlopen打开libc.so,dlsym找到__FD_ISSET_chk,直接传入一个大于1024的FD,并没有崩溃,成功!





你可能感兴趣的:(语言,平台)