繁体   English   中英

从 c 中的数据文件读取

[英]Reading from a data file in c

我一直在研究 Jon Erickson 的 The Art of Exploitation,但在从文件和他的代码中读取数据时,我遇到了一个症结。

有./notetaker 和./notesearch 两个程序,前者用于创建带有用户id 的笔记,后者用于检索当前用户的笔记。

但是,在做笔记并尝试通过 ./notesearch 访问它之后,笔记不会像书中建议的那样显示为文本。

到目前为止,我已经推断出在 ./notetaker 中创建的文件是一个数据文件,而不是文本文件,因此当它打印出来时是不可读的。

那么为什么作者建议他的代码有效,而实际上却没有,最简单的解决方法是什么。

我已经开始将 fopen、fgets() 等视为解决方案,但它似乎与原始代码相去甚远。

如果我让 ./notesearch 查看一个随机文本文件,它将以人类可读的形式打印出来,所以我认为问题在于原始文件的创建及其类型。

但不幸的是,我不知道如何克服这个问题

来自 ./notetaker 的片段

int main(int argc, char *argv[]) {
    int userid;
    int file_descriptor;
    char *buffer, *datafile;

    buffer = (char *) ec_malloc(100);
    datafile = (char *) ec_malloc(20);
    strcpy(datafile, "notes");

    if (argc < 2)
        usage(argv[0], datafile);

    strcpy(buffer, argv[1]);

    printf("[DEBUG] buffer @ %p: '%s'\n", buffer, buffer);
    printf("[DEBUG] datafile @ %p: '%s'\n", datafile, datafile);

    strncat(buffer, "\n", 1); //adds a newline to end

    // opening file
    file_descriptor = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if (file_descriptor == -1)
        fatal("in main() while opening file");
    printf("[DEBUG] file descriptor is %d\n", file_descriptor);
    userid = getuid();

    // write data
    if (write(file_descriptor, &userid, 4) == -1)
        fatal("in main() while writing userid to file");
    write(file_descriptor, "\n", 1);
    if (write(file_descriptor, buffer, strlen(buffer)) == -1)
        fatal("in main() while writing buffer to file");
    write(file_descriptor, "\n", 1);

    // closing file
    if (close(file_descriptor) == -1)
        fatal("in main() while closing file");

来自 ./notesearch 的片段

#define FILENAME "notes"

int print_notes(int, int, char *);
int find_user_note(int, int);
int search_note(char *, char *);

int main(int argc, char *argv[]) {
    int userid, printing = 1, file_descriptor;
    char search_string[100];

    if (argc > 1)
        strcpy(search_string, argv[1]);
    else
        search_string[0] = 0;

    userid = getuid();
    file_descriptor = open(FILENAME, O_RDONLY);
    if (file_descriptor == -1)
        fatal("in main() while opening file for reading");

    while (printing)
        printing = print_notes(file_descriptor, userid, search_string);

    printf("------ [ end of note data ] ------\n");
    close(file_descriptor);
}

// print notes for a given uid
// can match an optional search string
int print_notes(int file_descriptor, int uid, char *search_string) {
    int note_length;
    char byte = 0, note_buffer[100];

    note_length = find_user_note(file_descriptor, uid);

    // if EOF return 0
    if (note_length == -1)
        return 0;

    read(file_descriptor, note_buffer, note_length); // read note data
    note_buffer[note_length] = 0; // terminate string

    // print note if search_string
    if (search_note(note_buffer, search_string))
        printf("------ [ note data ] ------\n");
        printf(note_buffer);
        printf("\n");
    return 1;
}

// finds next note for given uid
int find_user_note(int file_descriptor, int user_uid) {
    int note_uid = -1;
    unsigned char byte;
    int length;

    while (note_uid != user_uid) {
        if (read(file_descriptor, &note_uid, 4) != 4) // read uid data
            return -1;
        if (read(file_descriptor, &byte, 1) != 1) // read newline separator
            return -1;

        byte = length = 0;

        while (byte != '\n') {
            if (read(file_descriptor, &byte, 1) != 1) // read a single byte
                return -1;
            length++;
        }
    }

    // rewind file by bytes length
    lseek(file_descriptor, length * -1, SEEK_CUR);

    printf("[DEBUG] found a %d byte note for user id %d\n", length, note_uid);
    return length;
}

已解决:在 32 位 vm 上尝试了代码,一切都很好,虽然不完全确定为什么会这样,但目前是我的工作。

这可能是因为代码对整数和其他类型的大小做出了假设,而这些假设不应该。 例如...

int userid;
... 
userid = getuid();
...
if (write(file_descriptor, &userid, 4) == -1)
    fatal("in main() while writing userid to file");

那里有两个错误。 getuid返回一个uid_t ,而不是一个int 它们可能大小相同,因此可能会起作用。

更重要的是,他们将userid的大小硬编码为 4 个字节。 userid是一个int ,它只能保证至少为 2 个字节。 在 32 位机器上,它通常是 4 个字节(32 位)。 在 64 位机器上,它是 8 个字节(64 位)。

它适用于 32 位 VM,因为int有 4 个字节。

相反,使用正确的类型和sizeof来获取大小。

uid_t userid;
... 
userid = getuid();
...
if (write(file_descriptor, &userid, sizeof(userid)) == -1)
    fatal("in main() while writing userid to file");

总的来说,这段代码的质量很差。 我希望这样写是为了说明目的。

  • strcpy(buffer, argv[1])strcpy(search_string, argv[1])存在缓冲区溢出的风险。
  • 有很多地方他们无法检查文件操作是否成功。
  • 有一个欺骗性的if条件。
    if (search_note(note_buffer, search_string))
        printf("------ [ note data ] ------\n");
        printf(note_buffer);
        printf("\n");

缩进使它看起来像是在if ,但缺少大括号意味着它真的是这样的:

    if (search_note(note_buffer, search_string)) {
        printf("------ [ note data ] ------\n");
    }
    printf(note_buffer);
    printf("\n");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM