010 rar.bt

LittleEndian();

local const uint16 SignatureLen = 7;
const string RarSignature = "Rar!" + '\x1A' + '\x07';

///////////////

struct FileHeadBlock;
struct OldCommentBlock;
struct OldSubBlock;
struct SubBlock;

///////////////

enum <byte> RarBlockType
{
	MARKER=0x72, ARCHIVE, FILE_OR_DIR, COMMENT_OLD, AV_OLD_1, SUBBLOCK_OLD, RR_OLD, AV_OLD_2, SUBBLOCK, _END_
};

////////////////

local uint16 _flags = 0;

/// info:
local uquad iBlocksCounter = 0;
local uquad iFiles = 0;
local uquad iDirs = 0;
local uquad iComments = 0;
local uquad iSubBlocks = 0;
local uquad iUniNames = 0;
local uquad iBadCRCCounter = 0;
local ubyte iMinVerToUnpack = 0xff;
local ubyte iMaxVerToUnpack = 0;
local uquad iTotalUnpackedSize = 0;
local uint iAV1 = 0;
local uint iAV2 = 0;

////////////////

enum <ubyte> OsType 
{ 
	_MS_DOS, _OS_2, _Win32, _Unix, _Mac_OS, _BeOS 
};

enum <char> PackMethod 
{ 
	Store='0', Fastest, Fast, Normal, Good, Best 
};

enum <uint16> SubType_OldStyle
{
	OS2_EA = 0x0100
};

struct UnixStyleAttrs
{
	uint32 owner_may_eXecute : 1;
	uint32 owner_may_Write : 1;
	uint32 owner_may_Read : 1;

	uint32 group_may_eXecute : 1;
	uint32 gorup_may_Write : 1;
	uint32 group_may_Read : 1;

	uint32 everybody_may_eXecute : 1;
	uint32 everybody_may_Write : 1;
	uint32 everybody_may_Read : 1;

	uint32 _s : 1; // ??
	uint32 _s : 1; // ??
	
	uint32 _unused : 21;
};

struct DosFileAttrs
{
	uint32 READONLY : 1; //              0x00000001  
	uint32 HIDDEN : 1; //                0x00000002  
	uint32 SYSTEM : 1; //                0x00000004  
	uint32 VOLUME : 1;
	uint32 DIRECTORY : 1; //             0x00000010
	uint32 ARCHIVE : 1; //               0x00000020
	uint32 _res : 26;
};

struct WinFileAttrs
{
	uint32 READONLY : 1;
	uint32 HIDDEN : 1;
	uint32 SYSTEM : 1;
	uint32 VOLUME : 1;
	uint32 DIRECTORY : 1;
	uint32 ARCHIVE : 1;
	uint32 DEVICE : 1;
	uint32 NORMAL : 1;
	uint32 TEMPORARY : 1;
	uint32 SPARSE_FILE : 1;
	uint32 REPARSE_POINT : 1;
	uint32 COMPRESSED : 1;
	uint32 OFFLINE : 1;
	uint32 NOT_CONTENT_INDEXED : 1;
	uint32 ENCRYPTED : 1;
	uint32 _res2 : 17;
};

struct CommonBlockFlags
{
	ushort _reserved : 14;
	ushort OLD_VERSION_IGNORE : 1;
	ushort ADD_SIZE_PRESENT : 1;
};

struct MainHeadFlags
{
	ubyte ARCHIVE_VOLUME : 1;
	ubyte ARCHIVE_COMMENT_PRESENT : 1;
	ubyte ARCHIVE_LOCKED : 1;
	ubyte ARCHIVE_SOLID : 1;
	ubyte NEW_VOLUME_NAMING : 1; 
	ubyte AV_PRESENT : 1;
	ubyte RECOVERY_PRESENT : 1;
	ubyte BLOCK_HEADERS_ENCRYPTED : 1;
	ubyte IS_FIRST_VOLUME : 1;
	ubyte _reserved : 5;
	ubyte OLD_VERSION_IGNORE : 1;
	ubyte ADD_SIZE_PRESENT : 1;
};


enum <byte> FileDictType
{
	_64K, _128K, _256K, _512K, _1024K, _2048K, _4096K, _Directory
};

struct FileHeadFlags
{
	ubyte from_PREV_VOLUME : 1;
	ubyte to_NEXT_VOLUME : 1;
	ubyte PASSWORD_ENCRYPTED : 1;
	ubyte FILE_COMMENT_PRESENT : 1;
	ubyte SOLID : 1;
	FileDictType DICTIONARY : 3;
	ubyte HIGH_SIZE : 1;
	ubyte has_UNICODE_FILENAME : 1;
	ubyte ENCRYPTION_SALT : 1;
	ubyte IS_OLD_FILE_VERSION : 1;
	ubyte EXTENDED_TIME_INFO : 1;
	ubyte _reserved : 1;
	ubyte OLD_VERSION_IGNORE : 1;
	ubyte ADD_SIZE_PRESENT : 1;
};

struct RarBlock
{
	local quad iOfs = FTell();

	uint16 HEAD_CRC <format=hex, fgcolor=cRed>;

	RarBlockType HeadType <fgcolor=cGreen>;

	_flags = ReadUShort(FTell());

	if (HeadType == ARCHIVE)
		MainHeadFlags HEAD_FLAGS; 
	else if (HeadType == FILE_OR_DIR)
		FileHeadFlags HEAD_FLAGS;
	else
		CommonBlockFlags HEAD_FLAGS;

	++iBlocksCounter;

	if (HeadType < MARKER || HeadType > _END_)
	{
		Warning("Unknown Header Type (0x%02x) in Block #%Lu", HeadType, iBlocksCounter);
		Printf("Unknown Header Type (0x%02x) in Block #%Lu\n", HeadType, iBlocksCounter);
	}

	uint16 HeaderSize;

	if (HeaderSize < 7)
	{
		Warning("Invalid block size (%u) in Block #%Lu", HeaderSize, iBlocksCounter);
		Printf("Invalid block size (%u) in Block #%Lu\n", HeaderSize, iBlocksCounter);
		return -1;
	}

	if (HeadType != MARKER)
	{
		local uint16 crcCheck = Checksum(CHECKSUM_CRC32, startof(HeadType), HeaderSize-sizeof(HEAD_CRC)) & 0xFFFF;
		if (crcCheck != HEAD_CRC)
		{
            Warning("Header CRC mismatch in Block #%Lu", iBlocksCounter);
			Printf("Header CRC mismatch in Block #%Lu: expected CRC is 0x%X, got 0x%X\n", iBlocksCounter, crcCheck, HEAD_CRC);
			++iBadCRCCounter;
		}
	}

	if (HEAD_FLAGS.ADD_SIZE_PRESENT)
		uint32 RawDataSize;
	else
		local uint32 RawDataSize = 0;

	switch (HeadType) {
	case ARCHIVE:
		uint16 _reserved1;
		uint32 _reserved2;
		if (HEAD_FLAGS.ARCHIVE_COMMENT_PRESENT) struct RarBlock MainComment;
		break;
	case FILE_OR_DIR:
		if (HEAD_FLAGS.DICTIONARY == 7)
		{
			++iDirs;
			FileHeadBlock dir;
		}
		else
		{
			++iFiles;
			FileHeadBlock file;
		}
		break;
	case COMMENT_OLD:
		OldCommentBlock cmm;
		break;
	case SUBBLOCK_OLD:
		OldSubBlocksub;
		break;
	case SUBBLOCK:
		SubBlock sub;
		break;
	case AV_OLD_1:
		++iAV1;
		Printf("*** AV was found (RAR v. < 2.60) @ block #%Lu.\n", iBlocksCounter);
		break;
	case AV_OLD_2:
		++iAV2;
		Printf("*** AV was found (RAR v. 2.60 - 2.9x) @ block #%Lu.\n", iBlocksCounter);
		break;
	}

	iOfs = HeaderSize - (FTell() - iOfs);

	if (iOfs > 0)
		ubyte _reserved[iOfs];

	if (RawDataSize > 0)
		ubyte _raw[RawDataSize] <format=hex, fgcolor=cBlue>;
};

struct FileHeadBlock
{
	uint32 UnpackedSize;
	iTotalUnpackedSize += UnpackedSize;

	OsType Host_OS;
	uint32 FileCRC32 <format=hex>;
	DOSTIME FileTime;
	DOSDATE FileDate;
	ubyte VersionToUnpack;

	if (VersionToUnpack > iMaxVerToUnpack)
		iMaxVerToUnpack = VersionToUnpack;
	
	if (VersionToUnpack < iMinVerToUnpack)
		iMinVerToUnpack = VersionToUnpack;

	PackMethod Method;
	uint16 NameSize;

	switch (Host_OS) {
	case _Win32:
		WinFileAttrs Attributes;
		break;
	case _MS_DOS:
	case _Mac_OS:
	case _OS_2:
		DosFileAttrs Attributes;
		break;
	case _Unix:
	case _BeOS:
		UnixStyleAttrs Attributes;
		break;
	default:
		uint32 Attributes <format=binary>;
	}

	if (_flags & 0x0100)
	{
		uint32 HIGH_PACK_SIZE;
		uint32 HIGH_UNP_SIZE;

		iTotalUnpackSize += (HIGH_UNP_SIZE << 32);
	}

	if (_flags & 0x0200)
	{
		++iUniNames;

		string FileName;
		uint16 WideFileNameData[(NameSize-sizeof(FileName))/2];
	}
	else
		char FileName[NameSize];

	if (_flags & 0x0008)
	{
		RarBlock FileComment; // used in RAR v. <= 3.11
	}

	if (_flags & 0x0400)
		uquad SALT <format=hex>;
};

/////////////////

struct OldCommentBlock {
	++iComments;

	uint16 UnpackedSize;
	ubyte VersionToUnpack;
	PackMethod Method;
	uint16 CommentCRC <format=hex>;
	
	Printf("*** Old style CommentBlock:  (Block #%Lu)\n", iBlocksCounter);
};

struct OldSubBlock {
	++iSubBlocks;
	
	SubType_OldStyle SubType;
	ubyte _reserved;
	
	Printf("*** Old style SubBlock: %u (Block #%Lu)\n", SubType, iBlocksCounter);
};

struct SubBlock {
	++iSubBlocks;

	ubyte _unknown_to_me_1[15];
	ubyte SubTypeLen;
	ubyte _unknown_to_me_2[5];
	char SubType[SubTypeLen];

	Printf("*** SubBlock: %s (Block #%Lu)\n", SubType+'\0', iBlocksCounter);
	switch (SubType) {
	case "CMT":
		++iComments;
		break;
	case "AV":
		Printf("*** Authenticity Verification info (RAR v. 3.x) @ block #%Lu.\n", iBlocksCounter);
		break;
	case "RR":
		Printf("*** Recovery Record was found (RAR v. 3.x) @ block #%Lu.\n", iBlocksCounter);
		break;
	}
};

/////////////////

local string fn = GetFileName();
local quad SignaturePos = 0;
local char Signature[SignatureLen];

if (Strstr(fn, ".rar") != Strlen(fn)-4)
{
	Warning("Seeking for RAR signature...");

	local quad _p = FindFirst(RarSignature);
	if (_p >= 0)
		FSeek(_p);
	else
	{
		Warning("Not a RAR archive!");
		return -1;
	}

	Warning("RAR signature found at 0x%08x.", _p);
	Printf("RAR signature found at 0x%08x.\n", _p);
}
else
{
	ReadBytes(Signature, SignaturePos, SignatureLen);

	if (Strcmp(Signature, RarSignature))
	{
		Warning("Invalid RAR Archive Signature!");
		return SignaturePos;
	}
}

RarBlock Marker;

RarBlock ArcHeader;
if (ArcHeader.HeadType != ARCHIVE)
{
	Warning("Main archive header is either bad or missing!");
	return -2;
}
else
{
	Printf("It is a %s%s %s %s RAR archive.\n", 
		SignaturePos > 0 ? "SelF-eXtractable " : "",
		ArcHeader.HEAD_FLAGS.ARCHIVE_LOCKED ? "LOCKED" : "non-locked",
		ArcHeader.HEAD_FLAGS.ARCHIVE_SOLID ? "SOLID" : "regular", 
		ArcHeader.HEAD_FLAGS.ARCHIVE_VOLUME ? "VOLUME'd" : "one-part");

	if (ArcHeader.HEAD_FLAGS.ARCHIVE_COMMENT_PRESENT)
		Printf("Main comment is present.\n");
	if (ArcHeader.HEAD_FLAGS.AV_PRESENT)
		Printf("Old style Authenticity Verification is present.\n");
	if (ArcHeader.HEAD_FLAGS.RECOVERY_PRESENT)
		Printf("Recovery Record is present.\n");

	if (ArcHeader.HEAD_FLAGS.BLOCK_HEADERS_ENCRYPTED)
	{
		Printf("It's an encrypted archive. Cannot proceed, exiting...\n");
		return -3;
	}
}

while (!FEof())
{  
	RarBlock block;
}

if (block.HeadType != _END_ && iMaxVerToUnpack > 20)
{
	Warning("END Marker block was expected here.");
}

if (iFiles || iDirs)
{
	Printf("Version to unpack: %u.%u\n", iMaxVerToUnpack / 10, iMaxVerToUnpack % 10);
	if (iMinVerToUnpack != iMaxVerToUnpack)
		Printf("Some data can also be retrieved by an earlier version of %u.%u\n", 
			iMinVerToUnpack /10, iMinVerToUnpack %10);
}

Printf("Files: %Lu, Dirs: %Lu, Comments: %Lu, SubBlocks: %Lu, Unpacked Size: %Lu\n", iFiles, iDirs, iComments, iSubBlocks, iTotalUnpackedSize);
Printf("UNICODE Names: %Lu\n", iUniNames);
if (iBadCRCCounter)
	Printf("%Lu blocks corrupted.\n", iBadCRCCounter);
Printf("Done. %Lu blocks processed.\n", iBlocksCounter);

posted on 2017-11-15 20:26  千缕情丝  阅读(399)  评论(0编辑  收藏  举报

导航