myxxd

xxd应用截图


1. xxd 的主要功能是什么?

xxd 是一个基于文本的十六进制编辑器。它主要用于将二进制文件转换为十六进制形式进行查看和编辑。它可以显示文件的十六进制表示形式,并提供了对十六进制数据进行修改的功能。

2. 需要使用什么系统调用来实现?

为了实现类似 xxd 的功能,可以使用以下系统调用来操作文件:

  • open():用于打开文件。
  • read():用于从文件读取数据。
  • write():用于将数据写入文件。
  • close():用于关闭文件。

使用这些系统调用可以读取和写入二进制文件及执行相关的编辑操作。

3. 推导过程及命令

下面是一个示例的推导过程和对应的命令:

  • 打开文件:

    int fd = open("binary_file", O_RDWR);
    if (fd == -1) {
        perror("open failed");
        return -1;
    }
    

    这个命令打开名为 binary_file 的文件,并以可读写方式打开。如果打开文件失败,open() 将返回 -1。

  • 读取二进制文件的内容并输出十六进制字符串:

    char buf[1024];
    ssize_t nread;
    while ((nread = read(fd, buf, sizeof(buf))) > 0) {
        for (int i = 0; i < nread; i++) {
            printf("%02x", buf[i]);
        }
    }
    

    这个命令使用循环,按块读取文件内容,并使用 read() 函数将读取到的数据转换为十六进制字符串并输出。

  • 编辑十六进制字符串并将修改后的数据写回文件:

    // 假设修改后的十六进制字符串存储在 hex_str 变量中
    int hex_len = strlen(hex_str);
    int bin_len = hex_len / 2;
    char bin_data[bin_len];
    for (int i = 0; i < bin_len; i++) {
        sscanf(&hex_str[i * 2], "%2hhx", &bin_data[i]);
    }
    lseek(fd, 0, SEEK_SET);
    write(fd, bin_data, bin_len);
    

    这个命令首先计算修改后的十六进制字符串所对应的字节数,并将其转换为对应的二进制数据。然后使用 lseek() 将文件指针移动到文件开头,再使用 write() 将二进制数据写入文件。

  • 关闭文件:

    if (close(fd) == -1) {
        perror("close failed");
        return -1;
    }
    

    这个命令使用 close() 关闭文件。如果关闭文件失败,close() 将返回 -1。

写出实现xxd的伪代码

```python
# 打开文件
file = open("binary_file", "rb+")

# 读取二进制文件的内容
data = file.read()

# 将数据转换为十六进制字符串
hex_str = ""
for byte in data:
    hex_str += format(byte, "02x")

# 输出十六进制字符串
print(hex_str)

# 编辑十六进制字符串(示例:将第一个字节修改为0xFF)
# 假设要修改的字节位置为 offset
offset = 0
new_byte = 0xFF

# 计算要修改的字节在十六进制字符串中的索引
hex_index = offset * 2

# 将新的字节值转换为十六进制字符串
new_hex_byte = format(new_byte, "02x")

# 替换原始的十六进制字符串中的字节
hex_str = hex_str[:hex_index] + new_hex_byte + hex_str[hex_index+2:]

# 将修改后的十六进制字符串转换回二进制数据
new_data = bytes.fromhex(hex_str)

# 将修改后的数据写回文件
file.seek(0)
file.write(new_data)

# 关闭文件
file.close()

编写myxxd实现xxd功能

以下是使用 C 语言编写的 myxxd.c 文件来实现类似 xxd 命令的功能:

#include <stdio.h>

#define BYTES_PER_LINE 16

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <filename>\n", argv[0]);
        return 1;
    }

    FILE *file = fopen(argv[1], "rb");
    if (!file) {
        printf("Failed to open file: %s\n", argv[1]);
        return 1;
    }

    unsigned char buffer[BYTES_PER_LINE];
    size_t read_bytes;

    for (int line_count = 0; (read_bytes = fread(buffer, sizeof(unsigned char), BYTES_PER_LINE, file)); line_count++) {
        printf("%08x: ", line_count * BYTES_PER_LINE);

        for (int i = 0; i < BYTES_PER_LINE; i++) {
            if (i < read_bytes) {
                printf("%02x ", buffer[i]);
            } else {
                printf("   ");
            }

            if (i == BYTES_PER_LINE / 2 - 1) {
                printf(" ");
            }
        }

        printf(" | ");

        for (int i = 0; i < read_bytes; i++) {
            if (buffer[i] >= 32 && buffer[i] <= 126) {
                printf("%c", buffer[i]);
            } else {
                printf(".");
            }
        }

        printf("\n");
    }

    fclose(file);
    return 0;
}

将以上代码保存到名为 myxxd.c 的文件中,然后使用 C 编译器(如 gcc)进行编译。
例如,在终端中执行以下命令:

gcc -o myxxd myxxd.c

这将生成可执行文件 myxxd。接下来,你可以使用该程序来查看指定文件的十六进制表示。例如:

./myxxd sample.txt

输出将类似于下面的格式:

00000000: 54 68 69 73 20 69 73 20 | This is
00000008: 61 20 73 61 6d 70 6c 65 | a sample
00000010: 20 66 69 6c 65 20 74 6f | file to
00000018: 20 74 65 73 74 20 74 68 | test th
00000020: 65 20 6d 79 20 6d 79 78 | e my mx
00000028: 78 64 2e                | xd.

改进后的myxxd.c

以下是对 myxxd.c 进行改进以支持 -h-t 参数的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BYTES_PER_LINE 16

void print_hex(unsigned char *buffer, size_t read_bytes, int line_count) {
    printf("%08x: ", line_count * BYTES_PER_LINE);

    for (int i = 0; i < BYTES_PER_LINE; i++) {
        if (i < read_bytes) {
            printf("%02x ", buffer[i]);
        } else {
            printf("   ");
        }

        if (i == BYTES_PER_LINE / 2 - 1) {
            printf(" ");
        }
    }

    printf(" | ");

    for (int i = 0; i < read_bytes; i++) {
        if (buffer[i] >= 32 && buffer[i] <= 126) {
            printf("%c", buffer[i]);
        } else {
            printf(".");
        }
    }

    printf("\n");
}

int main(int argc, char *argv[]) {
    int show_header = 0;
    int show_tail = 0;
    int n_header = 0;
    int n_tail = 0;

    if (argc < 2) {
        printf("Usage: %s [<options>] <filename>\n", argv[0]);
        printf("Options:\n");
        printf("  -h <n>   Show first n bytes\n");
        printf("  -t <n>   Show last n bytes\n");
        return 1;
    }

    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0) {
            if (i == argc - 1) {
                printf("Error: Missing number argument for option '-h'\n");
                return 1;
            } else {
                show_header = 1;
                n_header = atoi(argv[++i]);
            }
        } else if (strcmp(argv[i], "-t") == 0) {
            if (i == argc - 1) {
                printf("Error: Missing number argument for option '-t'\n");
                return 1;
            } else {
                show_tail = 1;
                n_tail = atoi(argv[++i]);
            }
        } else {
            break;
        }
    }

    if (argc - show_header - show_tail != 2) {
        printf("Error: Missing filename argument\n");
        return 1;
    }

    FILE *file = fopen(argv[argc - 1], "rb");
    if (!file) {
        printf("Failed to open file: %s\n", argv[argc - 1]);
        return 1;
    }

    fseek(file, 0, SEEK_END);
    size_t len = ftell(file);
    fseek(file, 0, SEEK_SET);

    unsigned char buffer[BYTES_PER_LINE];
    size_t read_bytes;
    int line_count = 0;

    if (show_header) {
        n_header = n_header < len ? n_header : len;
        printf("Header %d bytes:\n", n_header);

        for (line_count = 0; n_header && (read_bytes = fread(buffer, sizeof(unsigned char), BYTES_PER_LINE, file)); line_count++) {
            print_hex(buffer, read_bytes, line_count);
            n_header -= read_bytes;
        }

        if (n_header > 0) {
            printf("%08x:\n", line_count * BYTES_PER_LINE);
        }
    }

    if (show_tail) {
        n_tail = n_tail < len ? n_tail : len;
        fseek(file, len - n_tail, SEEK_SET);
        printf("Tail %d bytes:\n", n_tail);

        line_count = (len - n_tail) / BYTES_PER_LINE;

        while (n_tail && (read_bytes = fread(buffer, sizeof(unsigned char), BYTES_PER_LINE, file))) {
            print_hex(buffer, read_bytes, line_count++);
            n_tail -= read_bytes;
        }

        if (n_tail > 0) {
            printf("%08x:\n", line_count * BYTES_PER_LINE);
        }
    }

    if (!show_header && !show_tail) {
        printf("File size: %zu bytes\n", len);

        while ((read_bytes = fread(buffer, sizeof(unsigned char), BYTES_PER_LINE, file))) {
            print_hex(buffer, read_bytes, line_count++);
        }
    }

    fclose(file);
    return 0;
}

与初始版本的程序不同,该程序能够根据命令行传入的 -h-t 参数来显示文件的部分内容。如果传入 -h n,程序将显示文件头部的前 n

posted @ 2023-11-29 08:42  20211312徐元琦  阅读(8)  评论(0编辑  收藏  举报