求助:跨进程获取delphi控件TDBGridEh的内容

[复制链接]
2271|3
手机看帖
扫描二维码
随时随地手机跟帖
xxzouzhichao|  楼主 | 2016-9-2 22:38 | 显示全部楼层 |阅读模式
如题:
有一个第三方软件用了TDBGridEh控件,想获取表格控件上的内容,网上看到有用dll hook的办法获取TstringGrid的内容
因此也想用dll hook的办法获取TDBGridEh内容,求高人指点一下
我自己另外写了一个测试软件,可以获取到这个测试软件的对象实例,
但是目标软件无法获取,findcontrol总是失败


以下是我自己写的测试软件的TDBGgridEh的spy++信息:
捕获0.JPG
以下是目标软件的TDBGgridEh的spy++信息:
捕获1.JPG
以下是hook的dll的源码
unit UHook;

interface

uses Windows, Messages, SysUtils, Controls, Grids, DBGrids, DBGridEh, DBGridEhImpExp, Classes;

procedure InstallHook(MainWnd, DestWnd: HWND); stdcall;
procedure UninstallHook; stdcall;
function GetHookedCell: PChar; stdcall;

implementation

uses UShare;

var
  ControlAtom: TAtom;
  ControlAtomString: string;
  RM_GetObjectInstance: DWORD;  // registered window message


function MyFindControl_test(Handle: HWnd): TWinControl;
type  
  PObjectInstance = ^TObjectInstance;
  TObjectInstance = packed record  
    Code: Byte;            { 短跳转 $E8 }  
    Offset: Integer;       { CalcJmpOffset(Instance, @Block^.Code); }
    Next: PObjectInstance; { MainWndProc 地址 }
    Self: Pointer;         { 控件对象地址 }
  end;  
var  
  wc: PObjectInstance;  
begin  
  Result := nil;  
  wc     := Pointer(GetWindowLong(Handle, GWL_WNDPROC));  
  if wc <> nil then  
  begin  
    Result := wc.Self;  
  end;  
end;


function MyFindControl(Handle: HWnd): TWinControl;
var
  OwningProcess: DWORD;
begin
  Result := nil;
  if (Handle <> 0) and (GetWindowThreadProcessID(Handle, OwningProcess) <> 0) and
     (OwningProcess = GetCurrentProcessId) then
  begin
    if GlobalFindAtom(PChar(ControlAtomString)) = ControlAtom then
      Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom)))
    else
          Result := Pointer(SendMessage(Handle, RM_GetObjectInstance, 0, 0));
        MessageBeep(MB_OK);
  end;
end;

function MsgWndProc(hwnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
var
  DG: TDBGridEh;
  aName: array [0..255] of Char;
begin
  case Msg of
    CM_QUERYROW:                      //获取行数
      begin
        Result := -1;
        if P^.DestWnd <> 0 then
        begin
          GetClassName(P^.DestWnd, aName, 256);
          //if string(aName) = 'TDBGridEh' then MessageBeep(MB_OK);
          DG := Pointer(MyFindControl(P^.DestWnd));
          if DG <> nil then Result := DG.Height;
        end;
        Exit;
      end;
    CM_QUERYCOL:                              //获取列数
      begin
        Result := -1;
        if P^.DestWnd <> 0 then
        begin
          GetClassName(P^.DestWnd, aName, 256);
          //if string(aName) = 'TDBGridEh' then MessageBeep(MB_OK);
          DG := Pointer(MyFindControl(P^.DestWnd));
          if DG <> nil then Result := DG.Width;
        end;
        Exit;
      end;
    CM_HOOKCELL:                                //获取内容
      begin
        DG := Pointer(MyFindControl(P^.DestWnd));
        //if DG <> nil then MessageBeep(MB_OK);
        SaveDBGridEhToExportFile(TDBGridEhExportAsText, DG, 'c:/GridData.txt', true);
        Exit;
      end;
  end;
  Result := DefWindowProc(hwnd, Msg, WParam, LParam);
end;

function GetMsgProc(Code: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
begin
  if Code = HC_ACTION then
  begin
  end;
  Result := CallNextHookEx(P^.hkMsg, Code, WParam, LParam);
end;

procedure InstallHook(MainWnd, DestWnd: HWND); stdcall;
begin
  if P^.hkMsg = 0 then
    P^.hkMsg := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, HInstance, 0);
  P^.HostWnd := MainWnd;
  P^.HostPID := GetCurrentProcessId;
  P^.DestWnd := DestWnd;
end;

procedure UninstallHook; stdcall;
begin
  if P^.hkMsg <> 0 then
  begin
    UnhookWindowsHookEx(P^.hkMsg);
    P^.hkMsg := 0;
  end;
end;

function GetHookedCell: PChar; stdcall;
begin
  Result := P^.Text;
end;

var
  DoClear: Boolean;
  DestPID: DWORD;
  DestProcess: Boolean = False;
  UtilWindowClass: TWndClass = (
    style: 0;
    lpfnWndProc: @MsgWndProc;
    cbClsExtra: 0;
    cbWndExtra: 0;
    hInstance: 0;
    hIcon: 0;
    hCursor: 0;
    hbrBackground: 0;
    lpszMenuName: nil;
    lpszClassName: 'THookSGMsgWindow');

initialization
  hMapFile := OpenFileMapping(FILE_MAP_WRITE, False, cMapFileName);
  DoClear := hMapFile = 0;
  if hMapFile = 0 then
    hMapFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE,
      0, SizeOf(TShareData), cMapFileName);
  P := MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, 0);
  if DoClear then FillChar(P^, SizeOf(TShareData), 0);
  //ControlAtomString := Format('ControlOfs%.8X%.8X', [GetModuleHandle(nil), GetCurrentThreadID]);
  //ControlAtomString := Format('ControlOfs%.8X%.8X', [$50300000, $00000F50]);
  //ControlAtomString := Format('ControlOfs%.8X%.8X', [$00400000, GetCurrentThreadID]);
  ControlAtomString := Format('ControlOfs%.8X%.8X', [GetWindowLong(P^.DestWnd, GWL_HINSTANCE), GetWindowThreadProcessId(P^.DestWnd)]);
  ControlAtom := GlobalAddAtom(PChar(ControlAtomString));
  RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString));
  if P^.DestWnd <> 0 then
  begin
    GetWindowThreadProcessId(P^.DestWnd, DestPID);
    if DestPID = GetCurrentProcessId then
    begin
          MessageBeep(MB_OK);
      DestProcess := True;
      //UtilWindowClass.hInstance := HInstance;
          UtilWindowClass.hInstance := GetWindowLong(P^.DestWnd, GWL_HINSTANCE);
      Windows.RegisterClass(UtilWindowClass);
      P^.MsgWnd := CreateWindowEx(
        WS_EX_TOOLWINDOW,              // extended window style
        UtilWindowClass.lpszClassName, // pointer to registered class name
        UtilWindowClass.lpszClassName, // pointer to window name
        WS_POPUP,                      // window style
        0,                             // horizontal position of window
        0,                             // vertical position of window
        0,                             // window width
        0,                             // window height
        0,                             // handle to parent or owner window
        0,                             // handle to menu, or child-window identifier
        GetWindowLong(P^.DestWnd, GWL_HINSTANCE),                     // handle to application instance
        nil);                          // pointer to window-creation data
      PostMessage(P^.HostWnd, CM_MSGWNDCREATED, P^.MsgWnd, 1);
    end;
  end;
finalization
  if DestProcess then
  begin
    DestroyWindow(P^.MsgWnd);
    PostMessage(P^.HostWnd, CM_MSGWNDCREATED, P^.MsgWnd, 0);
  end;
  GlobalDeleteAtom(ControlAtom);
  ControlAtomString := '';
  UnmapViewOfFile(P);
  CloseHandle(hMapFile);
end.
现在我怀疑是spy++信息中的实例句柄不一致导致的(图中用红笔标示),但又不知道如何修改程序,以前没用过delphi,完全新手
在网上找到一篇靠边的文档,但是信息也不全:
http://bbs.csdn.net/topics/90085650?list=lz

相关帖子

yyy71cj| | 2016-9-4 07:04
xxzouzhichao 发表于 2016-9-3 17:06
版本不一致也会失败么?没想过这点额,但我该怎么才能知道原软件的delphi版本呢? ...

如果你自己编写的能勾到,而别人编写的勾不到,这一般就只有版本差异了,一般的编码是不会带有版本号的。要不你尝试读取该编号控件相关的全部内存信息,自己解析?很可能只是一点小小的差异而已

回复
xxzouzhichao|  楼主 | 2016-9-3 10:16 | 显示全部楼层
yyy71cj 发表于 2016-9-3 07:58
delphi我是用了多年,但是对于这类问题印象也不深。不过可以指给你一个方法。先自己写一个应用,然后用你的 ...

自己写了一个应用,勾到了
但是目标应用就失败了

使用特权

评论回复
xxzouzhichao|  楼主 | 2016-9-3 17:06 | 显示全部楼层
yyy71cj 发表于 2016-9-3 12:07
那有可能版本不一致吧

版本不一致也会失败么?没想过这点额,但我该怎么才能知道原软件的delphi版本呢?

使用特权

评论回复
xxzouzhichao|  楼主 | 2016-9-4 10:55 | 显示全部楼层
yyy71cj 发表于 2016-9-4 07:04
如果你自己编写的能勾到,而别人编写的勾不到,这一般就只有版本差异了,一般的编码是不会带有版本号的。 ...

这个主意不错!!!!!!!!!!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

298

帖子

6

粉丝