文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>injectso dl_open失败分析

injectso dl_open失败分析

时间:2007-04-17  来源:loughsky

injectso技术应该是比较成熟的技术,但看其相关的文档却大多是前几年的。 我按照injectso教程里面讲述的方式,实验了一下,却报出了下面的错误。
error while loading shared libraries: dlopen: invalid caller
按原来的文档,_dl_open的参数caller,是无关紧要的,设置为0。实际上看来并非如此。 查看了glibc的代码,也没有发现能够报invalid caller的地方,最后,找到了一个patch。
http://www.filewatcher.com/p/compat-glibc-2.3.2-95.30.src.rpm.14008569/glibc-execstack-fix3.patch.html
在这里
static void
 dl_open_worker (void *a)
 {
@@ -166,11 +232,17 @@ dl_open_worker (void *a)
   bool any_tls;
 #endif
 
+#ifdef SHARED
+  /* Check whether _dl_open() has been called from a valid DSO.  */
+  if (check_libc_caller (args->caller_dl_open) != 0)
+    _dl_signal_error (0, "dlopen", NULL, N_("invalid caller"));
那么我来看下args是如何定义的?
@@ -66,7 +67,10 @@ struct dl_open_args
 {
   const char *file;
   int mode;
-  const void *caller;
+  /* This is the caller of the dlopen() function.  */
+  const void *caller_dlopen;
+  /* This is the caller if _dl_open().  */
+  const void *caller_dl_open;
   struct link_map *map;
 };
我们再来看下check_libc_caller就会明白了。
static int
+internal_function
+check_libc_caller (const void *caller)
+{
+  static const char expected1[] = LIBC_SO;
+  static const char expected2[] = LIBDL_SO;
+
+  /* If we already know the address ranges, just test.  */
+  static const void *expected1_from;
+  static const void *expected1_to;
+  static const void *expected2_from;
+  static const void *expected2_to;
+
+  if (expected1_from == NULL)
+    {
+      /* The only other DSO which is allowed to call these functions is
+  libdl.  Find the address range containing the caller.  */
+      struct link_map *l;
+
+      for (l = GL(dl_loaded); l != NULL; l = l->l_next)
+ if (strcmp (expected1, l->l_name) == 0)
+   {
+   is_1:
+     expected1_from = (const void *) l->l_map_start;
+     expected1_to = (const void *) l->l_map_end;
+   }
+ else if (strcmp (expected1, l->l_name) == 0)
+   {
+   is_2:
+     expected2_from = (const void *) l->l_map_start;
+     expected2_to = (const void *) l->l_map_end;
+   }
+ else
+   {
+     struct libname_list *runp = l->l_libname;
+
+     while (runp != NULL)
+       {
+  if (strcmp (expected1, runp->name) == 0)
+    goto is_1;
+  else if (strcmp (expected2, runp->name) == 0)
+    goto is_2;
+
+  runp = runp->next;
+       }
+   }
+
+      assert (expected1_from != NULL);
+    }
+
+  /* When there would be more than two expected caller we could use an
+     array for the values but for now this is cheaper.  */
+  if ((caller >= expected1_from && caller < expected1_to)
+      || (caller >= expected2_from && caller < expected2_to))
+    return 0;
+
+  return 1;
+}
也就是说,它会来判断caller指针所在的范围,他应该在LIBC_SO LIBDL_SO映射的库文件中,
#define LIBC_SO "libc.a"
#define LIBDL_SO "libdl.a"
也就是说,调用dl_open的函数,应该在这两个库中。
因此,我怀疑,glibc为了防止injectso,而在glibc的代码中打了一些patch,来防止这个问题。
而我们正常的在程序中调用函数dl_open时,我们在编译的时候增加了一个选项 -ldl,这就是指要使用libdl.a
那么injectso的这条路是不是就走不通了吗? 我考虑是否可以自己伪造一个linkmap表,来欺骗它。但这样的话,对于那些真的使用libdl的,会造成问题。最好能在程序load时,不管用不用,都自动把libdl库load进来。
相关阅读 更多 +
排行榜 更多 +
准时宝

准时宝

游戏工具 下载
伐木大亨

伐木大亨

模拟经营 下载
超可爱的卡皮巴拉闯关

超可爱的卡皮巴拉闯关

动作格斗 下载