Бывают ситуации, когда есть софт и хочется в него добавить какую-нибудь очень нужную функцию, нехватающую для полного счастья, но вот незадача ни исходников, ни реализованной системы плагинов в программе нет. Как же быть, смириться и забыть или пойти через дремучий лес и воплотить свою мечту. Вот об одном из возможных путей решения и пойдет речь далее.
Все, о чем будет написано ниже, не является инструкцией к действию, а всего-навсего маленькое сумасшествие из раздела «зачем это надо». В качестве испытуемого возьмем стандартный Notepad. Для примера, реализуем в блокноте конвертацию выделенного текста в hex вид, добавив дополнительный пункт в меню – “String to Hex”.
Реализация задуманного.
Функцию конвертации реализуем в отдельной динамической библиотеке (dll). Для её загрузки в процесс notepad.exe можно использовать разные способы, один из таких – правка таблицы импорта и добавление в неё нашей библиотеки. Правку таблицы можно легко осуществить, например LoadPE (PE Editor -> Directories -> Import Table). Добавим импортируемую функцию, обозвав ее именем InitPlugin и укажем имя библиотеки, в которой реализуется данная функция, например plugin.dll. Сохраняем блокнот с исправленной таблицей импорта. Теперь при запуске блокнот будет требовать наличие plugin.dll с экспортируемой функцией InitPlugin. На этом пытки бинарника блокнота прекращаем и переходим к реализации нашей динамической библиотеки.
Создадим шаблон будущей библиотеки:
library plugin;
uses Windows, Messages, SysUtils;
procedure InitPlugin(); stdcall; begin
end;
procedure DLLEntryPoint(Reason: DWORD); begin case Reason of Dll_Process_Attach: begin
end; Dll_Process_Detach: begin
end; end; end;
exports InitPlugin;
begin if @DllProc = nil then begin DllProc:= @DLLEntryPoint; DllEntryPoint(Dll_Process_Attach); end; end.
Добавим в него функцию конвертации строки в шестнадцатеричное представление:
function StrToHexStr(Str: String): String;
var
i: Integer;
const
Hex = '0123456789ABCDEF';
begin
Result:= '';
for i:= 1 to Length(Str) do
Result:= Result + Hex[Str[i] shr $4 + 1] + Hex[Str[i] and $0f + 1]
end;
И функцию, выполняющую обратное преобразование hex строки в обычную строку:
function HexStrToStr(Str: String): String;
var
HexValue: Integer;
begin
while (Length(Str)>0) do begin
HexValue:= StrToInt('$' + Copy (Str, 1, 2));
Delete(Str, 1, 2);
Result:= Result + Chr (HexValue);
end;
end;
Следующим шагом получим идентификаторы элемента управления Edit и меню Notepad. Но тут есть один момент, при загрузке plugin.dll контролы еще не инициализированы, и получить их указатели не получится, поэтому прибегнем к небольшой хитрости и создадим новый тред, в котором через 100 мс вызовем инициализацию нашего plugin’a. Таким образом код модуля будет выглядеть так:
var hThread: DWORD;
procedure DLLEntryPoint(Reason: DWORD); begin case Reason of Dll_Process_Attach: begin hThread:= CreateThread(nil, 0, @InitPlugin, nil,0,DWORD(nil^)); end; Dll_Process_Detach: begin CloseHandle(hThread); end; end; end;
Что бы обрабатывать выбранные пункты меню, и вызывать соответствующие обработчики событий, нам надо обрабатывать сообщение WM_COMMAND, а для этого придется подменить процедуру WinProc основного окна, делается это при помощи вызова SetWindowLong с параметром GWL_WNDPROC. Для всех сообщений, которые мы не будем обрабатывать нужно вызывать оригинальный обработчик через вызов CallWindowProc :
function WindowProc(hDlg, uMsg, wParam, lParam: DWORD): LongInt; stdcall;
begin
case uMsg of
WM_COMMAND: begin
Result:= 0;
case LOWORD(wParam) of
IDC_StrToHex: begin StrToHex; Exit; end;
IDC_HexToStr: begin HexToStr; Exit; end;
end;
end;
WM_DESTROY: begin
DestroyMenu(hSubMenu);
end;
end;
Result:= CallWindowProc(wpOrigProc, hDlg, uMsg, wParam, lParam);
end;
procedure InitPlugin(); stdcall;
begin
sleep(100);
hMainDlg:= FindWindow('Notepad', nil);
hEdit:= FindWindowEx(hMainDlg, 0, 'Edit', nil);
wpOrigProc:= Pointer(GetWindowLong(hMainDlg, GWL_WNDPROC));
SetWindowLong(hMainDlg, GWL_WNDPROC, Cardinal(@WindowProc));
// Insert Menu plugin's
hMainMenu:= GetMenu(hMainDlg);
hSubMenu:= CreatePopupMenu;
AddItemMenu(hMainMenu, hSubMenu,'&Plugins', 4);
AddItemPopur(hSubMenu,'String -> Hex', IDC_StrToHex);
AddItemPopur(hSubMenu,'Hex -> String', IDC_HexToStr);
RedrawWindow(hMainDlg, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_UPDATENOW);
end;
Добавление пунктов меню делаем через InsertMenuItem, назначая “Srting -> Hex” и “Hex -> String” индексы IDC_StrToHex и IDC_HexToStr соответственно.
Извращения прилогаются (notepad win7 ×86):

— Maestro · 19 Ноябрь 2015, 10:38 · #
Алексей привет! Очень интересный материал. Было бы интересно почитать про внедрение в код андроид apk, с дезассемблированием, дебагом и обратной сборкой apk!