mirror of https://github.com/x64dbg/btparser
457 lines
9.9 KiB
Plaintext
457 lines
9.9 KiB
Plaintext
|
//-----------------------------------
|
||
|
//--- 010 Editor v2.0 Binary Template
|
||
|
//
|
||
|
// File: RARTemplate2.bt
|
||
|
// Author: Alexander Sherman
|
||
|
// Purpose: Defines a template for
|
||
|
// parsing RAR files.
|
||
|
// Revision: 7.03
|
||
|
//-----------------------------------
|
||
|
|
||
|
|
||
|
// RAR archive structures
|
||
|
// Based on TECHNOTE.TXT from the RAR archiver distribution
|
||
|
|
||
|
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);
|