Бывают ситуации, когда есть софт и хочется в него добавить какую-нибудь очень нужную функцию, нехватающую для полного счастья, но вот незадача ни исходников, ни реализованной системы плагинов в программе нет. Как же быть, смириться и забыть или пойти через дремучий лес и воплотить свою мечту. Вот об одном из возможных путей решения и пойдет речь далее.
Все, о чем будет написано ниже, не является инструкцией к действию, а всего-навсего маленькое сумасшествие из раздела «зачем это надо». В качестве испытуемого возьмем стандартный 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!