Замена главной иконки исполняемого файла
Замена главной иконки исполняемого файла
Продолжаем тему иконок. Сегодня разберем способ, как можно заменить главную иконку приложения на другую. Зачем это надо? Например, может возникнуть потребность заменить иконку в неком исполняемом файле на иконку документа Word или PDF ;) Или надо перенести в свежесобранный патч иконку из обрабатываемой им софтины. Или, как в моем случае, вам не нравится оригинальная иконка какого-нибудь приложения и вы хотите поменять ее на что-нибудь свое. Применение этой технологии вы определите для себя сами. Как говорила Масяня в одноименном мультике: "Мое дело подарок подарить, а ты уж думай, что с этой хренью делать".
Исходное положение. Есть файл с иконкой или мультииконкой и есть целевой исполняемый файл с одной или несколькими иконками в ресурсах. Задача заключается в переносе иконок из файла в ресурсы.
Для работы потребуются две структуры, описывающие внутренности группы иконок в ресурсах и в файле с иконками. FASM про них, естественно, ничего не знает.
Code (Assembler) : Убрать нумерацию
- ; Структуры для работы с иконками в группе
- struct ICONDIR
- idReserved dw ? ; Зарезервировано (должно быть 0)
- idType dw ? ; Тип ресурса (1 для иконок)
- idCount dw ? ; Количество изображений в иконке
- ends
- struct GRPICONDIRENTRY
- bWidth db ? ; Ширина изображения в пикселах
- bHeight db ? ; Высота изображения в пикселах
- bColorCount db ? ; Количество цветов
- bReserved db ? ; Зарезервировано
- wPlanes dw ? ; Зарезервировано
- wBitCount dw ? ; Зарезервировано
- dwBytesInRes dd ? ; Размер данных изображения
- nID dw ? ; ID иконки в ресурсах
- ends
Code (Assembler) : Убрать нумерацию
- ; Максимально допустимое количество иконок в группе
- MAX_ICONS = 128
- ; Целевой файл
- szTarget db 'change_target.exe',0
- ; Файл с иконками
- szIcon db 'change_source.ico',0
- pMem dd ? ; Память для файла с иконками
- dFIconNum dd ? ; Количество иконок в файле
- hTarget dd ? ; Хэндл загруженного целевого файла
- hResource dd ? ; Хэндл обновляемых ресурсов целевого файла
- hGroup dd ? ; Хэндл и память для группы иконок
- pGroup dd ?
- dGIconNum dd ? ; Количество иконок в группе
- dID dd ? ; ID обновляемой иконки
- dDiscard dd ? ; Флаг применения сделанных изменений
- ; Массив с ID иконок в группе
- IconsID rw MAX_ICONS
- iid_len = $-IconsID
- ; Заготовка для RT_GROUP_ICON
- res_head ICONDIR
- res_data rb (sizeof.GRPICONDIRENTRY*MAX_ICONS)
- res_len = $-res_head
Code (Assembler) : Убрать нумерацию
- ; Загрузить в память файл иконки
- invoke CreateFile,szIcon,GENERIC_READ,0,0,OPEN_EXISTING,0,0
- cmp eax,-1
- je loc_exit
- mov ebx,eax
- invoke GetFileSize,ebx,NULL
- mov esi,eax
- invoke GlobalAlloc,GMEM_FIXED,eax
- or eax,eax
- jz loc_exit
- mov [pMem],eax
- invoke _lread,ebx,eax,esi
- invoke CloseHandle,ebx
- ; Проверить корректность файла с иконками
- mov esi,[pMem]
- cmp word [esi+ICONDIR.idReserved],0
- jne loc_free_mem
- cmp word [esi+ICONDIR.idType],1
- jne loc_free_mem
- ; Получить количество иконок в файле
- movzx eax,word [esi+ICONDIR.idCount]
- or eax,eax
- jz loc_free_mem
- ; Установленное нами максимальное количество иконок в файле
- cmp eax,MAX_ICONS
- ja loc_free_mem
- ; Сохранить количество иконок
- mov [dFIconNum],eax
- ...
- ...
- ...
- loc_free_mem:
- ; Очистить память файла иконки
- invoke GlobalFree,[pMem]
Переходим к обработке целевого файла. Его надо загрузить в память функцией LoadLibrary и параллельно с этим подготовить ресурсы для редактирования при помощи функции BeginUpdateResource. Если замена иконок пройдет без ошибок, то останется только выгрузить файл из памяти, а изменения в ресурсах зафиксировать функцией EndUpdateResource.
Code (Assembler) : Убрать нумерацию
- ; Сохранять изменения в ресурсах
- mov [dDiscard],FALSE
- ; Загрузить целевой файл в память
- invoke LoadLibrary,szTarget
- or eax,eax
- jz loc_free_mem
- ; Хэндл загруженного целевого файла
- mov [hTarget],eax
- ; Начать обновление ресурсов
- invoke BeginUpdateResource,szTarget,FALSE
- or eax,eax
- jz loc_unload
- ; Хэндл обновляемых ресурсов целевого файла
- mov [hResource],eax
- ; Найти и обработать первую группу иконок в ресурсах
- invoke EnumResourceNames,[hTarget],RT_GROUP_ICON,\
- EnumResNameProc,NULL
- ; Выгрузить файл из памяти
- invoke FreeLibrary,[hTarget]
- ; Применить изменения в ресурсах, но только если не было ошибок
- invoke EndUpdateResource,[hResource],[dDiscard]
- jmp loc_free_mem
- loc_unload:
- ; Выгрузить файл из памяти
- invoke FreeLibrary,[hTarget]
Code (Assembler) : Убрать нумерацию
- ;---------------------------------------------------
- ; Поиск первой группы иконок
- ;---------------------------------------------------
- proc EnumResNameProc hModule:DWORD, lpszType:DWORD, lpszName:DWORD, lParam:DWORD
- pusha
- ; Обновить данные для всех языков
- invoke EnumResourceLanguages,[hModule],[lpszType],[lpszName],\
- EnumResLangProc,NULL
- or eax,eax
- jnz @f
- ; Языков не найдено, возможно, битый ресурс
- mov [dDiscard],TRUE
- @@:
- popa
- ; Обрабатываем только первую группу иконок
- mov eax,FALSE
- ret
- endp
Вся основная работа с ресурсами выполняется в callback-функции перебора языков. Код подробно прокомментирован, но я еще поясню все происходящее словами.
Code (Assembler) : Убрать нумерацию
- ;---------------------------------------------------
- ; Обработка всех языков для этой группы иконок
- ;---------------------------------------------------
- proc EnumResLangProc hModule:DWORD, lpszType:DWORD, lpszName:DWORD,\
- wIDLanguage:DWORD, lParam:DWORD
- pusha
- ; Очистить память для новой группы
- invoke RtlZeroMemory,res_head,res_len
- invoke RtlZeroMemory,IconsID,iid_len
- ; Найти группу иконок в ресурсах
- invoke FindResourceEx,[hModule],[lpszType],[lpszName],[wIDLanguage]
- or eax,eax
- jnz @f
- ; Группа не найдена, файл не обновлять
- mov [dDiscard],TRUE
- jmp .loc_next
- @@:
- mov [hGroup],eax
- ; Загрузить группу иконок
- invoke LoadResource,[hModule],[hGroup]
- or eax,eax
- jnz @f
- ; Загрузить не удалось, файл не обновлять
- mov [dDiscard],TRUE
- jmp .loc_next
- @@:
- ; Получить указатель на начало данных в памяти
- invoke LockResource,eax
- mov [pGroup],eax
- ; Проверить корректность группы
- mov esi,[pGroup]
- cmp word [esi+ICONDIR.idType],1
- je @f
- ; Тип ресурса не соответствует группе иконок
- mov [dDiscard],TRUE
- jmp .loc_next
- @@:
- ; Получить количество иконок в группе
- movzx eax,word [esi+ICONDIR.idCount]
- or eax,eax
- jnz @f
- ; Количество иконок нулевое
- mov [dDiscard],TRUE
- jmp .loc_next
- @@:
- cmp eax,MAX_ICONS
- jbe @f
- ; Количество иконок превышает максимально допустимое
- mov [dDiscard],TRUE
- jmp .loc_next
- @@:
- mov [dGIconNum],eax
- ; Сохранить ID отдельных иконок из группы
- add esi,sizeof.ICONDIR
- mov edi,IconsID
- mov ecx,[dGIconNum]
- @@:
- add esi,12
- movsw
- loop @b
- ; Скопировать заголовок иконок из файла в группу
- mov esi,[pMem]
- mov edi,res_head
- mov ecx,sizeof.ICONDIR
- rep movsb
- xor ebx,ebx
- .process_icon:
- ; Скопировать параметры иконок из файла в группу
- ; bWidth, bHeight, bColorCount, bReserved
- movsd
- ; wPlanes, wBitCount
- movsd
- ; dwBytesInRes
- lodsd
- ; Размер данных иконки
- mov edx,eax
- stosd
- ; ID иконки из списка ресурсов
- movzx ecx,word [IconsID+ebx*2]
- or ecx,ecx
- jnz .id_ok
- ; В ресурсах иконки закончились, но в файле еще есть
- push edx
- ; Найти первый свободный ID для новой иконки
- mov ecx,[dID]
- .scan_res:
- inc ecx
- push ecx
- invoke FindResourceEx,[hModule],RT_ICON,ecx,[wIDLanguage]
- pop ecx
- or eax,eax
- jnz .scan_res
- pop edx
- .id_ok:
- ; Записать ID иконки в группу
- mov eax,ecx
- mov [dID],eax
- stosw
- ; Смещение данных относительно начала файла иконки
- lodsd
- add eax,[pMem]
- ; Обновить ресурсы
- invoke UpdateResource,[hResource],RT_ICON,ecx,\
- [wIDLanguage],eax,edx
- or eax,eax
- jnz @f
- ; Заменить иконку не удалось
- mov [dDiscard],TRUE
- jmp .loc_next
- @@:
- ; Следующая иконка из файла
- inc ebx
- cmp ebx,[dFIconNum]
- jb .process_icon
- ; Удалить все оставшиеся в группе иконки
- .delete_icons:
- movzx eax,[IconsID+ebx*2]
- or eax,eax
- jz .delete_icons_done
- invoke UpdateResource,[hResource],RT_ICON,eax,[wIDLanguage],0,0
- or eax,eax
- jnz @f
- ; Удалить иконку не удалось
- mov [dDiscard],TRUE
- jmp .loc_next
- @@:
- inc ebx
- jmp .delete_icons
- .delete_icons_done:
- ; Вычислить размер группы иконок
- mov eax,[dFIconNum]
- mov ecx,sizeof.GRPICONDIRENTRY
- mul ecx
- add eax,sizeof.ICONDIR
- ; Обновить группу иконок в файле
- invoke UpdateResource,[hResource],RT_GROUP_ICON,[lpszName],\
- [wIDLanguage],res_head,eax
- or eax,eax
- jnz .loc_next
- ; Обновить группу иконок не удалось
- mov [dDiscard],TRUE
- .loc_next:
- popa
- mov eax,TRUE
- ; Если есть хоть одна ошибка, то больше ничего не обрабатываем
- cmp [dDiscard],TRUE
- jne @f
- mov eax,FALSE
- @@:
- ret
- endp
В приложении пример программы с исходным текстом, которая заменяет иконку в ресурсах другого исполняемого файла на иконку из файла.
Просмотров: 2025 | Комментариев: 2
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(26.04.2018 в 10:44):
Не проблема, нарисую статью и про извлечение иконок из файлов.
Сергей Озеров
(26.04.2018 в 00:06):
Спасибо за Ваш блог и Ваши уроки ! Вы упомянули извлечение значка из файла для патчера, можете поделиться как это написать на fasm?
Добавить комментарий
Заполните форму для добавления комментария