Если ваш X-сервер не поддерживает XResQueryClientIds
с расширением v1.2 X-ресурсов я не знаю простой способ надежно запросить идентификатор процесса. Однако есть и другие способы.
Если у вас просто есть окно перед вами и вы еще не знаете его идентификатор - это легко узнать. Просто откройте терминал рядом с рассматриваемым окном, запустите xwininfo
его и нажмите на это окно. xwininfo
покажет вам идентификатор окна.
Итак, давайте предположим, что вы знаете идентификатор окна, например, 0x1600045, и хотите узнать, каков процесс, которым он принадлежит.
Самый простой способ проверить, кому принадлежит это окно, - запустить для него XKillClient, то есть:
xkill -id 0x1600045
и посмотреть, какой процесс только что умер. Но только если вы не против убить его, конечно!
Другой простой, но ненадежный способ - проверить его _NET_WM_PID
и WM_CLIENT_MACHINE
свойства:
xprop -id 0x1600045
Это то, что инструменты любят xlsclients
и xrestop
делают.
К сожалению, эта информация может быть неверной не только потому, что процесс был злым и изменил их, но и потому, что он был ошибочным. Например, после некоторого сбоя / перезапуска Firefox я видел осиротевшие окна (я полагаю, из плагина flash) с _NET_WM_PID
указанием на процесс, который давно умер.
Альтернативный способ - бежать
xwininfo -root -tree
и проверьте свойства родителей рассматриваемого окна. Это также может дать вам некоторые советы о происхождении окна.
Но! Хотя вы можете не узнать, какой процесс создал это окно, все же есть способ узнать, откуда этот процесс подключился к X-серверу. И этот путь для настоящих хакеров. :)
Идентификатор окна 0x1600045, который вы знаете с нулевыми младшими битами (т. Е. 0x1600000), является «клиентской базой». И все идентификаторы ресурсов, выделенные для этого клиента, «основаны» на нем (0x1600001, 0x1600002, 0x1600003 и т. Д.). X-сервер хранит информацию о своих клиентах в массиве clients [], а для каждого клиента его «база» хранится в переменной clients [i] -> clientAsMask. Чтобы найти X-сокет, соответствующий этому клиенту, вам нужно подключиться к X-серверу с помощью gdb
, пройтись по массиву clients [], найти клиент с этим clientAsMask
и напечатать его дескриптор сокета, хранящийся в ((OsCommPtr) (clients [i] - > osPrivate)) -> ФД.
Может быть подключено много X-клиентов, поэтому, чтобы не проверять их все вручную, давайте воспользуемся функцией gdb:
define findclient
set $ii = 0
while ($ii < currentMaxClients)
if (clients[$ii] != 0 && clients[$ii]->clientAsMask == $arg0 && clients[$ii]->osPrivate != 0)
print ((OsCommPtr)(clients[$ii]->osPrivate))->fd
end
set $ii = $ii + 1
end
end
Когда вы найдете сокет, вы можете проверить, кто к нему подключен, и, наконец, найти процесс.
ВНИМАНИЕ : НЕ подключайте GDB к X-серверу изнутри X-сервера. GDB приостанавливает процесс, к которому он присоединяется, поэтому, если вы подключитесь к нему изнутри X-сессии, вы заморозите свой X-сервер и не сможете взаимодействовать с GDB. Вы должны либо переключиться на текстовый терминал ( Ctrl+Alt+F2
), либо подключиться к своей машине через ssh.
Пример:
Найдите PID вашего X-сервера:
$ ps ax | grep X
1237 tty1 Ssl+ 11:36 /usr/bin/X :0 vt1 -nr -nolisten tcp -auth /var/run/kdm/A:0-h6syCa
Идентификатор окна - 0x1600045, поэтому клиентская база - 0x1600000. Подключитесь к X-серверу и найдите дескриптор сокета клиента для этой клиентской базы. Вам понадобится отладочная информация, установленная для X-сервера (пакет -debuginfo для rpm-Distribution или пакет -dbg для deb).
$ sudo gdb
(gdb) define findclient
Type commands for definition of "findclient".
End with a line saying just "end".
> set $ii = 0
> while ($ii < currentMaxClients)
> if (clients[$ii] != 0 && clients[$ii]->clientAsMask == $arg0 && clients[$ii]->osPrivate != 0)
> print ((OsCommPtr)(clients[$ii]->osPrivate))->fd
> end
> set $ii = $ii + 1
> end
> end
(gdb) attach 1237
(gdb) findclient 0x1600000
$1 = 31
(gdb) detach
(gdb) quit
Теперь вы знаете, что клиент подключен к серверному сокету 31. Используйте, lsof
чтобы найти, что это за сокет:
$ sudo lsof -n | grep 1237 | grep 31
X 1237 root 31u unix 0xffff810008339340 8512422 socket
(здесь «X» - это имя процесса, «1237» - его pid, «root» - пользователь, от которого он запускается, «31u» - дескриптор сокета)
Там вы можете увидеть, что клиент подключен по TCP, затем вы можете перейти на компьютер, к которому он подключен, и проверить netstat -nap
там, чтобы найти процесс. Но, скорее всего, вы увидите там сокет Unix, как показано выше, что означает, что это локальный клиент.
Чтобы найти пару для этого сокета Unix, вы можете использовать технику MvG
(вам также понадобится отладочная информация для вашего установленного ядра):
$ sudo gdb -c /proc/kcore
(gdb) print ((struct unix_sock*)0xffff810008339340)->peer
$1 = (struct sock *) 0xffff810008339600
(gdb) quit
Теперь, когда вы знаете клиентский сокет, используйте, lsof
чтобы найти PID, содержащий его:
$ sudo lsof -n | grep 0xffff810008339600
firefox 7725 username 146u unix 0xffff810008339600 8512421 socket
Вот и все. Процесс, сохраняющий это окно, называется «firefox» с идентификатором процесса 7725
Редактирование 2017 : Есть больше вариантов, как видно на сайте Кто получил другой конец этой пары сокетов Unix? , В Linux 3.3 или выше и lsof
4.89 или выше вы можете заменить пункты с 3 по 5 выше:
lsof +E -a -p 1237 -d 31
чтобы узнать, кто находится на другом конце сокета на fd 31 процесса X-сервера с идентификатором 1237.