转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> Delphi程序 >> 正文
Delphi版COM高级应用         ★★★★

Delphi版COM高级应用

作者:闵涛 文章来源:闵涛的学习笔记 点击数:2260 更新时间:2009/4/23 18:25:51

Delphi深度探索之外壳执行操作记录器

作者: 哈巴狗的小窝 来源:希赛网 http://www.csai.cn 2006年01月20日

记录外壳的活动

  记录外壳活动有很多好处,比如当需要监控用户的行为,回溯系统崩溃前的过程。实现这一功能的关键工具相当简单,它就是COM接口IShellExecuteHook。编写一个实现了这一接口的COM对象后,再在系统中注册,就可以容易地控制并影响Windows外壳的运行。Windows 98和Windows 2000都支持IShellExecuteHook外壳扩展,而在Windows 95和Windows NT 4.0上则必须安装活动桌面扩展后才支持(也就是说必须安装IE 4.01)。

  一个实现了IShellExecuteHook接口的COM对象可以截获所有对ShellExecute和ShellExecuteEx函数的调用。ShellExecute和ShellExecuteEx函数主要用于执行应用程序,它们可以接收一个文件名并能自动获得同文件名相关的可执行文件名。此外,它们还支持系统安全认证。如果在NT上设定了用户的可执行权限,ShellExecute和ShellExecuteEx函数将会在创建新的进程前检查权限(CreateProcess和WinExec函数则没有这项功能)。函数调用的流程如下:

  (1)获得将要运行的可执行文件名。

  (2)根据程序名检查用户执行权限。

  (3)激活全部已注册的IshellExecuteHook扩展。

  (4)当所有扩展和权限都同意执行,创建新的进程并返回。

  Windows外壳大量调用ShellExecute和ShellExecuteEx函数来执行几乎是所有的资源管理器的操作,比如双击目录、浏览文件夹内容、打印编辑文档、查看文件属性、选择文档的上下文相关菜单等等。此外,开始菜单的运行对话框和DOS方式下的Start.exe也使用ShellExecuteEx函数来执行程序。简单地说几乎用户的所有外壳操作都可以被扩展截获,包括其他应用程序对ShellExecute和ShellExecteEx的调用。



编写外壳活动记录器

  首先需要创建一个进程内COM对象,选菜单命令New | ActiveX Library,然后点击菜单New|Com Object,创建COM对象框架,按图2.14填充对话框的内容,然后点击OK按钮。Delphi就会自动生成框架文件,并保存生成的文件。

  IShellExecuteHook的接口定义在shlobj.pas单元中,添加shlobj到单元uses部分,然后添加IShellExecuteHooko方法原型到COM对象声明部分,声明部分代码如下:

unit ShellExecuteHookObj;

interface

uses

Windows, ActiveX, ComObj, ShlObj, ShellAPI;

type

TTShellExecuteHook = class (TComObject, IShellExecuteHook)

protected

function Execute(var ShellExecuteInfo: TShellExecuteInfo): HResult; stdcall;

end;

const

Class_TShellExecuteHook: TGUID = ''''{935FA400-243D-11D3-B06E-857B2AE2BE64}'''';

  下面就是用来截获并记录外壳操作的实现部分,一旦外壳扩展被注册后,每次ShellExecute 和ShellExecuteEx函数运行时都会调用COM对象的Execute函数。我们的核心代码就是通过Execute方法实现的。方法定义如下:

function TTShellExecuteHook.Execute(
var ShellExecuteInfo: TShellExecuteInfo): HResult;

  Execute方法会从外壳获得一个类型为TshellExecuteInfo的参数,参数定义如下:

_SHELLEXECUTEINFOA = record

cbSize: DWORD;

fMask: ULONG;

Wnd: HWND;

lpVerb: PAnsiChar;

lpFile: PAnsiChar;

lpParameters: PAnsiChar;

lpDirectory: PAnsiChar;

nShow: Integer;

hInstApp: HINST;

{ Optional fields }

lpIDList: Pointer;

lpClass: PAnsiChar;

hkeyClass: HKEY;

dwHotKey: DWORD;

hIcon: THandle;

hProcess: THandle;

end;

  这个记录结构中的lpFile包含了要运行的文件名,而lpVerb则表明执行的动作,动作由一些标准的字符串代表,比如,open(打开)、print(打印)、edit(编辑)、explore(浏览)、properties(属性)、find(查找)和其他上下文菜单的命令名。 有时,lpFile并不包含可执行文件名,这是因为ShellExecute接到的运行参数是一个文档名。比如当我们在资源管理器中双击文本文件时,Windows用文本文件名作为参数调用ShellExecute函数,而ShellExecute函数则获得同文本文件相关联的可执行文件名,然后执行。

  TShellExecuteInfo结构中还记录了要运行程序的很多信息,然而这里我们只能在Execute方法中修改nCmdShow参数,nCmdShow参数定义了窗口在运行后的显示状态,包括最大化、最小化、正常等选项,对于其他参数的修改都会被外壳忽略。除此之外,在Execute方法中可以根据情况允许外壳继续缺省的任务或通知外壳取消执行,这可以通过Execute函数的返回值来实现。

  如果Execute的返回值为S_FALSE,外壳就继续缺省的任务,如果返回S_OK,则外壳认为扩展已经成功,就不再继续执行了。另外如果返回一个错误代码或系统无法识别的值,则外壳会弹出错误信息。这给了我们一个控制程序运行的机会,比如可以限制任何对记事本的调用,代码如下:

function TTShellExecuteHook.Execute(
var ShellExecuteInfo: TShellExecuteInfo): HResult;

var

FileName: String;

begin

Result := S_FALSE;

with ShellExecuteInfo do

begin

FileName := UpperCase(ExtractFileName(lpFile));

if Pos(''''NOTEPAD'''', FileName) = 1 then

begin

Result := S_OK;

hInstApp := 32;

MessageBox(Wnd, ''''不允许记事本运行!'''', ''''错误'''', MB_OK or MB_ICONERROR);

end;

end;

end;

  进一步,我们甚至可以利用这点实现一个自定义的安全认证机制,根据用户要求限制运行的程序。有兴趣的朋友可以试验一下,一定很有意思。

  有一点要注意的是,在Execute方法下不能调用ShellExecute和ShellExecuteEx函数外部程序,如果是这样的话,我们的Execute方法又会被新的ShellExecute调用,这样系统就会进入死循环。如果我们确实想在Execute方法中调用外部程序的话,可以使用CreateProcess或WinExec函数来替代。这两个函数不会被ShellExecuteHook截获。

  对于外壳动作记录器来说,只要在Execute方法中记录程序信息到日志文件中就可以了,代码非常简单,因为所有需要的信息都在TShellExecuteInfo记录中包含了,这里只记录运行的动作、文件名和时间,需要记录其他信息的话,大家可自行修改,代码示意如下:

function TTShellExecuteHook.Execute(
var ShellExecuteInfo: TShellExecuteInfo): HResult;

var

FileStream: TFileStream;

a:TStringList;

S:string;

begin

Result := S_FALSE;

with ShellExecuteInfo do

begin

FileStream:=TFileStream.Create(''''c:\shellexecutehook.txt'''',fmopenwrite);

S:=string(lpVerb)+'''':''''+string(lpFile)+DateTimeToStr(Now)+#13#10;

FileStream.Seek(FileStream.Size,soFromBeginning);

FileStream.Write(PChar(S)^,Length(S));

FileStream.Free;

end;

end;

注册ShellExecuteHook

  要想使COM对象被外壳加载,需要在注册表中注册一些信息。在下面这个子键中添加COM类的GUID及描述字符串后就可以了(描述字符串可以不赋值,但不妨给一个以便于识别)。

HKEY_LOCAL_MACHINE

SOFTWARE

Microsoft

Windows

CurrentVersion

Explorer

ShellExecuteHooks

{CLSID}= ''''描述字符串''''

  修改注册表可以通过重载COM的类工厂的UpdateRegistry方法来实现。代码示意如下:

implementation

uses ComServ, SysUtils;

resourcestring

sCreateRegKeyError = ''''创建注册表项失败'''';

type

TShellExComObjectFactory = class(TComObjectFactory)

public

procedure UpdateRegistry(Register: Boolean); override;

end;

{ TShellExComObjectFactory }

procedure TShellExComObjectFactory.UpdateRegistry(Register: Boolean);

const

hellExecuteHooksKey=''''
SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks'''';

var

Handle: HKey;

Status, Disposition: Integer;

ClassID: String;

begin

ClassID := GUIDToString(Class_TShellExecuteHook);

if Register then

begin

Status := RegCreateKeyEx(HKEY_LOCAL_MACHINE, PChar(
ShellExecuteHooksKey), 0, '''''''',REG_OPTION_NON_VOLATILE,
KEY_READ or KEY_WRITE, nil, Handle, @Disposition);

if Status = 0 then

begin

Status := RegSetValueEx(Handle, PChar(ClassID), 0, REG_SZ,

PChar(Description), Length(Description) + 1);

RegCloseKey(Handle);

end;

end else

begin

Status := RegOpenKeyEx(HKEY_LOCAL_MACHINE, PChar(ShellExecuteHooksKey), 0,

KEY_READ or KEY_WRITE, Handle);

if Status = 0 then

begin

Status := RegDeleteValue(Handle, PChar(ClassID));

RegCloseKey(Handle);

end;

end;

if Status <> 0 then raise EOleError.Create(sCreateRegKeyError);

inherited UpdateRegistry(Register);

[1] [2] [3]  下一页


[聊天工具]Google Suggest十大妙用  [聊天工具]保驾护航Web迅雷 全新版本给你更多安全
[聊天工具]玩转火狐的Cookie 让火狐狸吃好小甜饼!  [聊天工具]P2P下载的好工具 POCO完全攻略
[聊天工具]横扫一切高价话费 Vbuzzer八分钱国际长途任你打  [聊天工具]众人拾柴火焰高 改进迅雷于不经意间 迅雷
[聊天工具]中英文互翻 Google Toolbar4中文版试用手记  [聊天工具]巧用µTorrent 体验国外下载站的乐趣
[聊天工具]可远程搜索桌面—Google Desktop 3全新体验  [聊天工具]腾讯浏览器 TT 之实用技巧荟萃 TT,技巧荟萃
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台