Исходного кода, разумеется, у меня нет, поэтому придется действовать иначе — найти участок кода, который отвечает за отрисовку имён файлов, и соответствующим образом его поправить. Поправлять будем очевидным образом — запишем в нужное место call на нашу функцию, которая будет проверять имена файлов, устанавливать соответствующий цвет и затем возвращать управление в исходную точку.
Найти нужный участок кода легко — достаточно открыть dc32.exe в IDA и поискать вызовы функций типа ExtTextOutA. Незадолго перед ней находится SetTextColor, которая, собственно, и устанавливает цвет текста. Нужный нам фрагмент выглядит так:
.text:00435372 mov edx, [esp+0B4h+var_70] .text:00435376 mov edi, [eax] .text:00435378 add esp, 8 .text:0043537B mov ecx, [esi+4] .text:0043537E and edx, 0FFFFFFh .text:00435384 push edx ; COLORREF .text:00435385 mov eax, [ecx+4] .text:00435388 push eax ; HDC .text:00435389 call ds:SetTextColor
В edx, очевидно, содержится цвет. Имя файла в виде null-terminated строки лежит по адресу [ebx]. Точнее, там лежит строчка, соответствующая тому, что будет отображаться на экране: пространство между именем и расширением заполнено пробелами, само имя, если оно слишком длинное, обрезается многоточием. В принципе, можно было бы вытащить и настоящее имя, но для наших целей это не потребуется.
Внедряться будем следующим образом: запишем по адресу 0043537E две команды: mov eax, &Hook_FNDisplay; call eax, где &Hook_FNDisplay — адрес функции, которая будет заниматься дополнительной работой (регистр eax мы в данном месте можем смело «портить»).
HANDLE phandle = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 0, pid); if (phandle == NULL) return FALSE; int addr = 0x43537E; BYTE hook_code[7] = {0xb8, 0, 0, 0, 0, 0xff, 0xd0}; LPVOID hook_addr = &Hook_FNDisplay; memcpy(&hook_code[1], &hook_addr, 4); WriteProcessMemory(phandle, (LPVOID)addr, &hook_code, sizeof(hook_code), 0);
Семибайтный массив hook_code содержит коды указанных выше инструкций.
Теперь обратимся к самой процедуре Hook_FNDisplay. Объявим её как __declspec(naked), чтобы компилятор не сгенерировал ненужный нам код («пролог» и «эпилог»). В самом начале настроим стек, сохраним в стеке регистры и запомним в локальных переменных имя файла и его цвет:
__asm { pop eax push ebp mov ebp, esp sub esp, __LOCAL_SIZE mov filename, ebx and edx, 0xffffff mov color, edx pushad }
Перед выходом, соответственно, восстановим регистры и указатель стека. Кроме того, надо позаботиться о том, чтобы на вершине стека после ret остался заданный нами цвет, ведь при внедрении нашего кода мы «затёрли» команду push edx:
__asm{ popad mov edx, color mov esp, ebp pop ebp push edx push eax ret }
Основная логика — между этими двумя ассемблерными вставками. Идея очевидна:
filename_len = strlen((char*)filename); if (_strcmpi((char*)((size_t)filename + filename_len - 4), "djvu") == 0) color = 0xFF00FF;
Код оформляется в виде обычной DLL, которая затем инжектируется маленькой утилиткой CLI DLL-Injector (спасибо Glowfall за наводку).
Здесь я описал основную идею. Полный код не выкладываю, поскольку он ещё требует работы: как минимум надо сделать удобную возможность конфигурирования раскрасок. Благодарю за внимание и буду рад конструктивной критике. 😉
ссылка на оригинал статьи http://habrahabr.ru/post/176663/
Добавить комментарий