На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
  
> Список окон , Без использования Winapi :-)
    Итак, сегодня мы окунемся в мир MS, мир недокументированный. Обычно, для получения списка окон или свойств окна мы используем API навроде:
    ExpandedWrap disabled
      EnumWindows();
      GetWindow();
      GetWindowLong();
      GetWindowText();
      SetWindowLong();
      SetWindowText();
      SendMessage(); // (в некоторых случаях. Например, WM_CHANGEUISTATE)


    В данном примере мы используем всего две ф-ции из недр Windows. Одну для получения массива некоторых данных, другую - для удобства (дабы не лезть в ядро).
    Если погуглить, например по слову "ValidateHwnd", то можно найти много информации на эту тему. Однако она весьма разрознена и, хоть и авторы пытались ее развернуть по максимуму, получилось это слабо. Отчего-то многие, по привычке (видимо, на wasm.ru всегда идут в лоб) ищут данные дизассемблированием подсистемы win32k и user32. В принципе, даже нашли универсальные способы (для всех версий WinNT, начиная с win2k) поиска нужных участков кода и получения из него данных. ЕМНИП, способ хоть и железный, но некрасивый. Мы пойдем другим путем.
    Впрочем, без проверки версии ОС нам тоже не обойтись, ибо структура, коей будем пользоваться недокументирована и в ней от версии к версии добавляются/удаляются какие-то поля. Но на мой взгляд - это мелочи, - данные мы получим верные, надо будет только в зависимости от версии ОС их разобрать.

    Итак. Начнем с того, что нам известно.
    Все ф-ции по работе с окошками используют некий описатель HWND, который объявлен как opaque в MSDN и больше там информации нет. На самом деле HWND состоит из двух полей типа USHORT. Старшее слово - это уникальный индекс, который был введен разработчиками MS для внутренних целей, но потом они от него отказались, потому что много софта, писавшегося под win передавали HWND в виде USHORT и этот индекс всегда терялся, поэтому в данный момент он не используется, хотя и всегда добавляется в HWND. Более интересно младшее слово - это индекс в таблице описателей графической подсистемы win32. По этому индексу мы можем получить структуру, описывающую объект. Между прочим, в этой таблице хранятся описатели не только окон, но и:
    - Таймеры; (те самые, что создаются через SetTimer())
    - Меню;
    - Хуки;
    - Данные буфера обмена;
    - Акселлераторы;

    Ну и прочие объекты, в данном моменте нам неинтересные (кому интересно - могут глянуть на сайте reactos, например).
    А вот теперь, самое интересное. Тут, как говорится, есть две новости - одна плохая, другая - хорошая. Данная таблица описателей (точнее объекты, на которые она ссылается) хранится в памяти ядра (конкретнее по адресам 0xbfXXXXXX - зависит от версии ОС, но в winxp sp2/3 там). Но, однако, некоторая часть этой таблицы отображена в user-mode пространство и может быть прочитана (но не изменена!). Этой некоторой части таблицы нам будет достаточно. Во-первых, то, что мы можем подсмотреть - это окна, меню, хуки и еще пара типов объектов. Причем, отображены не все описатели для этих объектов, а только те, которые представлены на текущей для процесса оконной станции (WinStation).
    Ну, для начала этих окон будет достаточно.
    Теперь, задачи перед нами стоят следующие: получить адрес этой таблицы (а она будет в user-mode пространстве), найти указатель на объект по HWND, а затем по этому указателю (который указывает в область ядра) найти указатель на копию объекта в user-mode.
    Начнем с первого: получим адрес таблицы. В гуглах обычно пишут следующее: для таких-то версий ОС адреса этой таблицы (в user32.dll) такие-то, либо по GetProcAddress ищем такую-то функцию в user32.dll, а там по сигнатурам ищем нужный участок кода и из этого участка получаем адрес этой самой таблицы. Как я уже говорил - эти методы не для нас. Мы же белые люди?
    Для получения адреса этой самой штуки надо подключится к серверу csrss (раньше он отвечал за всю графическую подсистему, сейчас, насколько мне известно, из него вынули б0льшую часть функционала и перенесли в другие места). Несмотря на то, что user32 при инициализации подключается к серверу, мы можем сделать это еще раз и получить свою собственную копию данных.
    Подключение выполняется с помощью недокументированной функции CsrClientConnectToServer. Описание найти в интернете сложно, поэтому приведу его здесь:
    ExpandedWrap disabled
      NTSTATUS
      WINAPI
      CsrClientConnectToServer(
          IN PWSTR ObjectDirectory,  // объектная директория, из которой получать данные
          IN ULONG ServerDllIndex,   // тип запрашиваемой информации
          IN OUT PVOID ConnectionInformation,  // структура, в которой мы получим необходимые данные
          IN OUT PULONG ConnectionInformationLength, // ее длина
          OUT PBOOLEAN CalledFromServer // мы - есть сервер?
          );

    Какие поля тут имеются. Ну во-первых, ObjectDirectory. В нашем случае нас интересуют объекты графической подсистемы, а они хранятся в директории \Windows (не путать с папкой Windows!):
    ExpandedWrap disabled
      #define WINSS_OBJECT_DIRECTORY_NAME     L"\\Windows"

    Тип запрашиваемой информации: объекты USER
    ExpandedWrap disabled
      #define USERSRV_SERVERDLL_INDEX         3


    Структура данных:
    ExpandedWrap disabled
      typedef struct _tagUSERCONNECT
      {
          ULONG ulVersion;        //  Версия подсистемы (как правило это 0x50000000. Хотя на Vista и 7 могло поменяться на 0x60000000, но данный момент меня мало интересовал).
          ULONG ulCurrentVersion;     //  Not required
          DWORD dwDispatchCount;      //  
          SHAREDINFO siClient;        //  А здесь хранится самая важная структура. В интернете упоминания о ней можно найти по названию переменной gSharedInfo.
      } USERCONNECT, *PUSERCONNECT;


    Здесь важно следующее:
    - во-первых, версия должна быть указана обязательно;
    - во-вторых, размер структуры при вызове ф-ции должен _точно_ соответствовать нашей, иначе нам покажут STATUS_UNSUCCESSFUL и больше ничего.
    Если все ОК, то *siClient = FALSE (как правило, ибо мы не сервер CSRSS), в ConnectionInformation запишется требуемая нами информация.

    Итак:
    ExpandedWrap disabled
      // undocumented.cpp
       
      SHAREDINFO gSharedInfo;
      PSERVERINFO gpsi;
       
      BOOL RetreiveSharedInfo()
      {
           ULONG sz = sizeof(USERCONNECT);
           BOOLEAN pserv = FALSE;
           USERCONNECT uc = { 0 };
           uc.ulVersion = 0x50000000;
          
           if ( STATUS_SUCCESS != CsrClientConnectToServer(WINSS_OBJECT_DIRECTORY_NAME, USERSRV_SERVERDLL_INDEX, &uc, &sz, &pserv) )
                 return FALSE;
       
          gSharedInfo = uc.siClient;
          gpsi = uc.psi;
          return TRUE;
      }


    Обратимся к структуре SHAREDINFO:
    ExpandedWrap disabled
      typedef struct tagSHAREDINFO {
          PSERVERINFO psi;        // здесь лежит некоторая интересующая нас информация, см. ниже
          struct _HANDLEENTRY   *aheList;         // таблица описателей
          PVOID *pDispInfo;       // информация о текущем дисплее
          ULONG                  ulSharedDelta;   // Эта дельта - разница между значением указателя на ядро и значением указателя на пользовательскую память (маппинг)
                                                  // Сложно сказать, что это за дельта, но нам она не понадобится.
          LPWSTR pszDllList;      // все нижележащие поля нам неинтересны
       
          WNDMSG awmControl[FNID_END - FNID_START + 1];
       
          WNDMSG DefWindowMsgs;
          WNDMSG DefWindowSpecMsgs;
      } SHAREDINFO, *PSHAREDINFO;



    Далее приведу только часть структуры PSERVERINFO, где лежит информация, которая нам интересна:
    ExpandedWrap disabled
      typedef struct tagSERVERINFO {      // si
          WORD    wRIPFlags;              // RIPF_ flags
          WORD    wSRVIFlags;             // SRVIF_ flags
          WORD    wRIPPID;                // PID of process to apply RIP flags to (zero means all)
          WORD    wRIPError;              // Error to break on (zero means all errors are treated equal)
       
          DWORD   cHandleEntries;         // count of handle entries in array
      } SERVERINFO, *PSERVERINFO;

    Здесь нам интересно поле cHandleEntries, которое обозначает размер таблицы aheList.

    Ну и наконец, что у нас лежит в элементах массива:
    ExpandedWrap disabled
      typedef struct _HANDLEENTRY {
          PVOID   phead;                  /* указатель на объект. Указывает в область ядра!!! */
          PVOID   pOwner;                 /* владелец объекта (процесс или поток) */
          BYTE    bType;                  /* тип объекта (TYPE_WINDOW, TYPE_MENU, etc) */
          BYTE    bFlags;                 /* флаги (например, HANDLEF_DESTROY) */
          WORD    wUniq;                  /* индекс уникальности (не используется) */
      } HANDLEENTRY, *PHE;


    Интересующая нас информация об окне лежит в памяти по указателю phead. Для окна эта структура выглядит следующим образом:
    ExpandedWrap disabled
      typedef struct tagCOMMON_WNDCLASS
      {
          int           cWndReferenceCount; // число окошек, созданных этим классом
          UINT          style;            
          WNDPROC_PWND  lpfnWndProc;      
          int           cbclsExtra;
          int           cbwndExtra;
          HANDLE        hModule;
          PVOID         spicn;
          PVOID         spcur;
          HBRUSH        hbrBackground;
          LPWSTR        lpszMenuName;
          LPSTR         lpszAnsiClassName;  // самое главное - имя класса!
          PVOID         spicnSm;
      } COMMON_WNDCLASS;
       
       
      typedef struct tagCLS {
          struct tagCLS *             pclsNext;           // указатель а следующий класс
          ATOM                        atomClassName;
          WORD                        fnid;              
          PVOID                       rpdeskParent;    /* десктоп */
          PDCE                        pdce;            /* объект DC (Device Context) */
          WORD                        hTaskWow;
          WORD                        CSF_flags;           /* внутренние флаги */
          LPSTR                       lpszClientAnsiMenuName;     /* имя ресурса меню ansi */
          LPWSTR                      lpszClientUnicodeMenuName;  /* имя ресурса меню unicode */
       
          PCALLPROCDATA               spcpdFirst;       /* процедура обработчика */
          struct tagCLS *             pclsBase;        /* Начало массива классов */
          struct tagCLS *             pclsClone;       /* Начало копии массива классов */
       
          BOOL                fFlag;
          COMMON_WNDCLASS             wc;              // пользовательские данные класса (похожа на WNDCLASS, но есть некоторые отличия)
      } CLS, *PCLS, **PPCLS;
       
      typedef struct _WW
      {
          ULONG       state1;
          ULONG       state2;
          DWORD       dwStyleEx;
          DWORD       dwStyle;
          HMODULE     hInstance;
          WORD        hMod16;
          WORD        fnid;
      } WW, *PWW;
       
      typedef struct tagWND {          // wnd
          THRDESKHEAD   head;    // информация о текущем десктопе и потоке, которому принадлежит окошко
       
          WW            ww;       // различная оконная информация: стили, hInstance и т.п.
          struct tagWND *                 spwndNext;    // указатель на объект следующего окна
          struct tagWND *                 spwndPrev;    // ...предыдущего
          struct tagWND *                 spwndParent;  // ...родительского
          struct tagWND *                 spwndChild;   // ...дочернего
          struct tagWND *                 spwndOwner;   // ..."босс" для нашего окна
       
          RECT                 rcWindow;     // размеры окна
          RECT                 rcClient;     // ...и его клиентской части
       
          PVOID                lpfnWndProc;   // указатель на процедуру-обработчика окна
       
          PCLS                 pcls;         // информация о классе окна
       
          HRGN                 hrgnUpdate;   // регион отрисовки
       
          PVOID              ppropList;    // Указатель на PropList (SetProp/GetProp итд)
          PVOID              pSBInfo;   // указатель на данные полос прокрутки
       
          PVOID                spmenuSys;  // Указатель на объект системного меню
          PVOID                spmenu;     // Menu handle or ID
       
          HRGN                 hrgnClip;     // еще один регион для отрисовки
       
          LARGE_UNICODE_STRING strName;      // текст окна (не тот, который задается через WM_SET/GETTEXT, а тот, что через Set/GetWindowText
          int                  cbwndExtra;   // Размер пользовательских данных (Get/SetWindowLong).
          struct tagWND *      spwndLastActive; // Последний активный попап
          HIMC                 hImc;         // input context
          ULONG                dwUserData;   // Пользовательские данный (Get/SetWindowLong(GWL_USERDATA)
      } WND,*PWND;


    Итак, мы все знаем. Осталось только получить указатель на эту структуру в юзер-спэйсе (мы ведь помним, что они хранятся вне адресного пространства юзер-мода, но отмаплены на юзер-память).
    Этот указатель получается следующим образом: есть некая дельта, которую необходимо вычесть из адреса ядра и мы получим валидный адрес в юзер-моде:
    ExpandedWrap disabled
      PWND pwnd = PWND(ULONG(p->phead) - g_uDelta); // <<-- все, здесь мы можем получить доступ к данным

    Несмотря на то, что сервер csrss нам дал какую-то дельту, но, как ни странно - это не она. :) Нужная нам дельта есть в TEB. Приводить структуру TEB я не буду (можно поглядеть на нее здесь. Там нас мало что интересует, кроме поля Win32ClientInfo. По непонятным причинам оно везде обозначено так ULONG Win32ClientInfo[62];. Однако это не массив лонгов, а самая обычная структура, которая выглядит так:
    ExpandedWrap disabled
      #define CVKKEYCACHE                 32
      #define CBKEYCACHE                  (CVKKEYCACHE >> 2)
       
      #define CVKASYNCKEYCACHE            16
      #define CBASYNCKEYCACHE             (CVKASYNCKEYCACHE >> 2)
       
      typedef struct _CLIENTINFO {
          DWORD               CI_flags;               // Needs to be first because CSR
          DWORD               cSpins;
          DWORD               dwExpWinVer;
          DWORD       dwUnknownFlags;
          DWORD               dwCompatFlags;
          DWORD               dwTIFlags;
          PVOID       pDeskInfo;
          ULONG               ulClientDelta;
          PVOID               phkCurrent;
          DWORD               fsHooks;
          CALLBACKWND         CallbackWnd;
          DWORD               dwHookCurrent;
          int                 cInDDEMLCallback;
          HANDLE              hDdemlCallbackInst;
          PVOID               pClientThreadInfo;
          DWORD               dwHookData;
          DWORD               dwKeyCache;
          BYTE                afKeyState[CBKEYCACHE];
          DWORD               dwAsyncKeyCache;
          BYTE                afAsyncKeyState[CBASYNCKEYCACHE];
          BYTE                afAsyncKeyStateRecentDown[CBASYNCKEYCACHE];
          WORD                CodePage;
          HKL                 hKL;
          BYTE                achDbcsCF[2];
          MSG                 msgDbcsCB;
      } CLIENTINFO, *PCLIENTINFO;

    Здесь тоже мало интересного, кроме поля ulClientDelta - это и есть нужная нам дельта. Получим ее так:
    ExpandedWrap disabled
      g_uDelta = PCLIENTINFO(&PTEB(NtCurrentTeb())->Win32ClientInfo)->ulClientDelta;


    Вот теперь мы во всеоружии!
    Тут, правда, необходимо учесть вот что: не все объекты отмаплены в наше пространство, поэтому надо как-то отделить мух от котлет. Для начала вспомним, что мы можем получить информацию только о тех окнах, которые присутствуют на нашем десктопе. В THRDESKHEAD структуры tagWND есть поле rpdesk - указатель на объект десктопа (что там лежит - неважно, важен сам указатель). Будем сравнивать его с указателем окна нашего десктопа (GetDesktopWindow()). Но для того, чтобы коснуться этого, надо написать ту самую ValidateHwnd:
    ExpandedWrap disabled
      PWND ValidateHwnd(HWND hWnd)
      {
           USHORT index = LOWORD(hWnd), wUniq = HIWORD(hWnd);
           if ( index >= 0 && index < gpsi->cHandleEntries )
           {
                  if ( gSharedInfo.aheList[index].bType == TYPE_WINDOW )
                                   return PWND(ULONG(gSharedInfo.aheList[index].phead) - g_uDelta);
           }
           return NULL;
      }


    Разберем структуру THRDESKHEAD:
    ExpandedWrap disabled
      typedef struct _HEAD {
          HANDLE h;        // здесь h = hWnd
          DWORD   cLockObj;
      } HEAD, *PHEAD;
       
      typedef struct _THROBJHEAD {
          HEAD head;
          PVOID pti;      // PTHREADINFO
      } THROBJHEAD, *PTHROBJHEAD;
       
      typedef struct _DESKHEAD {
          PVOID    rpdesk;
          PBYTE    pSelf;
      } DESKHEAD, *PDESKHEAD;
       
      typedef struct _THRDESKHEAD {
          THROBJHEAD thr;
          DESKHEAD deskhead;
      } THRDESKHEAD, *PTHRDESKHEAD;

    И тут есть поле rpdesk, которое нам и нужно.
    Ну что ж, попробуем написать перечисление окошек:
    ExpandedWrap disabled
      void MyEnumWindows()
      {
          HWND hDesktop = GetDesktopWindow();
          PWND pDesktop = ValidateHwnd(hDesktop);
       
          PVOID rpdesk = pDesktop->head.deskhead.rpdesk;
       
          ULONG count = gpsi->cHandleEntries;
          for(ULONG c = 0; c < count; ++c)
          {
                if ( gSharedInfo.aheList[c].bType == TYPE_WINDOW )
                {
                      PWND pwnd = PWND(ULONG(gSharedInfo.aheList[c].phead) - g_uDelta);
                      __try    // здесь поступаем не очень красиво. Если объект не отмаплен в юзер-спейс - он может указать на мусор
                      {
                          if ( pwnd->head.deskhead.rpdesk == rpdesk ) // наше окно! (и здесь возможно исключение, либо какой-нибудь NULL, который будет отсеян)
                          {
                               LPWSTR strName = LPWSTR(ULONG(pwnd->strName.Buffer) - g_uDelta);
                               PCLS pcls = PCLS(ULONG(pwnd->pcls) - g_uDelta); // да-да! Нам придется вычислять смещения для всех указателей структуры!
                               LPSTR strClassname = LPSTR(ULONG(pcls->lpszAnsiClassName) - g_uDelta);
                               printf("Window: hwnd = 0x%08x; class: `%s`; title: `%ws`\n", pwnd->head.thr.h, strClassname, strName);
                          }
                      __except(EXCEPTION_EXECUTE_HANDLER)
                      {
                           // не наше окно :(
                           continue;
                      }
                }
          }
      }

    Реализация перечисления окон не очень хороша. В данном случае, подход в последней процедуре не очень красивый, но хочется сделать побыстрее и покороче. В действительности нужно было бы весьма заковыристыми путями получить десктоп потока (pOwner в HANDLEENTRY, который, кстати, тоже указывает в ядро) и сравнить с десктопом DesktopWindow.

    Пока все. (позже добавлю информацию на тему структуры WW из tagWND, там тоже есть интересная информация). Исходники добавлю позже!

    © ALXR
      Цитата
      видимо, на wasm.ru всегда идут в лоб

      Цитата
      Вот теперь мы во всеоружии!

      Twister, это вы? :)
      А если нет -
      ALXR, хоть для приличия могли бы его упомянуть.
      Ведь вот же как крепко засел у вас в памяти его "Инжект: лезем через окно", аж до прямого заимствования:
      Цитата
      Ну, вот мы и во всеоружии!
        Простите! Генерил по ходу написания статьи. Чесслово, его статьей не пользовался. :) Исключительно свои мысли (но статью его читал, да).
        Пользовался исключительно всем известными текстовыми файлами формата c/cpp + win32dasm.
          ALXR, очень интересно. Спасибо.
            Источник информации не раскрыт :)
              Twister пришел. :)

              ALXR
              Хотел бы сделать некоторые замечания. Дело в том, что структура tagWND неплохо так меняется от версии к версии, поэтому использовать её описание, а не смещения, довольно опасно. Нужные смещения для разных версий могу предоставить, если надо.

              Так же вы утверждаете, что в системе не используется индекс уникальности. Это верно лишь для систем от Висты и выше. Для других эта часть хэндла проверяется и, следовательно, должна быть учтена нами.

              Далее. Сейчас (точнее уже давно) мне известен способ получения структуры SharedInfo через CsrClientConnectToServer(), но на момент написания статьи про инжект я до этого не дорыл. Так что извиняйте - чем были богаты, тому были и рады. :)

              Еще могу предоставить вот какую инфу, наверняка Вы с этим еще не столкнулись. Совершенно верно то, что в юзерспейс отмаплена таблица окон текущей Windowstation, соответственно там содержатся окна всех ёё десктопов. Но пройтись по окнам чужих десктопов вам не удастся даже переключив соответствующий поток на целевой десктоп. Дело в том, что указатель spwndChild не заполнен для чужих десктоп-окон (те, что получаются с помощью GetDesktopWindow). Я был сильно поражен, узнав о такой вот "безопасности". В ядре, однако, все заполнено и прекрасно читается. Так же поле ulClientDelta будет невалидно для окон чужих десктопов. Так что если вы захотите написать браузер всех окон, то использовать придется драйвер.

              Я когда-то начал писать такую утилиту, но квартирная кража способствовала утере исходников, так что чудом уцелела лишь не самая свежая версия, да и то в бинарном виде. Можете оценить: hxxp://slil.ru/28861826. Правда она не будет работать под w7 и vista sp2.

              Цитата
              позже добавлю информацию на тему структуры WW из tagWND, там тоже есть интересная информация


              Там, на мой взгляд, интересны лишь стили окон и сам принцип их хранения. Правда изменить их методом DKOM у меня так и не получилось, система сразу синела.

              B.V.
              Салют, сто лет не виделись! :)

              Цитата
              Источник информации не раскрыт


              Скорее всего это сорцы ReactOS (в wrk нет исходников win32k.sys), которые я бы не рекомендовал использовать при исследованиях Windows. Либо это сорцы Windows 2000. Дизассемблированием в трудах ALXR не пахнет, либо я не унюхал :)

              PS. А вообще, информацию по этой теме давно пора обновить. В моей статье, к примеру, есть грубые ошибки. Да и устарела она уже...
              Сообщение отредактировано: _twister -
                _twister, рад, что вы тут появились! Одним системщиком здесь больше, а то и поговорить не с кем. :)

                Цитата _twister @
                Дело в том, что структура tagWND неплохо так меняется от версии к версии, поэтому использовать её описание, а не смещения, довольно опасно. Нужные смещения для разных версий могу предоставить, если надо.

                Совершенно верно, я об этом и писал. :)
                Цитата ALXR @
                Впрочем, без проверки версии ОС нам тоже не обойтись, ибо структура, коей будем пользоваться недокументирована и в ней от версии к версии добавляются/удаляются какие-то поля. Но на мой взгляд - это мелочи, - данные мы получим верные, надо будет только в зависимости от версии ОС их разобрать.

                При описании структуры я об этом не напомнил - моя ошибка, не думаю о читателе.

                Цитата _twister @
                Так же вы утверждаете, что в системе не используется индекс уникальности. Это верно лишь для систем от Висты и выше. Для других эта часть хэндла проверяется и, следовательно, должна быть учтена нами.

                Честно говоря, не нашел мест, где она проверяется. АПИ вполне работает в таком виде GetWindowLong(HWND(LOWORD(hwnd)), GWL_STYLE) например, корректно. Возможно, где-то недоглядел.

                Цитата _twister @
                Далее. Сейчас (точнее уже давно) мне известен способ получения структуры SharedInfo через CsrClientConnectToServer(), но на момент написания статьи про инжект я до этого не дорыл. Так что извиняйте - чем были богаты, тому были и рады. :)

                Не-не, статья действительно уже давно была написана и на это скидку я делаю, конечно. Дело в другом. Информацию о CsrClientConnectToServer я нашел только в одном месте и то оно там случайно оказалось. :)

                Цитата _twister @
                Еще могу предоставить вот какую инфу, наверняка Вы с этим еще не столкнулись. Совершенно верно то, что в юзерспейс отмаплена таблица окон текущей Windowstation, соответственно там содержатся окна всех ёё десктопов. Но пройтись по окнам чужих десктопов вам не удастся даже переключив соответствующий поток на целевой десктоп. Дело в том, что указатель spwndChild не заполнен для чужих десктоп-окон (те, что получаются с помощью GetDesktopWindow). Я был сильно поражен, узнав о такой вот "безопасности". В ядре, однако, все заполнено и прекрасно читается. Так же поле ulClientDelta будет невалидно для окон чужих десктопов. Так что если вы захотите написать браузер всех окон, то использовать придется драйвер.

                Поверьте, столкнулся. И не нашел красивых способов работать с pti (хотя возможно они и есть). Выкручивался в кернел-мод примерно вот так:
                ExpandedWrap disabled
                  if ( !ObOpenObjectByPointer(PTHREADINFO(pt->pti)->w32t.pEThread, 0, NULL, 0, NULL, KernelMode, &hThread) )
                  {
                      THREAD_INFORMATION ti;
                      ULONG len;
                      if ( !ZwQueryInformationThread(hThread, 0, &ti, sizeof(ti), &len) )
                      {
                          pcid[c].UniqueProcess = ti.ClientId.UniqueProcess;
                          pcid[c].UniqueThread = ti.ClientId.UniqueThread;
                      }
                      ZwClose(hThread);
                  }

                Жутко не хотелось работать с еще одной opaque. :(
                Ну и получилось... См. аттач.

                Цитата _twister @
                Там, на мой взгляд, интересны лишь стили окон и сам принцип их хранения. Правда изменить их методом DKOM у меня так и не получилось, система сразу синела.

                Да? Вероятно, какие-то новые значения стилей окна для системы были неожиданностью... Старший байт dwStyleEx я менял и фокус честно переставал отрисовываться. Возможно, так можно менять не все.

                Цитата _twister @
                Скорее всего это сорцы ReactOS (в wrk нет исходников win32k.sys), которые я бы не рекомендовал использовать при исследованиях Windows. Либо это сорцы Windows 2000. Дизассемблированием в трудах ALXR не пахнет, либо я не унюхал :)

                Для упрощения статьи я листинги и рассуждения не приводил. :) Но поковыряться пришлось, ибо 2к это уже не ХР и не виста. :)

                Цитата _twister @
                Я когда-то начал писать такую утилиту, но квартирная кража способствовала утере исходников, так что чудом уцелела лишь не самая свежая версия, да и то в бинарном виде. Можете оценить: hxxp://slil.ru/28861826. Правда она не будет работать под w7 и vista sp2.

                В данный момент я в процессе рефакторинга одной из утилиток на эту тему (BV я ее уже показывал). Если интересно, доведу код до хоть какого-нибудь приличного состояния и можем над ней поработать (если будет время, а у меня оно заканчивается :().

                Ну а что касается сырцов reactos - то сами сырцы действительно мало интересны, но спасибо я им готов сказать за описания некоторых структур плюс дефайны для разных версий Виндовсов.

                Еще раз Welcome! :)
                Прикреплённая картинка
                Прикреплённая картинка
                  Цитата
                  _twister, рад, что вы тут появились! Одним системщиком здесь больше, а то и поговорить не с кем.
                  Спасибо! :) Ну, я на самом деле зарегистрировался здесь еще чёрти когда. Просто не заходил. Сегодня меня уведомили о посте на столь редкую тематику, ну я и не смог обойти это стороной. Пришлось, правда, заюзать восстановление пароля к аккаунту, теперь дата моей регистрации светится как 24.02.10, а сообщение одно (это второе). Вот интересно - что это за глюк такой? Хотя может быть я регистрировался заново.
                  Ну а если о системном програмировании здесь не с кем пообщаться, то почему бы не заглянуть на тот же wasm.ru, forum.sysinternals.com, kernelmode.info? ;)

                  Цитата
                  Честно говоря, не нашел мест, где она проверяется.
                  Ну как же? Проверка есть в ValidateHwnd(), если мне не изменяет память.

                  Цитата
                  Информацию о CsrClientConnectToServer я нашел только в одном месте и то оно там случайно оказалось.
                  А чего там искать-то? Грузим user32 с симвалами в Иду, ищем все места где упоминается g_SharedInfo, находим конкретное место где она заполняется и смотрим откуда берутся данные. Оно и приведет нас к CsrClientConnectToServer(). Прототип ее можно взять в сорцах винды, ну или в крайнем случае в сорцах ReactOS.

                  Цитата
                  Выкручивался в кернел-мод примерно вот так:
                  Много лишних действий, старайтесь заботиться о скорости. :) Смещение ClientId в структуре ETHREAD легко найти для любой версии дизассемблированием PsGetCurrentThreadId():
                  ExpandedWrap disabled
                    .text:004B07E8 _PsGetCurrentThreadId@0 proc near
                    .text:004B07E8                 mov     eax, large fs:124h
                    .text:004B07EE                 mov     eax, [eax+230h] ; <<<
                    .text:004B07F4                 retn
                    .text:004B07F4 _PsGetCurrentThreadId@0 endp


                  Цитата
                  Возможно, так можно менять не все.
                  Возможно, я уже не могу сказать, над чем тогда экспериментировал. Проблему решил вызовом неэкспортируемой функции, что лежит на уровень ниже Shadow SSDT'шной NtUserSetWindowLong().

                  По поводу совместной работы над какой-то утилитой... Врядли. Я месяца полтора назад обещал EP_X0FF сделать для RkU детектор скрытых окон (а то повадились всякие ArtMoney и HideToolz их скрывать), но копеечная работа встала где-то на половине из-за тотальной нехватки времени. В крайнем случае, я всегда могу подсобить советом, либо уже имеющимися исходниками. Да и код своего драйвера от той утерянной утилиты я полностью восстановил в Иде, его могу дать.
                  Сообщение отредактировано: _twister -
                    Буду много признателен, если напишите низкоуровневую функцию для извлечения указателя на текст окна. :rolleyes:
                    А то постоянное копирование через GetWindowText не устраивает. :no:
                      Цитата _twister @
                      А чего там искать-то? Грузим user32 с симвалами в Иду, ищем все места где упоминается g_SharedInfo, находим конкретное место где она заполняется и смотрим откуда берутся данные.

                      Именно так и делал, разве что символы я не грузил, но подизасмил, да. А речь шла про прототип (и поиск в интернетах), да и вообще интересно было как люди ее пользуют. Нашел только на одном каком-то форуме среди обсуждения какой-то сторонней темы.
                      Цитата _twister @
                      Ну как же? Проверка есть в ValidateHwnd(), если мне не изменяет память.

                      Есть. Но условие там весьма условное. По сути оно и не проверяется.

                      Цитата _twister @
                      Много лишних действий, старайтесь заботиться о скорости.

                      Да вот выбирать приходится между скоростью и дизасмом. Очень не хочется прибегать к поиску указателей в коде (а ну его изменят? Поиск по сигнатурам? Зыбко...), разве что когда других путей нет. А вот с хуками (если время будет засесть за них), похоже придется прибегнуть.

                      Цитата _twister @
                      Возможно, я уже не могу сказать, над чем тогда экспериментировал. Проблему решил вызовом неэкспортируемой функции, что лежит на уровень ниже Shadow SSDT'шной NtUserSetWindowLong().

                      Хм. По-моему, даже в ней есть доп проверки, что-то типа if ( 0 != (dwFlagsEx & ~WS_EX_VALIDFALGS) ) RIPERR0(ERROR_INVALID_PARAMETER...)

                      Цитата _twister @
                      В крайнем случае, я всегда могу подсобить советом, либо уже имеющимися исходниками. Да и код своего драйвера от той утерянной утилиты я полностью восстановил в Иде, его могу дать.

                      Дело-то не в исходниках. Дело во времени. :) Я бы и рад выложить, да незамутненным гражданам смотреть там не на что.

                      Цитата AZote @
                      Буду много признателен, если напишите низкоуровневую функцию для извлечения указателя на текст окна. :rolleyes:

                      Ф-ция в первом посте. :) Только не пытайся записать по тому адресу какие-либо данные. GPF схватишь.
                        Цитата ALXR @
                        Ф-ция в первом посте.

                        А можете привести пример извлечения указателя на текст с помошью вашей функции? :blush:
                        Цитата ALXR @
                        Только не пытайся записать по тому адресу какие-либо данные. GPF схватишь.

                        Мне только читать :victory:
                          Там же написано.
                          ExpandedWrap disabled
                                               if ( pwnd->head.deskhead.rpdesk == rpdesk ) // наше окно! (и здесь возможно исключение, либо какой-нибудь NULL, который будет отсеян)
                                                {
                                                     LPWSTR strName = LPWSTR(ULONG(pwnd->strName.Buffer) - g_uDelta);
                                                     PCLS pcls = PCLS(ULONG(pwnd->pcls) - g_uDelta); // да-да! Нам придется вычислять смещения для всех указателей структуры!
                                                     LPSTR strClassname = LPSTR(ULONG(pcls->lpszAnsiClassName) - g_uDelta);
                                                     printf("Window: hwnd = 0x%08x; class: `%s`; title: `%ws`\n", pwnd->head.thr.h, strClassname, strName);
                                                }

                          Вот strName - это оно.
                          НО! Вот что неплохо бы учесть.
                          Цитата ALXR @
                          Впрочем, без проверки версии ОС нам тоже не обойтись, ибо структура, коей будем пользоваться недокументирована и в ней от версии к версии добавляются/удаляются какие-то поля. Но на мой взгляд - это мелочи, - данные мы получим верные, надо будет только в зависимости от версии ОС их разобрать.


                          Цитата _twister @
                          Дело в том, что структура tagWND неплохо так меняется от версии к версии, поэтому использовать её описание, а не смещения, довольно опасно. Нужные смещения для разных версий могу предоставить, если надо.

                          Так что лучше GetWindowText.
                            По поводу смещений:
                            ExpandedWrap disabled
                              procedure InitOffsets();
                              var
                                osvi: _OSVERSIONINFOEXW;
                              begin
                              memzero(@osvi, SizeOf(OSVERSIONINFOEX));
                              osvi.dwOSVersionInfoSize := SizeOf(OSVERSIONINFOEX);
                              RtlGetVersion(@osvi);
                               
                              offs_fnid := $2A;
                              offs_spwndNext := $2C;
                               
                              if osvi.dwBuildNumber >= 6001 then
                                offs_strName := $88
                              else
                                if osvi.dwBuildNumber = 2195 then
                                  offs_strName := $80
                                else
                                  offs_strName := $84;
                               
                              if osvi.dwBuildNumber = 2195 then
                                begin
                               
                                offs_pcls        := $60;
                                offs_lpszAnsiClassName := $50;
                                offs_STATEOFFSET := $0C;
                                offs_spwndParent := $30;
                                offs_spwndChild  := $34;
                                offs_spwndOwner  := $38;
                               
                                end
                              else
                                begin
                               
                                offs_pcls        := $64;
                                offs_lpszAnsiClassName := $54;
                                offs_STATEOFFSET := $10;
                                offs_spwndParent := $34;
                                offs_spwndChild  := $38;
                                offs_spwndOwner  := $3C;
                               
                                end;
                              end;
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0,1105 ]   [ 16 queries used ]   [ Generated: 28.04.24, 01:53 GMT ]