【问题标题】:Implementing my own "strings" tool -- missing sequences GNU strings finds实现我自己的“字符串”工具——缺少 GNU 字符串发现的序列
【发布时间】:2018-12-25 15:54:10
【问题描述】:

我想以编程方式读取二进制文件中的文本/字符串。

我的目标的确切替代方案是 Linux 中的 strings shell 命令。

当我运行strings -n 4 /bin/dd shell 命令时,它会打印 818 行文本。

我怎样才能像strings 命令那样找到二进制中的所有字符串?


我的代码使用 read 而不是 fgetc 并在找到 EOF 后为其余文本添加了打印块。

/bin/dd 可以找到 813 个词,但strings 仍然可以找到 818 个词。有什么区别?

另一个问题;您能否建议此代码的性能改进?我猜read(1) 不是最快的方法。

最新更新的代码

#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>

bool isPrintable(unsigned char c)
{
    if(c >= 0x20 && c <= 0x7e || c == 0x09)
    {
        return true;
    }
    return false;
}

int main(int argc, char * argv [])
{
    char buffer[300];
    char *p = buffer;
    char ch;
    int fd;

    if(argc < 2)
    {
        printf("Usage: %s file", argv[0]);
        return 1;
    }

    fd = open(argv[1], O_RDONLY);
    if(0 <= fd)
    {
        while(1 == read(fd, &ch, 1))
        {
            if(isPrintable(ch) && (p - buffer < sizeof(buffer) - 3))
            {
                *p++ = ch;
            }
            else
            {
                if(p - buffer >= 4) // print collected text
                {
                    *p++ = '\n';
                    *p++ = '\0';
                    printf("%s", buffer);
                }
                p = buffer;
            }
        }
        if(p - buffer >= 4) // print the rest, if any
        {
            *p++ = '\n';
            *p++ = '\0';
            printf("%s", buffer);
        }
        close(fd);
    }
    else
    {
        printf("Could not open %s\n", argv[1]);
        return 1;
    }

    return 0;
}

这是mystringsstrings 的性能测量。 strings 可以在更短的时间内找到更多的文字。

$ time ./mystrings /lib/i386-linux-gnu/libc-2.27.so | wc -l
11852
real    0m0,917s
user    0m0,271s
sys 0m0,629s

$ time strings /lib/i386-linux-gnu/libc-2.27.so | wc -l
12026
real    0m0,028s
user    0m0,027s
sys 0m0,000s

即使我使用fopenfreadfclose 也没有那么快:

$ time ./mystrings2 /lib/i386-linux-gnu/libc-2.27.so | wc -l
11852
real    0m0,084s
user    0m0,070s
sys 0m0,004s

我也愿意接受任何有关性能改进的建议。

【问题讨论】:

  • 你试过调试了吗?
  • 很大程度上取决于具体的文件。 stringsbinutils 的一部分,因此它知道如何解析常见的可执行格式以直接获取字符串表;它仅适用于不是 ELF/dwarf/etc 的东西。需要猜测的文件,然后只查找彼此相邻的可打印字符序列。
  • Where can I find code for binary utility 'strings' of Linux? 的可能重复项另请参阅strings.c 源代码。
  • OP,如果您的动机是修复代码,请花一些精力调试它。您可以使用printf 'hello\377world' &gt; file 作为测试用例,其中strings 显示两个字符串,而您的代码没有显示。
  • fgetc 返回 int 而不是 char 和 @thatotherguy 有你的号码。他仔细选择了那个测试用例。想清楚。如果找不到调试器,请使用一张纸。

标签: c linux string shell binary


【解决方案1】:

您必须包含制表符。这些有十六进制代码 0x09。

您可以通过将其添加到您的可打印测试来修复它:

if(c >= 0x20 && c <= 0x7e || c == 0x09)

十分钟前:

哇哦,我不知道为什么这个程序在这个人的/bin/dd 中找到 813 个单词,而 strings 找到 818。为什么有人会认为我会?

但是,我确实有一个编译器和一个 Unix 系统,所以我可以做一些研究来尝试找出答案。

首先我在我的系统上尝试过:

$ ./yourprogram /bin/dd > yours && wc -l yours
807 yours

$ strings -n 4 /bin/dd > theirs && wc -l theirs
812 theirs

好的,不同的数字,但仍然有区别。然后我查看了差异:

$ diff -u yours theirs
--- yours       2018-07-17 15:13:27.188357492 -0700
+++ theirs      2018-07-17 15:13:56.905429280 -0700
@@ -182,7 +182,7 @@
 ATUH
 t9[]A\
 []A\
-[]A\
+8      []A\
 AUAT1
 []A\A]
 HiD$
@@ -210,7 +210,9 @@
 XZL;t$
 \$ I
 AUATI
+;'u    H
 []A\A]
+       v*H

它很乱,但它表明你找到了[]A\,而strings 找到了8 []A\。检查文件显示这是一个制表符。然后我可以创建一个测试用例:

$ printf 'hello\tworld' > file

$ strings file
hello    world

$ ./yourprogram file
hello
world

所以程序似乎无法识别 Tab,而 strings 可以。为什么程序不认为它是可打印的?

我在man ascii中查到了:

Oct   Dec   Hex   Char
───────────────────────────────────────
011   9     09    HT  '\t' (horizontal tab)

我将其与代码查找的内容进行了比较。我可以在调试器中运行它或添加printf 语句来尝试确定它为什么无法识别0x09,但我可以看到它要求字符至少为0x20 才能认为它是可打印的。

我更新了isPrintable 以将其添加为特例:

    if(c >= 0x20 && c <= 0x7e || c == 0x09)

并重新编译并重新运行:

$ ./yourprogram /bin/dd | wc -l
812

现在计数匹配了,我可以将其发布为答案,并假装我使用了一些哈利波特修补符咒或秘密关卡锁定能力,而不仅仅是研究和测试。

【讨论】:

  • 谢谢!我接受您的回答,因为您也解决了 readgetc 问题。 strings.c 文件上的其他内容让我感到困惑,我错过了 tab char 的缺失。如果您对 EDIT1 版本提供一些性能建议,我将非常高兴。
猜你喜欢
  • 2012-07-28
  • 1970-01-01
  • 1970-01-01
  • 2022-12-04
  • 2021-03-28
  • 1970-01-01
  • 2021-10-16
  • 2015-03-15
  • 1970-01-01
相关资源
最近更新 更多