📄 exeimage.pas
字号:
tmpSt.wHour:=1;
tmpSt.wMinute:=1;
tmpSt.wSecond:=0;
tmpSt.wMilliseconds:=0;
tmpDt:=SystemTimeToDateTime(tmpSt);
tmpDt:=tmpDt+TimeDateStamp/3600/24;
tmpStr:=FormatDateTime('yyyy-mm-dd hh:nn:ss',tmpDt);
}
// tmpStr:=FormatDateTime('yyyy-mm-dd hh:nn:ss',FileDateToDateTime(TimeDateStamp));
v[3]:=VarArrayOf([tmpExeOffSet+8,Format('%.8x',[TimeDateStamp]),Format('文件创建日期/时间 %s',[''])]);
v[4]:=VarArrayOf([tmpExeOffSet+12,Format('%.8x',[PointerToSymbolTable]),'符号表偏移地址(用于调试)']);
v[5]:=VarArrayOf([tmpExeOffSet+16,Format('%.8x',[NumberOfSymbols]),'符号表中符号个数']);
v[6]:=VarArrayOf([tmpExeOffSet+20,Format('%.4x',[SizeOfOptionalHeader]),Format('可选头部结构大小:%d字节',[FPENTHead.FileHeader.SizeOfOptionalHeader])]);
tmpStr:=CheckFileCharacteristics(Characteristics);
v[7]:=VarArrayOf([tmpExeOffSet+22,Format('%.4x',[Characteristics]),Format('文件信息标记(%s)',[tmpStr])]);
end;
result:=v;
end;
{ 返回分析的Dos头信息 }
function TExeImage.AnalysisDosHeader: Variant;
var
V: Variant;
i: Word;
tmpStr:String;
begin
v:=VarArrayCreate([0,18],varVariant);
with FPEDosHead do
begin
v[0]:=VarArrayOf([0,Format('%.4x',[e_magic]),'DOS标记值']);
v[1]:=VarArrayOf([2,Format('%.4x',[e_cblp]),'文件最后页的字节']);
v[2]:=VarArrayOf([4,Format('%.4x',[e_cp]),'文件的页数']);
v[3]:=VarArrayOf([6,Format('%.4x',[e_crlc]),'重定位']);
v[4]:=VarArrayOf([8,Format('%.4x',[e_cparhdr]),'段头的大小']);
v[5]:=VarArrayOf([10,Format('%.4x',[e_minalloc]),'段分配最少值']);
v[6]:=VarArrayOf([12,Format('%.4x',[e_maxalloc]),'段分配最大值']);
v[7]:=VarArrayOf([14,Format('%.4x',[e_ss]),'SS(堆栈段寄存器)初始值']);
v[8]:=VarArrayOf([16,Format('%.4x',[e_sp]),'SP(堆栈指针寄存器)初始值']);
v[9]:=VarArrayOf([18,Format('%.4x',[e_csum]),'校验和']);
v[10]:=VarArrayOf([20,Format('%.4x',[e_ip]),'IP(指令指针寄存器)初始值']);
v[11]:=VarArrayOf([22,Format('%.4x',[e_cs]),'CS(代码段寄存器)初始值']);
v[12]:=VarArrayOf([24,Format('%.4x',[e_lfarlc]),'重定位表的文件地址']);
v[13]:=VarArrayOf([26,Format('%.4x',[e_ovno]),'覆盖号']);
tmpStr:='';
for i:=0 to 3 do
tmpStr:=tmpStr+Format('%.4x',[e_res[i]]);
v[14]:=VarArrayOf([28,tmpStr,'保留字']);
v[15]:=VarArrayOf([36,Format('%.4x',[e_oemid]),'OEM标记']);
v[16]:=VarArrayOf([38,Format('%.4x',[e_oeminfo]),'OEM信息']);
tmpStr:='';
for i:=0 to 9 do
tmpStr:=tmpStr+Format('%.4x',[e_res2[i]]);
v[17]:=VarArrayOf([40,tmpStr,'保留字']);
v[18]:=VarArrayOf([60,Format('%.8x',[_lfanew]),'指向NT头文件地址']);
end;
result:=v;
end;
{ 返回分析的可选头部的信息 }
function TExeImage.AnalysisOptionHeader: Variant;
var
V: Variant;
tmpExeOffSet: Integer;
tmpStr: String;
i:integer;
tmpArray: Array[0..15] of String;
begin
v:=VarArrayCreate([0,60],varVariant);
tmpExeOffSet:=FPEDosHead._lfanew+SizeOf(TImageNTHeaders)-SizeOf(TImageOptionalHeader);
with FPENTHead.OptionalHeader do
begin
v[0]:=varArrayOf([tmpExeOffSet+0,Format('%.4x',[Magic]),'$010B 表示 Exe Image,$0107 表示 ROM Image']);
v[1]:=varArrayOf([tmpExeOffSet+2,Format('%.2x%.2x',[MajorLinkerVersion,MinorLinkerVersion]),Format('编译器版本:V%d.%d',[MajorLinkerVersion,MinorLinkerVersion])]);
v[2]:=varArrayOf([tmpExeOffSet+4,Format('%.8x',[SizeOfCode]),'代码段大小']);
v[3]:=varArrayOf([tmpExeOffSet+8,Format('%.8x',[SizeOfInitializedData]),'含初始化数据块大小']);
v[4]:=varArrayOf([tmpExeOffSet+12,Format('%.8x',[SizeOfUninitializedData]),'所有需要载入虚拟地址空间的数据块大小']);
v[5]:=varArrayOf([tmpExeOffSet+16,Format('%.8x',[AddressOfEntryPoint]),Format('程序将从$%.8x开始执行',[AddressOfEntryPoint])]);
v[6]:=varArrayOf([tmpExeOffSet+20,Format('%.8x',[BaseOfCode]),'代码段起始RVA']);
v[7]:=varArrayOf([tmpExeOffSet+24,Format('%.8x',[BaseOfData]),'数据段起始RVA']);
v[8]:=varArrayOf([tmpExeOffSet+28,Format('%.8x',[ImageBase]),'程序载入基址']);
v[9]:=varArrayOf([tmpExeOffSet+32,Format('%.8x',[SectionAlignment]),'块对齐的大小']);
v[10]:=varArrayOf([tmpExeOffSet+36,Format('%.8x',[FileAlignment]),'块原始数据对齐的大小']);
v[11]:=varArrayOf([tmpExeOffSet+40,Format('%.4x',[MajorOperatingSystemVersion]),'所需OS主版本号']);
v[12]:=varArrayOf([tmpExeOffSet+42,Format('%.4x',[MinorOperatingSystemVersion]),'所需OS副版本号']);
v[13]:=varArrayOf([tmpExeOffSet+44,Format('%.4x',[MajorImageVersion]),'用户自定义主版本号']);
v[14]:=varArrayOf([tmpExeOffSet+46,Format('%.4x',[MinorImageVersion]),'用户自定义副版本号']);
v[15]:=varArrayOf([tmpExeOffSet+48,Format('%.4x',[MajorSubSystemVersion]),'Win32子系统主版本号']);
v[16]:=varArrayOf([tmpExeOffSet+50,Format('%.4x',[MinorSubSystemVersion]),'Win32子系统副版本号(4.0版后的对话框才有3D效果)']);
v[17]:=varArrayOf([tmpExeOffSet+52,Format('%.8x',[MajorImageVersion]),'保留未用']);
v[18]:=varArrayOf([tmpExeOffSet+56,Format('%.8x',[SizeOfImage]),'内存中整个PE映像体的大小']);
v[19]:=varArrayOf([tmpExeOffSet+60,Format('%.8x',[SizeOfHeaders]),'PE表头及块表的大小']);
v[20]:=varArrayOf([tmpExeOffSet+64,Format('%.8x',[CheckSum]),'检验和(可执行文件通常为0)']);
case Subsystem of
1: TmpStr:='不需要子系统,(例如驱动程序)';
2: TmpStr:='在Windows GUI子系统中运行';
3: TmpStr:='在Windows字元模式子系统中运行(也就是console应用程序)';
5: TmpStr:='在OS/2字元模式子系统中运行(也就是OS/2 1.x应用程序)';
7: TmpStr:='在Posix字元模式子系统中运行';
else TmpStr:='';
end;
v[21]:=varArrayOf([tmpExeOffSet+68,Format('%.4x',[SubSystem]),tmpStr]);
case DllCharacteristics of
1: TmpStr:='当DLL被载入一个行程的地址空间时呼叫';
2: TmpStr:='当一个行程结束时呼叫';
3: TmpStr:='当一个行程开始时呼叫';
4: TmpStr:='当DLL退出时呼叫';
else
TmpStr:='DLL特性,通常为0';
end;
v[22]:=varArrayOf([tmpExeOffSet+70,Format('%.4x',[DllCharacteristics]),tmpStr]);
v[23]:=varArrayOf([tmpExeOffSet+72,Format('%.8x',[SizeOfStackReserve]),'保留堆栈大小,预设为$00100000(1MB)']);
v[24]:=varArrayOf([tmpExeOffSet+76,Format('%.8x',[SizeOfStackCommit]),'委派初始堆栈大小,预设为$00001000(1页)']);
v[25]:=varArrayOf([tmpExeOffSet+80,Format('%.8x',[SizeOfHeapReserve]),'保留虚拟内存大小']);
v[26]:=varArrayOf([tmpExeOffSet+84,Format('%.8x',[SizeOfHeapCommit]),'委派初始虚拟内存大小']);
v[27]:=varArrayOf([tmpExeOffSet+88,Format('%.8x',[LoaderFlags]),'装载器标记值']);
v[28]:=varArrayOf([tmpExeOffSet+92,Format('%.8x',[NumberOfRvaAndSizes]),'数据入口的数目']);
//数据目录信息
tmpArray[0]:='导出函数表';
tmpArray[1]:='导入函数表';
tmpArray[2]:='资源表';
tmpArray[3]:='异常表';
tmpArray[4]:='安全表';
tmpArray[5]:='重定位表';
tmpArray[6]:='调试信息表';
tmpArray[7]:='机器详细描述表';
tmpArray[8]:='相对虚拟地址(RVA)表';
tmpArray[9]:='线程局部存储器(TLS)表';
tmpArray[10]:='启动配置表';
tmpArray[11]:='限制导入表';
tmpArray[12]:='导入地址表';
tmpArray[13]:='滞后加载导入表';
tmpArray[14]:='COM运行时描述表';
tmpArray[15]:='保留';
for i:=0 to 15 do
if DataDirectory[i].VirtualAddress=0 then
begin
v[28+2*i+1]:=varArrayOf([tmpExeOffSet+96+8*i,Format('%.8x',[DataDirectory[i].VirtualAddress]),'→'+tmpArray[i]+'←']);
v[28+2*i+2]:=varArrayOf([tmpExeOffSet+100+8*i,Format('%.8x',[DataDirectory[i].Size]),'']);
end
else begin
v[28+2*i+1]:=varArrayOf([tmpExeOffSet+96+8*i,Format('%.8x',[DataDirectory[i].VirtualAddress]),tmpArray[i]+'的RVA地址']);
v[28+2*i+2]:=varArrayOf([tmpExeOffSet+100+8*i,Format('%.8x',[DataDirectory[i].Size]),' &大小']);
end;
end;
Result:=v;
end;
{ 返回块表的描述信息 }
function TExeImage.AnalySisSectionDescript:Variant;
var
v:Variant;
i,j:Word;
tmpName:String;
begin
v:=VarArrayCreate([0,9],varVariant);
for i:=0 to FSectionNum-1 do
with FPESectionHead[i] do
begin
tmpName:='';
for j:=0 to IMAGE_SIZEOF_SHORT_NAME-1 do
tmpName:=tmpName+Chr(Name[j]);
tmpName:=trim(tmpName);
v[i]:=VarArrayOf([tmpName,PointerToRawData,SizeOfRawData]);
end;
Result:=v;
end;
{ 返回指定块表的头信息 }
function TExeImage.AnalySisSectionHeader(AIndex: Word): Variant;
var
v:Variant;
tmpExeOffSet: Integer;
i:Word;
tmpStr:String;
tmpHex:String;
begin
v:=VarArrayCreate([0,9],varVariant);
tmpExeOffSet:=FPENTHeaderOffSet+SizeOf(FPENTHead)+AIndex*SizeOf(TImageSectionHeader);
with FPESectionHead[AIndex] do
begin
tmpStr:='';
tmpHex:='';
for i:=0 to 7 do
begin
tmpStr:=tmpStr+Chr(Name[i]);
tmpHex:=tmpHex+Format('%.2x',[Name[i]]);
end;
tmpStr:=trim(tmpStr);
v[0]:=VarArrayOf([tmpExeOffSet+0,tmpHex,Format('块表名称:%s',[tmpStr])]);
v[1]:=VarArrayOf([tmpExeOffSet+8,Format('%.8x',[Misc.VirtualSize]),Format('实际长度:%d 字节',[Misc.VirtualSize])]);
v[2]:=VarArrayOf([tmpExeOffSet+12,Format('%.8x',[VirtualAddress]),'块RVA(相对虚拟地址)']);
v[3]:=VarArrayOf([tmpExeOffSet+16,Format('%.8x',[SizeOfRawData]),'块物理长度']);
v[4]:=VarArrayOf([tmpExeOffSet+20,Format('%.8x',[PointerToRawData]),'块基于文件的偏移量']);
v[5]:=VarArrayOf([tmpExeOffSet+24,Format('%.8x',[PointerToRelocations]),'重定位的偏移量']);
v[6]:=VarArrayOf([tmpExeOffSet+28,Format('%.8x',[PointerToLineNumbers]),'行号表的偏移量']);
v[7]:=VarArrayOf([tmpExeOffSet+32,Format('%.4x',[NumberOfRelocations]),'重定位的项目数目']);
v[8]:=VarArrayOf([tmpExeOffSet+34,Format('%.4x',[NumberOfLineNumbers]),'行号表的行号数目']);
v[9]:=VarArrayOf([tmpExeOffSet+36,Format('%.8x',[Characteristics]),Format('块属性(%s)',[CheckSectionCharacteristics(Characteristics)])]);
end;
Result:=v;
end;
constructor TExeImage.CreateImage(AFileName: String);
var
i: Word;
begin
//指定各类型的记录个数
FPEDosHeadRecSize:=19;
FPECoffHeadRecSize:=8;
FPEOptionHeadRecSize:=61;
FPESectionHeadRecSize:=10;
//创建文件内存流.
FExeStream:=TMemoryStream.Create;
FExeStream.LoadFromFile(AFileName); ////这部分可能要更改,以让其能打开已经使用的文件
FFileName := AFileName;
try
{ 读出Dos头数据并识别Dos头标记 }
FExeStream.Seek(0,soFromBeginning);
FExeStream.Read(FPEDosHead,SizeOf(FPEDosHead));
if FPEDosHead.e_magic <> IMAGE_DOS_SIGNATURE then
begin
ExeError('尚未支持此类文件格式!');
abort;
end;
FPENTHeaderOffSet:=FPEDosHead._lfanew;
{ 读出Dos-NT间的数据--称之为Dos桩 }
{
ExeStream.Seek(SizeOf(PEDosHead),soFromBeginning);
SetLength(PEBetweenDosAndNT,PEDosHead._lfanew-SizeOf(PEDosHead));//设置数据长度
for i:=0 to (PEDosHead._lfanew-SizeOf(PEDosHead))-1 do
ExeStream.Read(PEBetweenDosAndNT[i],SizeOf(Byte));
}
{ 读出NT头数据并识别NT头标记 }
FExeStream.Seek(FPENTHeaderOffSet,soFromBeginning);
FExeStream.Read(FPENTHead,SizeOf(FPENTHead));
if (FPENTHead.Signature <> IMAGE_NT_SIGNATURE)
and (FPENTHead.Signature <> IMAGE_OS2_SIGNATURE)
and (FPENTHead.Signature <> IMAGE_VXD_SIGNATURE) then
begin
ExeError(Format('所选文件[%s]不是标准PE文件格式!',[AFileName]));
abort;
end;
FExportDirExists := FPENTHead.OptionalHeader.DataDirectory[0].Size<>0;
FImportDirExists := FPENTHead.OptionalHeader.DataDirectory[1].Size<>0;
FResourceDirExists := FPENTHead.OptionalHeader.DataDirectory[2].Size<>0;
{ 获取块表头数据 }
FExeStream.Seek(FPENTHeaderOffSet+SizeOf(FPENTHead),soFromBeginning);
SetLength(FPESectionhead,FPENTHead.FileHeader.NumberOfSections);
FSectionNum:=FPENTHead.FileHeader.NumberOfSections;
for i:=0 to FSectionNum-1 do
FExeStream.Read(FPESectionHead[i],SizeOf(TImageSectionHeader));
FResDataNum := 0;
if IsResourceExists then //此处不要用FResourceDirExists来替代.
FResDataNum:=GetResDataNum; //计算资源数据的个数
except
ExeError(Format('文件[%s]操作出现异常!',[AFileName]));
end;
end;
{ 获取指定段的内存流 }
function TExeImage.GetSegStream(AOffset: Integer;
ACount: Word): TMemoryStream;
Const
Max_Buf=1024;
var
tmpSegStream: TMemoryStream;
ResBuffer:array[0..Max_Buf-1] of Byte;
i:Integer;
begin
tmpSegStream:=TMemoryStream.Create;
tmpSegStream.SetSize(ACount);
//定位到文件内存流,读取指定段的数据到另一块内存区.
FExeStream.Seek(AOffSet,soFromBeginning);
for i:=0 to ACount div Max_Buf do
begin
FExeStream.Read(ResBuffer,Max_Buf);
tmpSegStream.Write(ResBuffer,Max_Buf);
end;
i:=ACount mod Max_Buf;
if i>0 then
begin
FExeStream.Read(ResBuffer,i);
tmpSegStream.Write(ResBuffer,i);
end;
result:=tmpSegStream;
end;
{ 取得资源中经过处理的位图文件流 }
function TExeImage.GetBitmapStream(AOffset:Integer;ACount:Word): TMemoryStream;
Const
Max_Buf=1024;
function GetDInColors(BitCount: Word): Integer;
begin
case BitCount of
1, 4, 8: Result := 1 shl BitCount;
else
Result := 0;
end;
end;
var
tmpSegStream: TMemoryStream;
tmpBFH: TBitmapFileHeader;
tmpBIH: TBitmapInfoHeader;
tmpBCH: TBitmapCoreHeader;
ResBuffer:array[0..Max_Buf-1] of Byte;
ClrUsed,i:Integer;
begin
FillChar(tmpBFH,SizeOf(tmpBFH),#0);
tmpBFH.bfType := $4D42;;
tmpBFH.bfSize := SizeOf(tmpBFH)+ACount;
FExeStream.Seek(AOffSet,soFromBeginning);
FExeStream.Read(tmpBIH,SizeOf(tmpBIH));
if tmpBIH.biSize = SizeOf(tmpBIH) then
begin
ClrUsed := tmpBIH.biClrUsed;
if ClrUsed = 0 then
ClrUsed := GetDInColors(tmpBIH.biBitCount);
tmpBFH.bfOffBits := ClrUsed * SizeOf(TRgbQuad) +
SizeOf(tmpBIH) + SizeOf(tmpBFH);
end
else
begin
FExeStream.Seek(AOffset,soFromBeginning);
FExeStream.Read(tmpBCH,SizeOf(tmpBCH));
ClrUsed := GetDInColors(tmpBCH.bcBitCount);
tmpBFH.bfOffBits := ClrUsed * SizeOf(TRGBTriple) +
SizeOf(tmpBCH) + SizeOf(tmpBFH);
end;
tmpSegStream:=TMemoryStream.Create;
tmpSegStream.SetSize(tmpBFH.bfSize);
tmpSegStream.Write(tmpBFH,SizeOf(tmpBFH));
FExeStream.Seek(AOffSet,soFromBeginning);
for i:=0 to ACount div Max_Buf do
begin
FExeStream.Read(ResBuffer,Max_Buf);
tmpSegStream.Write(ResBuffer,Max_Buf);
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -