•  

ГлавнаяIndyЧастые вопросы по Indy → Необходимо сделать программу, для перехвата пересылаемых данных, не мешая работе этих 2 программ

Создано: 03.06.2014 20:10:10 · Исправлено: 03.06.2014 20:10:10 · Прочтений: 736

Есть 2 приложения: MainProg (16 - разрядное) и TransProg (32 - разрядное).
MainProg посылает данные TransProg путем сообщений.

Т.е. определяет запущен ли процесс TransProg. Если запущен, то получает его Handle и отсылает ему данные.
Цель: Необходимо сделать программу, для перехвата пересылаемых данных, не мешая работе этих 2 программ.

Исходные данные:

Запускаем WinSight32 смотрим сообщения программы MainProg:

WM_USER + 0x7D00 (810004X) sent wp=000B0690 lp=00000000
WM_USER + 0x7D00 (810004X) sent wp=000B0690 lp=00000007
WM_USER + 0x7D00 (810004X) sent wp=000B0690 lp=00000001
WM_USER + 0x7D00 (810004X) sent wp=000B0690 lp=00000006
WM_USER + 0x7D00 (810004X) sent wp=000B0690 lp=00000002
WM_USER + 0x7D00 (810004X) sent wp=000B0690 lp=00000003
WM_USER + 0x7D00 (810004X) sent wp=000B0690 lp=00000004

Смотрим сообщения программы TransProg:

WM_COPYDATA (4a04x) sent wp=000006A4 lp=0012FD24 from hwnd 06a4 Data Item: 00000000, 28 byte @0012fd3c cf f7 24 41 00 00 00 00 00 00 00 00 28 5c 33 41 00 00 00 00 33 5f 56 45 00 00 00 00
WM_COPYDATA (4a04x) sent wp=000006A4 lp=0012FD40 from hwnd 06a4 Data Item: 00000007, 0 byte @00000000
WM_COPYDATA (4a04x) sent wp=000006A4 lp=0012FCC0 from hwnd 06a4 Data Item: 00000001, 128 byte @0012FCD8 01 00 … … …
WM_COPYDATA (4a04x) sent wp=000006A4 lp=0012FD40 from hwnd 06a4 Data Item: 00000006, 0 byte @00000000
WM_COPYDATA (4a04x) sent wp=000006A4 lp=0012FD3C from hwnd 06a4 Data Item: 00000002, 4 byte @0012fd54 33 5f 56 45
WM_COPYDATA (4a04x) sent wp=000006A4 lp=0012FCDC from hwnd 06a4 Data Item: 00000003, 98 byte @0012Fcf4 02 00 … … …
WM_COPYDATA (4a04x) sent wp=000006A4 lp=0012FD40 from hwnd 06a4 Data Item: 00000004, 5850 byte @00d60000 1d … … …

Собственно все, что идет после Data Item это то что мне нужно. Что делать с данными я знаю. Но как перехватить данные посланные другому приложению я не знаю.

Мои догадки:
необходимо делать глобальный хук на сообщения и фильтровать на то, что нужно.

Подскажите как это сделать.
SetWindowsHookEx и далее по ссылкам или гуглить. Наверное, вас интересует WH_GETMESSAGE или WH_CALLWNDPROC.
Я никогда раньше не делал ничего подобного. Поэтому мне интересен опыт других людей.
Гугл - это хорошо когда знаешь, что искать.
На готовое решения моей задачи я не надеюсь.
Перечитывал вот эту статью http://www.delphimaster.ru/articles/hooks/index.html несколько раз.

Все равно многое чего не понятно.
1) нужно перехватывать данные из MainProg или TransProg?
Если MainProg посылает, значит логично думать, что именно ее сообщения нам и нужно перехватывать (WM_USER + 0x7D00). Но, тогда почему в TransProg приходят сообщения вида WM_COPYDATA с данными? Что (WM_USER + 0x7D00) = WM_COPYDATA?
2) Если MainProg начинает посылать данные только тогда, когда процесс TransProg запущен. Значит без TransProg значения из MainProg мне не получить? Пробовал я процесс таким же именем обзывать и caption у формы аналогично делать - бесполезно. Видимо сразу после запуска TransProg, посылает сообщение о запуске программе MainProg. Но это не главное. Пусть работает параллельно TransProg. Главное выдернуть данные и не мешать этим двум процессам.


Согласно статьи http://www.delphimaster.ru/articles/hooks/index.html
Начнем с простого, без всяких там CreateFileMapping.

Поправьте если не правильно!

1) Делаем DLL:

library hook_dll1;

uses
  Windows,
  Messages,
  Forms;

var
  SysHook : HHook = 0; 
  Wnd : Hwnd = 0;

function SysMsgProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
begin
  Wnd:=TMsg(Pointer(lParam)^).hwnd;
  // if TMsg(Pointer(lParam)^).message = WM_USER + $7D00 then
  if TMsg(Pointer(lParam)^).message = WM_COPYDATA then
    MessageBox(0, А вот и наши данные, Информация, 0);
  { Пытаемся передать сообщение дальше по цепочке hook-ов. }
  Result:= CallNextHookEx(SysHook, Code, wParam, lParam);
end;

{ Процедура установки HOOK-а}
procedure hook(switch : Boolean) export; stdcall;
begin
  if switch=true then
    //SysHook := SetWindowsHookEx(WH_GETMESSAGE, @SysMsgProc, HInstance, 0)
    SysHook := SetWindowsHookEx(WH_CALLWNDPROC, @SysMsgProc, HInstance, 0)

  else
  begin
    UnhookWindowsHookEx(SysHook);
    SysHook := 0;
  end;
end;

exports hook;

begin

end.


2) Создаем Свое прилажение:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

{для динамической загрузки функций из DLL}
type
  MyProcType = procedure (flag : Boolean); stdcall;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Hdll : HWND; { дескриптор загружаемой DLL (для динамической загрукзки)}

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  hook: MyProcType;
begin

  @hook:= nil; // инициализируем переменную hook

{ ********* динамическая загрузка **************}

  Hdll:= LoadLibrary(PChar(hook_dll1.dll)); { загрузка DLL }
  if Hdll > HINSTANCE_ERROR then            { если всё без ошибок, то }
    begin
      @hook:=GetProcAddress(Hdll, hook);    { получаем указатель на необходимую процедуру}
      Button2.Enabled:=True;
      Button1.Enabled:=False;
      hook(true);
    end
  else
    ShowMessage(Ошибка при загрузке DLL !);

{ **********************************************}
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  hook: MyProcType;
begin
  @hook:= nil; // инициализируем переменную hook
  if Hdll > HINSTANCE_ERROR then
    begin                                  { если всё без ошибок, то }
      @hook:=GetProcAddress(Hdll, hook);  { получаем указатель на необходимую процедуру}
      Button1.Enabled:=True;
      Button2.Enabled:=False;
      hook(false);                          {вызываем нужную процедуру из DLL}
    end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FreeLibrary(Hdll); { при закрытии формы - освобождаем DLL }
end;

end.


А в результате данные я не перехватываю.

Может я вообще все не так понял?
Короче говоря максимум что мне удается сделать, так это вызвать сбой при проникновении в чужой процесс. Причем чужой процесс слетает напрочь, а мой остается.

Делаю я это вот так:
SysHook := SetWindowsHookEx(WH_MAXHOOK, @SysMsgProc, HInstance, 0);
При

>>> wParam : word

это неудивительно.
Ну подскажите тогда, что не так.
LRESULT CALLBACK SysMsgProc
(
int nCode, // флажок сообщения
WPARAM wParam, // не определен
LPARAM lParam // адрес структуры с данными сообщения
);

Если он не определен, тогда какой тип нужно установить?
Я попробовал Вот ТАк:
library hook_dll;

uses
  Windows,
  Messages,
  Forms;

const
  MMFName: PChar = MyMMF; // имя объекта файлового отображения

{структура, поля которой будут отображены в файл подкачки}
type
  PGlobalDLLData = ^TGlobalDLLData;
  TGlobalDLLData = packed record
    SysHook: HWND; // дескриптор установленной ловушки
  end;

var
  GlobalData: PGlobalDLLData;
  MMFHandle: THandle;

{Данная ф-ия вызывается системой каждый раз, когда возникает какое-то событие в
dialog box-е, message box-е, menu, или scroll bar-е}
function SysMsgProc(code : integer; wParam: longint; lParam : longint) : longint; stdcall;
begin
  if code = HC_ACTION then
  begin
    if TMsg(Pointer(lParam)^).message = wm_COpyData then
    {Вывожу сообщение при удачной работе.}
      MessageBox(0, РАБОТАЕТ!!!!!!, Наконецто!!!!!!!, 0);
  end;
  {Пытаемся передать сообщение дальше по цепочке hook-ов. }
  Result:= CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
end;

{Процедура установки HOOK-а}
procedure hook(switch : Boolean) export; stdcall;
begin
  if switch=true then
  begin
    {Устанавливаю HOOK, если он не установлен (switch=true). }
    GlobalData^.SysHook := SetWindowsHookEx(WH_GETMESSAGE, @SysMsgProc, HInstance, 0);
    if GlobalData^.SysHook <> 0 then
        MessageBox(0, HOOK1 установлен !, Message from Exampel2/Process1, 0)
      else
        MessageBox(0, HOOK1 установить не удалось !, Message from Exampel2/Process1, 0);
  end
  else
  begin

    {Удаляю функцию-фильтр, если она установлена (т.е. switch=false). }
    if UnhookWindowsHookEx(GlobalData^.SysHook) then
      MessageBox(0, HOOK1 снят !, Message from Exampel2/Process1, 0)
    else
      MessageBox(0, HOOK1 снять не удалось !, Message from Exampel2/Process1, 0);
  end;
end;

procedure OpenGlobalData();
begin
  {получаем объект файлового отображения}
//  MMFHandle:= CreateFileMapping(DWord(-1), nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName); // можно так, но лучше: см. след. строку
  MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName);

  if MMFHandle = 0 then
    MessageBox(0, Cant create FileMapping, Message from Exampel2/Process1, 0);

  {отображаем глобальные данные на АП вызывающего процесса и получаем указатель
  на начало выделенного пространства}
  GlobalData:= MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData));
  if GlobalData = nil then
    begin
      CloseHandle(MMFHandle);
      MessageBox(0, Cant make MapViewOfFile, Message from Exampel2/Process1, 0);
    end;

end;

procedure CloseGlobalData();
begin
  UnmapViewOfFile(GlobalData);
  CloseHandle(MMFHandle);
end;

procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
  case dwReason of
    DLL_PROCESS_ATTACH: OpenGlobalData;
    DLL_PROCESS_DETACH: CloseGlobalData;
  end;
end;

exports hook;

begin
//MessageBox(0, PChar(Application.ExeName), Message from Exampel1/Process1, 0);
  {назначим поцедуру переменной DLLProc}
  DLLProc:= @DLLEntryPoint;
  {вызываем назначенную процедуру для отражения факта присоединения данной
  библиотеки к процессу}
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.



Я реально что-то не понимаю.
Люди добрые пожалуйста помогите, очень надо. Проект стоит из-за этой мелочи.
Самое интересное - это, то что WinSight32 может читать чужие данные.
Вы бы хоть говорили, в чём проблема-то.
А случаем не здесь ли собака зарыта?
MainProg (16 - разрядное) и TransProg (32 - разрядное)
Внедрять ловушку надо в TransProg. Так что 16-ти разрядность MainProg вроде не должна мешать.
Может попробовать по другому решить задачу?
Например:
MainProg собирает данные и передает путем сообщений программе TransProg. Которая рассылает эти данные по сети клиентам (я думаю что через компонент indy). При этом использует систему команд. Команды естественно мне не известны. Если знать эту систему команд, то задача также будет решена.
Цель: извлечь данные.
Есть еще маленькое, но - MainProg пишет также данные в БД. И самым идеальным вариантом было бы извлечение данных от туда. Так вот проблема кроется в том, что в БД данные записываются с задержкой не по времени, а по количеству записей. т.е. некий буфер.
Задача проекта: извлечь данные и передать программе отображающие эти данные, по сети, на другой машине.
Первоначально было сделано извлечение именно из БД. Но заказчика это не устроило. ТАк как в реальности получается большая задержка.