Windows C++ API:如何将整个二进制文件读入缓冲区?

Posted

技术标签:

【中文标题】Windows C++ API:如何将整个二进制文件读入缓冲区?【英文标题】:Windows C++ API: How do I read an entire binary file into a buffer? 【发布时间】:2021-05-14 22:18:36 【问题描述】: 操作系统:Windows 10 目标平台:x86

我正在尝试将任意长度的二进制文件的全部内容加载到字符数组中。该数组的内容稍后将被复制到使用VirtualAlloc 保留的内存位置。到目前为止,这是我的代码:

#include <windows.h>
#include <fileapi.h>
#include <tchar.h>

int __cdecl _tmain(int argc, TCHAR* argv[])

    HANDLE payload;
    if (argc != 2) 
        _tprintf(TEXT("Usage: runp.exe [payload_file]\nExecutes the specified binary payload.\n"));
        return 0;
    
    _tprintf(TEXT("[*] Loading binary payload: %s\n"), argv[1]);
    payload = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
    if (payload == INVALID_HANDLE_VALUE) 
        _tprintf(TEXT("[!] Could not open payload: %s\n"), argv[1]);
    
    else 
        DWORD size = GetFileSize(payload, NULL);
        _tprintf(TEXT("[*] Payload found: %d bytes.\n"), size);

        // TROUBLE STARTS HERE
        LPDWORD bytes_read = 0;
        char* buffer = new char[size + 1];
        if (FALSE == ReadFile(payload, buffer, size, bytes_read, NULL)) 
            _tprintf(TEXT("[!] Could not read payload!\n"));
        
        else 
            _tprintf(TEXT("[*] Payload read!\n"));
        
        delete[] buffer;
        // TROUBLE ENDS HERE

    
    CloseHandle(payload);
    return 0;

这是一个失败的例子:

PS C:\path\to\binary> echo "Demonstration file." > demo.file
PS C:\path\to\binary> .\runp.exe .\demo.file
[*] Loading binary payload: .\demo.file
[*] Payload found: 44 bytes.
[!] Could not read payload!

程序正确检测并识别二进制文件的大小,但我无法将文件内容读入自定义大小的缓冲区。

Windows 上的 C++ 不是我的母语。 Python 更适合我的速度,但我在这里别无选择。任何帮助将不胜感激。

【问题讨论】:

如果您必须将整个二进制文件读入内存,我强烈建议您研究“c++ 内存映射文件窗口”。您的进程可能没有足够的内存分配给它来将二进制文件完整地读入内存。历代以来的大多数程序都只将块读入内存(是的,包括磁带卷盘的日子)。 在大多数平台上,文件空间多于 RAM。您需要弄清楚如何将文件读入大于系统 RAM 的内存中。 问题可能是LPDWORD bytes_read = 0;,而不是LPDWORD,你应该使用DWORD并将参数传递为&amp;bytes_read 如果您在打开文件时指定FILE_FLAG_OVERLAPPED,则意味着您计划异步读取它。这意味着ReadFile 的最后一个参数不能为NULL。异步读取即使成功也返回 FALSE。 docs.microsoft.com/en-us/windows/win32/api/fileapi/… 长话短说,删除FILE_FLAG_OVERLAPPED 另外,除非您计划支持 Windows 98,否则请停止使用 TCHAR 宏和 T 函数,例如 _tprintf。自 Windows XP 以来,它们就完全无关紧要了。不幸的是,Visual Studio 项目模板中仍然有这些垃圾。 【参考方案1】:

在大家的帮助下,我能够克服我在代码中遇到的问题。根据selbie 的建议,我无法完全删除所有TCHAR 内容,因为CreateFile 函数不接受文件名的字符数组,也不能在不使用_tmain 格式的情况下编译主功能。 (同样,Windows 上的 C++ 不是我的母语,所以毫无疑问有更好的方法来实现这一点。)但我确实添加了 \0(空字节)来终止缓冲区内容。我还合并了Retired Ninja 和Mark Ransom 建议的更改。以下是应用这些更改后的代码:

#include <windows.h>
#include <fileapi.h>
#include <stdio.h>
#include <tchar.h>

int __cdecl _tmain(int argc, TCHAR* argv[])

    HANDLE payload;
    if (argc != 2) 
        printf("Usage: runp.exe [payload_file]\nExecutes the specified binary payload.\n");
        return 0;
    
    printf("[*] Loading binary payload: %ws\n", argv[1]);
    payload = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (payload == INVALID_HANDLE_VALUE) 
        printf("[!] Could not open payload: %ws\n", argv[1]);
    
    else 
        DWORD size = GetFileSize(payload, NULL);
        DWORD bytes_read = 0;
        char* buffer = new char[size + 1];
        if (FALSE == ReadFile(payload, buffer, size, &bytes_read, NULL)) 
            printf("[!] Could not read payload!\n");
        
        else 
            buffer[bytes_read] = '\0';
            printf("[*] %d bytes read.\n[*] File contents:\n\n%s\n", bytes_read, buffer);
        
        delete[] buffer;
    
    CloseHandle(payload);
    return 0;

这里是一个正在运行的程序的演示:

C:\path\to\binary>echo Demonstration! > test.txt

C:\path\to\binary>type test.txt
Demonstration!

C:\path\to\binary>runp.exe test.txt
[*] Loading binary payload: test.txt
[*] 17 bytes read.
[*] File contents:

Demonstration!

再次感谢大家的有益建议!

【讨论】:

以上是关于Windows C++ API:如何将整个二进制文件读入缓冲区?的主要内容,如果未能解决你的问题,请参考以下文章

C++如何将一个存有数据的文本文件转换为二进制文件?

如何使用 Windows 运行时使用 C# 实现 C++ API?

Android开发学习

Visual C++ 2008:无法将 win64 设置为项目的活动构建配置

如何使用 npm 在 64 位系统上构建 32 位二进制文​​件?

C++ 在 Windows API 中创建一个单独的线程,程序终止?