Update to 7-Zip Version 18.05

This commit is contained in:
Tino Reichardt
2018-10-21 14:23:28 +02:00
parent 51dc99984a
commit 78fc3c9bc5
208 changed files with 13958 additions and 3588 deletions

View File

@@ -109,7 +109,8 @@ void CVersion::ToProp(NCOM::CPropVariant &prop)
prop = sz;
}
static const unsigned kHeaderSize = 4 + 20;
static const unsigned kCoffHeaderSize = 20;
static const unsigned kPeHeaderSize = 4 + kCoffHeaderSize;
static const unsigned k_OptHeader32_Size_MIN = 96;
static const unsigned k_OptHeader64_Size_MIN = 112;
@@ -125,15 +126,14 @@ struct CHeader
UInt16 OptHeaderSize;
UInt16 Flags;
bool Parse(const Byte *p);
void ParseBase(const Byte *p);
bool ParseCoff(const Byte *p);
bool ParsePe(const Byte *p);
bool IsDll() const { return (Flags & PE_IMAGE_FILE_DLL) != 0; }
};
bool CHeader::Parse(const Byte *p)
void CHeader::ParseBase(const Byte *p)
{
if (Get32(p) != k_Signature32)
return false;
p += 4;
G16( 0, Machine);
G16( 2, NumSections);
G32( 4, Time);
@@ -141,6 +141,13 @@ bool CHeader::Parse(const Byte *p)
G32(12, NumSymbols);
G16(16, OptHeaderSize);
G16(18, Flags);
}
bool CHeader::ParsePe(const Byte *p)
{
if (Get32(p) != k_Signature32)
return false;
ParseBase(p + 4);
return OptHeaderSize >= k_OptHeader32_Size_MIN;
}
@@ -380,6 +387,10 @@ void CSection::Parse(const Byte *p)
G32(36, Flags);
}
// IMAGE_FILE_*
static const CUInt32PCharPair g_HeaderCharacts[] =
{
{ 1, "Executable" },
@@ -399,39 +410,65 @@ static const CUInt32PCharPair g_HeaderCharacts[] =
{ 15, "Big-Endian" }
};
static const CUInt32PCharPair g_DllCharacts[] =
// IMAGE_DLLCHARACTERISTICS_*
static const char * const g_DllCharacts[] =
{
{ 5, "HighEntropyVA" },
{ 6, "Relocated" },
{ 7, "Integrity" },
{ 8, "NX-Compatible" },
{ 9, "NoIsolation" },
{ 10, "NoSEH" },
{ 11, "NoBind" },
{ 12, "AppContainer" },
{ 13, "WDM" },
{ 14, "GuardCF" },
{ 15, "TerminalServerAware" }
NULL
, NULL
, NULL
, NULL
, NULL
, "HighEntropyVA"
, "Relocated"
, "Integrity"
, "NX-Compatible"
, "NoIsolation"
, "NoSEH"
, "NoBind"
, "AppContainer"
, "WDM"
, "GuardCF"
, "TerminalServerAware"
};
static const CUInt32PCharPair g_SectFlags[] =
// IMAGE_SCN_* constants:
static const char * const g_SectFlags[] =
{
{ 3, "NoPad" },
{ 5, "Code" },
{ 6, "InitializedData" },
{ 7, "UninitializedData" },
{ 9, "Comments" },
{ 11, "Remove" },
{ 12, "COMDAT" },
{ 15, "GP" },
{ 24, "ExtendedRelocations" },
{ 25, "Discardable" },
{ 26, "NotCached" },
{ 27, "NotPaged" },
{ 28, "Shared" },
{ 29, "Execute" },
{ 30, "Read" },
{ 31, "Write" }
NULL
, NULL
, NULL
, "NoPad"
, NULL
, "Code"
, "InitializedData"
, "UninitializedData"
, "Other"
, "Comments"
, NULL // OVER
, "Remove"
, "COMDAT"
, NULL
, "NO_DEFER_SPEC_EXC"
, "GP" // MEM_FARDATA
, NULL // SYSHEAP
, "PURGEABLE" // 16BIT
, "LOCKED"
, "PRELOAD"
, NULL
, NULL
, NULL
, NULL
, "ExtendedRelocations"
, "Discardable"
, "NotCached"
, "NotPaged"
, "Shared"
, "Execute"
, "Read"
, "Write"
};
static const CUInt32PCharPair g_MachinePairs[] =
@@ -699,7 +736,6 @@ class CHandler:
{
CMyComPtr<IInStream> _stream;
CObjectVector<CSection> _sections;
UInt32 _peOffset;
CHeader _header;
UInt32 _totalSize;
Int32 _mainSubfile;
@@ -720,9 +756,12 @@ class CHandler:
bool _parseResources;
bool _checksumError;
bool IsOpt() const { return _header.OptHeaderSize != 0; }
COptHeader _optHeader;
bool _allowTail;
bool _coffMode;
HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
@@ -742,7 +781,10 @@ class CHandler:
}
public:
CHandler(): _allowTail(false) {}
CHandler(bool coffMode = false):
_coffMode(coffMode),
_allowTail(coffMode)
{}
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail)
INTERFACE_IInArchive(;)
@@ -841,6 +883,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
NCOM::CPropVariant prop;
switch (propID)
{
case kpidPhySize: prop = _totalSize; break;
case kpidComment: if (!_versionFullString.IsEmpty()) prop = _versionFullString; break;
case kpidShortComment:
if (!_versionShortString.IsEmpty())
prop = _versionShortString;
else
{
PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop);
}
break;
case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break;
// case kpidIsSelfExe: prop = !_header.IsDll(); break;
// case kpidError:
case kpidWarning: if (_checksumError) prop = "Checksum error"; break;
case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
case kpidMTime:
case kpidCTime: TimeToProp(_header.Time, prop); break;
case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
default:
if (IsOpt())
switch (propID)
{
case kpidSectAlign: prop = _optHeader.SectAlign; break;
case kpidFileAlign: prop = _optHeader.FileAlign; break;
case kpidLinkerVer:
@@ -857,37 +927,19 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidInitDataSize: prop = _optHeader.InitDataSize; break;
case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break;
case kpidImageSize: prop = _optHeader.ImageSize; break;
case kpidPhySize: prop = _totalSize; break;
case kpidHeadersSize: prop = _optHeader.HeadersSize; break;
case kpidChecksum: prop = _optHeader.CheckSum; break;
case kpidComment: if (!_versionFullString.IsEmpty()) prop = _versionFullString; break;
case kpidShortComment:
if (!_versionShortString.IsEmpty())
prop = _versionShortString;
else
{
PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop);
}
break;
case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break;
case kpidExtension:
if (_header.IsDll())
prop = _optHeader.IsSybSystem_EFI() ? "efi" : "dll";
prop = "dll";
else if (_optHeader.IsSybSystem_EFI())
prop = "efi";
break;
// case kpidIsSelfExe: prop = !_header.IsDll(); break;
// case kpidError:
case kpidWarning: if (_checksumError) prop = "Checksum error"; break;
case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break;
case kpidSubSystem: TYPE_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;
case kpidMTime:
case kpidCTime: TimeToProp(_header.Time, prop); break;
case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break;
case kpidStackReserve: prop = _optHeader.StackReserve; break;
case kpidStackCommit: prop = _optHeader.StackCommit; break;
@@ -898,8 +950,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
// case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
// case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
// case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break;
case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
}
}
prop.Detach(value);
return S_OK;
@@ -1056,7 +1107,24 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime:
case kpidCTime:
TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break;
case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break;
case kpidCharacts:
if (item.IsRealSect)
{
UInt32 flags = item.Flags;
const UInt32 MY__IMAGE_SCN_ALIGN_MASK = 0x00F00000;
AString s = FlagsToString(g_SectFlags, ARRAY_SIZE(g_SectFlags), item.Flags & ~MY__IMAGE_SCN_ALIGN_MASK);
const UInt32 align = ((flags >> 20) & 0xF);
if (align != 0)
{
char sz[32];
ConvertUInt32ToString(1 << (align - 1), sz);
s.Add_Space();
s += "align_";
s += sz;
}
prop = s;
}
break;
case kpidZerosTailIsAllowed: if (!item.IsRealSect) prop = true; break;
}
}
@@ -1073,8 +1141,17 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
return S_OK;
const unsigned kEntrySize = 28;
UInt32 numItems = debugLink.Size / kEntrySize;
if (numItems * kEntrySize != debugLink.Size || numItems > 16)
if (numItems > 16)
return S_FALSE;
// MAC's EFI file: numItems can be incorrect. Only first CDebugEntry entry is correct.
// debugLink.Size = kEntrySize + some_data, pointed by entry[0].
if (numItems * kEntrySize != debugLink.Size)
{
// return S_FALSE;
if (numItems > 1)
numItems = 1;
}
UInt64 pa = 0;
unsigned i;
@@ -2114,6 +2191,31 @@ HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchi
return S_OK;
}
bool CHeader::ParseCoff(const Byte *p)
{
ParseBase(p);
if (PointerToSymbolTable < kCoffHeaderSize)
return false;
if (NumSymbols >= (1 << 24))
return false;
if (OptHeaderSize != 0 && OptHeaderSize < k_OptHeader32_Size_MIN)
return false;
// 18.04: we reduce false detections
if (NumSections == 0 && OptHeaderSize == 0)
return false;
for (unsigned i = 0; i < ARRAY_SIZE(g_MachinePairs); i++)
if (Machine == g_MachinePairs[i].Value)
return true;
if (Machine == 0)
return true;
return false;
}
static inline bool CheckPeOffset(UInt32 pe)
{
// ((pe & 7) == 0) is for most PE files. But there is unusual EFI-PE file that uses unaligned pe value.
@@ -2133,10 +2235,10 @@ API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size)
UInt32 pe = Get32(p + 0x3C);
if (!CheckPeOffset(pe))
return k_IsArc_Res_NO;
if (pe + kHeaderSize > size)
if (pe + kPeHeaderSize > size)
return k_IsArc_Res_NEED_MORE;
CHeader header;
if (!header.Parse(p + pe))
if (!header.ParsePe(p + pe))
return k_IsArc_Res_NO;
return k_IsArc_Res_YES;
}
@@ -2144,32 +2246,47 @@ API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size)
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{
UInt32 coffOffset = 0;
if (_coffMode)
{
Byte h[kStartSize];
_mainSubfile = -1;
RINOK(ReadStream_FALSE(stream, h, kStartSize));
if (h[0] != 'M' || h[1] != 'Z')
return S_FALSE;
/* most of PE files contain 0x0090 at offset 2.
But some rare PE files contain another values. So we don't use that check.
if (Get16(h + 2) != 0x90) return false; */
_peOffset = Get32(h + 0x3C);
if (!CheckPeOffset(_peOffset))
Byte h[kCoffHeaderSize];
RINOK(ReadStream_FALSE(stream, h, kCoffHeaderSize));
if (!_header.ParseCoff(h))
return S_FALSE;
}
else
{
Byte h[kHeaderSize];
RINOK(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(stream, h, kHeaderSize));
if (!_header.Parse(h))
return S_FALSE;
UInt32 _peOffset;
{
Byte h[kStartSize];
RINOK(ReadStream_FALSE(stream, h, kStartSize));
if (h[0] != 'M' || h[1] != 'Z')
return S_FALSE;
/* most of PE files contain 0x0090 at offset 2.
But some rare PE files contain another values. So we don't use that check.
if (Get16(h + 2) != 0x90) return false; */
_peOffset = Get32(h + 0x3C);
if (!CheckPeOffset(_peOffset))
return S_FALSE;
coffOffset = _peOffset + 4;
}
{
Byte h[kPeHeaderSize];
RINOK(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL));
RINOK(ReadStream_FALSE(stream, h, kPeHeaderSize));
if (!_header.ParsePe(h))
return S_FALSE;
}
}
UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize;
_totalSize = _peOffset + kHeaderSize + bufSize;
const UInt32 optStart = coffOffset + kCoffHeaderSize;
const UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize;
_totalSize = optStart + bufSize;
CByteBuffer buffer(bufSize);
RINOK(ReadStream_FALSE(stream, buffer, bufSize));
if (_header.OptHeaderSize != 0)
if (!_optHeader.Parse(buffer, _header.OptHeaderSize))
return S_FALSE;
@@ -2207,7 +2324,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
for (i = 0; i < _sections.Size(); i++)
_sections[i].UpdateTotalSize(_totalSize);
bool thereISDebug;
bool thereISDebug = false;
if (IsOpt())
{
RINOK(LoadDebugSections(stream, thereISDebug));
const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
@@ -2256,8 +2375,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
_totalSize += (UInt32)k;
}
}
}
if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= 512)
if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= optStart)
{
if (_header.NumSymbols >= (1 << 24))
return S_FALSE;
@@ -2306,11 +2426,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
}
if (IsOpt())
if (_optHeader.CheckSum != 0)
{
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
UInt32 checkSum = 0;
RINOK(CalcCheckSum(stream, _totalSize, _peOffset + kHeaderSize + k_CheckSum_Field_Offset, checkSum));
RINOK(CalcCheckSum(stream, _totalSize, optStart + k_CheckSum_Field_Offset, checkSum));
_checksumError = (checkSum != _optHeader.CheckSum);
}
@@ -2333,6 +2454,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
const CSection &sect = _sections[i];
CMixItem mixItem;
mixItem.SectionIndex = i;
if (IsOpt())
if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty())
{
const unsigned numMixItems = _mixItems.Size();
@@ -2480,6 +2602,8 @@ STDMETHODIMP CHandler::Close()
{
_totalSize = 0;
_checksumError = false;
_mainSubfile = -1;
_stream.Release();
_sections.Clear();
_mixItems.Clear();
@@ -2675,10 +2799,41 @@ REGISTER_ARC_I(
0,
NArcInfoFlags::kPreArc,
IsArc_Pe)
}
namespace NCoff {
API_FUNC_static_IsArc IsArc_Coff(const Byte *p, size_t size)
{
if (size < NPe::kCoffHeaderSize)
return k_IsArc_Res_NEED_MORE;
NPe::CHeader header;
if (!header.ParseCoff(p))
return k_IsArc_Res_NO;
return k_IsArc_Res_YES;
}
}
/*
static const Byte k_Signature[] =
{
2, 0x4C, 0x01, // x86
2, 0x64, 0x86, // x64
2, 0x64, 0xAA // ARM64
};
REGISTER_ARC_I_CLS(
*/
REGISTER_ARC_I_CLS_NO_SIG(
NPe::CHandler(true),
"COFF", "obj", 0, 0xC6,
// k_Signature,
0,
// NArcInfoFlags::kMultiSignature |
NArcInfoFlags::kStartOpen,
IsArc_Coff)
}
namespace NTe {