информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Где водятся OGRыСетевые кракеры и правда о деле ЛевинаПортрет посетителя
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Ростелеком заподозрили в попытке... 
 Линуксовый ботнет, распространяющийся... 
 Конец поддержки Internet Explorer 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Вот пробую сделать то же самое, но уже в своём процессе и законном обработчике окна. Тоже названия веток не определяются. Хэндл проверял - не ноль. Где я опять туплю? 07.12.06 03:36  Число просмотров: 1784
Автор: Vedrus <Serokhvostov Anton> Статус: Member
Отредактировано 07.12.06 03:54  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
<programming>
[win32] tvm_getitem в "чужом" окне 05.12.06 12:33  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Такая проблема. Нужно определить текущий элемент в контроле SysListTreeView32 в чужом окне (хэндл контрола получаю через Windows Hooks и EnumChildWindows). Попробовал через TVM_GETITEM (он же TreeView_GetItem), но это сообщение возвращает ошибку. Такое подозрение, что это сообщение нельзя использовать с чужими окнами. Вот как я делал:
	HTREEITEM hTreeItem;
	TVITEM    tvi;

	hTreeItem = TreeView_GetSelection(hwndControl);

	tvi.hItem = hTreeItem;
	tvi.mask = TVIF_TEXT;

	TreeView_GetItem(hwndControl, &tvi);


---
Вот скажи мне, вернёт тебе винда указатель на текст... 05.12.06 14:50  
Автор: HandleX <Александр М.> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>
А теперь давай порассуждаем...

На что указатель? Верно, на память. В адресном пространстве какого процесса? Как ты думаешь, вот если ты бы писал венды, стал бы ты парить моск, копируя букаффки из адресного пространства одного процеса в адресное пространство другого (насколько я понимаю, у тебя хендл окна ДРУГОГО процесса)? Вот я бы не стал. Поскольку 99,9999 использования этого сообщения наблюдается в своём процессе со своими контролами -)) И программеры M$ тоже себя этим не стали утруждать. Поэтому берём VirtualAllocEx (аллоцируем память под букаффки в читаемом процессе), шлём соответств. мессидж в чужое окно с соотв. указателем на память, валидном в ТОМ процессе, а потом читаем чужое адресное пространство с помощью ReadProcessMemory(). И не забываем, что в 9x-ME виндах этих функций нет.

Удачи.
Вот пробую сделать то же самое, но уже в своём процессе и законном обработчике окна. Тоже названия веток не определяются. Хэндл проверял - не ноль. Где я опять туплю? 07.12.06 03:36  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
Отредактировано 07.12.06 03:54  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
В паскале разберёшься? Кину тебе пример кода, который запускает Regedit и переводит его на нужную ветку в его TreeView. 07.12.06 06:37  
Автор: HandleX <Александр М.> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>

Procedure ShowServiceRegKey(aServiceName: String; FormWnd: HWND);
Type
  TRemoteBuff = Record
    Item: TTVITEM;
    aStr: Packed Array[0..820] Of Char;
  End;
  pRemoteBuff = ^TRemoteBuff;

  Function GetSFieldCount(aStr: String; Delimiter: Char = #9): DWORD;
  Var TempP: PChar;
  Begin
    TempP := PChar(aStr);
    If aStr = '' Then Result := 0
    Else Result := 1;
    While TempP^ <> #0 Do
    Begin
      If TempP^ = Delimiter Then
        Inc(Result);
      Inc(TempP);
    End;
  End;

  Function GetSField(aStr: String; anIndex: DWord; Delimiter: Char = #9): String;
  Var
    TempP: PChar;
    Counter: DWORD;
    Ind1, Ind2: Integer;
  Begin
    Counter := 0;
    Result := '';
    TempP := PChar(aStr);
    Ind1 := -1; Ind2 := -1;
    While TempP^ <> #0 Do
    Begin
      If TempP^ = Delimiter Then Inc(Counter);
      If Counter = anIndex Then
        If Ind1 = -1 Then
          Ind1 := TempP - PChar(aStr);
      If Counter > anIndex Then
      Begin
        Ind2 := TempP - PChar(aStr);
        Break;
      End;
      Inc(TempP);
    End;
    If TempP^ = #0 Then
      Ind2 := StrEnd(PChar(aStr)) - PChar(aStr);
    If Ind1 <> 0 Then Inc(Ind1);
    Result := Copy(aStr, Ind1 + 1, Ind2 - Ind1)
  End;

  Procedure ConnectHostToRegedit(aRegMainWnd: HWND; aHostName: String);

    Function GetChildEditControl(aParent: HWND): HWND;
      Function EnumProc(aHwnd: HWND; RetValue: PDWORD): BOOL; StdCall;
      Var aBuff: String[255];
      Begin
        SetLength(aBuff, GetClassName(aHwnd, @aBuff[1], 254));

        If (OSVersion.dwMajorVersion >= 5) And (OSVersion.dwMinorVersion >= 1) Then Result := Not (aBuff = 'RichEdit20W')
        Else Result := Not (aBuff = 'Edit');

        If Not Result Then
          RetValue^ := aHwnd;
      End;
    Begin
      EnumChildWindows(aParent, @EnumProc, DWORD(@Result));
    End;

    Function GetWindowClass(aWnd: HWND): String;
    Begin
      SetLength(Result, 255);
      SetLength(Result, GetClassName(aWnd, PChar(Result), Length(Result)));
    End;

  Var
    fWnd, eWnd: HWND;
    mHndl, subMenu: HMENU;
    mID: Integer;
  begin
    If aRegMainWnd = 0 Then Exit;

    mHndl := GetMenu(aRegMainWnd);
    Win32Check(mHndl <> 0);

    subMenu := GetSubMenu(mHndl, 0);
    Win32Check(SubMenu <> 0);

    If (OSVersion.dwMajorVersion >= 5) And (OSVersion.dwMinorVersion >= 1) Then mID := GetMenuItemID(SubMenu, 6)
    Else mID := GetMenuItemID(SubMenu, 3);
    Win32Check(mID > 0);

    Win32Check(PostMessage(aRegMainWnd, WM_COMMAND, mID, 0));

    Repeat
      fWnd := GetForegroundWindow;
      Sleep(50);
    Until Pos('#', GetWIndowClass(fWnd)) <> 0;

    Win32Check(fWnd <> 0);

    eWnd := GetChildEditControl(fWnd);
    Win32Check(eWnd <> 0);

    Win32Check(SendMessage(eWnd, WM_SETTEXT, 0, DWORD(PChar(aHostName))) <> 0);

    SendMessage(fWnd, WM_KEYDOWN, 13, 0);
    SendMessage(fWnd, WM_KEYUP, 13, 0);

  End;

  Function MakeFintInAnotherProcess(aProcess: THandle; aRemBuff: PRemoteBuff; aHwnd: HWND; aKey: String): Boolean;

    Procedure WriteStrToBuff(aStr: String);
    Var
      aSrc: Pointer;
      aSize, Written: DWORD;
    Begin
      aSrc := PChar(aStr);
      aSize := Length(aStr) + 1;
      If aSize > High(aRemBuff.aStr) Then
        Raise Exception.Create('String is too long!');
      Win32Check(WriteProcessMemory(aProcess, @aRemBuff^.aStr, aSrc, aSize, Written));
      Win32Check(Written = aSize);
    End;

    Function ReadStrFromBuff: String;
    Var Readed: DWORD;
    Begin
      SetLength(Result, High(aRemBuff.aStr));
      Win32Check(ReadProcessMemory(aProcess, @aRemBuff.aStr, PChar(Result), High(aRemBuff.aStr), Readed));
      Win32Check(Readed = High(aRemBuff.aStr));
      SetLength(Result, StrLen(PChar(Result)));
    End;

    Function ReadStrFromAddr(anAddr: Pointer): String;
    Var
      Readed: DWORD;
      Buff: Char;
      pTemp: Pointer;
    Begin
      pTemp := anAddr;
      Result := '';
      Repeat
        Win32Check(ReadProcessMemory(aProcess, pTemp, @Buff, 1, Readed));
        Win32Check(Readed = 1);
        If Buff <> #0 Then
          Result := Result + Buff;
        Inc(DWORD(pTemp));
      Until Buff = #0;
    End;

    Procedure WriteItemToBuff(Const Item: TTVITEM);
    Var Written: DWORD;
    Begin
      Win32Check(WriteProcessMemory(aProcess, aRemBuff, @Item, SizeOf(Item), Written));
      Win32Check(Written = SizeOf(Item));
    End;

    Procedure ReadItemFromBuff(Var Item: TTVITEM);
    Var Readed: DWORD;
    Begin
      Win32Check(ReadProcessMemory(aProcess, aRemBuff, @Item, SizeOf(Item), Readed));
      Win32Check(Readed = SizeOf(Item));
    End;

    Function GetItemText(anItem: THandle): String;
    Var ItemParams: TTVITEM;
    Begin
      ZeroMemory(@ItemParams, SizeOf(ItemParams));
      ItemParams.mask := TVIF_TEXT;
      ItemParams.hItem := HTREEITEM(anItem);
      ItemParams.pszText := @aRemBuff.aStr;
      ItemParams.cchTextMax := 400;
      WriteItemToBuff(ItemParams);
      Win32Check(TreeView_GetItem(aHwnd, aRemBuff.Item));
      ReadItemFromBuff(ItemParams);
      If ItemParams.pszText = Nil Then Result := ''
      Else
        If ItemParams.pszText = @aRemBuff.aStr Then Result := ReadStrFromBuff
        Else Result := ReadStrFromAddr(ItemParams.pszText);
    End;

    Function FindChild(aParent: THandle; aText: String): THandle;
    Var
      anItem: THandle;
      Compares: Integer;
      TempStr: String;
    Begin
      Result := 0;
      anItem := DWORD(TreeView_GetNextItem(aHwnd, HTREEITEM(aParent), TVGN_CHILD));
      If anItem = 0 Then Exit;
      Repeat
        TempStr := GetItemText(anItem);
        Compares := AnsiCompareStr(aText, TempStr);
        If Compares = 0 Then Break;
        anItem := DWORD(TreeView_GetNextSibling(aHwnd, HTREEITEM(anItem)));
      Until anItem = 0;
      If Compares = 0 Then Result := anItem;
    End;

    Function FindNextItem(fromItem: THandle; aText: String): THandle;
    Var
      anItem: THandle;
      Compares: Integer;
      TempStr: String;
    Begin
      Result := 0;
      anItem := fromItem;
      If anItem = 0 Then Exit;
      Compares := -1;
      Repeat
        anItem := SendMessage(aHwnd, TVM_GETNEXTITEM, TVGN_NEXT, anItem);
        If anItem = 0 Then Break;
        TempStr := GetItemText(anItem);
        Compares := AnsiCompareText(aText, TempStr);
      Until Compares = 0;
      If Compares = 0 Then Result := anItem;
    End;

  Var
    anItem, TempItem: THandle;
    J, Max: Integer;
    TempStr: String;
  Begin

    Max := GetSFieldCount(aKey, '\') - 1;
    Result := Max >= 0;
    If Not Result Then Exit;

    anItem := DWORD(TreeView_GetRoot(aHwnd));
    Result := anItem <> 0;
    If Not Result Then Exit;

    If (MainForm.HostName <> '') AND (UpperCase(MainForm.HostName) <> UpperCase(LocalHostName)) Then
    Begin
      ConnectHostToRegedit(GetParent(aHwnd), MainForm.HostName);
      Repeat
        Sleep(100);
        TempItem := FindNextItem(DWORD(TreeView_GetRoot(aHwnd)), MainForm.HostName);
      Until TempItem <> 0;
      anItem := TempItem;
      Result := anItem <> 0;
      If Not Result Then Exit;
    End;

    Result := TreeView_Expand(aHwnd, HTREEITEM(anItem), TVE_EXPAND);
    If Not Result Then Exit;

    For J := 0 To Max Do
    Begin
      TempStr := GetSField(aKey, J, '\');
      anItem := FindChild(anItem, TempStr);
      Result := anItem <> 0;
      If Not Result Then Exit;
      TreeView_Expand(aHwnd, HTREEITEM(anItem), TVE_EXPAND);
      If J = Max Then
        Result := TreeView_SelectItem(aHwnd, HTREEITEM(anItem)) <> HTREEITEM(0);
    End;

  End;

  Function GetWindowProcessIDByTopmostWindowClass(aClass: String; Var aWnd: HWND): DWORD;
  begin
    Result := 0;
    aWnd := FindWindow(PChar(aClass), Nil);
    If aWnd = 0 Then Exit;
    GetWindowThreadProcessID(aWnd, @Result);
  End;

  Function GetChildTreeView(aParent: HWND): HWND;
    Function EnumProc(aHwnd: HWND; RetValue: PDWORD): BOOL; StdCall;
    Var aBuff: String[255];
    Begin
      SetLength(aBuff, GetClassName(aHwnd, @aBuff[1], 254));
      Result := Not (aBuff = 'SysTreeView32');
      If Not Result Then
        RetValue^ := aHwnd;
    End;
  Begin
    EnumChildWindows(aParent, @EnumProc, DWORD(@Result));
  End;

  Function ShellExecuteAndWaitForIdle(ExePath: String): THandle;
  Var anInfo: TShellExecuteInfo;
  Begin
    ZeroMemory(@anInfo, SizeOf(anInfo));
    anInfo.cbSize := SizeOf(anInfo);
    anInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
    anInfo.Wnd := FormWnd;
    anInfo.lpVerb := 'Open';
    anInfo.lpFile := PChar(ExePath);
    anInfo.nShow := SW_SHOWNORMAL;
    If Not ShellExecuteEx(@anInfo) Then Abort;
    Result := anInfo.hProcess;
    Win32Check(WaitForInputIdle(Result, INFINITE) <> $FFFFFFFF);
  End;

Var
  pID, pHndl: THandle;
  rBuff: PRemoteBuff;
  aHwnd: HWND;
Begin
  pHndl := 0;
  pID := GetWindowProcessIDByTopmostWindowClass('RegEdit_RegEdit', aHwnd);
  If pId = 0 Then
    If GetLastError = ERROR_FILE_NOT_FOUND Then
    Begin
      pHndl := ShellExecuteAndWaitForIdle('regedit.exe');
      pID := GetWindowProcessIDByTopmostWindowClass('RegEdit_RegEdit', aHwnd);
      Win32Check(pID <> 0);
    End Else RaiseLastWin32Error
  Else pHndl := OpenProcess(PROCESS_ALL_ACCESS, False, pID);
  Win32Check(pHndl <> 0);
  Try
    If IsIconic(aHwnd) Then ShowWindow(aHwnd, SW_Restore);
    SetForegroundWindow(aHwnd);

    aHwnd := GetChildTreeView(aHwnd);
    Win32Check(aHwnd <> 0);

    rBuff := VirtualAllocEx(pHndl, Nil, SizeOf(rBuff), MEM_COMMIT, PAGE_READWRITE);
    Win32Check(rBuff <> Nil);
    Try
      If Not MakeFintInAnotherProcess(pHndl, rBuff, aHwnd, 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\' + aServiceName) Then
        Raise Exception.Create('Error dialing with Regedit ;-)');
    Finally
      Win32Check(VirtualFreeEx(pHndl, rBuff, 0, MEM_RELEASE) <> Nil);
    End;
  Finally
    CloseHandle(pHndl);
  End;
End;

---
В задаче обошлось текущим процессом. Был ещё один касяк у... 26.12.06 17:55  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
В задаче обошлось текущим процессом. Был ещё один касяк у меня: в pszText не ложил ссылку на существующий буфер
	char   buf[200];
	TVITEM tvi;
	...........
	tvi.hItem = TreeView_GetSelection(hwndTree);
	tvi.mask  = TVIF_TEXT;					// команда на получение текста
	tvi.cchTextMax = 40;					// максимум 40 символов
	tvi.pszText = buf;					// буфер для текста
	TreeView_GetItem(hwndTree, &tvi)

---
Спасибо за код. Читая его у себя касяк и нашёл.
Там все еще забавнее 05.12.06 15:16  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>
> стали утруждать. Поэтому берём VirtualAllocEx (аллоцируем
> память под букаффки в читаемом процессе), шлём соответств.
> мессидж в чужое окно с соотв. указателем на память,
> валидном в ТОМ процессе, а потом читаем чужое адресное
> пространство с помощью ReadProcessMemory(). И не забываем,

Как минимум WM_GETTEXT (скорее всего и common control-ы тоже) смотрит чтобы окно принадлежало тому же процессу, что и поток, пославший оный gettext. Если процессы разные - текст не копируется вообще. Единственный реальный способ - CreateRemoteThread-выделение памяти-получение строки-копирование через WriteProcessMemory в родительский процесс
В своё время писал софтину, которая открывает regedit на нужном ключе реестра. Там нет RemoteThread, есть только то, о чём я говорил выше. 06.12.06 08:13  
Автор: HandleX <Александр М.> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>
Ну значит Common Control-ы не проверяют процесс. А зря. Если любой процесс может выставить буфером-приемником любой адрес в адресном пространстве жертвы, то завалить такую апликуху - раз плюнуть 06.12.06 15:04  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2022 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach