Из всех файловых менеджеров ДИСКо Командир мне нравится больше всего. Вопрос «почему?» к данному посту не имеет отношения, так что останавливаться на этом я не буду. К сожалению, у этого файлового менеджера отсутствует некоторая функциональность, которая бы мне очень не помешала. Например, он не умеет подсвечивать файлы разных типов разными цветами. Попробуем это исправить!
Исходного кода, разумеется, у меня нет, поэтому придется действовать иначе — найти участок кода, который отвечает за отрисовку имён файлов, и соответствующим образом его поправить. Поправлять будем очевидным образом — запишем в нужное место 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 за наводку).
Здесь я описал основную идею. Полный код не выкладываю, поскольку он ещё требует работы: как минимум надо сделать удобную возможность конфигурирования раскрасок. Благодарю за внимание и буду рад конструктивной критике. ;)
Автор: EvgeshaS