Должен выглядеть так:
Особенно внимательно нужно просмотреть процедуру sub_402400, там много такого кода.
Также могу посоветовать вызов функции 4015A0 просто убрать – от этого ничего не изменится, так как там отладочная информация.
Также в файле пару раз встречается конструкция switch, с областью данных в конце процедуры
Я вышел из положения так:
Но можно, например, заменить на 8 операций сравнения и последующих условных переходов.
Кроме того, надо не забыть подключить нужные библиотеки
include masm32\include\msvcrt.inc
includelib masm32\lib\msvcrt.lib
К именам функций atof, _CIacos, _CIasin добавить префикс “crt_”.
Добавление кода и данных в notepad.exe
Теперь у нас есть исходный код, который мы будем добавлять в notepad.exe. Настал момент задуматься над тем, как сделать, чтобы код работал, чтобы все “длинные” переходы были правильными, чтобы данные, на которые ссылается код, были там, где надо. На данный момент базовый адрес нашей тестовой программы 400000h, базовый адрес по которому грузится notepad.exe равен 1000000h, но это нам не помешает.
Теперь нам потребуется возможность по редактированию секций PE файла, для этого воспользуемся редактором PE Tools, он поддерживает все необходимые операции по манипулированию секциями. В связи с тем, что секции в памяти должны идти одна за другой, а код мы будем добавлять в конец файла, нам потребуется код с базовым адресом, лежащим за пределами адреса Image Base + Size of Image (1000000h+13000h). Необходимо немного модифицировать наше тестовое приложение, а именно необходимо изменить адрес загрузки нашей программы. Еще раз компилируем программу, на этот раз с ключом /BASE:0x1020000. Выбор числа 0x1020000 связан с тем, что адрес загрузки файла должен быть кратен 64 Кб. Берем получившуюся программу и копируем на диск секцию кода и данных.
Следующим шагом открываем notepad.exe в PE Tools и пробуем расположить секции в памяти так, как они располагались в нашей тестовой программе. Делаем это, манипулируя полями Virtual Size и Virtual Offset каждой секции. Согласно стандарту PE, секции в файле должны идти одна за другой. У меня получилось вот так:
Я поступил следующим образом: просто добавил так называемые Fake секции в те места, где получались разрывы. Это просто секции, заполненные нулями в памяти и не занимающие места на диске.
Следующая проблема - это импорт. Беглый осмотр, показал наличие нескольких функций в тестовой программе, которых нет в notepad.exe. Здесь есть несколько вариантов решения: можно написать небольшую процедуру, подгружающую нужные библиотеки и узнающую адреса нужных функций. Можно просто расширить импорт, и здесь нам поможет программа IIDKing v2.0. Запускаем утилиту и указываем, какие функции, и из какой библиотеки нужно добавить. После того как программа отработала, замечаем, что модифицированный файл notepad.exe увеличился еще на одну секцию, и именно в ней теперь находятся новые функции импорта. После этого надо подправить поле Size of Image в опциональном заголовке.
Настало время проверить работоспособность нашего “мутанта”. Запускаем модифицированный блокнот на исполнение. Убеждаемся, что он не работает. Если все сделано, так как я описал, то проблема связанна с “bound import” я просто отключил его и notepad.exe загружался без проблем. Делается это следующим образом: идем в список директорий PE файла и вместо адреса и размера “ Bound Import Directory” прописываем нули.
Написание кода взаимодействия приложения с добавленным кодом
Теперь настало время написать интерфейс взаимодействия блокнота с нашим добавленным кодом. Необходимо найти свободное место в новом файле (это совсем не трудно) и дописать туда код, который будет брать выражение, и передавать его в функцию для вычисления, а затем выводить результат обратно в блокнот. Я решил, что буду использовать пространство в конце секции кода, которую мы вставили из тестовой программы, там, в конце секции остался код, который не будет использоваться в блокноте, его мы и заменим. Как потом выяснилось, это не самое лучшее решение, а втиснуть код в невостребованное пространство оказалось сложно: код влез байт в байт, лучше выбрать свободное место с запасом.
Модифицируем интерфейс нашего блокнота. Я поступил следующим образом: просто добавил новый пункт в меню “Формат”. Сделать это можно любой программой, которая позволяет редактировать ресурсы. Я воспользовался Restorator-ом. Новому пункту меню необходимо дать уникальный идентификатор в пределах всего меню. Я назначил число 34.
Необходимо найти место в программе, где будет сделана вставка кода, который будет отрабатывать при выборе нового пункта меню. Необходимо найти адрес, по которому расположена оконная функция отработки сообщений. И поставим код, производящий прыжок на код обработки:
Здесь мы просто вставили “длинный” прыжок JMP 010236F5. Теперь идем по адресу 010236F5 и пишем код обработки выбора пункта меню “Вычислить”. Далее я приведу код, а затем эго прокомментирую:
Первые 2 строчки этого кода просто взяты с того места, где мы добавили код для прыжка на вставленный код (там он затерся), следующие 2 строчки проверка на то, что выбран именно добавленный пункт меню. Далее идут два вызова функции SendMessageW с сообщением EM_LINEFROMCHAR, первый раз, чтобы узнать на какой строчке установлен курсор ввода, второй раз с сообщением EM_GETLINE, чтобы получить строку с выражением. После этого по адресу 01024BF4 находится выражение для вычисления, но тут нас ждет одна неприятность: текст в буфере находится в UNICOD кодировке, а наша функция для вычисления выражений работает только с ANSI форматом строк. Дальнейший код это исправит, функция WideCharToMultiByte переводит UNICOD строки в формат ANSI. Функция вызывается 2 раза: первый раз, чтобы определить размер строки, затем для преобразования. Сразу за этим следует вызов функции для вычисления выражения. Следующий код делает обратное преобразование из ANSI в UNICOD с помощью функции MultiByteToWideChar. Далее идет вызов функции SendMessageW с сообщением EM_REPLACESEL для вставки строки “=” (строка находится по адресу 010237EB), а затем строки с результатом выражения.
Вот собственно и все! Мы получили работающий файл. Блокнот с расширенной функциональностью.
Здесь можно скачать файлы к статье: исходный код, добавляемого кода и конечный результат.
© GMax
.text:004038C8 fstp dbl_413348[ecx]
pop ebx
mov esp, ebp
pop ebp
retn
CalcFunc endp
align 4
;off_4042EC dd offset loc_40411A ; DATA XREF: CalcFunc+7Ar
; dd offset loc_4038F0 ; jump table for switch statement
; dd offset loc_403CE2
; dd offset loc_403991
; dd offset loc_403940
; dd offset loc_4038A5
; dd offset loc_403883
; dd offset loc_403861
; align 10h
pop ebx
mov esp, ebp
pop ebp
retn
.data
off_4042EC dd offset loc_40411A ; DATA XREF: CalcFunc+7Ar
dd offset loc_4038F0 ; jump table for switch statement
dd offset loc_403CE2
dd offset loc_403991
dd offset loc_403940
dd offset loc_4038A5
dd offset loc_403883
dd offset loc_403861
.code
CalcFunc endp
Добавление функциональности в готовые программы
Дата публикации 8 июл 2007