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;
}
我正在尝试打开 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;
}