java中操作系统的名称(不是“os.name”)

时间:2009-08-18 12:31:05

标签: java operating-system jvm runtime.exec

我想知道如何掌握jvm运行的那种操作系统。它也必须是“安全的”,所以System.getProperty("os.name")实际上不是一个选项,因为它可以通过-D指令轻易绕过它。

通过“安全”,我的意思是不容置疑。它适用于桌面应用程序。用户总是可以对代码进行反混淆,反编译,编辑和重新编译,但这比将-D传递给jvm要困难得多。我们想要修补不平凡,而不是不可能(因为那是不可能的)。

12 个答案:

答案 0 :(得分:15)

首先,不可能保护代码不被其运行时环境任意操纵。但是为了使它至少难以欺骗你的支票,最好的选择可能是某种基于OS fingerprinting的文件系统。

File.listRoots()是你的出发点;在类Unix系统上,它将返回一个包含/ etc,/ usr等特征目录的根。在Windows上,它将返回多个结果,但AFAIK OS安装驱动器不一定是C:并且特征目录不同Windows版本和语言环境 - 小心不要假设每个人都运行英文版的Vista。

你可以投入大量的工作来识别不同版本的Windows和Linux,以及BSD或MacOS - 一旦它在那里,从编译后的代码中删除支票可能会花费很少的工作。

答案 1 :(得分:8)

系统属性是我所知道的获取操作系统信息的唯一方法。甚至OperatingSystemMXBean也从os.X系统属性中获取其值。

如果有人可以修改您的应用程序的启动方式,那么与os.name正确相比,您遇到的问题更严重。

但是,如果您担心在应用程序运行时设置该属性的恶意代码,您可以使用Java安全管理器来确保安全地保护这些属性。

答案 2 :(得分:8)

你为什么担心这个?如果最终用户愚蠢到捣乱os。*属性,为什么不让应用程序爆炸呢?

话虽如此,这些可能适合您的目的

//can be defeated by adding com.apple.eawt.Application to the classpath
public boolean isMac() {
    try {
        Class.forName("com.apple.eawt.Application");
        return true;
    } catch(Exception e) {
        return false;
    }
}

//can be defeated by creating a cmd.exe in PATH
public boolean isWin() {
    try{
        Runtime.getRuntime().exec( new String[]{"cmd.exe","/C","dir"} ).waitFor();
        return true;
    } catch (Exception e) {
        return false;
    }
}

public boolean isLinux() {
    if(isMac()) return false;
    try{
        Runtime.getRuntime().exec(  new String[]{"sh","-c","ls"} ).waitFor();
        return true;
    } catch (Exception e) {
        return false;
    }
}

答案 3 :(得分:2)

您可以通过Runtime类(exec方法)运行外部cmd(如“ver”)来获取os的版本(如果在windows中)或“uname -a”

答案 4 :(得分:1)

Apache commons-vfs抽象了一些处理,因此您只需处理OsOsFamily。但是在内部,它仍然使用System.getProperty(..)来获取值。我不知道JVM获取这些值的任何其他方式。

如果有人能够更改传递给JVM的属性,那么处理它们时遇到的问题要比更改奇怪属性要大。

你能详细说明安全意味着什么。从谁那里安全?

答案 5 :(得分:1)

你可以使用exec来尝试运行一些你可以期望在一个操作系统或另一个操作系统上存在的无害程序 - 例如windows的“c:\ windows \ system \ dir.exe”和“/ bin / ls” * nix - 并查看它们是否成功运行或炸弹。但当然有人知道你正在这样做,并试图破坏它,他们可以用这些名字创建可执行文件。

你究竟想要从哪个方面获得安全保障?如果有人故意搞砸了你的应用程序的启动然后它因为你试图运行不存在的命令而爆炸,那么适当的反应就不会是“如果你的脚受伤了,就不要再用脚踩自己了。”如果你所做的只是运行操作系统命令,大概是用户能够访问你应用程序之外的那些命令,所以我不知道操作系统如何撒谎会危及安全性。

答案 6 :(得分:0)

除了使用您提到的属性外,VM中没有公共API。

我希望,由于Java应该是安全的,因此VM会忽略从命令行覆盖这些值的任何尝试,但事实并非如此。

您可能会尝试不允许写入这些值的SecurityManager,但我的猜测是,那么该值将为空(因为VM也无法更改它)。

答案 7 :(得分:0)

您还可以通过System.getenv()检查环境变量,但用户也可以在启动之前自由修改这些变量。在启动应用程序时,将变量修改为命令行的一部分并不是那么容易(至少在Windows上)。

答案 8 :(得分:0)

如果安全性是您的主要目标,您可能想尝试添加一些JNI。 首先,如果您尝试在Linux或OS X中加载DLL,我敢打赌它会崩溃/不加载。 其次,从该DLL可以调用操作系统的API,因此您不仅限于Java环境提供的内容。

答案 9 :(得分:0)

我同意jni / jna是一个更好的选择。只需调用Native.loadLibrary(“myLib”)之类的东西,在windows上它将在linux上加载myLib.dll - myLib.so。这是最安全的方式,一个人就是不能搞砸它。将所有特定于操作系统的代码放在库中,并将编译后的版本保存在jar中。

答案 10 :(得分:0)

现代Linux系统有一个特殊文件/proc/version,它提供内核版本ID。因此,如果该文件存在匹配合适的模式(例如,从单词Linux开始),则增加了在Linux计算机上运行的可能性。相反,如果它不存在或与该模式不匹配,您可以确定您没有在Linux上运行。

答案 11 :(得分:-2)

为什么不合并以下内容并使用它进行插值,这种方式可能很难避开。

public class OpertingSystemInfo 
{
    public static void main(String[] args)
    {
        String nameOS = "os.name";        
        String versionOS = "os.version";        
        String architectureOS = "os.arch";
    System.out.println("\n    The information about OS");
        System.out.println("\nName of the OS: " + 
System.getProperty(nameOS));
        System.out.println("Version of the OS: " + 
System.getProperty(versionOS));
        System.out.println("Architecture of THe OS: " + 
System.getProperty(architectureOS));
    }
}