获取Delphi所有类的类信息
Delphi遍历进程中所有Class的TypeInfo,即便是在implementation中的class或者其他
class的private的子class.
一般普通EXE中的TypeInfo存放在PAGE_EXECUTE_*的内存中,而BPL则存放在PAGE_READ_WRITE的内存中.
所以我们要做的是遍历可执内存的内存片,然后找出TypeInfo的特征.
这里我是只找Class的类型信息,特征是tkClass,classname合法,
沿着typedata中的ParentInfo往前追溯,直到找到TObject的类型信息.
那么认为这是个合法的class的TypeInfo
为了不产生class的类型信息本单元没用使用任何和class有关的东西,以免多产生class的类型信息
unit UnitClassInfoEx; interface uses
{$IFDEF VER230} // XE2
{$DEFINE HAS_UNITSCOPE}
{$ENDIF}
{$IFDEF VER240} // XE3
{$DEFINE HAS_UNITSCOPE}
{$ENDIF}
{$IFDEF VER250} // XE4
{$DEFINE HAS_UNITSCOPE}
{$ENDIF}
{$IFDEF HAS_UNITSCOPE}
WinAPI.Windows, System.TypInfo;
{$ELSE}
Windows, TypInfo;
{$ENDIF} type
PTypeInfos = array of PTypeInfo;
TModules = array of HModule;
{$IFNDEF CPUX64}
// Delphi 早期版本NativeInt计算起来会有内部错误
NativeUInt = Cardinal;
NativeInt = Integer;
{$ENDIF}
// 获取一个指定模块中的类信息
function GetAllClassInfos_FromModule(AModule: HModule): PTypeInfos;
// 从system的Modulelist里面枚举模块,获取模块中类信息
function GetAllClassInfos_FromSystemModuleList(): PTypeInfos; function GetProcessModules(): TModules; implementation const
MinClassTypeInfoSize = SizeOf(TTypeKind) + { name } + SizeOf(Tclass) +
SizeOf(PPTypeInfo) + SizeOf(smallint) + { unitname }; type
TMemoryRegion = record
BaseAddress: NativeInt;
MemorySize: NativeInt;
end; TMemoryRegions = array of TMemoryRegion; function EnumProcessModules(hProcess: THandle; lphModule: PDWORD; cb: DWORD;
var lpcbNeeded: DWORD): BOOL; stdcall; external 'psapi.dll'; function GetProcessModules(): TModules;
var
cb: DWORD;
ret: BOOL;
begin
if EnumProcessModules(GetCurrentProcess, nil, , cb) then
begin
SetLength(Result, cb div SizeOf(HModule));
if not EnumProcessModules(GetCurrentProcess, @Result[], cb, cb) then
Result := nil;
end;
end; function IsValidityMemoryBlock(MemoryRegions: TMemoryRegions;
address, Size: NativeUInt): Boolean;
var
MemoryRegion: TMemoryRegion;
i: Integer;
mbi: TMemoryBasicInformation;
begin
{
if VirtualQueryEx(GetCurrentProcess, Pointer(address), mbi, SizeOf(mbi)) <> 0
then
begin
GetTickCount;
end;
}
Result := False; //for MemoryRegion in MemoryRegions do
for i := low(MemoryRegions) to High(MemoryRegions) do
begin
MemoryRegion := MemoryRegions[i];
if (address >= MemoryRegion.BaseAddress) and
((address + Size) <= (MemoryRegion.BaseAddress + MemoryRegion.MemorySize))
then
begin
Result := True;
Exit;
end;
end;
end; procedure GetExecutableMemoryregions(var MemoryRegions: TMemoryRegions);
var
address: NativeUInt;
mbi: memory_basic_information;
processhandle: THandle;
stop: NativeUInt;
begin
processhandle := GetCurrentProcess;
SetLength(MemoryRegions, );
address := ;
{$IFDEF CPUX64}
stop := $7FFFFFFFFFFFFFFF
{$ELSE}
stop := $7FFFFFFF;
{$ENDIF}
while (address < stop) and (VirtualQueryEx(processhandle, Pointer(address),
mbi, SizeOf(mbi)) <> ) and ((address + mbi.RegionSize) > address) do
begin
if (mbi.state = MEM_COMMIT) and
(((mbi.Protect and PAGE_EXECUTE_READ) = PAGE_EXECUTE_READ) or
((mbi.Protect and PAGE_READWRITE) = PAGE_READWRITE) or
((mbi.Protect and PAGE_EXECUTE_READWRITE) = PAGE_EXECUTE_READWRITE)) then
begin
// executable
SetLength(MemoryRegions, Length(MemoryRegions) + );
MemoryRegions[Length(MemoryRegions) - ].BaseAddress :=
NativeUInt(mbi.BaseAddress);
MemoryRegions[Length(MemoryRegions) - ].MemorySize := mbi.RegionSize;
end; inc(address, mbi.RegionSize);
end; end; procedure GetExecutableMemoryRegionsInRang(address, stop: NativeUInt;
var MemoryRegions: TMemoryRegions);
var
mbi: memory_basic_information;
processhandle: THandle;
begin
processhandle := GetCurrentProcess;
SetLength(MemoryRegions, ); while (address < stop) and (VirtualQueryEx(processhandle, Pointer(address),
mbi, SizeOf(mbi)) <> ) and ((address + mbi.RegionSize) > address) do
begin
if (mbi.state = MEM_COMMIT) and
(((mbi.Protect and PAGE_EXECUTE_READ) = PAGE_EXECUTE_READ) or
((mbi.Protect and PAGE_READWRITE) = PAGE_READWRITE) or
((mbi.Protect and PAGE_EXECUTE_READWRITE) = PAGE_EXECUTE_READWRITE)) then
begin
// executable
SetLength(MemoryRegions, Length(MemoryRegions) + );
MemoryRegions[Length(MemoryRegions) - ].BaseAddress :=
NativeUInt(mbi.BaseAddress);
MemoryRegions[Length(MemoryRegions) - ].MemorySize := mbi.RegionSize;
end; inc(address, mbi.RegionSize);
end; end; function IsValidityClassInfo(ProcessMemoryRegions: TMemoryRegions; p: PAnsiChar;
var RealResult: PTypeInfos): Boolean; forward; function IsValidityString(p: PAnsiChar; Length: Byte): Boolean;
var
i: Integer;
begin
{
我假定Delphi的ClassName都是英文.中文的话实际上会被UTF8编码.
另外这个也不包含编译器编译时产生临时类的类名.
临时类名为了不和程序员手写的类重名一般都有@#$之类的
}
Result := True;
if p^ in ['a' .. 'z', 'A' .. 'Z', '_'] then
begin
for i := to Length - do
begin { 类名有时会有. ,比如内嵌类,UnitName也会有.泛型类名会有<> }
if not(p[i] in ['a' .. 'z', '<', '>', 'A' .. 'Z', '_', '.', '' .. ''])
then
begin
Result := False;
Exit;
end;
end;
end
else
Result := False;
end; function FindTypeInfo(const RealResult: PTypeInfos; p: Pointer): Boolean;
var
i: Integer;
begin
Result := False;
for i := Low(RealResult) to High(RealResult) do
if RealResult[i] = p then
begin
Result := True;
Break;
end;
end; procedure AddTypeInfo(var RealResult: PTypeInfos; p: PTypeInfo);
begin
//if FindTypeInfo(RealResult, p) then
if p^.Name = 'TForm1.TTT' then begin
GetTickCount;
//Exit;
end;
SetLength(RealResult, Length(RealResult) + );
RealResult[Length(RealResult) - ] := p;
end; function IsValidityClassData(ProcessMemoryRegions: TMemoryRegions; p: PAnsiChar;
var RealResult: PTypeInfos): Boolean;
var
td: PTypeData;
parentInfo: PPTypeInfo;
parentFinded : Boolean;
begin
Result := False;
td := PTypeData(p);
parentInfo := td.parentInfo;
if not IsValidityString(@td.UnitName[], Byte(td.UnitName[])) then
Exit;
if GetTypeData(TypeInfo(TObject)) = td then
begin
Result := True;
Exit;
end;
if not IsValidityMemoryBlock(ProcessMemoryRegions, NativeUInt(parentInfo),
SizeOf(Pointer)) then
Exit;
if not IsValidityMemoryBlock(ProcessMemoryRegions, NativeUInt(parentInfo^),
MinClassTypeInfoSize) then
Exit;
{ 遍历ParentInfo,直到找到TObject为止 }
parentFinded := FindTypeInfo(RealResult, parentInfo^);
if parentFinded
or IsValidityClassInfo(ProcessMemoryRegions, PAnsiChar(parentInfo^),
RealResult) then
begin
Result := True;
if not parentFinded then
AddTypeInfo(RealResult, ParentInfo^);
Exit;
end;
end; function IsValidityClassInfo(ProcessMemoryRegions: TMemoryRegions; p: PAnsiChar;
var RealResult: PTypeInfos): Boolean;
var
classNamelen: Byte;
classname: ansistring;
begin
Result := False;
if not IsValidityMemoryBlock(ProcessMemoryRegions, NativeUInt(p),
MinClassTypeInfoSize) then
Exit;
if IsBadReadPtr(p, MinClassTypeInfoSize) then
Exit; if ord(p^) = ord(tkClass) then // ord(tkClass) = 7
begin
inc(p);
classNamelen := ord(p^);
SetLength(classname, classNamelen);
Move((p + )^, PAnsiChar(classname)^, classNamelen); if (classNamelen in [ .. $FE]) then { Shortstring第一个字节是长度,最多254个 }
begin
inc(p);
if IsValidityString(PAnsiChar(p), classNamelen) then
begin
// OutputDebugStringA(PAnsiChar(classname));
inc(p, classNamelen);
if IsValidityClassData(ProcessMemoryRegions, p, RealResult) then
begin
Result := True;
Exit;
end;
end;
end;
end;
end; procedure GetRegionClassInfos(ProcessMemoryRegions: TMemoryRegions;
const MemoryRegion: TMemoryRegion; var RealResult: PTypeInfos);
var
p: PAnsiChar;
MaxAddr: NativeInt;
begin
p := PAnsiChar(MemoryRegion.BaseAddress);
MaxAddr := MemoryRegion.BaseAddress + MemoryRegion.MemorySize -
MinClassTypeInfoSize;
while NativeInt(p) < MaxAddr do
begin
if IsValidityClassInfo(ProcessMemoryRegions, p, RealResult) then
begin
AddTypeInfo(RealResult, PTypeInfo(p));
// OutputDebugStringA(PAnsiChar('classname = ' + PTypeInfo(p).Name));
inc(p, MinClassTypeInfoSize);
end
else
inc(p);
end;
end; function _GetAllClassInfos_FromModule(ProcessMemoryRegions: TMemoryRegions;
AModule: HModule): PTypeInfos;
var
MemoryRegions: TMemoryRegions;
i: Integer;
addr, stop: NativeUInt;
dos: PImageDosHeader;
nt: PImageNtHeaders;
begin
Result := nil;
// SetLength(Result, 1);
// Result[0] := TypeInfo(TObject);
//
MemoryRegions := nil;
addr := AModule;
dos := PImageDosHeader(addr);
nt := PImageNtHeaders(addr + dos^._lfanew); GetExecutableMemoryRegionsInRang(addr, addr + nt.OptionalHeader.SizeOfImage,
MemoryRegions);
for i := Low(MemoryRegions) to High(MemoryRegions) do
begin
GetRegionClassInfos(ProcessMemoryRegions, MemoryRegions[i], Result);
// OutputDebugString(PChar(format('(%d;%d)',[MemoryRegions[i].BaseAddress,MemoryRegions[i].MemorySize])));
end;
end; function GetAllClassInfos_FromModule(AModule: HModule): PTypeInfos;
var
ProcessMemoryRegions: TMemoryRegions;
begin
GetExecutableMemoryregions(ProcessMemoryRegions);
Result := _GetAllClassInfos_FromModule(ProcessMemoryRegions, AModule);
end; function GetAllClassInfos_FromSystemModuleList(): PTypeInfos;
var
ProcessMemoryRegions: TMemoryRegions;
lm: PLibModule;
moduleTypeInfos: PTypeInfos;
i: Integer;
oldLen: Integer;
s: string;
begin
Result := nil;
//SetLength(Result, 1);
//Result[0] := TypeInfo(TObject);
//
lm := LibModuleList;
GetExecutableMemoryregions(ProcessMemoryRegions);
while True do
begin
SetLength(s, MAX_PATH);
GetModuleFileName(lm.Instance, PChar(s), Length(s));
OutputDebugString(PChar(s));
moduleTypeInfos := _GetAllClassInfos_FromModule(ProcessMemoryRegions,
lm.Instance);
oldLen := Length(Result);
SetLength(Result, oldLen + Length(moduleTypeInfos));
for i := Low(moduleTypeInfos) to High(moduleTypeInfos) do
Result[oldLen + i] := moduleTypeInfos[i]; if lm.Next = nil then
Break;
lm := lm.Next;
end;
end; end.
参考:http://www.cnblogs.com/key-ok/p/3506509.html
获取Delphi所有类的类信息的更多相关文章
- php反射机制获取未知类的详细信息
使用ReflectionClass就可以获取未知类的详细信息 demo: require("hello.php"); $class = new ReflectionClass(&q ...
- Java反射获取类和对象信息全解析
反射可以解决在编译时无法预知对象和类是属于那个类的,要根据程序运行时的信息才能知道该对象和类的信息的问题. 在两个人协作开发时,你只要知道对方的类名就可以进行初步的开发了. 获取类对象 Class.f ...
- 反射01 Class类的使用、动态加载类、类类型说明、获取类的信息
0 Java反射机制 反射(Reflection)是 Java 的高级特性之一,是框架实现的基础. 0.1 定义 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对 ...
- 反射技术的入口 获取类的Class信息
package com.sxt.reflect; import com.sxt.reflect.entity.Student; /* * 获取类的Class信息 */ public class Tes ...
- iOS - 音乐播放器需要获取音乐文件的一些数据信息(封装获取封面图片的类)
// // AVMetadataInfo.h // AVMetadata // // Created by Wengrp on 15/10/27. // Copyright © 2015年 Wengr ...
- 一个获取google chrome扩展crx文件信息的PHP操作类
此类中实现了从crx文件获取扩展的Appid.获取manifest.json文件内容.将crx文件转换为一般zip文件 代码如下: <?php class CrxParserException ...
- Delphi内建异常类 异常处理参考
标签: delphiexceptionwindowscasting编程integer 2012-05-19 12:53 2579人阅读 评论(0) 收藏 举报 分类: Delphi(96) [详细过程 ...
- Delphi 类的类 class of 用法
http://blog.csdn.net/blue_morning/article/details/8815609 Delphi 类的类 class of 用法 这个概念本来在一个关于Delphi ...
- 利用反射api查找一个类的具体信息
讲到这个实例,首先介绍下本人,我是一个php程序猿.从事drupal开发2年多.能够说从实习開始就接触这个,至今没有换过.drupal给我的感觉是俩字"强大",今天写一个views ...
- Delphi中的线程类 - TThread详解
Delphi中的线程类 - TThread详解 2011年06月27日 星期一 20:28 Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本 ...
随机推荐
- [置顶] JQuery插件学习教程
这是JQuery其它常用插件的视频教程,包括validate插件,.comet插件等.同时有大量实例项目,如果你是喜欢JQuery的童鞋千万不要错过. 教程的内容有: 1_validate插件(1) ...
- IOS的工程目录结构和生命周期
IOS的工程目录结构和生命周期 ·simple table文件夹:工程相关源代码和配置文件 BIDAppDelegate : 委托的声明和实现 BIDViewController: 视图控 ...
- 基于GPUImage的实时美颜滤镜
1.背景 前段时间由于项目需求,做了一个基于GPUImage的实时美颜滤镜.现在各种各样的直播.视频App层出不穷,美颜滤镜的需求也越来越多.为了回馈开源,现在我把它放到了GitHub https:/ ...
- Java基础知识强化之集合框架笔记31:集合之泛型类的概述和基本使用
1. 为什么会有泛型呢? (1)早期的Object类型可以接收任意的对象类型,但是在实际使用中,会有类型转换的问题,也存在这隐患,所以Java提供了泛型来解决这个安全问题. 2. 泛型类的使用: (1 ...
- css考核点整理(六)-水平居中定位的几种方式
定宽 text-align: center 父容器position:relative:子容器 position:absolute;left:50%; margin-left: 宽度/2 .Ce ...
- hdu 5073 Galaxy
题意是给定n个点,让求找到一个点p使得sigma( (a[i] - p) ^ 2 ) 最小,其中a[i]表示第i个点的位置.其中有k个点不用算. 思路:发现这道题其实就是求n-k个点方差. 那么推一下 ...
- <legend>标签
健康信息身高: 体重: 如果表单周围没有边框,说明您的浏览器太老了. <!DOCTYPE HTML> <html> <body> <form> < ...
- Html网页生成Pdf
在http://code.google.com/p/wkhtmltopdf/downloads/list下载安装程序. 1.添加引用 using System.Diagnostics; 添加引用 2. ...
- PAT_2-08. 用扑克牌计算24点
一副扑克牌的每张牌表示一个数(J.Q.K分别表示11.12.13,两个司令都表示6).任取4张牌,即得到4个1~13的数,请添加运算符 (规定为加+ 减- 乘* 除/ 四种)使之成为一个运算式.每个数 ...
- .net RAW(16)与GUID互相转换
.net 1.raw转guidnew guid(byte[] id);2.guid转rawGuid result;string ids = BitConverter.ToString(result.T ...