- Регистрация
- 9 Май 2015
- Сообщения
- 1,227
- Баллы
- 155
Alphaskins - мой софт, мои правила.
Как то раз мне захотелось украсить свой софт альфаскинами, выбрал я значит самый крутой скин, скомпилировал приложение и.....
Unregistered skin has been loaded.
If you have a key for this skin, please insert it in the KeyList.
Я был очень раздосадован данной несправедливостью! Какой то альфаскин посмел В МОЁМ софте показывать всплывающие окна! Ну а т.к. я еврей и платить 20 баксов за какой то скин не намерен, то решил пойти другим путём - перехватить это сообщение вообще, и в данной статье я напишу как это сделать.
Плюсы Delphi по сравнению с C# и прочими си - мы можем творить всё что угодно со своим приложением! Кстати не только со своим, вообще с любыми. Можно даже модифицировать код программы на лету всего десятком строчек! И назревает вопрос - а зачем платить если можно без труда выпилить это сообщение при старте? Раз Delphi даёт нам такие возможности, то грех не воспользоваться!
Что бы перехватить это сообщение - нам нужно поправить таблицу импорта. Если кто не знает что такое таблица импорта то поясню: в программе есть модули (DLL файлы) в которых содержатся готовые функции такие как MessageBox, что бы вызвать эту функцию программе нужно знать адрес, вот как раз таблица импорта и хранит этот адрес.
Делать это нужно до того как приложение начнёт выполнение, а значит перехватывать мы будем на точке входа:
Не мудрствуя лукаво я погуглил и нашёл в интернете кучу информации по перехвату, но самым стабильным оказался метод с правкой таблицы импорта. Тут всё просто: мы создаём свою функцию которая будет выводить сообщения на экран (или не выводить в случае с альфаскином) и подменяем стандартную функцию нашей.
Всё, теперь мы восстановили контроль над своим приложением и сэкономили 20 баксов.
Как то раз мне захотелось украсить свой софт альфаскинами, выбрал я значит самый крутой скин, скомпилировал приложение и.....
Unregistered skin has been loaded.
If you have a key for this skin, please insert it in the KeyList.

Я был очень раздосадован данной несправедливостью! Какой то альфаскин посмел В МОЁМ софте показывать всплывающие окна! Ну а т.к. я еврей и платить 20 баксов за какой то скин не намерен, то решил пойти другим путём - перехватить это сообщение вообще, и в данной статье я напишу как это сделать.
Плюсы Delphi по сравнению с C# и прочими си - мы можем творить всё что угодно со своим приложением! Кстати не только со своим, вообще с любыми. Можно даже модифицировать код программы на лету всего десятком строчек! И назревает вопрос - а зачем платить если можно без труда выпилить это сообщение при старте? Раз Delphi даёт нам такие возможности, то грех не воспользоваться!
Что бы перехватить это сообщение - нам нужно поправить таблицу импорта. Если кто не знает что такое таблица импорта то поясню: в программе есть модули (DLL файлы) в которых содержатся готовые функции такие как MessageBox, что бы вызвать эту функцию программе нужно знать адрес, вот как раз таблица импорта и хранит этот адрес.
Делать это нужно до того как приложение начнёт выполнение, а значит перехватывать мы будем на точке входа:

Не мудрствуя лукаво я погуглил и нашёл в интернете кучу информации по перехвату, но самым стабильным оказался метод с правкой таблицы импорта. Тут всё просто: мы создаём свою функцию которая будет выводить сообщения на экран (или не выводить в случае с альфаскином) и подменяем стандартную функцию нашей.
Всё, теперь мы восстановили контроль над своим приложением и сэкономили 20 баксов.
Код:
program Project1;
uses
Windows, Forms, Unit1;
var
OrigAddr: Pointer = nil;
{$R *.res}
function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
type
TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
begin
if lpCaption <> 'Unregistered skin' then
Result := TOrigMessageBoxA(OrigAddr)(Wnd, lpText, lpCaption, uType);
end;
function Intercept(const OldProc, NewProc: FARPROC): Boolean;
var
ImportEntry: PImageImportDescriptor;
Thunk: PImageThunkData;
Protect: DWORD;
ImageBase: Cardinal;
DOSHeader: PImageDosHeader;
NTHeader: PImageNtHeaders;
begin
Result := False;
if OldProc = nil then Exit;
if NewProc = nil then Exit;
ImageBase := GetModuleHandle(nil);
DOSHeader := PImageDosHeader(ImageBase);
NTHeader := PImageNtHeaders(DWORD(DOSHeader) + DWORD(DOSHeader^._lfanew));
ImportEntry := PImageImportDescriptor(
DWORD(ImageBase)+
DWORD(NTHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
);
while ImportEntry^.Name <> 0 do begin
Thunk := PImageThunkData(DWORD(ImageBase) + DWORD(ImportEntry^.FirstThunk));
while Pointer(Thunk^._function) <> nil do begin
if Pointer(Thunk^._function) = OldProc then begin
if VirtualProtect(@Thunk^._function, SizeOf(DWORD), PAGE_EXECUTE_READWRITE, Protect) then
try
InterlockedExchange(Integer(Thunk^._function), Integer(NewProc));
Result := True;
finally
VirtualProtect(@Thunk^._function, SizeOf(DWORD), Protect, Protect);
FlushInstructionCache(GetCurrentProcess, @Thunk^._function, SizeOf(DWORD));
end;
end else Inc(PAnsiChar(Thunk), SizeOf(TImageThunkData32));
end;
ImportEntry := Pointer(Integer(ImportEntry) + SizeOf(TImageImportDescriptor));
end;
end;
begin
OrigAddr:=GetProcAddress(GetModuleHandle(user32), 'MessageBoxA');
Intercept(OrigAddr, @InterceptedMessageBoxA);
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.