UACME/Source/Akagi/compress.c

351 lines
6.9 KiB
C

/*******************************************************************************
*
* (C) COPYRIGHT AUTHORS, 2014 - 2016
*
* TITLE: COMPRESS.C
*
* VERSION: 2.00
*
* DATE: 16 Nov 2015
*
* Compression support.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
*******************************************************************************/
#include "global.h"
#ifndef _DEBUG
#undef GENERATE_COMPRESSED_PAYLOAD
#else
#ifdef _WIN64
#include "hibiki64.h"
#include "fubuki64.h"
#include "kongou64.h"
#else
#include "hibiki32.h"
#include "fubuki32.h"
#include "kongou32.h"
#endif
#endif
/*
* EncodeBuffer
*
* Purpose:
*
* Decrypt/Encrypt given buffer.
*
*/
VOID EncodeBuffer(
PVOID Buffer,
ULONG BufferSize
)
{
ULONG k, c;
PUCHAR ptr;
if ((Buffer == NULL) || (BufferSize == 0))
return;
k = 'ftp2';
c = BufferSize;
ptr = Buffer;
do {
*ptr ^= k;
k = _rotl(k, 1);
ptr++;
--c;
} while (c != 0);
}
/*
* CompressBufferLZNT1
*
* Purpose:
*
* Compress given buffer with LZ algorithm.
*
* Use VirtualFree to release returned buffer when it no longer needed.
*
*/
PUCHAR CompressBufferLZNT1(
_In_ PUCHAR SrcBuffer,
_In_ ULONG SrcSize,
_Inout_ PULONG FinalCompressedSize
)
{
BOOL cond = FALSE;
NTSTATUS status;
ULONG CompressedSize = 0;
ULONG CompressBufferWorkSpaceSize = 0;
ULONG CompressFragmentWorkSpaceSize = 0;
ULONG CompBufferSize = 0;
PVOID WorkSpace = NULL;
PUCHAR CompBuffer = NULL;
if (FinalCompressedSize == NULL)
return NULL;
do {
status = RtlGetCompressionWorkSpaceSize(
COMPRESSION_FORMAT_LZNT1,
&CompressBufferWorkSpaceSize,
&CompressFragmentWorkSpaceSize
);
//accept nothing but STATUS_SUCCESS
if (status != STATUS_SUCCESS) {
break;
}
WorkSpace = (PVOID)VirtualAlloc(NULL, CompressBufferWorkSpaceSize,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (WorkSpace == NULL) {
break;
}
//original size + safe buffer + sizeof header
CompBufferSize = SrcSize + 0x1000 + sizeof(ULONG);
CompBuffer = (PUCHAR)VirtualAlloc(NULL, CompBufferSize,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (CompBuffer == NULL) {
break;
}
CompressedSize = 0;
status = RtlCompressBuffer(
COMPRESSION_FORMAT_LZNT1,
SrcBuffer,
SrcSize,
&CompBuffer[4],
CompBufferSize,
4096,
&CompressedSize,
WorkSpace
);
if (status != STATUS_SUCCESS) {
VirtualFree(CompBuffer, 0, MEM_RELEASE);
break;
}
*(PULONG)&CompBuffer[0] = SrcSize;//save original size
CompressedSize += sizeof(ULONG); //add header size
*FinalCompressedSize = CompressedSize;
} while (cond);
if (WorkSpace != NULL) {
VirtualFree(WorkSpace, 0, MEM_RELEASE);
}
return CompBuffer;
}
/*
* DecompressBufferLZNT1
*
* Purpose:
*
* Decompress buffer compressed with LZ algorithm.
*
* Use VirtualFree to release returned buffer when it no longer needed.
*
*/
PUCHAR DecompressBufferLZNT1(
_In_ PUCHAR CompBuffer,
_In_ ULONG CompSize,
_In_ ULONG UncompressedBufferSize,
_Inout_ PULONG FinalUncompressedSize
)
{
PUCHAR UncompBuffer = NULL;
NTSTATUS status;
UncompBuffer = (PUCHAR)VirtualAlloc(NULL, UncompressedBufferSize,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (UncompBuffer == NULL) {
return NULL;
}
status = RtlDecompressBuffer(
COMPRESSION_FORMAT_LZNT1,
UncompBuffer,
UncompressedBufferSize,
CompBuffer,
CompSize,
FinalUncompressedSize
);
if (status != STATUS_SUCCESS) { //accept only success value
if (UncompBuffer) {
VirtualFree(UncompBuffer, 0, MEM_RELEASE);
UncompBuffer = NULL;
}
}
return UncompBuffer;
}
#ifdef GENERATE_COMPRESSED_PAYLOAD
/*
* CompressPayload
*
* Purpose:
*
* Create compressed and encrypted by xor files. Used only during development.
* NOT for usage with release.
*
*/
VOID CompressPayload(
VOID
)
{
PUCHAR Data;
ULONG FinalCompressedSize = 0;
#ifdef _WIN64
Data = CompressBufferLZNT1((PUCHAR)Fubuki64, sizeof(Fubuki64), &FinalCompressedSize);
#else
Data = CompressBufferLZNT1((PUCHAR)Fubuki32, sizeof(Fubuki32), &FinalCompressedSize);
#endif
if (Data) {
EncodeBuffer(Data, FinalCompressedSize);
#ifdef _WIN64
supWriteBufferToFile(TEXT("fubuki64.cd"), Data, FinalCompressedSize);
#else
supWriteBufferToFile(TEXT("fubuki32.cd"), Data, FinalCompressedSize);
#endif
VirtualFree(Data, 0, MEM_RELEASE);
}
FinalCompressedSize = 0;
#ifdef _WIN64
Data = CompressBufferLZNT1((PUCHAR)Hibiki64, sizeof(Hibiki64), &FinalCompressedSize);
#else
Data = CompressBufferLZNT1((PUCHAR)Hibiki32, sizeof(Hibiki32), &FinalCompressedSize);
#endif
if (Data) {
EncodeBuffer(Data, FinalCompressedSize);
#ifdef _WIN64
supWriteBufferToFile(TEXT("hibiki64.cd"), Data, FinalCompressedSize);
#else
supWriteBufferToFile(TEXT("hibiki32.cd"), Data, FinalCompressedSize);
#endif
VirtualFree(Data, 0, MEM_RELEASE);
}
FinalCompressedSize = 0;
#ifdef _WIN64
Data = CompressBufferLZNT1((PUCHAR)Kongou64, sizeof(Kongou64), &FinalCompressedSize);
#else
Data = CompressBufferLZNT1((PUCHAR)Kongou32, sizeof(Kongou32), &FinalCompressedSize);
#endif
if (Data) {
EncodeBuffer(Data, FinalCompressedSize);
#ifdef _WIN64
supWriteBufferToFile(TEXT("kongou64.cd"), Data, FinalCompressedSize);
#else
supWriteBufferToFile(TEXT("kongou32.cd"), Data, FinalCompressedSize);
#endif
VirtualFree(Data, 0, MEM_RELEASE);
}
}
#endif
/*
* DecompressPayload
*
* Purpose:
*
* Decode payload and then decompress it.
*
*/
PVOID DecompressPayload(
_In_ PVOID CompressedBuffer,
_In_ ULONG CompressedBufferSize,
_Inout_ PULONG DecompressedBufferSize
)
{
BOOL cond = FALSE, bResult;
PUCHAR Data = NULL, UncompressedData = NULL, Ptr;
ULONG FinalDecompressedSize = 0, k, c;
__try {
bResult = FALSE;
do {
Data = VirtualAlloc(NULL, CompressedBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (Data == NULL)
break;
supCopyMemory(Data, CompressedBufferSize, CompressedBuffer, CompressedBufferSize);
EncodeBuffer(Data, CompressedBufferSize);
Ptr = Data;
c = *(PULONG)&Ptr[0]; //query original size
Ptr += sizeof(ULONG); //skip header
k = CompressedBufferSize - sizeof(ULONG); //new compressed size without header
UncompressedData = DecompressBufferLZNT1(Ptr, k, c, &FinalDecompressedSize);
if (UncompressedData == NULL)
break;
//validate uncompressed data
if (!supVerifyMappedImageMatchesChecksum(UncompressedData, FinalDecompressedSize)) {
OutputDebugString(TEXT("Invalid file checksum"));
break;
}
bResult = TRUE;
} while (cond);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
return NULL;
}
if (Data != NULL) {
VirtualFree(Data, 0, MEM_RELEASE);
}
if (bResult == FALSE) {
if (UncompressedData != NULL) {
VirtualFree(UncompressedData, 0, MEM_RELEASE);
UncompressedData = NULL;
}
FinalDecompressedSize = 0;
}
if (DecompressedBufferSize) {
*DecompressedBufferSize = FinalDecompressedSize;
}
return UncompressedData;
}