首页
社区
课程
招聘
[原创]挂钩DragQueryFileW,增强软件文件拖拽功能
发表于: 2019-9-30 13:28 5805

[原创]挂钩DragQueryFileW,增强软件文件拖拽功能

2019-9-30 13:28
5805
代码写的很丑(非专业人员。。。哈哈哈)

有款内部使用的软件,该软件可以拖拽文件进行快速操作,但是有个问题,该软件不支持遍历子文件夹,进行大量文件操作的时候十分不便。
所以就写了一个挂钩dll,修改软件对拖拽的执行过程,实现文件夹内文件遍历。
思路:hook DragQueryFileW 函数,先取出拖拽的文件列表,如果是文件夹则遍历文件添加入文件列表。等程序请求文件列表时,将整理好的列表返回给程序。
DragQueryFileW函数说明:
UINT DragQueryFileW(
  HDROP  hDrop,
  UINT   iFile,
  LPWSTR lpszFile,
  UINT   cch
);
When the function copies a file name to the buffer, the return value is a count of the characters copied, not including the terminating null character.

If the index value is 0xFFFFFFFF, the return value is a count of the dropped files. Note that the index variable itself returns unchanged, and therefore remains 0xFFFFFFFF.

If the index value is between zero and the total number of dropped files, and the lpszFile buffer address is NULL, the return value is the required size, in characters, of the buffer, not including the terminating null character.

具体代码如下:
library Project1;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  windows, Winapi.ShellAPI, System.IOUtils, System.Types,
  HookUtils,
  HookIntfs,
  messages,
  sysutils,
  tlhelp32;

{$R *.res}

var
  old_DragQueryFileW: function(hDrop: hDrop; iFile: UINT; lpszFile: LPWSTR;
    cch: UINT): UINT; stdcall;

type
  Tfilename = record
    filename: array [0 .. 255] of WideChar;
  end;

var
  g_files: array [0 .. 9999] of Tfilename;

function _DragQueryFileW(hDrop: hDrop; iFile: UINT; lpszFile: LPWSTR; cch: UINT)
  : UINT; stdcall;
var
  res: UINT;
  i, k: Integer;
  tmp: array [0 .. 255] of WideChar;
  LList: TStringDynArray;
  str: string;
begin

  if iFile = $FFFFFFFF then
  begin
    res := old_DragQueryFileW(hDrop, iFile, lpszFile, cch);

    k := 0;
    for i := 0 to res - 1 do
    begin
      // ZeroMemory(@tmp,Length(tmp)*SizeOf(WideChar));
      old_DragQueryFileW(hDrop, i, @tmp, Length(tmp) * SizeOf(WideChar));
      if DirectoryExists(string(tmp)) then
      begin
        LList := TDirectory.GetFiles(tmp, '*.*',
          TSearchOption.soAllDirectories);
        for str in LList do
        begin
          ZeroMemory(@g_files[k].filename, 256 * SizeOf(WideChar));
          CopyMemory(@g_files[k].filename, PWideChar(str),
            Length(str) * SizeOf(WideChar));
          inc(k);
          if k > 9999 then
          begin
            MessageBoxW(0, '文件数量不能超过10000个', '错误', MB_OK + MB_ICONSTOP +
              MB_TOPMOST);
            Exit;
          end;
        end;
      end
      else
      begin
        ZeroMemory(@g_files[k].filename, 256 * SizeOf(WideChar));
        CopyMemory(@g_files[k].filename, @tmp, Length(tmp) * SizeOf(WideChar));
        inc(k);
        if k > 9999 then
        begin
          MessageBoxW(0, '文件数量不能超过10000个', '错误', MB_OK + MB_ICONSTOP +
            MB_TOPMOST);
          Exit;
        end;

      end;
    end;
  end
  else
  begin
    CopyMemory(lpszFile, @g_files[iFile].filename, 256 * SizeOf(WideChar));
  end;
  Result := k;
end;

procedure hook();
begin
  if not Assigned(old_DragQueryFileW) then
  begin
    HookProc(shell32, 'DragQueryFileW', @_DragQueryFileW, @old_DragQueryFileW);
  end
  else
  begin
    if Assigned(old_DragQueryFileW) then
    begin
      UnHookProc(@old_DragQueryFileW);
    end;
    @old_DragQueryFileW := nil;
  end;
end;

procedure DllEntryPoint(fdwReason: DWORD);
begin
  case fdwReason of
    DLL_THREAD_ATTACH:
      hook;
    DLL_THREAD_DETACH:
      hook;
    DLL_PROCESS_DETACH:
      hook;
    DLL_PROCESS_ATTACH:
      hook;
  end;
end;

begin
  DLLProc := @DllEntryPoint;
end.

过程很简单,做个记录,方便有需要的朋友查阅

代码中使用了

lsuper

  大佬的hook单元,在此表示感谢!
# DelphiHookUtils

Delphi API Hook 工具项目

![LOGO](https://github.com/delphilite/DelphiHookUtils/raw/master/Doc/Logo.jpg)

## 由来

国庆帝都雾霾,一直闷家里发霉,也终于有时间搞搞自己的东东了!

年初基于 wr960204 武稀松大哥的 HookUtils 写了个 x64 的东东,效果很 8 错,不过呢,这个实现基于 BeaEngine 的静态库,额外胖了几百 K,对于我这只有“洁癖”的程序员,着实不爽!

之前关注过 BeaEngine 官网还有个 LDE64(Length Disassembler Engine)的东东,事实上对于武大哥那份 Hook 的实现,BeaEngine 只是为了查找足够的“代码间隙”,其实单个 LDE 应该是 ok 的!

遂,花了两天时间搞了这个东东:

[https://github.com/delphilite/DelphiHookUtils](https://github.com/delphilite/DelphiHookUtils)

## 实现

基于 LDE64 相对 BeaEngine 的优势非常明显,新 HookUtils 代码编译大约 10K 左右,相对武大哥“原版”,新版 HookUtils 主要修改:

 1. 参考 wr960204 武稀松 的原始实现: 

[https://code.google.com/p/delphi-hook-library](https://code.google.com/p/delphi-hook-library) 

 2. 修改 BeaEngine 引擎为 LDE64 长度反编译引擎,大幅降低大小

[https://github.com/BeaEngine/lde64](https://github.com/BeaEngine/lde64)

 3. 去除原始实现对多线程冻结的处理,通常建议 Hook/Unhook 放到单元初始化、析构中做,否则可能因改写内存没挂起其他线程造成错误 

 4. 由 HookUtils 中拆分 COM 相关函数至 HookIntfs 单元

## 其他

初步 Delphi 2007-10.3, Lazarus/Typhon/FPC/FMX x86/x64 for Win 一切正常,大家有问题及时反馈 !?

============================================================================================================
接上文,功能dll写好了,但是有个问题:这样每次都要远程注入目标软件,使用还是有所不便,需要找个方法让软件自动加载我们的dll。

解决方法:修改软件的导入表,把我们的dll添加进去,让它随软件自动加载。
使用工具:Stud_PE
软件如下:


修改dll程序入口如下:
begin
  hook;
end.
这样重新编译后当软件加载我们的dll的时候就可以自动运行我们的钩子函数。

下一步修改目标导入表:


添加我们的dll到导入表中,导入函数随便选一个,反正用不到。

这样最终修改的程序完成了运行时自动加载目标dll,当然首先要把dll放到和程序同一目录下。

=================================================================================================
全文完。    By Lxm 2019.9.30



[课程]FART 脱壳王!加量不加价!FART作者讲授!

最后于 2019-9-30 17:12 被moomlxm编辑 ,原因: 添加内容
收藏
免费 1
支持
分享
最新回复 (4)
雪    币: 2081
活跃值: (1711)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
N年没用delphi了,忽然看到一篇,很亲切啊。
2019-9-30 17:37
0
雪    币: 4200
活跃值: (4178)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
https://github.com/MahdiSafsafi/DDetours

这个不是现成的Delphi版Detours么
2019-9-30 20:50
0
雪    币: 209
活跃值: (773)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
现在还有人用Delphi?
2019-10-1 09:59
0
雪    币: 419
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
delphi用来写这些小程序还是挺方便的,现在用delphi都是满满的情怀
2019-10-1 10:32
0
游客
登录 | 注册 方可回帖
返回
//