Якщо ваш X-сервер не підтримує XResQueryClientIds
з розширенням v1.2 X-ресурсів я не знаю простий спосіб надійно запросити ідентифікатор процесу. Однак є й інші способи.
Якщо у вас просто вікно перед собою і ще не знаєте його посвідчення особи - це легко знайти. Просто відкрийте термінал поруч із відповідним вікном, запустіть xwininfo
його та натисніть на це вікно. xwininfo
покаже вам вікно-ідентифікатор.
Тож припустимо, що ви знаєте ідентифікатор вікна, наприклад 0x1600045, і хочете знайти, який процес має його.
Найпростіший спосіб перевірити, кому належить це вікно - це запустити для нього XKillClient, тобто:
xkill -id 0x1600045
і подивіться, який процес щойно загинув. Але тільки якщо ви не проти вбити це, звичайно!
Ще один простий, але ненадійний спосіб - перевірити його _NET_WM_PID
та WM_CLIENT_MACHINE
властивості:
xprop -id 0x1600045
Ось які інструменти люблять xlsclients
і xrestop
роблять.
На жаль, ця інформація може бути невірною не лише тому, що процес був злим і змінив їх, а й тому, що він баггі. Наприклад, після деякої аварії / перезавантаження Firefox я бачив осиротілих вікон (з флеш-плагіну, я думаю) із _NET_WM_PID
вказівкою на процес, який давно помер.
Альтернативний спосіб - бігти
xwininfo -root -tree
і перевірити властивості батьків відповідного вікна. Це також може дати вам підказки щодо походження вікон.
Але! Хоча ви можете не знайти, який процес створив це вікно, все ж є спосіб знайти, звідки цей процес підключився до X-сервера. І такий шлях - для справжніх хакерів. :)
Ідентифікатор вікна 0x1600045, який ви знаєте з нульовими бітами (тобто 0x1600000), є "клієнтською базою". І всі ідентифікатори ресурсів, виділені для цього клієнта, "базуються" на ньому (0x1600001, 0x1600002, 0x1600003 тощо). X-сервер зберігає інформацію про своїх клієнтів у масиві client [], а для кожного клієнта його "база" зберігається у змінній client [i] -> clientAsMask. Щоб знайти X-socket, відповідний цьому клієнту, вам потрібно підключитися до X-сервера gdb
, пройти по масиву client [], знайти клієнта з цим clientAsMask
і надрукувати його дескриптор сокета, що зберігається в ((OsCommPtr) (clients [i] - > osPrivate)) -> fd.
Можливо, підключено багато 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-сервера з INSIDE 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-дистрибуцій або -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" з id-процесом 7725
2017 Редагувати : Існує більше варіантів, як видно на сайті Хто має інший кінець цієї unix-сокета? . У версії Linux 3.3 або вище та lsof
версії 4.89 або вище, ви можете замінити пункти 3–5 вище:
lsof +E -a -p 1237 -d 31
щоб дізнатись, хто знаходиться на іншому кінці сокета на fd 31 процесу X-сервера з ідентифікатором 1237.