ReadFile 后重置句柄

Reset handle after ReadFile

我正在尝试打开 windows 上的文件并检查魔术字节是否与 windows PE32 匹配。如果我 运行 下面的代码和 return 就在函数 ReadFile 调用之前 problemFunction 代码工作正常并且它在函数的末尾打印 5a4d主功能。但是,如果我在 ReadFile 调用 problemFunction 之后 return,那么我会在 dos->e_magic != PIMAGE_DOS_HEADER 检查中退出。

#include <Windows.h>
#include <winternl.h>

void problemFunction(HANDLE *fh) {
    DWORD fileSize = GetFileSize(fh, NULL);
    if (!fileSize) { CloseHandle(fh); exit(1); }

    BYTE* pByte = new BYTE[fileSize];
    DWORD dw;
    ReadFile(*fh, pByte, fileSize, &dw, NULL);
    // could be wrong but i think i need to run SetFilePointer here but not sure on what to do.
    return;
}

int main() {
    const char* filepath = "C:\windows\file\path\to\exe";
    HANDLE fh = CreateFileA(filepath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(fh == INVALID_HANDLE_VALUE) { CloseHandle(fh); exit(1); }

    problemFunction(&fh);

    DWORD fileSize = GetFileSize(fh, NULL);
    if (!fileSize) { CloseHandle(fh); exit(1); }

    BYTE* pByte = new BYTE[fileSize];
    DWORD dw;
    ReadFile(fh, pByte, fileSize, &dw, NULL);

    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pByte;

    if (dos->e_magic != IMAGE_DOS_SIGNATURE) { CloseHandle(fh); exit(1); }
    // dos->e_magic should be 5a4d for MZ, windows PE
}

我想我需要在 problemFunction read 调用之后用

之类的东西重置文件指针
LONG reset = -sizeof(DWORD);
SetFilePointer(*fh, reset, NULL, FILE_END);

但我无法让它工作。

谢谢

你的代码有很多问题。

problemFunction()HANDLE* 指针作为输入,但在将其传递给 GetFileSize()CloseHandle() 时并未取消对该指针的引用。但它在将指针传递给 ReadFile() 时取消引用指针。

您必须在关闭 STRICT Type Checking 的情况下编译您的代码,否则您的代码将无法编译。您应该始终在启用 STRICT 的情况下进行编译。

HANDLE 是一个指针类型,所以没有必要通过指针传递它,除非你要修改它的值,而这段代码没有这样做。因此,您应该更改 problemFunction() 以按原样采用 HANDLE 而不是采用 HANDLE* 指针。

此外,GetFileSize() 不会像您的代码假设的那样在失败时 return 0。它实际上 returns INVALID_FILE_SIZE 即 -1,即 0XFFFFFFFF 作为 DWORD。这在 documentation:

中有明确说明

If the function fails and lpFileSizeHigh is NULL, the return value is INVALID_FILE_SIZE. To get extended error information, call GetLastError.

但是,最重要的是,您在 main() 中对 ReadFile() 的第二次调用没有读取您期望的内容,因为在 problemFunction() 中对 ReadFile() 的第一次调用已经读取了数据(并泄露了它!),但您并没有在读取之后将 HANDLE 返回到文件的开头,因此对 ReadFile() 的第二次调用可以再次读取它。你是正确的,你需要为此使用 SetFilePointer()

话虽如此,请尝试更像这样的事情:

#include <Windows.h>
#include <winternl.h>

bool test(HANDLE fh) {
    DWORD fileSize = GetFileSize(fh, NULL);
    if (fileSize == INVALID_FILE_SIZE) {
        return false;
    }

    BYTE* pByte = new BYTE[fileSize];
    DWORD dw;
    if (!ReadFile(fh, pByte, fileSize, &dw, NULL)) {
        delete[] pByte;
        return false;
    }

    // use pByte as needed...

    delete[] pByte;

    if (SetFilePointer(fh, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
        return false;
    }

    return true;
}

int main() {
    const char* filepath = "C:\windows\file\path\to\exe";
    HANDLE fh = CreateFileA(filepath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fh == INVALID_HANDLE_VALUE) {
        return 1;
    }

    if (!test(fh)) {
        CloseHandle(fh);
        return 1;
    }

    DWORD fileSize = GetFileSize(fh, NULL);
    if (fileSize == INVALID_FILE_SIZE) {
        CloseHandle(fh);
        return 1;
    }

    BYTE* pByte = new BYTE[fileSize];
    DWORD dw;
    if (!ReadFile(fh, pByte, fileSize, &dw, NULL) || dw < sizeof(IMAGE_DOS_HEADER)) {
        CloseHandle(fh);
        return 1;
    }

    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pByte;

    if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
        delete[] pByte;
        CloseHandle(fh);
        return 1;
    }

    ...

    delete[] pByte;
    CloseHandle(fh);

    return 0;
}