ReadFile之后重置句柄

问题描述 投票:0回答:1

我正在尝试在Windows上打开文件,并检查魔术字节是否与Windows PE32匹配。如果我运行下面的代码并在函数ReadFile中的problemFunction调用之前返回,则该代码可以正常工作,并且在主函数的末尾显示5a4d。但是,如果在ReadFile中的problemFunction调用之后返回,则在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);

但是我无法使它正常工作。

谢谢

c++ winapi readfile
1个回答
0
投票

您的代码有很多问题。

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

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

HANDLE是指针类型,因此不需要通过指针传递它,除非您要修改它的值,而此代码不会这样做。因此,您应该更改problemFunction()使其原样使用HANDLE而不是使用HANDLE*指针。

此外,GetFileSize()不会在失败时返回0,就像您的代码所假定的那样。它实际上返回为[-1]的INVALID_FILE_SIZE,即0XFFFFFFFF作为DWORDdocumentation中明确指出:

如果函数失败并且lpFileSizeHigh为NULL,则返回值为INVALID_FILE_SIZE。要获取扩展的错误信息,请调用GetLastError。

但是,最重要的是,您对ReadFile()内部的main()的第二次调用未读取您的期望,因为对ReadFile()内部的problemFunction()的第一次调用已经读取了数据(并且泄漏了!) ,但是在读取之后您没有将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;
}
© www.soinside.com 2019 - 2024. All rights reserved.