Blog. Just Blog

Получение списка иконок в трее

Версия для печати Добавить в Избранное Отправить на E-Mail 18.07.2010 | Категория: Образ мышления: Assembler | Автор: ManHunter
Иногда приложению требуется получить список иконок, находящихся в трее, а также список приложений, которые их туда разместили. Это может быть нужно для обнаружения некоторых скрывающихся приложений, для эмуляции кликов на иконках, ну или просто для спортивного интереса. В любом случае для получения списка иконок надо сделать следующее: найти в трее панель с иконками, при помощи сообщения TB_BUTTONCOUNT получить количество иконок, а затем через отправку сообщения TB_GETBUTTON получить всю необходимую информацию по каждой иконке. Теперь рассмотрим все шаги подробнее.

Работать с вложенными окнами трея мы уже умеем, здесь практически то же самое, разница только в названиях классов дочерних окон.
  1. ; Сегмент данных
  2. section '.data' data readable writeable 
  3. ...
  4. class1  db 'Shell_TrayWnd',0    ; Название класса окна трея
  5. class2  db 'TrayNotifyWnd',0    ; Название класса панели уведомлений
  6. class3  db 'SysPager',0         ; Трей
  7. class4  db 'ToolbarWindow32',0  ; Панель с иконками
  8.  
  9. ToolbarHandle   dd ?            ; Хэндл окна с иконками
  10. ...
  11. ; Сегмент кода
  12. section '.code' code readable executable
  13.         ...
  14.         ; Найти окно трея
  15.         invoke  FindWindow,class1,NULL
  16.         or      eax,eax
  17.         jz      exit_process
  18.  
  19.         ; Найти панель уведомлений
  20.         invoke  FindWindowEx,eax,NULL,class2,NULL
  21.         or      eax,eax
  22.         jz      exit_process
  23.  
  24.         ; Найти трей
  25.         invoke  FindWindowEx,eax,NULL,class3,NULL
  26.         or      eax,eax
  27.         jz      exit_process
  28.  
  29.         ; Найти панель иконок в трее
  30.         invoke  FindWindowEx,eax,NULL,class4,NULL
  31.         or      eax,eax
  32.         jz      exit_process
  33.  
  34.         ; Сохранить хэндл окна с иконками
  35.         mov     [ToolbarHandle],eax
  36.         ...
Теперь у нас есть хэндл окна панели инструментов с иконками в трее. Получим количество иконок в панели.
  1.         ; Получить количество иконок в трее
  2.         invoke  SendMessage,eax,TB_BUTTONCOUNT,0,0
  3.         or      eax,eax
  4.         jz      exit_process
  5.  
  6.         ; Сохранить количество иконок в трее
  7.         mov     [IconsCount],eax
Количество иконок тоже есть. Осталось перебрать их в цикле и получить всю необходимую информацию. Для этого используется сообщение TB_GETBUTTON и структура TBBUTTON для получения результата. Однако, если сейчас попробовать послать окну панели сообщение TB_GETBUTTON, то в результате не получим ничего. Почему? Потому что память, в которую будут записываться данные, обязательно должна принадлежать процессу, который является владельцем окна трея (обычно это explorer.exe).

Ненадолго отвлечемся от трея и выделим блок памяти нужного размера в контексте процесса-владельца трея. Размер блока равен размеру структуры TBBUTTON.
  1.         ; Получить ID процесса-владельца трея
  2.         invoke  GetWindowThreadProcessId,[ToolbarHandle],ProcId
  3.         ; Открыть процесс с полным доступом
  4.         invoke  OpenProcess,PROCESS_ALL_ACCESS,FALSE,[ProcId]
  5.         or      eax,eax
  6.         ; Фокус не удался
  7.         jz      exit_process
  8.  
  9.         ; Сохранить хэндл процесса-владельца трея
  10.         mov     [hProcess],eax
  11.  
  12.         ; Выделить блок памяти в контексте процесса
  13.         invoke  VirtualAllocEx,[hProcess],NULL,dword sizeof.TBBUTTON,\
  14.                 MEM_COMMIT,PAGE_READWRITE
  15.         or      eax,eax
  16.         jz      exit_process
  17.  
  18.         ; Сохранить указатель на блок памяти
  19.         mov     [lpData],eax
Теперь все готово для приема данных, можно приступать к перебору иконок в трее. В структуре TBBUTTON двойное слово dwData - указатель на блок расширенных данных, которые определяются приложением. В нашем случае по этому адресу лежит структура EXTRADATA, не описанная в FASM:
  1. ; Структура пользовательских данных иконки
  2. struct EXTRADATA
  3.         Wnd dd ?  ; Хэндл родительского окна иконки
  4.         uID dd ?  ; Стиль отображения иконки
  5. ends
Поскольку все нужные данные находятся в другом процессе, читать их будем через функцию ReadProcessMemory: сперва структуру TBBUTTON, а затем соответствующую ей структуру EXTRADATA. Зная хэндл окна-владельца каждой иконки, можно получить идентификатор процесса, которому принадлежит окно, а по нему, в свою очередь, можно узнать имя исполняемого файла. Для получения имени есть несколько методов, в этом примере я буду использовать функцию CreateToolhelp32Snapshot.
  1.         ; Перебрать все иконки в трее
  2. loc_loop:
  3.         dec     [IconsCount]
  4.  
  5.         ; Получить иконку из трея с индексом IconsCount
  6.         invoke  SendMessage,[ToolbarHandle],TB_GETBUTTON,[IconsCount],[lpData]
  7.         ; Прочитать структуру иконки
  8.         invoke  ReadProcessMemory,[hProcess],[lpData],button,\
  9.                 dword sizeof.TBBUTTON,BytesRead
  10.         or      eax,eax
  11.         jz      exit_process
  12.         ; Прочиталась вся структура?
  13.         cmp     [BytesRead],sizeof.TBBUTTON
  14.         jnz     exit_process
  15.  
  16.         ; Прочитать пользовательские данные иконки
  17.         invoke  ReadProcessMemory,[hProcess],[button.dwData],extra,\
  18.                 dword sizeof.EXTRADATA,BytesRead
  19.         or      eax,eax
  20.         jz      exit_process
  21.         ; Прочиталась вся структура?
  22.         cmp     [BytesRead],sizeof.EXTRADATA
  23.         jnz     exit_process
  24.  
  25.         ; Это скрытая иконка?
  26.         mov     eax,[extra.uID]
  27.         and     eax,80000000h
  28.         or      eax,eax
  29.         ; Да, пропустить
  30.         jnz     loc_loop
  31.  
  32.         ; Окно процесса существует?
  33.         invoke  IsWindow,[extra.Wnd]
  34.         or      eax,eax
  35.         jz      loc_loop
  36.  
  37.         ; Получить Id процесса, чья иконка находится в трее
  38.         invoke  GetWindowThreadProcessId,[extra.Wnd],ProcTrayId
  39.  
  40.         ; Снимок процессов системы
  41.         invoke  CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
  42.         mov     ebx,eax
  43.  
  44.         ; Перебрать в цикле все процессы
  45.         mov     eax,sizeof.PROCESSENTRY32
  46.         mov     [ProcEntry.dwSize],eax
  47.         invoke  Process32First,ebx,ProcEntry
  48. @@:
  49.         cmp     eax,FALSE
  50.         je      @f
  51.         ; Это нужный нам процесс?
  52.         mov     eax,[ProcEntry.th32ProcessID]
  53.         cmp     eax,[ProcTrayId]
  54.         je      @f
  55.         ; Следующий процесс
  56.         invoke  Process32Next,ebx,ProcEntry
  57.         or      eax,eax
  58.         jz      loc_loop
  59.         jmp     @b
  60. @@:
  61.         push    eax
  62.         ; Закрыть хэндл
  63.         invoke  CloseHandle,ebx
  64.         pop     eax
  65.  
  66.         ; Имя файла определить не удалось
  67.         or      eax,eax
  68.         jz      @f
  69.  
  70.         invoke  wsprintf,buff,mask,ProcEntry.szExeFile
  71.         add     esp,12
  72.  
  73.         ; Записать имя файла в консоль
  74.         invoke  lstrlen,buff
  75.         invoke  WriteConsole,[stdout],buff,eax,BytesRead,NULL
  76. @@:
  77.         ; Все иконки обработали?
  78.         cmp     [IconsCount],0
  79.         ja      loc_loop
  80.  
  81.         ; Очистить память и ресурсы
  82.         invoke  VirtualFreeEx,[ProcId],[lpData],0,MEM_RELEASE
  83.         invoke  CloseHandle,[ProcId]
Описанный метод протестирован и гарантированно работает в Windows XP и Windows 7, но не работает в альтернативных оболочках типа Aston Desktop, потому что в них используются другие названия классов окон и их иерархия.

В приложении консольная программа с исходником, выводящая на экран список исполняемых файлов всех приложений, иконки которых видны в трее.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Tray.Applications.Listing.Demo.zip (3,501 bytes)


Просмотров: 429 | Комментариев: 7

Комментарии

Отзывы посетителей сайта о статье
ManHunter (28.07.2010 в 10:15):
Дублируй, я не против.
umka (28.07.2010 в 10:00):
А можно на Delphi продублировать???
В принципе, понятно, но есть пару мест...
Спасибо.
ManHunter (19.07.2010 в 19:36):
Прислали ответ:

Уважаемый [skipped],
Ваш запрос был проанализирован. Это ложное срабатывание. Исправлено.
Спасибо за сотрудничество.
--
С уважением,
Служба вирусного мониторинга ООО "Доктор Веб"
Isaev (18.07.2010 в 21:09):
Это паранойя у него... из-за ReadProcessMemory видимо
ManHunter (17.07.2010 в 15:27):
Ладно, тогда пока не разрулится ситуация, в аттаче будет только исходник без исполняемого файла. Какой-то клинический, блин, случай.
alek64 (17.07.2010 в 15:23):
все равно ругается :)
Trojan.DownLoader1.15057
ManHunter (17.07.2010 в 11:46):
Как выяснилось, DrWeb почему-то считает скомпилированный файл вирусом. Ща отправлю вебовцам, пусть исправляют.
http://www.virustotal.com/ru/a...e-1279352768
Спасибо alek64 за информацию. Чуток подправил код, теперь порядок :)

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п. будут удаляться. Злостным нарушителям доступ к сайту может быть заблокирован.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
Copyright © ManHunter / PCL
При использовании материалов ссылка на сайт обязательна
Время генерации: 0,17 сек. MySQL: 2 (0,002 сек.)
Наверх