代码之家  ›  专栏  ›  技术社区  ›  Phillip

实现我自己的“strings”工具-GNU strings找到的缺失序列

  •  0
  • Phillip  · 技术社区  · 6 年前

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

    我的目标是 strings Linux中的shell命令。

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

    我怎么能找到所有二进制字符串 命令呢?


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

    它可以在 /bin/dd ,但仍然 可以找到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;
    }
    

    以下是对 mystrings 是的。 可以在更短的时间内找到更多的文本。

    $ 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
    

    即使我用 fopen 我是说, fread 我是说, fclose 不是很快:

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

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

    1 回复  |  直到 6 年前
        1
  •  4
  •   that other guy    6 年前

    必须包含制表符。它们有十六进制代码0x09。

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

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

    十分钟前:

    哦,哇,我不知道为什么这个程序会在这个人的 /bin/dd 虽然 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\ 虽然 发现 8 []A\ . 检查文件时会显示这是一个制表符然后我可以创建一个测试用例:

    $ printf 'hello\tworld' > file
    
    $ strings file
    hello    world
    
    $ ./yourprogram file
    hello
    world
    

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

    我查过了 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
    

    现在计数匹配了,我可以把这个作为一个答案,假装我用了一些哈利波特的魔法或秘密等级锁定能力,而不仅仅是研究和测试。