Всем хай! Сегодня мы займемся исследованием работы такой системной утилиты, как taskmgr.exe. Вам никогда не хотелось узнать, что кроется внутри?
Для этого увлекательного процесса будем использовать IDA Pro. Можнокупить по огромной цене на официальном сайте скачать с форумов.
Для простоты реверсить будем 32-х битную версию.
В Windows x86 она лежит по пути \Windows\system32\taskmgr.exe
В Windows x64 по пути \Windows\SysWOW64\taskmgr.exe
Откроем 32-х битную версию. Добрые мелкомягкие предоставили нам ее вместе с Debug информацией. Так что когда спросит о загрузке дебаг инфы жмите Yes.
Окно откроется на точке входа. Там будет всякая инициализация окон и т.д. Она нас не интересует. Идем во вкладку import и смотрим какие функции импортирует.
Список довольно огромный. Есть несколько способов найти в исполняемом файле интересуемый нас функционал:
1) Поиск вызовов нужных нам API функций
2) Трассировка в отладчике
Так как второй способ громоздкий и неудобный крайне для оконных приложений, то выбираем первый. Для интереса найдем код, который отвечает за поиск процессов. Как узнать при помощи какой функции это происходит?
Использовать будем API Monitor. При помощи данной софтины можно посмотреть какие API вызывает программа в ходе своей работы и в каком порядке! Прекрасно!
Качаем по ссылке: http://www.rohitab.com/downloads
Качайте x64 версию, она установит и x86 и x64. Далее запускаем API Monitor 32-bit. Слева выбираем в API Filter: Nt Native, System Services и Undocumented. Это мы сделали из предположения, что скорее всего используются либо низкоуровневые ( еще ниже WinAPI ) вызовы функций Native API, либо WINAPI функции по управлению объектами ядра: хэндлы, файлы, процессы, треды. А также сделали предположение, что может быть что-то недокументированное. Запускаем taskmgr. Видим огромное количество API.
Мы можем их всех просматривать, но так дело не пойдет. Сузим круг поиска. Раскроем NT Native и System Services, чтобы выбрать там только Processes and threads. Запустим еще раз.
Увидим там огромный список. Подождите! Он весь состоит из TlsGetValue и TlsSetValue. Жмем по ним и выбираем Hide API (Delete)
Видим, что используются Native API функции, как мы и предполагали.
# Time of Day Thread Module API Return Value Error Duration
11 1:43:46.027 AM 1 KERNELBASE.dll NtOpenProcess ( 0x0016f8b4, PROCESS_QUERY_INFORMATION, 0x0016f888, 0x0016f8a0 ) STATUS_SUCCESS 0.0000060
12 1:43:46.027 AM 1 KERNELBASE.dll NtQueryInformationProcess ( 0x000000b8, ProcessSessionInformation, 0x0016f8a8, 4, NULL ) STATUS_SUCCESS 0.0000021
13 1:43:46.027 AM 1 taskmgr.exe GetCurrentProcess ( ) GetCurrentProcess() 0.0000013
14 1:43:46.027 AM 1 KERNELBASE.dll NtSetInformationThread ( GetCurrentThread(), ThreadImpersonationToken, 0x0016f89c, 4 ) STATUS_SUCCESS 0.0000034
15 1:43:46.027 AM 1 KERNELBASE.dll NtQueryInformationProcess ( GetCurrentProcess(), ProcessDefaultHardErrorMode, 0x0016f8b0, 4, NULL ) STATUS_SUCCESS 0.0000021
16 1:43:46.027 AM 1 KERNELBASE.dll NtQueryInformationProcess ( GetCurrentProcess(), ProcessDefaultHardErrorMode, 0x0016f89c, 4, NULL ) STATUS_SUCCESS 0.0000013
17 1:43:46.027 AM 1 KERNELBASE.dll NtSetInformationProcess ( GetCurrentProcess(), ProcessDefaultHardErrorMode, 0x0016f8ac, 4 ) STATUS_SUCCESS 0.0000021
Итак. Посмотрим в каких областях вызываются данные функции. Возвращаемся в IDA, выбираем imports и ищем там, например, NtQueryInformationProcess
Жмем по ней два раза и видим нечто подобное:
Мы оказались внутри таблицы импорта! Выбираем часть строки, где
Это список внутренних функций, где используется NtQueryInformationProcess. Нажав два раза на любую из функций мы окажемся на строчке, где вызывается наша искомая API
Но... тут нет создания списка процессов. Как так?
Давайте уберем фильтр, выбрав все Native API и запустим скрипт. Итак, предположим, что обновление происходит, как только taskmgr ловит появления новых процессов. Давайте пока работает API Monitor создадим пару процессов и закроем их через исследуемый диспетчер.
После выбивания мусорных функций и сравнения времени открытия/закрытия мы заметим вызов функции NtQuerySystemInformation
Посмотрим где она вызывается и найдем функцию:
; __int32 __thiscall CProcPage::UpdateProcInfoArray(CProcPage *this)
Которая отвечает за обновление информации о процессе.
Так что вот код, который ищет процессы. Теперь мы знаем, что чтобы скрыть наше приложение от диспетчера достаточно перехватить эту функцию! Таким способом вы можете исследовать что угодно
Для этого увлекательного процесса будем использовать IDA Pro. Можно
Для простоты реверсить будем 32-х битную версию.
В Windows x86 она лежит по пути \Windows\system32\taskmgr.exe
В Windows x64 по пути \Windows\SysWOW64\taskmgr.exe
Откроем 32-х битную версию. Добрые мелкомягкие предоставили нам ее вместе с Debug информацией. Так что когда спросит о загрузке дебаг инфы жмите Yes.
Окно откроется на точке входа. Там будет всякая инициализация окон и т.д. Она нас не интересует. Идем во вкладку import и смотрим какие функции импортирует.
Список довольно огромный. Есть несколько способов найти в исполняемом файле интересуемый нас функционал:
1) Поиск вызовов нужных нам API функций
2) Трассировка в отладчике
Так как второй способ громоздкий и неудобный крайне для оконных приложений, то выбираем первый. Для интереса найдем код, который отвечает за поиск процессов. Как узнать при помощи какой функции это происходит?
Использовать будем API Monitor. При помощи данной софтины можно посмотреть какие API вызывает программа в ходе своей работы и в каком порядке! Прекрасно!
Качаем по ссылке: http://www.rohitab.com/downloads
Качайте x64 версию, она установит и x86 и x64. Далее запускаем API Monitor 32-bit. Слева выбираем в API Filter: Nt Native, System Services и Undocumented. Это мы сделали из предположения, что скорее всего используются либо низкоуровневые ( еще ниже WinAPI ) вызовы функций Native API, либо WINAPI функции по управлению объектами ядра: хэндлы, файлы, процессы, треды. А также сделали предположение, что может быть что-то недокументированное. Запускаем taskmgr. Видим огромное количество API.
Мы можем их всех просматривать, но так дело не пойдет. Сузим круг поиска. Раскроем NT Native и System Services, чтобы выбрать там только Processes and threads. Запустим еще раз.
Увидим там огромный список. Подождите! Он весь состоит из TlsGetValue и TlsSetValue. Жмем по ним и выбираем Hide API (Delete)
Видим, что используются Native API функции, как мы и предполагали.
# Time of Day Thread Module API Return Value Error Duration
11 1:43:46.027 AM 1 KERNELBASE.dll NtOpenProcess ( 0x0016f8b4, PROCESS_QUERY_INFORMATION, 0x0016f888, 0x0016f8a0 ) STATUS_SUCCESS 0.0000060
12 1:43:46.027 AM 1 KERNELBASE.dll NtQueryInformationProcess ( 0x000000b8, ProcessSessionInformation, 0x0016f8a8, 4, NULL ) STATUS_SUCCESS 0.0000021
13 1:43:46.027 AM 1 taskmgr.exe GetCurrentProcess ( ) GetCurrentProcess() 0.0000013
14 1:43:46.027 AM 1 KERNELBASE.dll NtSetInformationThread ( GetCurrentThread(), ThreadImpersonationToken, 0x0016f89c, 4 ) STATUS_SUCCESS 0.0000034
15 1:43:46.027 AM 1 KERNELBASE.dll NtQueryInformationProcess ( GetCurrentProcess(), ProcessDefaultHardErrorMode, 0x0016f8b0, 4, NULL ) STATUS_SUCCESS 0.0000021
16 1:43:46.027 AM 1 KERNELBASE.dll NtQueryInformationProcess ( GetCurrentProcess(), ProcessDefaultHardErrorMode, 0x0016f89c, 4, NULL ) STATUS_SUCCESS 0.0000013
17 1:43:46.027 AM 1 KERNELBASE.dll NtSetInformationProcess ( GetCurrentProcess(), ProcessDefaultHardErrorMode, 0x0016f8ac, 4 ) STATUS_SUCCESS 0.0000021
Итак. Посмотрим в каких областях вызываются данные функции. Возвращаемся в IDA, выбираем imports и ищем там, например, NtQueryInformationProcess
Жмем по ней два раза и видим нечто подобное:
.idata:01001578 ; NTSTATUS __stdcall NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength)
.idata:01001578 extrn __imp__NtQueryInformationProcess@20:dword
Мы оказались внутри таблицы импорта! Выбираем часть строки, где
__imp__NtQueryInformationProcess
и жмем клавишу X ( английскую ), смотрим какой код ссылается на эту функцию
Это список внутренних функций, где используется NtQueryInformationProcess. Нажав два раза на любую из функций мы окажемся на строчке, где вызывается наша искомая API
Но... тут нет создания списка процессов. Как так?
Давайте уберем фильтр, выбрав все Native API и запустим скрипт. Итак, предположим, что обновление происходит, как только taskmgr ловит появления новых процессов. Давайте пока работает API Monitor создадим пару процессов и закроем их через исследуемый диспетчер.
После выбивания мусорных функций и сравнения времени открытия/закрытия мы заметим вызов функции NtQuerySystemInformation
Посмотрим где она вызывается и найдем функцию:
; __int32 __thiscall CProcPage::UpdateProcInfoArray(CProcPage *this)
Которая отвечает за обновление информации о процессе.
Так что вот код, который ищет процессы. Теперь мы знаем, что чтобы скрыть наше приложение от диспетчера достаточно перехватить эту функцию! Таким способом вы можете исследовать что угодно
.text:01002C5B ; __int32 __thiscall CProcPage::UpdateProcInfoArray(CProcPage *this)
.text:01002C5B ?UpdateProcInfoArray@CProcPage@@QAEJXZ proc near
.text:01002C5B ; CODE XREF: CProcPage::TimerEvent(void):loc_100C377 p
.text:01002C5B
.text:01002C5B var_1F8 = byte ptr -1F8h
.text:01002C5B var_1CC = dword ptr -1CCh
.text:01002C5B var_188 = dword ptr -188h
.text:01002C5B var_184 = dword ptr -184h
.text:01002C5B SystemInformation= byte ptr -0B0h
.text:01002C5B var_A8 = dword ptr -0A8h
.text:01002C5B var_A4 = dword ptr -0A4h
.text:01002C5B var_84 = dword ptr -84h
.text:01002C5B var_80 = dword ptr -80h
.text:01002C5B var_7C = dword ptr -7Ch
.text:01002C5B var_78 = dword ptr -78h
.text:01002C5B var_74 = dword ptr -74h
.text:01002C5B var_70 = dword ptr -70h
.text:01002C5B var_6C = dword ptr -6Ch
.text:01002C5B var_68 = dword ptr -68h
.text:01002C5B var_64 = _LARGE_INTEGER ptr -64h
.text:01002C5B var_5C = dword ptr -5Ch
.text:01002C5B var_58 = dword ptr -58h
.text:01002C5B var_54 = dword ptr -54h
.text:01002C5B var_50 = dword ptr -50h
.text:01002C5B var_4C = dword ptr -4Ch
.text:01002C5B i = dword ptr -48h
.text:01002C5B String = word ptr -44h
.text:01002C5B var_4 = dword ptr -4
.text:01002C5B
.text:01002C5B ; FUNCTION CHUNK AT .text:01002584 SIZE 0000001A BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:0100274F SIZE 00000040 BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:01002994 SIZE 00000041 BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:01002D5B SIZE 000000C6 BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:01003415 SIZE 0000002B BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:0100375A SIZE 00000055 BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:010038AF SIZE 0000005B BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:01003A7B SIZE 00000067 BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:0100673B SIZE 0000001C BYTES
.text:01002C5B ; FUNCTION CHUNK AT .text:0100C243 SIZE 00000134 BYTES
.text:01002C5B
.text:01002C5B mov edi, edi
.text:01002C5D push ebp
.text:01002C5E mov ebp, esp
.text:01002C60 sub esp, 1F8h
.text:01002C66 mov eax, ___security_cookie
.text:01002C6B xor eax, ebp
.text:01002C6D mov [ebp+var_4], eax
.text:01002C70 push ebx
.text:01002C71 push edi
.text:01002C72 push 8
.text:01002C74 xor eax, eax
.text:01002C76 mov ebx, ecx
.text:01002C78 pop ecx
.text:01002C79 push eax ; ReturnLength
.text:01002C7A lea edi, [ebp+var_84]
.text:01002C80 rep stosd
.text:01002C82 mov edi, ds:__imp__NtQuerySystemInformation@16 ; NtQuerySystemInformation(x,x,x,x)
.text:01002C88 push 2Ch ; SystemInformationLength
.text:01002C8A lea ecx, [ebp+SystemInformation]
.text:01002C90 push ecx ; SystemInformation
.text:01002C91 push eax ; SystemInformationClass
.text:01002C92 mov [ebp+var_5C], eax
.text:01002C95 mov [ebp+var_58], eax
.text:01002C98 mov [ebp+var_4C], eax
.text:01002C9B mov [ebp+i], eax
.text:01002C9E call edi ; NtQuerySystemInformation(x,x,x,x) ; NtQuerySystemInformation(x,x,x,x)
.text:01002CA0 test eax, eax
.text:01002CA2 jl loc_100C243
.text:01002CA8 push esi
.text:01002CA9 mov esi, [ebp+var_A8]
.text:01002CAF shr esi, 0Ah
.text:01002CB2 imul esi, [ebp+var_A4]
.text:01002CB9 push 0 ; ReturnLength
.text:01002CBB push 148h ; SystemInformationLength
.text:01002CC0 lea eax, [ebp+var_1F8]
.text:01002CC6 push eax ; SystemInformation
.text:01002CC7 push 2 ; SystemInformationClass
.text:01002CC9 mov [ebp+var_78], esi
.text:01002CCC call edi ; NtQuerySystemInformation(x,x,x,x) ; NtQuerySystemInformation(x,x,x,x)
.text:01002CCE test eax, eax
.text:01002CD0 jl loc_100C24D
.text:01002CD6 mov eax, dword_101E490
.text:01002CDB and dword ptr ?g_MEMMax@@3_JA+4, 0
.text:01002CE2 shr eax, 0Ah
.text:01002CE5 mov ecx, eax
.text:01002CE7 imul ecx, [ebp+var_1CC]
.text:01002CEE mov edi, eax
.text:01002CF0 imul eax, [ebp+var_184]
.text:01002CF7 imul edi, [ebp+var_188]
.text:01002CFE mov [ebp+var_6C], eax
.text:01002D01 mov [ebp+var_74], ecx
.text:01002D04 add eax, edi
.text:01002D06 mov ecx, ebx ; this
.text:01002D08 mov [ebp+var_68], eax
.text:01002D0B mov dword ptr ?g_MEMMax@@3_JA, esi ; __int64 g_MEMMax
.text:01002D11 call ?GetProcessInfo@CProcPage@@QAEJXZ ; CProcPage::GetProcessInfo(void)
.text:01002D16 mov [ebp+var_54], eax
.text:01002D19 test eax, eax
.text:01002D1B jge loc_100C257
.text:01002D21 jmp loc_100C353
.text:01002D26 ; ---------------------------------------------------------------------------
.text:01002D26
.text:01002D26 loc_1002D26: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)-503 j
.text:01002D26 ; CProcPage::UpdateProcInfoArray(void)+9611 j
.text:01002D26 push eax ; unsigned __int32
.text:01002D27 push dword ptr [ebx+0Ch] ; struct CPtrArray *
.text:01002D2A call ?FindProcInArrayByPID@@YGPAVCProcInfo@@PAVCPtrArray@@K@Z ; FindProcInArrayByPID(CPtrArray *,ulong)
.text:01002D2F test eax, eax
.text:01002D31 jnz loc_100C271
.text:01002D37
.text:01002D37 loc_1002D37: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+9651 j
.text:01002D37 mov eax, [esi+30h]
.text:01002D3A add eax, [esi+28h]
.text:01002D3D mov ecx, [esi+34h]
.text:01002D40 adc ecx, [esi+2Ch]
.text:01002D43 add [ebp+var_5C], eax
.text:01002D46 mov eax, [esi+4Ch]
.text:01002D49 adc [ebp+var_58], ecx
.text:01002D4C add [ebp+var_84], eax
.text:01002D52 mov eax, [esi+4]
.text:01002D55 add [ebp+var_80], eax
.text:01002D58 inc [ebp+var_7C]
.text:01002D58 ?UpdateProcInfoArray@CProcPage@@QAEJXZ endp ; sp-analysis failed
.text:01002D58
.text:01002D5B ; START OF FUNCTION CHUNK FOR ?UpdateProcInfoArray@CProcPage@@QAEJXZ
.text:01002D5B
.text:01002D5B loc_1002D5B: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)-509 j
.text:01002D5B ; CProcPage::UpdateProcInfoArray(void)+9640 j
.text:01002D5B mov eax, [esi]
.text:01002D5D add [ebp+var_50], eax
.text:01002D60 cmp ?gdwSessionId@@3KA, 0FFFFFFFFh ; ulong gdwSessionId
.text:01002D67 jz loc_100673B
.text:01002D6D
.text:01002D6D loc_1002D6D: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+3AE9 j
.text:01002D6D ; CProcPage::UpdateProcInfoArray(void)+3AF7 j
.text:01002D6D cmp dword ptr [esi], 0
.text:01002D70 jnz loc_100C25B
.text:01002D76 mov eax, [ebp+var_5C]
.text:01002D79 sub eax, [ebp+var_4C]
.text:01002D7C mov ecx, [ebp+var_58]
.text:01002D7F sbb ecx, [ebp+i]
.text:01002D82 mov dword ptr [ebp+var_64], eax
.text:01002D85 mov eax, [ebp+var_7C]
.text:01002D88 xor esi, esi
.text:01002D8A mov dword ptr [ebp+var_64+4], ecx
.text:01002D8D mov ?g_cProcesses@@3KA, eax ; ulong g_cProcesses
.text:01002D92 cmp dword_101E554, esi
.text:01002D98 jnz loc_100C2B1
.text:01002D9E jmp loc_100C2CC
.text:01002DA3 ; ---------------------------------------------------------------------------
.text:01002DA3
.text:01002DA3 loc_1002DA3: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+B2C j
.text:01002DA3 ; CProcPage::UpdateProcInfoArray(void)+9680 j
.text:01002DA3 push eax ; dwProcessId
.text:01002DA4 push 0 ; bInheritHandle
.text:01002DA6 push 1000h ; dwDesiredAccess
.text:01002DAB call ds:__imp__OpenProcess@12 ; OpenProcess(x,x,x)
.text:01002DB1 mov [ebp+i], eax
.text:01002DB4 test eax, eax
.text:01002DB6 jnz loc_100275D
.text:01002DBC
.text:01002DBC loc_1002DBC: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)-4DD j
.text:01002DBC mov eax, [esi+40h]
.text:01002DBF cmp eax, 4
.text:01002DC2 jle loc_100C2EC
.text:01002DC8 cmp eax, 6
.text:01002DCB jle loc_1002783
.text:01002DD1 cmp eax, 8
.text:01002DD4 jg loc_1003415
.text:01002DDA mov dword ptr [esi+40h], 20h
.text:01002DE1
.text:01002DE1 loc_1002DE1: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)-4E3 j
.text:01002DE1 ; CProcPage::UpdateProcInfoArray(void)-4D1 j ...
.text:01002DE1 push dword ptr [esi+44h] ; unsigned __int32
.text:01002DE4 push dword ptr [ebx+0Ch] ; struct CPtrArray *
.text:01002DE7 call ?FindProcInArrayByPID@@YGPAVCProcInfo@@PAVCPtrArray@@K@Z ; FindProcInArrayByPID(CPtrArray *,ulong)
.text:01002DEC test eax, eax
.text:01002DEE jz loc_1003A7B
.text:01002DF4 push 1 ; int
.text:01002DF6 push ebx ; struct CProcPage *
.text:01002DF7 push dword ptr stru_101E120+4
.text:01002DFD mov ecx, eax ; this
.text:01002DFF push dword ptr stru_101E120 ; union _LARGE_INTEGER
.text:01002E05 push esi ; struct _SYSTEM_PROCESS_INFORMATION *
.text:01002E06 push dword ptr [ebp+var_64+4]
.text:01002E09 push dword ptr [ebp+var_64] ; union _LARGE_INTEGER
.text:01002E0C call ?SetData@CProcInfo@@QAEJT_LARGE_INTEGER@@PBU_SYSTEM_PROCESS_INFORMATION@@0PAVCProcPage@@H@Z ; CProcInfo::SetData(_LARGE_INTEGER,_SYSTEM_PROCESS_INFORMATION const *,_LARGE_INTEGER,CProcPage *,int)
.text:01002E11 mov [ebp+var_54], eax
.text:01002E14 test eax, eax
.text:01002E16 jge loc_100C321
.text:01002E1C jmp loc_100C353
.text:01002E1C ; END OF FUNCTION CHUNK FOR ?UpdateProcInfoArray@CProcPage@@QAEJXZ
Очень хороший блог! надеюсь на продолжение публикиций
ОтветитьУдалить