Сейчас на форуме: UniSoft, laslo, bartolomeo (+5 невидимых)

 eXeL@B —› Программирование —› Висячая консоль и как с этим бороться
Посл.ответ Сообщение


Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 04 августа 2011 18:13 · Поправил: DenCoder
· Личное сообщение · #1

UPD. Под "висячей" консолью здесь имеется ввиду окно-консоль, адекватно обрабатывающее WM-сообщения, кроме как минимум WM_CLOSE, хотя процессов, к которым оно было присоединено, уже нет.

UPD2. WinXP SP3 x86. csrss.exe и winsrv.dll 5.1.2600.5512. Не были использованы wowexec, ntvdm и какие-либо вообще эмуляторы

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

Code:
  1. @echo off
  2. goto run
  3. :run
  4. time /t
  5. ping -2 -1 -60 ya.ru
  6. goto run


Создал ярлык на него и... периодически, в 20-30% случаев, если консоль работает достаточно долго (может быть это с её буфером связано, который увеличен до 5000 строк), то её не закрыть. То ли это баг винды (WinXP SP3), то ли следствие кривой заплатки, но нажимаем на красный крестик консольного окна с пингами, cmd.exe и ping.exe завершаются, а окно висит. Да к тому же перезагрузиться после такого без резета не получается. Много раз хотел отладчиком как-нибудь подсоединиться в тот самый момент, когда окну шлётся WM_CLOSE, но чтобы при этом проявил себя как раз этот самый баг... Не представляю, как это осуществимо...

И вот вчера проявилось опять то же самое. Надоело терпеть глюки винды, поэтому взял Process Explorer. Как известно, у консольных окон процесс-владелец csrss.exe, значит у него должны быть оконные процедуры для консолек. Чуть позже я узнал, что обработка сообщений консолей в winsrv.dll. К тому же через csrss.exe происходит запуск/завершение процессов. Первое, что в голову пришло - какой-то из двух процессов (cmd или ping) до конца не завершился, не отсоединил консоль - вот и результат. Process Explorer'ом навёл на csrss - полно хэндлов работающих процессов и среди них <Non-existent process>:pid... Чем хорош Process Explorer - это тем, что показывает адрес объекта в ядре(на lower pane в режиме Handles - меню View->Lower pane->Handles), для процесса - EPROCESS. Отладчиком WinDbg идём в local kernel debugging и смотрим, что по этому адресу... К сожалению, я так и научил его дружить нормально с символами, поэтому не всегда в нём могу получить описание нужной структуры. Поэтому пришлось для этого воспользоваться идой. Хотя, видно, символы не те, потому что ида из сети достаёт гораздо лучше, чем те, которые скачал когда-то(к примеру, nt!PspTerminateProcess в символах для ntoskrnl.exe нет, но ида достаёт те, в которых есть).

Итак, первое, что можно увидеть - в _EPROCESS._KPROCESS._DISPATCHER_HEADER.SignalState - 1. То есть тот самый Non-existent process, всё-таки завершился, но его EPROCESS почему-то не убрался из списка. По каким причинам, гадать можно долго. Ради интереса узнаём, что это был за процесс - в _EPROCESS.ImageFileName прописано ping.exe. Вероятно, это и есть виновник - не отсоединился вовремя от консоли... Вместе с коллегой придумывали разные варианты, теоретически, как исправить ситуацию. Но отсутствие у нас в символах PspTerminateProcess заставило изменить стратегию. Повисло ведь окно, значит надо выяснить почему... В winsrv.dll, чьё апи юзает csrss.exe, наткнулся на несколько интересных функций. Среди них ConsoleClientConnectRoutine, ConsoleClientDisconnectRoutine, RemoveConsole... ConsoleWindowProc - кажется то, что надо. Нашли, что у консольного окна сначала получается USER_DATA: pUserData = GetWindowLong(hWnd, GWL_USERDATA); которая является адресом какой-то структуры. Для WM_CLOSE по смещению 0x140 в ней сначала проверяются флаги, и если один из них false, то HandleCtrlEvent в конце концов добавляет флаг 4 по смещению 0x1B8... Мы ждали более логичного конца типа DestroyWindow, а тут... Искать и перебирать все возможные обращения к этому флагу с проверкой оказалось утомительным - их было много... Эксперименты с этим флагом тоже ничего не дали... Тогда может быть pUserData + 0x140 что-нибудь даст? Провёл пару экспериментов - установка тех или иных флагов вызывал глюки отображения окна консоли, сброс возвращал окно к прежнему виду... хм... Взведение всех флагов избавило от проблемы - консоль наконец закрылась Ну на всякий случай вернул всё обратно, мало ли что. Таким образом, код завершения такого повисшего окна примерно такой:

Code:
  1. LONG pUserData = GetWindowLong(hWnd, GWL_USERDATA);
  2. DWORD pid;
  3. GetWindowThreadProcessId(hWnd, &pid);
  4. HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid);
  5. DWORD dwOldFlags, dwNewFlags = -1;
  6. ReadProcessMemory(hProcess, (void*)(pUserData + 0x140), &dwOldFlags, 4, NULL);
  7. WriteProcessMemory(hProcess, (void*)(pUserData + 0x140), &dwNewFlags, 4, NULL);
  8. SendMessage(hWnd, WM_CLOSE, NULL, NULL);
  9. dwValue = 0x090800;
  10. WriteProcessMemory(hProcess, (void*)(pUserData + 0x140), &dwOldFlags, 4, NULL);
  11. CloseHandle(hProcess);


Единственное что - прозевал, нужен ли SendMessage... Дождусь очередного проявления бага - поисследую основательней... надеюсь

-----
IZ.RU




Ранг: 369.8 (мудрец), 400thx
Активность: 0.390
Статус: Участник

Создано: 04 августа 2011 18:22
· Личное сообщение · #2

Интересное исследование. Я тоже встречался с висячей консолью, но руки не доходили разобраться. Встроить бы ваш код в --> ProcessHacker <--, получилась бы полезная фича. Напишите его автору, возможность килять висячие консоли лишней не будет.

З.Ы. были бы все глюки винды такими безобидными...

-----
PGP key <0x1B6A24550F33E44A>





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 04 августа 2011 18:39
· Личное сообщение · #3

Да пока неполные исследования. Самое главное - установить возможные причины более конкретно.

-----
IZ.RU





Ранг: 307.9 (мудрец), 196thx
Активность: 0.180
Статус: Участник

Создано: 04 августа 2011 19:06
· Личное сообщение · #4

До кучи: http://www.nirsoft.net/utils/what_is_hang.html

-----
Don_t hate the cracker - hate the code.





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 04 августа 2011 19:21
· Личное сообщение · #5

mysterio пишет:
До кучи: http://www.nirsoft.net/utils/what_is_hang.html


На nirsoft пишут:
the user interface abruptly stops responding

В нашём случае консоль при этом реагирует адекватно почти на все действия. Кроме того, что её закрыть нельзя. "Висячая" консоль - не в смысле, что висит процесс, связанный с ней и консоль никак не реагирует, а наоборот, процессов уже нет, а консоль живёт своей жизнью.

P.S. Если б повесился csrss(здесь - в прямом, распространённом смысле), то только reset.

-----
IZ.RU





Ранг: 307.9 (мудрец), 196thx
Активность: 0.180
Статус: Участник

Создано: 04 августа 2011 19:31
· Личное сообщение · #6

DenCoder
Еще один утиль не помешает ;) Хуже от него не будет - авось кому да пригодится.

P.S. Иногда когда "висит" консоль (cmd) то обычно еще муляет процесс "wowexec.exe".

-----
Don_t hate the cracker - hate the code.





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 04 августа 2011 19:50
· Личное сообщение · #7

Нашёл в реестре HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems
Ключ Windows
Code:
  1. %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16


Вероятно, от некоторых значений параметров в ключе зависит работа консолей. А также вижу возможность заменить winsrv.dll заменить на другую... Только, похоже, она связана с basesrv.dll, так что там же менять и её... если, конечно, это имеет смысл...

-----
IZ.RU





Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 04 августа 2011 20:55 · Поправил: reversecode
· Личное сообщение · #8

а пинг именно в такой комбинации time ping goto ? а просто ping ?
у меня просто ping -t google.com запускается каждый день в течении нескольких лет подряд
и висит по 20 часов в день, и ничего подобно описаного не наблюдается вроде

ping правда запущен постоянно с окна far, а не с самой cmd
но в процессах он через cmd виден




Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 04 августа 2011 21:20
· Личное сообщение · #9

Да, именно в такой комбинации. Просто ping не проверял... Этот баг вообще трудно как поймать, так и спровоцировать. Пытаюсь, пытаюсь ))

-----
IZ.RU





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 24 августа 2011 07:32 · Поправил: DenCoder
· Личное сообщение · #10

Приём, описанный выше, хоть и грубый, но самый быстрый. Чего ещё? Вроде можно б было и закрыть темку... ан нет, упомяну две вещи:

1)
Code:
  1. struct CSR_PROCESS
  2. {
  3.   CLIENT_ID ClientId;
  4.   LIST_ENTRY ListLink;
  5.   LIST_ENTRY ThreadList;
  6.   CSR_PROCESS *Parent;
  7.   CSR_NT_SESSION *NtSession;
  8.   int ExpectedVersion;
  9.   int ClientPort;
  10.   int ClientViewBase;
  11.   int ClientViewBounds;
  12.   int ProcessHandle;
  13.   int SequenceNumber;
  14.   int Flags;
  15.   int DebugFlags;
  16.   int ProcessGroupId;
  17.   int ProcessGroupSequence;
  18.   int ReferenceCount;
  19.   int fVDM;
  20.   int LastMessageSequence;
  21.   int NumOutstandingMessages;
  22.   int ThreadCount;
  23.   LUID Luid;
  24.   int ShutdownFlags;
  25.   int ShutdownLevel;
  26.   int ServerDllPerProcessData[4];
  27. };


Это единственно близкая к правде структура для Windows XP SP3, которой нет в W2K и которая на реактос просто перетасована(как и некоторые другие структуры)...

2) В Windows время создания тредов назначается, оказывается, от 1 января 1601 года с точностью до 100 наносекунд... И если вдруг в _ETHREAD треда, пославшего LPC, время не сходится - то это достаточная причина, чтобы повесить консоль... Хотя по мере исследований ещё штук 5 насчитал

-----
IZ.RU



 eXeL@B —› Программирование —› Висячая консоль и как с этим бороться
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати