【问题标题】:Reset handle after ReadFileReadFile 后重置句柄
【发布时间】:2020-05-12 07:32:45
【问题描述】:

我正在尝试在 windows 上打开一个文件并检查魔术字节是否与 windows PE32 匹配。如果我运行下面的代码并在函数problemFunction 中的ReadFile 调用之前返回,则代码工作正常,并在主函数末尾打印5a4d。但是,如果我在 problemFunction 中的 ReadFile 调用之后返回,那么我会在 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 读取调用之后重置文件指针,例如

LONG reset = -sizeof(DWORD);
SetFilePointer(*fh, reset, NULL, FILE_END);

但我无法让它工作。

谢谢

【问题讨论】:

  • FILE_END 相对于文件末尾查找,您想从当前位置 (FILE_CURRENT) 向后查找,或者只是查找到开头(偏移量为 0 的 FILE_BEGIN)。
  • @JonathanPotter 感谢偏移量为 0 的 FILE_BEGIN 工作
  • 你的解释有些漏洞。 首先: “如果我[做某件事]代码可以正常工作”——那不是你的解决方案吗?代码工作正常。问题解决了! (如果您的意思是部分代码工作正常,请更准确。) 第二:您的示例代码从不调用@987654330 @,所以我看不出problemFunction 中的任何内容会如何影响您的结果。
  • @JaMiT 显然在main() 中对test() 的调用本来是要调用problemFunction()
  • @RemyLebeau 当我假设某事“显而易见”时,我至少在 90% 的情况下都是错误的。

标签: c++ winapi readfile


【解决方案1】:

您的代码存在许多问题。

problemFunction()HANDLE* 指针作为输入,但在将指针传递给 GetFileSize()CloseHandle() 时不会取消引用该指针。但是在将指针传递给ReadFile() 时,它正在取消引用指针。

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

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

此外,GetFileSize() 不会在失败时返回 0,就像您的代码假设的那样。它实际上返回INVALID_FILE_SIZE,即-1,即0XFFFFFFFF 作为DWORD。这在documentation中有明确说明:

如果函数失败并且 lpFileSizeHigh 为 NULL,则返回值为 INVALID_FILE_SIZE。要获取扩展的错误信息,请调用 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多