"Определение" потоков в чужом процессе.

Тема в разделе "WASM.WIN32", создана пользователем Rel, 13 окт 2009.

  1. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    Доброго времени суток! У меня есть необходимость копаться в потоках нескольких запущенных процессов, иногда переключать их контекст. Для перечисления потоков написал такую функцию:
    Код (Text):
    1. // В хедере
    2. typedef LONG (WINAPI* PZWQSI)(UINT, PVOID, ULONG, PULONG);         // Указатель на ZwQuerySystemInformation
    3.  
    4. // Совместимость ILP32 и LLP64
    5. #ifdef _WIN64
    6. #define MEMADR LONGLONG
    7. #else
    8. #define MEMADR DWORD
    9. #endif
    10.  
    11. // Информация о клиенте
    12. typedef struct _CLIENT_ID
    13. {
    14.     MEMADR UniqueProcess;
    15.     MEMADR UniqueThread;
    16. } CLIENT_ID, *PCLIENT_ID;
    17.  
    18. // Информация о потоках
    19. typedef struct _SYSTEM_THREADS
    20. {
    21.     LARGE_INTEGER KernelTime;
    22.     LARGE_INTEGER UserTime;
    23.     LARGE_INTEGER CreateTime;
    24.     ULONG         WaitTime;
    25.     PVOID         StartAddress;
    26.     CLIENT_ID     ClientId;
    27.     LONG          Priority;
    28.     LONG          BasePriority;
    29.     ULONG         ContextSwitchCount;
    30.     LONG          State;
    31.     LONG          WaitReason;
    32. } SYSTEM_THREADS, *PSYSTEM_THREAD;
    33.  
    34. // Информация о процессах
    35. typedef struct _SYSTEM_PROCESSES
    36. {
    37.     ULONG          NextEntryDelta;
    38.     ULONG          ThreadCount;
    39.     ULONG          Reserved1[6];
    40.     LARGE_INTEGER  CreateTime;
    41.     LARGE_INTEGER  UserTime;
    42.     LARGE_INTEGER  KernelTime;
    43.     USHORT         ProcessNameLength;
    44.     USHORT         ProcessNameMaxLength;
    45.     PWSTR          ProcessNameBuffer;
    46.     LONG           BasePriority;
    47. #ifdef _WIN64
    48.     ULONG          hz1;
    49.     ULONG          ProcessId;
    50.     ULONG          hz22;
    51.     ULONG          InheritedFromProcessId;
    52.     ULONG          hz3, hz4, hz5;
    53. #else
    54.     ULONG          ProcessId;
    55.     ULONG          InheritedFromProcessId;
    56. #endif
    57.     ULONG          HandleCount;
    58.     ULONG          Reserved2[2];
    59.     VM_COUNTERS    VmCounters;
    60.     IO_COUNTERS    IoCounters;
    61.     SYSTEM_THREADS Threads[1];
    62. } SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
    63.  
    64. // В цпп'шнике
    65. // Перечислить все тиды потоков процесса по пиду процесса
    66. // pid - пид процесса, тиды которого нужно перечислить
    67. // tids - указатель на память (буффер), куда вернуть список тидов
    68. // maxtids - максимальное количество тидов, на которое расчитан буффер
    69. ULONG GetProcessTidsArray(DWORD pid, DWORD* tids, ULONG maxtids)
    70. {
    71.     // Получаем адрес функции ZwQuerySystemInformation из ntdll.dll
    72.     if(m_LibNtdll == NULL) { m_LibNtdll = LoadLibrary(L"ntdll.dll"); }
    73.     PZWQSI pZwQuerySystemInformation = (PZWQSI)GetProcAddress(m_LibNtdll, "ZwQuerySystemInformation");
    74.     if(pZwQuerySystemInformation == NULL) { return 0; }
    75.  
    76.     // Подбираем размер буффера
    77.     PVOID buffer = NULL;
    78.     ULONG buflen = 0x8000;
    79.     ULONG retlen = 0;
    80.     LONG ret = 0;
    81.     do
    82.     {
    83.         buffer = VirtualAlloc(NULL, buflen, MEM_COMMIT, PAGE_READWRITE);
    84.         if(buffer == 0) { return 0; }
    85.  
    86.         ret = pZwQuerySystemInformation(5, buffer, buflen, &retlen);
    87.  
    88.         if(ret == (LONG)0xC0000004L)
    89.         {
    90.             VirtualFree(buffer, buflen, MEM_DECOMMIT);
    91.             buflen = buflen * 2;
    92.         }
    93.         else if(ret != (LONG)0x00000000L)
    94.         {
    95.             VirtualFree(buffer, buflen, MEM_DECOMMIT);
    96.             return 0;
    97.         }
    98.     }
    99.     while(ret == (LONG)0xC0000004L);
    100.  
    101.     // Копаемся в результатах, ищем нужный процесс
    102.     PSYSTEM_PROCESSES pProc = (PSYSTEM_PROCESSES)buffer;
    103.     bool pidfound = false;
    104.     while(1)
    105.     {
    106.         if(pProc->ProcessId == pid)
    107.         { pidfound = true; break; }
    108.         if(pProc->NextEntryDelta == 0) { break; }
    109.         else { pProc = PSYSTEM_PROCESSES((BYTE*)pProc + pProc->NextEntryDelta); }
    110.     }
    111.  
    112.     // Если нужный пид найден - возвращаем тиды массивом
    113.     if(pidfound)
    114.     {
    115.         if(pProc->ThreadCount < maxtids) // Если все влезает - возвращаем все
    116.         {
    117.             for(unsigned int t = 0; t < pProc->ThreadCount; t++)
    118.             { tids[t] = pProc->Threads[t].ClientId.UniqueThread; }
    119.             return pProc->ThreadCount;
    120.         }
    121.         else // Если не влезает, возвращаем то, что влезло
    122.         {
    123.             for(unsigned int t = 0; t < maxtids; t++)
    124.             { tids[t] = pProc->Threads[t].ClientId.UniqueThread; }
    125.             return maxtids;
    126.         }
    127.     }
    128.     else
    129.     { return 0; }
    130. }
    Как бы это алгоритм широко известен и работает, ну да ладно, проблема в другом. Отладчики умеют отличать потоки, разделяя их на: Main Thread, Worker Thread и RPC Thread. Мне было бы полезно уметь делать так же)) Думал, что это происходит по полю State или Priority, однако документации по этому поводу крайне мало, а отладка показала, что мои предположения были ошибочны. Может кто-нить что-нить знает по данному вопросу?))
     
  2. Rustem

    Rustem New Member

    Публикаций:
    0
    Регистрация:
    8 мар 2004
    Сообщения:
    429
    Адрес:
    Russia
    Rel
    По адресу функции потока должны опеределять его принадлежность, а так состояние и приоритет самому потоку изменить можно
     
  3. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    вы имели ввиду, что по главной функции потока можно определить его принадлежность? тобишь фактический если главная функция - main(), то поток будет являться главным потоком приложения? я об этом не подумал))) но тут возникают еще несколько вопросов))):
    1) как мне определить адрес главной функции (main()) другого процесса?
    2) в структуре system_threads поле startaddress означает именно адрес главной функции потока, или текущее значение регистра eip потока (регистра rip для x64)? просто разные "документации недокументированных структур" говорят по-разному))))
     
  4. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    Что это за функция то? EP?
    Что написано, то и значит - начальный адрес потока
     
  5. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    да именно она...
     
  6. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    конечно можно найти смещение относительно базового адреса, покопавшись в pe-заголовке, но мне хочется найти решение без доступа к исполняемому файлу...
     
  7. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    LDR_DATA_TABLE_ENTRY
     
  8. vitokop

    vitokop Member

    Публикаций:
    0
    Регистрация:
    20 май 2006
    Сообщения:
    48
    Из собственного опыта.......
    Делаем снимок потоков с отбором по PID процесса
    ПЕРВЫЙ в списке будет MainThread, наверное так устроено у мелкомягких, логично ?!

    Пример из собственного инструмента

    C:\Windows\System32\drivers\QcomWlanSrvx64.exe
    QcomWlanSrvx64.exe
    Процесс: 64 бит pid 3984
    0: 00000F94 ( 3988) Thread ID 8 base priority
    1: 0000115C ( 4444) Thread ID 8 base priority
    2: 00001CC8 ( 7368) Thread ID 8 base priority
    Всего потоков: 3
    Параметры потоков:
    0: 3988 1243550000 StackBase 124354C000 StackLimit 7FF637866E78 StartSAddress
    1: 4444 1243D00000 StackBase 1243CFD000 StackLimit 7FFD191D63D0 StartSAddress
    2: 7368 1243900000 StackBase 12438FE000 StackLimit 7FFD267B6320 StartSAddress

    Здесь MainThread будет

    3988 1243550000 StackBase 124354C000 StackLimit 7FF637866E78 StartSAddress

    7FF637866E78 StartSAddress => OEP программы

    и еще ................................................................

    C:\Windows\explorer.exe
    explorer.exe
    Процесс: 64 бит pid 6256
    0: 00001874 ( 6260) Thread ID 8 base priority
    1: 0000192C ( 6444) Thread ID 8 base priority
    2: 00001934 ( 6452) Thread ID 9 base priority
    3: 00001960 ( 6496) Thread ID 8 base priority
    4: 0000196C ( 6508) Thread ID 8 base priority
    5: 00001A1C ( 6684) Thread ID 8 base priority
    ..............................
    ...............................
    110: 00001E60 ( 7776) Thread ID 8 base priority
    111: 000016B8 ( 5816) Thread ID 8 base priority
    Всего потоков: 112
    Параметры потоков:
    0: 6260 00A80000 StackBase 00A6C000 StackLimit 7FF7566ED3F0 StartSAddress
    1: 6444 02F10000 StackBase 02F02000 StackLimit 7FFD267B6320 StartSAddress
    2: 6452 03090000 StackBase 03082000 StackLimit 7FFD25E2C900 StartSAddress
    3: 6496 03390000 StackBase 03382000 StackLimit 7FFD267B6320 StartSAddress
    4: 6508 04850000 StackBase 04842000 StackLimit 7FFD267B6320 StartSAddress
    5: 6684 05080000 StackBase 05072000 StackLimit 7FFD267B6320 StartSAddress
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    110: 7776 56A70000 StackBase 56A62000 StackLimit 7FFD267B6320 StartSAddress
    111: 5816 56AF0000 StackBase 56AE2000 StackLimit 7FFD267B6320 StartSAddress

    MainThread:
    0: 6260 00A80000 StackBase 00A6C000 StackLimit 7FF7566ED3F0 StartSAddres
    7FF7566ED3F0 StartSAddres => OEP программы
     
  9. TrashGen

    TrashGen ТрещГен

    Публикаций:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    1.191
    Адрес:
    подполье
    vitokop, вы привнесли свежее дуновение постенговой некрофилии, что, впрочем, никого тут давно не удивляет. Продолжайте отвечать на ответы;)
     
  10. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    Не, это - явно не рекорд некропостинга, вроде текущий рекорд был постом из 2007 года по-моему.
     
  11. TrashGen

    TrashGen ТрещГен

    Публикаций:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    1.191
    Адрес:
    подполье
    Rel, зато этот- без трех дней четырнадцатилетняя давность и некроответ был дан и поныне присутствующему среди нас Вам. Что Вы и можете отметить послезавтра, и с чем и поздравляем!
     
  12. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    Наконец-то я завершу свой проект 14-летней давности, буду всей своей программерской тимой отмечать, всех джунов набухаю в честь этого.
     
    TrashGen нравится это.
  13. Application

    Application Active Member

    Публикаций:
    1
    Регистрация:
    15 окт 2022
    Сообщения:
    110
    Еще немного лет и зероди проект будет доделан)
     
  14. Application

    Application Active Member

    Публикаций:
    1
    Регистрация:
    15 окт 2022
    Сообщения:
    110
    Давным давно, когда ко-фаундер был прыщавым школьником, он очень хотел
    научиться работать с компьютером. Вопреки ожиданиям, ничего сложного в этом не
    оказалось.

    Освоив монитор и клавиатуру, он возжелал научиться писать программы. И, как ни
    странно, ему это снова удалось.

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

    Так прошло 15 лет.

    А затем началось самое интересное: ко-фаундер оглянулся вокруг.

    Оказалось, что все кто хотели научиться работать с компьютером - научились. Из
    них, те кто хотели писать программы - пишут их. А те, кто раз попробовали
    скомпилить сплоет - компелируют его по сей день.

    (За исключением, конечно, обитателей хэкерных форумов и прочих).

    Таким образом был развеян миф об элитарности хэка и основано БХЦ.

    А главный хэкерный секрет заключается в том, что его не существует.

    То есть (фактически) научиться компелировать сплоеты может каждый.
     
    TrashGen нравится это.
  15. TrashGen

    TrashGen ТрещГен

    Публикаций:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    1.191
    Адрес:
    подполье
    Application, всё лишь потому, бро, что скамерсант от жидохеккера недалеко падает! lol
    --- Сообщение объединено, 14 окт 2023 ---
    Потоки переопределены. Ибо ваистену!:
     
    Application нравится это.
  16. sl0n

    sl0n Мамонт дзена **

    Публикаций:
    0
    Регистрация:
    26 сен 2003
    Сообщения:
    703
    Я думал вы с этим уже завязали =)) даже кнопка вызова тех кто не гуглится ...
     
    TrashGen нравится это.
  17. TrashGen

    TrashGen ТрещГен

    Публикаций:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    1.191
    Адрес:
    подполье
    sl0n, потому, что те, кто - уже совсем не те, а Баггерс по-прежнему Ненаказуемый, а вот и нотариально заверенный пруф:

    --- Сообщение объединено, 18 окт 2023 ---
    Да и как можно завязать с тем, что ононимус всё равно не забывает
     
    Win32Api нравится это.