【问题标题】:Java command or sub-routine which equivalent to bash strings command [closed]等效于 bash 字符串命令的 Java 命令或子例程 [关闭]
【发布时间】:2017-01-20 18:06:14
【问题描述】:

bash我可以做

strings someBinaryfile.exe

对于.exe(或.dll,或.so),它将只打印二进制文件的人类可读部分。

java 中是否有类似的库。我知道如何打开文件并打印它,但我只需要人类可读的部分。

【问题讨论】:

  • 感谢@Inian 格式化问题
  • strings 不是bash 命令;它是一个独立的程序,您可以从 Java 程序以及 bash 脚本运行。
  • 我了解@chepner - 除此之外,Java 中有没有类似用途的库?例如 apache commons(虽然我在 apache commons 库中找不到类似的函数)

标签: java bash binaries


【解决方案1】:

我不知道有任何预先存在的 Java 库可以完全复制 strings 的功能。如果您想考虑自己实现它,那么我们可以阅读Linux man page for strings 以更好地了解要求:

对于给定的每个文件,GNU 字符串打印可打印字符 至少 4 个字符长的序列(或给定的数字 使用下面的选项),后跟一个不可打印的字符。

因此,如果您想用纯 Java 代码实现自己的解决方案,那么您可以读取文件的每个字节,检查该字节是否可打印,并将这些字节的序列存储在缓冲区中。然后,一旦遇到不可打印的字符,如果缓冲区包含至少 4 个字节,则打印缓冲区的内容。例如:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.File;
import java.io.IOException;

class Strings {

    private static final int MIN_STRING_LENGTH = 4;

    public static void main(String[] args) throws IOException {
        for (String arg : args) {
            File f = new File(arg);
            if (!f.exists()) {
                System.err.printf("error: no such file or directory: %s%n", arg);
                continue;
            }
            if (!f.canRead()) {
                System.err.printf("error: permission denied: %s%n", arg);
                continue;
            }
            if (f.isDirectory()) {
                System.err.printf("error: path is directory: %s%n", arg);
                continue;
            }
            try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(f));
                        ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                for (int b = is.read(); b != -1; b = is.read()) {
                    if (b >= 0x20 && b < 0x7F) {
                        os.write(b);
                    } else {
                        if (os.size() >= MIN_STRING_LENGTH) {
                            System.out.println(new String(os.toByteArray(), "US-ASCII"));
                        }
                        os.reset();
                    }
                }
                if (os.size() >= MIN_STRING_LENGTH) {
                    System.out.println(new String(os.toByteArray(), "US-ASCII"));
                }
            }
        }
    }
}

这将涵盖strings 功能的基本近似,但还有更多细节需要考虑:

默认情况下,它只打印初始化和加载的字符串 目标文件的部分;对于其他类型的文件,它会打印 来自整个文件的字符串。

实现这部分变得更加复杂,因为您需要解析和理解二进制文件格式的不同部分,例如ELFWindows PE

另一个复杂的问题是字符编码:

-e 编码 --encoding=encoding 选择要查找的字符串的字符编码。可能的编码值为: s = 单 7 位字节字符(ASCII、ISO 8859 等,默认),S = 单 8 位字节字符,b = 16 位 bigendian,l = 16 位 littleendian,B = 32 位 bigendian,L = 32 位 littleendian。有用 用于查找宽字符串。 (l 和 b 适用于,例如, Unicode UTF-16/UCS-2 编码)。

我上面描述的更简单的逻辑假设是单字节字符。如果您需要识别编码为多字节字符的字符串,那么逻辑将需要更加小心地管理缓冲区、检查可打印性和检查字符串长度。

您可以将许多其他参数传递给strings,所有这些都在手册页中进行了描述。如果您需要完全复现所有这些功能,那么逻辑会更加复杂。

如果您不想实现这一点,那么您可以通过ProcessBuilder 类直接分叉并执行strings 并解析输出。权衡是它引入了一个外部依赖项,您的代码必须在安装了strings 的平台上运行,并且会产生一些开销来分叉和执行外部进程。根据具体情况,您的应用程序可能会或可能不会接受这种权衡。

【讨论】:

  • 太棒了!与 gnu strings 命令非常接近。谢谢@chris-nauroth
猜你喜欢
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-19
  • 2019-09-24
相关资源
最近更新 更多