366 lines
8.6 KiB
Plaintext
366 lines
8.6 KiB
Plaintext
{*******************************************************}
|
|
{ }
|
|
{ Tocsg.Prefetch }
|
|
{ }
|
|
{ Copyright (C) 2022 kku }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit Tocsg.Prefetch;
|
|
|
|
interface
|
|
|
|
uses
|
|
Tocsg.Obj, System.SysUtils, System.Classes, Winapi.Windows,
|
|
System.Generics.Collections;
|
|
|
|
const
|
|
PF_VER_1 = 17;
|
|
PF_VER_2 = 23;
|
|
PF_VER_3 = 26;
|
|
PF_VER_4 = 30;
|
|
|
|
type
|
|
TPfHeader = record
|
|
dwVer: DWORD;
|
|
arrSig: array[0..3] of AnsiChar;
|
|
dwUnknown1,
|
|
dwFSize: DWORD;
|
|
arrFName: array[0..29] of Char; // array[0..59] of AnsiChar;
|
|
dwPfHash,
|
|
dwUnknown2: DWORD;
|
|
end;
|
|
|
|
TPfFileInfoVer1 = record
|
|
dwOffset,
|
|
dwEntCnt,
|
|
dwOffsetTrace,
|
|
dwEntCntTrace,
|
|
dwOffsetFName,
|
|
dwFNameSize,
|
|
dwOffsetVolInfo,
|
|
dwVolNum,
|
|
dwVolSize: DWORD;
|
|
ftLastExeTime: TFileTime;
|
|
arrUnknown1: array [0..15] of AnsiChar;
|
|
dwExeCounter: DWORD;
|
|
dwUnknown2: DWORD;
|
|
end;
|
|
|
|
TPfFileInfoVer2 = record
|
|
dwOffset,
|
|
dwEntCnt,
|
|
dwOffsetTrace,
|
|
dwEntCntTrace,
|
|
dwOffsetFName,
|
|
dwFNameSize,
|
|
dwOffsetVolInfo,
|
|
dwVolNum,
|
|
dwVolSize: DWORD;
|
|
arrUnknown1: array [0..7] of AnsiChar;
|
|
ftLastExeTime: TFileTime;
|
|
arrUnknown2: array [0..15] of AnsiChar;
|
|
dwExeCounter: DWORD;
|
|
arrUnknown3: array [0..83] of AnsiChar;
|
|
end;
|
|
|
|
TPfFileInfoVer34 = record
|
|
dwOffset,
|
|
dwEntCnt,
|
|
dwOffsetTrace,
|
|
dwEntCntTrace,
|
|
dwOffsetFName,
|
|
dwFNameSize,
|
|
dwOffsetVolInfo,
|
|
dwVolNum,
|
|
dwVolSize: DWORD;
|
|
arrUnknown1: array [0..7] of AnsiChar;
|
|
arrLastExeTime: array [0..7] of TFileTime;
|
|
arrUnknown2: array [0..15] of AnsiChar;
|
|
dwExeCounter: DWORD;
|
|
arrUnknown3: array [0..95] of AnsiChar;
|
|
end;
|
|
|
|
TAssocFileEntVer1 = record
|
|
dwStartTime,
|
|
dwDuration,
|
|
dwFNameOffset,
|
|
dwFNameLen,
|
|
dwUnknown: DWORD;
|
|
end;
|
|
|
|
TAssocFileEntVer234 = record
|
|
dwStartTime,
|
|
dwDuration,
|
|
dwAverageDuration,
|
|
dwFNameOffset,
|
|
dwFNameLen,
|
|
dwUnknown: DWORD;
|
|
arrRefNTFS: array [0..7] of AnsiChar;
|
|
end;
|
|
|
|
TTgPrefetchAnal = class(TTgObject)
|
|
private
|
|
ms_: TMemoryStream;
|
|
PfHeader_: TPfHeader;
|
|
nRunCnt_: Integer;
|
|
ExeDtList_: TList<TDateTime>;
|
|
AssocFList_: TStringList;
|
|
sPfPath_,
|
|
sPath_,
|
|
sFName_: String;
|
|
function GetPfHeader(aStream: TStream): Boolean;
|
|
procedure ExtrPfInfoVer1;
|
|
procedure ExtrPfInfoVer2;
|
|
procedure ExtrPfInfoVer34;
|
|
function GetRunCount: Integer;
|
|
public
|
|
Constructor Create;
|
|
Destructor Destroy; override;
|
|
|
|
function LoadFromStream(aStream: TStream): Boolean;
|
|
function LoadFromFile(sPath: String): Boolean;
|
|
|
|
procedure Clear;
|
|
|
|
function GetExeDateTimeToText(sDm: String = ''; sDtFormat: String = ''): String;
|
|
function GetExeDateEnum: TEnumerator<TDateTime>;
|
|
|
|
property RunCount: Integer read GetRunCount;
|
|
property ExeDtList: TList<TDateTime> read ExeDtList_;
|
|
|
|
property FilePath: String read sPath_;
|
|
property FileName: String read sFName_;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Tocsg.Safe, Tocsg.Exception, Tocsg.NTDLL.Decompress, Tocsg.DateTime,
|
|
Tocsg.Strings, System.Math, Tocsg.Path;
|
|
|
|
{ TTgPrefetchAnal }
|
|
|
|
Constructor TTgPrefetchAnal.Create;
|
|
begin
|
|
Inherited Create;
|
|
sPfPath_ := '';
|
|
sPath_ := '';
|
|
sFName_ := '';
|
|
ms_ := nil;
|
|
ExeDtList_ := TList<TDateTime>.Create;
|
|
AssocFList_ := TStringList.Create;
|
|
end;
|
|
|
|
Destructor TTgPrefetchAnal.Destroy;
|
|
begin
|
|
FreeAndNil(AssocFList_);
|
|
FreeAndNil(ExeDtList_);
|
|
if ms_ <> nil then
|
|
FreeAndNil(ms_);
|
|
Inherited;
|
|
end;
|
|
|
|
function TTgPrefetchAnal.GetPfHeader(aStream: TStream): Boolean;
|
|
var
|
|
RtlHeader: TRtlHeader;
|
|
pSrc, pBuf: TBytes;
|
|
dwDecomLen: DWORD;
|
|
begin
|
|
Result := false;
|
|
if aStream.Size < SizeOf(PfHeader_) then
|
|
exit;
|
|
|
|
ZeroMemory(@PfHeader_, SizeOf(PfHeader_));
|
|
aStream.Position := 0;
|
|
|
|
ZeroMemory(@RtlHeader, SizeOf(RtlHeader));
|
|
if aStream.Read(RtlHeader, SizeOf(RtlHeader)) <> SizeOf(RtlHeader) then
|
|
exit;
|
|
|
|
if not CompareMem(@RtlHeader.arrSig[0], @AnsiString('MAM')[1], 3) then
|
|
exit;
|
|
|
|
SetLength(pSrc, aStream.Size - aStream.Position);
|
|
aStream.Read(pSrc[0], Length(pSrc));
|
|
SetLength(pBuf, RtlHeader.dwSize);
|
|
dwDecomLen := RtlDecompress(@pSrc[0], @pBuf[0], Length(pSrc), RtlHeader.dwSize, COMPRESSION_FORMAT_XPRESS_HUFF);
|
|
if dwDecomLen > 0 then
|
|
begin
|
|
ms_ := TMemoryStream.Create;
|
|
ms_.Write(pBuf[0], dwDecomLen);
|
|
ms_.Position := 0;
|
|
ms_.Read(PfHeader_, SizeOf(PfHeader_));
|
|
if PfHeader_.arrSig = 'SCCA' then
|
|
Result := true;
|
|
end;
|
|
end;
|
|
|
|
procedure TTgPrefetchAnal.ExtrPfInfoVer1;
|
|
var
|
|
FInfo: TPfFileInfoVer1;
|
|
begin
|
|
if ms_ = nil then
|
|
exit;
|
|
|
|
ms_.Read(FInfo, SizeOf(FInfo));
|
|
nRunCnt_ := FInfo.dwExeCounter;
|
|
ExeDtList_.Add(ConvFileTimeToDateTime(FInfo.ftLastExeTime));
|
|
end;
|
|
|
|
procedure TTgPrefetchAnal.ExtrPfInfoVer2;
|
|
var
|
|
FInfo: TPfFileInfoVer2;
|
|
begin
|
|
if ms_ = nil then
|
|
exit;
|
|
|
|
ms_.Read(FInfo, SizeOf(FInfo));
|
|
nRunCnt_ := FInfo.dwExeCounter;
|
|
ExeDtList_.Add(ConvFileTimeToDateTime(FInfo.ftLastExeTime));
|
|
end;
|
|
|
|
procedure TTgPrefetchAnal.ExtrPfInfoVer34;
|
|
var
|
|
FInfo: TPfFileInfoVer34;
|
|
i: Integer;
|
|
dwPos, dwEntSize,
|
|
dwNameOffset: DWORD;
|
|
AssocFileEnt: TAssocFileEntVer234;
|
|
pBuf: TBytes;
|
|
sPath: String;
|
|
begin
|
|
if ms_ = nil then
|
|
exit;
|
|
|
|
ms_.Read(FInfo, SizeOf(FInfo));
|
|
nRunCnt_ := FInfo.dwExeCounter;
|
|
for i := Low(FInfo.arrLastExeTime) to High(FInfo.arrLastExeTime) do
|
|
if (FInfo.arrLastExeTime[i].dwLowDateTime > 0) and (FInfo.arrLastExeTime[i].dwHighDateTime > 0) then
|
|
ExeDtList_.Add(ConvFileTimeToDateTime_Local(FInfo.arrLastExeTime[i])); // 로컬 타임으로 가져옴 22_0905 15:54:59 kku
|
|
// ExeDtList_.Add(ConvFileTimeToDateTime(FInfo.arrLastExeTime[i]));
|
|
|
|
SetLength(pBuf, 1024);
|
|
dwPos := FInfo.dwOffset;
|
|
dwNameOffset := FInfo.dwOffsetFName;
|
|
dwEntSize := SizeOf(AssocFileEnt);
|
|
for i := 0 to FInfo.dwEntCnt - 1 do
|
|
if dwPos < ms_.Size then
|
|
begin
|
|
ms_.Position := dwPos;
|
|
if ms_.Read(AssocFileEnt, dwEntSize) <> dwEntSize then
|
|
exit;
|
|
dwPos := ms_.Position;
|
|
|
|
with AssocFileEnt do
|
|
begin
|
|
if (dwNameOffset + dwFNameOffset + (dwFNameLen * 2)) < ms_.Size then
|
|
begin
|
|
ms_.Position := dwNameOffset + dwFNameOffset;
|
|
ZeroMemory(pBuf, 1024);
|
|
if ms_.Read(pBuf[0], dwFNameLen * 2) <> (dwFNameLen * 2) then
|
|
exit;
|
|
|
|
sPath := UpperCase(String(PChar(@pBuf[0])));
|
|
if GetFileExt(sPath) = 'EXE' then
|
|
begin
|
|
sPath_ := ExtractFilePath(sPath);
|
|
sFName_ := ExtractFileName(sPath);
|
|
end;
|
|
|
|
AssocFList_.Add(sPath);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TTgPrefetchAnal.LoadFromStream(aStream: TStream): Boolean;
|
|
begin
|
|
Clear;
|
|
Result := false;
|
|
|
|
try
|
|
if (aStream = nil) or (aStream.Size = 0) then
|
|
exit;
|
|
|
|
Result := GetPfHeader(aStream);
|
|
if not Result then
|
|
exit;
|
|
|
|
case PfHeader_.dwVer of
|
|
PF_VER_1 : ExtrPfInfoVer1;
|
|
PF_VER_2 : ExtrPfInfoVer2;
|
|
PF_VER_3,
|
|
PF_VER_4 : ExtrPfInfoVer34;
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(Self, E, 'Fail .. LoadFromStream()');
|
|
end;
|
|
end;
|
|
|
|
function TTgPrefetchAnal.LoadFromFile(sPath: String): Boolean;
|
|
var
|
|
fs: TFileStream;
|
|
begin
|
|
Result := false;
|
|
if not FileExists(sPath) then
|
|
exit;
|
|
|
|
try
|
|
sPfPath_ := sPath;
|
|
Guard(fs, TFileStream.Create(sPath, fmOpenRead));
|
|
Result := LoadFromStream(fs);
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgPrefetchAnal.Clear;
|
|
begin
|
|
if ms_ <> nil then
|
|
FreeAndNil(ms_);
|
|
Finalize(PfHeader_);
|
|
ZeroMemory(@PfHeader_, SizeOf(PfHeader_));
|
|
nRunCnt_ := 0;
|
|
ExeDtList_.Clear;
|
|
AssocFList_.Clear;
|
|
sPfPath_ := '';
|
|
sFName_ := '';
|
|
sPath_ := '';
|
|
end;
|
|
|
|
|
|
function TTgPrefetchAnal.GetRunCount: Integer;
|
|
begin
|
|
Result := Max(nRunCnt_, ExeDtList_.Count);
|
|
end;
|
|
|
|
function TTgPrefetchAnal.GetExeDateTimeToText(sDm: String = ''; sDtFormat: String = ''): String;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := '';
|
|
try
|
|
if sDm = '' then
|
|
sDm := ',';
|
|
for i := 0 to ExeDtList_.Count - 1 do
|
|
if sDtFormat <> '' then
|
|
SumString(Result, FormatDateTime(sDtFormat, ExeDtList_[i]), sDm)
|
|
else
|
|
SumString(Result, DateTimeToStr(ExeDtList_[i]), sDm);
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(Self, E, 'Fail .. GetExeDateTimeToCommaText()');
|
|
end;
|
|
end;
|
|
|
|
function TTgPrefetchAnal.GetExeDateEnum: TEnumerator<TDateTime>;
|
|
begin
|
|
Result := ExeDtList_.GetEnumerator;
|
|
end;
|
|
|
|
end.
|