C/C++ 使用API实现数据压缩与解压缩
在Windows编程中,经常会遇到需要对数据进行压缩和解压缩的情况,数据压缩是一种常见的优化手段,能够减小数据的存储空间并提高传输效率。Windows提供了这些API函数,本文将深入探讨使用Windows API进行数据压缩与解压缩的过程,主要使用ntdll.dll
库中的相关函数。
RtlGetCompressionWorkSpaceSize
RtlGetCompressionWorkSpaceSize 函数,位于ntdll.dll
库中。该函数用于获取数据压缩所需的工作空间大小。CompressionFormatAndEngine
参数指定压缩格式和引擎,CompressBufferWorkSpaceSize
和CompressFragmentWorkSpaceSize
分别用于输出缓冲区和片段的工作空间大小。
以下是该函数的声明:
typedef NTSTATUS(WINAPI *typedef_RtlGetCompressionWorkSpaceSize)(
_In_ USHORT CompressionFormatAndEngine,
_Out_ PULONG CompressBufferWorkSpaceSize,
_Out_ PULONG CompressFragmentWorkSpaceSize
);
该函数有以下参数:
- CompressionFormatAndEngine:指定压缩格式和引擎的参数。
- CompressBufferWorkSpaceSize:用于输出压缩缓冲区工作空间大小的指针。
- CompressFragmentWorkSpaceSize:用于输出压缩片段工作空间大小的指针。
函数返回NTSTATUS
类型的状态码,其中STATUS_SUCCESS
表示成功执行。
在使用这个函数时,你需要提供足够大的缓冲区来存储工作空间大小。可以按照以下步骤使用该函数:
- 加载 ntdll.dll 库。
- 获取 RtlGetCompressionWorkSpaceSize 函数地址。
- 定义变量用于存储工作空间大小。
- 调用 RtlGetCompressionWorkSpaceSize 函数,获取工作空间大小。
RtlCompressBuffer
RtlCompressBuffer 同样位于ntdll.dll
库中。该函数用于将数据进行压缩。CompressionFormatAndEngine
参数指定压缩格式和引擎,UncompressedBuffer
和UncompressedBufferSize
表示输入的未压缩数据,CompressedBuffer
和CompressedBufferSize
表示输出的压缩数据,UncompressedChunkSize
表示未压缩数据的块大小,FinalCompressedSize
表示最终压缩后的大小,WorkSpace
表示用于工作的缓冲区。
以下是该函数的声明:
typedef NTSTATUS(WINAPI *typedef_RtlCompressBuffer)(
_In_ USHORT CompressionFormatAndEngine,
_In_ PUCHAR UncompressedBuffer,
_In_ ULONG UncompressedBufferSize,
_Out_ PUCHAR CompressedBuffer,
_In_ ULONG CompressedBufferSize,
_In_ ULONG UncompressedChunkSize,
_Out_ PULONG FinalCompressedSize,
_In_ PVOID WorkSpace
);
该函数的参数包括:
- CompressionFormatAndEngine:指定压缩格式和引擎的参数。
- UncompressedBuffer:指向待压缩数据的指针。
- UncompressedBufferSize:待压缩数据的大小。
- CompressedBuffer:指向存储压缩数据的缓冲区的指针。
- CompressedBufferSize:存储压缩数据的缓冲区的大小。
- UncompressedChunkSize:未压缩的数据块的大小。
- FinalCompressedSize:用于输出最终压缩数据的大小的指针。
- WorkSpace:用于提供工作空间的指针。
函数返回NTSTATUS
类型的状态码,其中STATUS_SUCCESS
表示成功执行。
在使用这个函数时,你需要提供足够大的缓冲区来存储压缩后的数据。可以按照以下步骤使用该函数:
- 加载
ntdll.dll
库。 - 获取
RtlCompressBuffer
函数地址。 - 定义变量并分配内存用于存储未压缩的数据和压缩后的数据。
- 定义变量用于存储工作空间。
- 调用
RtlCompressBuffer
函数,将数据进行压缩。 - 处理压缩后的数据。
RtlDecompressBuffer
RtlDecompressBuffer 同样位于ntdll.dll
库中。该函数用于将压缩数据进行解压缩。CompressionFormat
参数指定压缩格式,UncompressedBuffer
和UncompressedBufferSize
表示输出的未压缩数据,CompressedBuffer
和CompressedBufferSize
表示输入的压缩数据,FinalUncompressedSize
表示最终解压缩后的大小。
以下是该函数的声明:
typedef NTSTATUS(WINAPI *typedef_RtlDecompressBuffer)(
_In_ USHORT CompressionFormat,
_Out_ PUCHAR UncompressedBuffer,
_In_ ULONG UncompressedBufferSize,
_In_ PUCHAR CompressedBuffer,
_In_ ULONG CompressedBufferSize,
_Out_ PULONG FinalUncompressedSize
);
该函数的参数包括:
- CompressionFormat:指定解压缩的格式。
- UncompressedBuffer:指向存储解压后数据的缓冲区的指针。
- UncompressedBufferSize:存储解压后数据的缓冲区的大小。
- CompressedBuffer:指向待解压数据的指针。
- CompressedBufferSize:待解压数据的大小。
- FinalUncompressedSize:用于输出最终解压后数据的大小的指针。
函数返回NTSTATUS
类型的状态码,其中STATUS_SUCCESS
表示成功执行。
在使用这个函数时,你需要提供足够大的缓冲区来存储解压后的数据。可以按照以下步骤使用该函数:
- 加载
ntdll.dll
库。 - 获取
RtlDecompressBuffer
函数地址。 - 定义变量并分配内存用于存储待解压的数据和解压后的数据。
- 调用
RtlDecompressBuffer
函数,将数据进行解压。 - 处理解压后的数据。
// 代码来源 《WINDOWS黑客编程技术详解》
// 作者:甘迪文
#include <Windows.h>
#include <iostream>
#include <windef.h>
typedef NTSTATUS(WINAPI *typedef_RtlGetCompressionWorkSpaceSize)(
_In_ USHORT CompressionFormatAndEngine,
_Out_ PULONG CompressBufferWorkSpaceSize,
_Out_ PULONG CompressFragmentWorkSpaceSize
);
typedef NTSTATUS(WINAPI *typedef_RtlCompressBuffer)(
_In_ USHORT CompressionFormatAndEngine,
_In_ PUCHAR UncompressedBuffer,
_In_ ULONG UncompressedBufferSize,
_Out_ PUCHAR CompressedBuffer,
_In_ ULONG CompressedBufferSize,
_In_ ULONG UncompressedChunkSize,
_Out_ PULONG FinalCompressedSize,
_In_ PVOID WorkSpace
);
typedef NTSTATUS(WINAPI *typedef_RtlDecompressBuffer)(
_In_ USHORT CompressionFormat,
_Out_ PUCHAR UncompressedBuffer,
_In_ ULONG UncompressedBufferSize,
_In_ PUCHAR CompressedBuffer,
_In_ ULONG CompressedBufferSize,
_Out_ PULONG FinalUncompressedSize
);
// 数据压缩
BOOL CompressData(BYTE *pUncompressData, DWORD dwUncompressDataLength, BYTE **ppCompressData, DWORD *pdwCompressDataLength)
{
BOOL bRet = FALSE;
NTSTATUS status = 0;
HMODULE hModule = NULL;
typedef_RtlGetCompressionWorkSpaceSize RtlGetCompressionWorkSpaceSize = NULL;
typedef_RtlCompressBuffer RtlCompressBuffer = NULL;
DWORD dwWorkSpaceSize = 0, dwFragmentWorkSpaceSize = 0;
BYTE *pWorkSpace = NULL;
BYTE *pCompressData = NULL;
DWORD dwCompressDataLength = 4096;
DWORD dwFinalCompressSize = 0;
do
{
// 加载 ntdll.dll
hModule = ::LoadLibrary("ntdll.dll");
if (NULL == hModule)
{
ShowError("LoadLibrary");
break;
}
// 获取 RtlGetCompressionWorkSpaceSize 函数地址
RtlGetCompressionWorkSpaceSize = (typedef_RtlGetCompressionWorkSpaceSize)::GetProcAddress(hModule, "RtlGetCompressionWorkSpaceSize");
if (NULL == RtlGetCompressionWorkSpaceSize)
{
ShowError("GetProcAddress");
break;
}
// 获取 RtlCompressBuffer 函数地址
RtlCompressBuffer = (typedef_RtlCompressBuffer)::GetProcAddress(hModule, "RtlCompressBuffer");
if (NULL == RtlCompressBuffer)
{
ShowError("GetProcAddress");
break;
}
// 获取WorkSpqce大小
status = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_STANDARD, &dwWorkSpaceSize, &dwFragmentWorkSpaceSize);
if (0 != status)
{
break;
}
// 申请动态内存
pWorkSpace = new BYTE[dwWorkSpaceSize];
if (NULL == pWorkSpace)
{
break;
}
::RtlZeroMemory(pWorkSpace, dwWorkSpaceSize);
while (TRUE)
{
// 申请动态内存
pCompressData = new BYTE[dwCompressDataLength];
if (NULL == pCompressData)
{
break;
}
::RtlZeroMemory(pCompressData, dwCompressDataLength);
// 调用RtlCompressBuffer压缩数据
RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, pUncompressData, dwUncompressDataLength, pCompressData, dwCompressDataLength, 4096, &dwFinalCompressSize, (PVOID)pWorkSpace);
if (dwCompressDataLength < dwFinalCompressSize)
{
// 释放内存
if (pCompressData)
{
delete[]pCompressData;
pCompressData = NULL;
}
dwCompressDataLength = dwFinalCompressSize;
}
else
{
break;
}
}
// 返回
*ppCompressData = pCompressData;
*pdwCompressDataLength = dwFinalCompressSize;
bRet = TRUE;
} while (FALSE);
// 释放
if (pWorkSpace)
{
delete[]pWorkSpace;
pWorkSpace = NULL;
}
if (hModule)
{
::FreeLibrary(hModule);
}
return bRet;
}
// 数据解压缩
BOOL UncompressData(BYTE *pCompressData, DWORD dwCompressDataLength, BYTE **ppUncompressData, DWORD *pdwUncompressDataLength)
{
BOOL bRet = FALSE;
HMODULE hModule = NULL;
typedef_RtlDecompressBuffer RtlDecompressBuffer = NULL;
BYTE *pUncompressData = NULL;
DWORD dwUncompressDataLength = 4096;
DWORD dwFinalUncompressSize = 0;
do
{
// 加载 ntdll.dll
hModule = ::LoadLibrary("ntdll.dll");
if (NULL == hModule)
{
break;
}
// 获取 RtlDecompressBuffer 函数地址
RtlDecompressBuffer = (typedef_RtlDecompressBuffer)::GetProcAddress(hModule, "RtlDecompressBuffer");
if (NULL == RtlDecompressBuffer)
{
break;
}
while (TRUE)
{
// 申请动态内存
pUncompressData = new BYTE[dwUncompressDataLength];
if (NULL == pUncompressData)
{
break;
}
::RtlZeroMemory(pUncompressData, dwUncompressDataLength);
// 调用RtlCompressBuffer压缩数据
RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, pUncompressData, dwUncompressDataLength, pCompressData, dwCompressDataLength, &dwFinalUncompressSize);
if (dwUncompressDataLength < dwFinalUncompressSize)
{
// 释放内存
if (pUncompressData)
{
delete[]pUncompressData;
pUncompressData = NULL;
}
dwUncompressDataLength = dwFinalUncompressSize;
}
else
{
break;
}
}
// 返回
*ppUncompressData = pUncompressData;
*pdwUncompressDataLength = dwFinalUncompressSize;
bRet = TRUE;
} while (FALSE);
// 释放
if (hModule)
{
::FreeLibrary(hModule);
}
return bRet;
}
int main(int argc, char *argv[])
{
DWORD i = 0;
BOOL bRet = FALSE;
char szBuffer[] = "DDDDDDDDDDGGGGGGGGGGGG";
DWORD dwBufferLength = ::lstrlen(szBuffer);
BYTE *pCompressData = NULL;
DWORD dwCompressDataLength = 0;
BYTE *pUncompressData = NULL;
DWORD dwUncompressDataLength = 0;
// 压缩数据
CompressData((BYTE *)szBuffer, dwBufferLength, &pCompressData, &dwCompressDataLength);
// 解压数据
UncompressData(pCompressData, dwCompressDataLength, &pUncompressData, &dwUncompressDataLength);
// 显示
printf("原数据为:\n");
for (i = 0; i < dwBufferLength; i++)
{
printf("%X ", szBuffer[i]);
}
printf("\n\n压缩数据为:\n");
for (i = 0; i < dwCompressDataLength; i++)
{
printf("%X ", pCompressData[i]);
}
printf("\n\n解压缩数据为:\n");
for (i = 0; i < dwUncompressDataLength; i++)
{
printf("%X ", pUncompressData[i]);
}
printf("\n");
// 释放
if (pUncompressData)
{
delete[]pUncompressData;
pUncompressData = NULL;
}
if (pCompressData)
{
delete[]pCompressData;
pCompressData = NULL;
}
system("pause");
return 0;
}
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!