簡體   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