Последние записи
- Windows 10 сменить администратора
- Рандомное слайдшоу
- Событие для произвольной области внутри TImage
- Удаление папки с файлами
- Распечатка файла
- Преобразовать массив байт в вещественное число (single)
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
29th
Перехват API функций. Основы. Delphi
Перехватывая API функции, мы увеличиваем наши возможности и граница им только наше воображение. Для прочтения данной статьи с максимальной пользой обязательны хоть начальные знания низкоуровневого программирования и знание архитектуры работы Windows.
Сегодня я вам расскажу наиболее действенную методику перехвата API функций – сплайсинг. Сплайсинг это подмена кода функции. Конечно, есть другой метод перехвата это редактирование таблицы импорта приложения. Рассказывать буду по порядку.
Когда вы пишете в своём приложении так
Function Func1(param*:type*):restype*;stdcall;external ‘libname.dll’;
Вы импортируете функцию статически. Адрес функции прописывается в таблице импорта вашего приложения (допустим, что адрес нашей функции $7BC56010).
адрес значение
……
$00405F56 7BC56010
……
А при вызове функции происходит так
Push …
push …
call dword ptr
Следовательно, для перехвата функции нам надо только подменить значение по адресу $00405F56 на своё, а для вызова оригинальной функции получать адрес функции через GetProcAddress. Но приложение может также получить адрес функции через GetProcAddress и вызывать перехватываемую функцию минуя, перехватчик. Данный метод бесперспективен.
Идём дальше. Теперь я объясню технику сплайсинга. Наша функция находится по адресу $7C80B529 и допустим, что там такой код
7C80B529 | 8BFF | mov | edi, edi |
7C80B52B | 55 | push | ebp |
7C80B52C | 8BEC | mov | ebp, esp |
7C80B52E | 837D 08 00 | cmp | dword ptr ss:[ebp+8], 0 |
Для перехвата функции от нас требуется только переписать начальный код функции, так чтобы он передавал управление нашему обработчику. Для передачи управления нашему обработчику достаточно всего лишь одной инструкции jmp на абсолютный адрес. Эта инструкция займёт всего лишь 5 байт – сам опкод этой инструкции ($E9) и значение для прыжка. Это значение вычисляется так
v=0-(s-d)
s – Смещение следующей команды
d – Требуемый адрес для jmp, т.е. адрес обработчика
Если немного переделать эту формулу, то она будет выглядеть так
v=d-FunctionAddress-5
Теперь при каждом вызове целевой функции, всегда будет передаваться управление нашему обработчику. А как теперь вызвать оригинальную функцию. При установке перехвата нам надо сохранять первые 5 байт функции. Для вызова оригинала надо восстанавливать надо функции и вызывать ее, потом снова устанавливать перехват. Объявим структуру в которой будем сохранять первые 5 байт функции:
PFunctionRestoreData = ^ TFunctionRestoreData;
TFunctionRestoreData = packed record
Address:Pointer;
val1:Byte;
val2:DWORD;
end;
Поле Address фактически в этой структуре не нужен (он просто не к чему), но, тем не менее, так удобнее снимать перехват, потом сами поймете, зачем это поле нужно. Назовём эту структуру “мост” к старой функции.
Теперь напишем функцию, которая будет устанавливать перехват:
{
ProcAddress, ????????? ?? ??????? ???????
NewProcAddress:pointer; ????????? ?? ??????? ???????????
RestoreDATA:PFunctionRestoreData ????????? ?? ???? ? ?????? ???????
Result: boolean ??????????
}
function SetCodeHook(ProcAddress, NewProcAddress: pointer; RestoreDATA:PFunctionRestoreData):boolean;
var
OldProtect, JMPValue:DWORD;
begin
Result:=False;
if not VirtualProtect(ProcAddress,5,PAGE_EXECUTE_READWRITE,OldProtect) then exit;
JMPValue := DWORD (NewProcAddress) – DWORD (ProcAddress) – 5;
RestoreDATA^.val1:= Byte(ProcAddress^);
RestoreDATA^.val2:= DWORD(Pointer(DWORD(ProcAddress)+1)^);
RestoreDATA^.Address:=ProcAddress;
byte(ProcAddress^):=$E9;
DWORD(Pointer(DWORD(ProcAddress)+1)^):=JMPValue;
Result:=VirtualProtect(ProcAddress,5,OldProtect,OldProtect);
end;
Мы сначала устанавливает атрибуты доступа к коду функции, так чтобы можно было его переписывать. Потом вычисляем значение для прыжка. Сначала сохраняем начало функции в запись, потом переписываем начало функции. В конце устанавливаем старые атрибуты доступа. Теперь напишем функцию которая будет снимать перехват:
{
Procedure: UnHookCodeHook
RestoreDATA:PFunctionRestoreData ????? ????? ? ?????? ???????
}
function UnHookCodeHook(RestoreDATA:PFunctionRestoreData):Boolean;
var
ProcAddress:Pointer;
OldProtect,JMPValue:DWORD;
begin
Result:=False;
ProcAddress:=RestoreDATA^.Address;
if not VirtualProtect(ProcAddress,5,PAGE_EXECUTE_READWRITE,OldProtect) then exit;
Byte(ProcAddress^):=RestoreDATA^.val1;
DWORD(Pointer(DWORD(ProcAddress)+1)^):=RestoreDATA^.val2;
Result:=VirtualProtect(ProcAddress,5,OldProtect,OldProtect);
end;
Я думаю, что здесь всё понятно – просто восстанавливаем начало перехватываемой функции. Адрес перехватываемой функции берём из структуры указатель, на которую передаётся функции в качестве единственного параметра.
Теперь напишем функцию, которая будет устанавливать перехват по имени функции. Я думаю что она тоже не слишком сложная.
{
ModuleHandle:HMODULE; Хендл модуля, в котором находится целевая функция
ProcedureName:PChar; Имя процедуры
NewProcedureAddress:Pointer; Указатель на процедуру перехватчик
RestoreDATA:PFunctionRestoreData Указатель на мост к старой функции
Result: Boolean Успешность установки перехвата
}
function SetProcedureHook(ModuleHandle:HMODULE;ProcedureName:PChar;NewProcedureAddress:Pointer;
RestoreDATA:PFunctionRestoreData):Boolean;
var
ProcAddress:Pointer;
begin
ProcAddress:=GetProcAddress(ModuleHandle,ProcedureName);
Result:=SetCodeHook(ProcAddress,NewProcedureAddress,RestoreDATA);
end;
Идём дальше. Описанные выше функции могут перехватывать функции только в текущем процессе. А как нам перехватывать функции в других процессах. Наиболее простой метод это засунуть перехватчик функции в DLL и в коде библиотечной функции устанавливать перехват, если DLL загружается в процесс и снимать перехват, если она выгружается. Тут ещё одна проблема: как заставить другой процесс загрузить нашу DLL’ку. Наиболее простое решение это создание удалённых потоков. Теперь всё по порядку.
Удалённый поток создаётся функцией CreateRemoteThread.
HANDLE CreateRemoteThread(
HANDLE hProcess, // хендл потока в котором создаётся поток
LPSECURITY_ATTRIBUTES lpThreadAttributes,//атрибуты безопасности
DWORD dwStackSize, //размер стека
LPTHREAD_START_ROUTINE lpStartAddress,//адрес функции потока т.е. адрес первой инструкции потока
LPVOID lpParameter, // указатель на параметр для функции
DWORD dwCreationFlags, // флаги создания
LPDWORD lpThreadId // указатель на переменную, в которой будет сохранён ID потока
);
Функция потока должна иметь следующие атрибуты
DWORD WINAPI ThreadFunc(PVOID pvPararn)
По ходу наверно WINAPI обозначает stdcall это не важно, что она обозначает, всё равно она должна быть объявлена как stdcall. У функции только один параметр -это обычный указатель. Теперь проанализируем ситуацию… Думаем…Шевелим мозгами…Функция LoadLibraryA имеет такие же атрибуты. Она принимает указатель на первый символ имени файла DLL(строка должна кончаться символом #0). Следовательно, функция LoadLibraryA полностью подходит для того, что бы она могла выступать в качестве функции потока. Так как она принимает указатель на строку в своём процессе, нам надо будет записать в память чужого процесса нашу строку и именем файла DLL. Это делается функцией WriteProcessMemory. Вот её описание
BOOL WriteProcessMemory(
HANDLE hProcess, // хендл процесса
LPVOID lpBaseAddress,// адрес по которому надо писать
LPVOID lpBuffer, // указатель на буфер
DWORD nSize, // количество байт для записи
LPDWORD lpNumberOfBytesWritten //количество реально записанных байт
);
Адрес функции LoadLibraryA мы получаем с помощью функции GetProcAddress так библиотека kernel32.dll и ntdll.dll грузятся во все процессы всегда по одним и тем же адресам, следовательно, то адрес, полученный в адресном пространстве нашего процесса, будет действителен и адресном пространстве любого другого процесса. Теперь напишем функцию, которая загружает вашу DLL в адресное пространство чужого процесса.
function LoadLibrary_Ex(ProcessID:DWORD;LibName:PChar):boolean;
var
pLL,pDLLPath:Pointer;
hProcess,hThr:THandle;
LibPathLen,_WR,ThrID:DWORD;
begin
Result:=False;
LibPathLen:=Length(string(LibName));
hProcess:=OpenProcess(PROCESS_ALL_ACCESS,false,ProcessID);
if hProcess=0 then exit;
pDLLPath:=VirtualAllocEx(hProcess,0,LibPathLen+1,MEM_COMMIT,PAGE_READWRITE);
if DWORD(pDLLPath)=0 then exit;
pLL:=GetProcAddress(GetModuleHandle(kernel32),’LoadLibraryA’);
WriteProcessMemory(hProcess,pDLLPath,LibName,LibPathLen+1,_WR);
hThr:=CreateRemoteThread(hProcess,0,0,pLL,pDLLPath,0,ThrID);
if hThr=0 then exit;
Result:=CloseHandle(hProcess);
end;
Таким образом, мы загрузили свою DLL в чужой процесс. Вообще – то внедрение своего кода это совсем другая история и требует написания отдельной статьи. Иногда процессу не разрешается изменение памяти системных процессов, таких как winlogon.exe, lsass.exe, smss.exe, csrss.exe и др. для этого нужна привилегия SeDebugPrivilege в исходник модуля для перехвата API функций есть функция EnableDebugPrivilege которая включает эту привилегию для текущего процесса.
Идём дальше. Теперь у нас мы научились загружать свою DLL в чужой процесс. Но для должного эффекта нам надо перехватывать DLL во всех процессах системы. Но как это сделать. Можно просто перечислять процессы через ToolHelp32 и загружать свою DLL в каждый найденный процесс. Но не приемлемо, так как во вновь созданных процессах функции не будут перехвачены. Но можно каждую секунду перечислять процессы, короче это тоже неприемлемо и очень долгая история. Самый простой метод это воспользоваться техникой так называемых хуков. Когда мы ставим глобальный хук на сообщения окон с помощью функции SetWindowsHookEx этой функции мы передаёт адрес функции обработчика и хендл DLL в которой находится функция обработчик. После того как какое-либо приложение хочет отправить какому-нибудь окну, то проверяется, установлена ли ловушка на сообщение, которое он хочет послать окну. Если да то загружается DLL, в которой находится обработчик сообщений, вызывается обработчик и т.д. Следовательно, после установки хука на сообщения наша DLL будет находиться во всех процессах, которые хотя бы один раз отправили сообщения окнам, т.е. почти во всех GUI процессах. Каркас DLL с перехватом функций будет выглядеть так примерно так
library HideDLL;
const
MutexName=’__API_HOOK’;
……………
//обработчик сообщений
function MsgProc(code:DWORD;wParam,lparam:DWORD):DWORD;stdcall;
begin
CallNextHookEx(SH,code,wParam,lparam);
end;
//внедрение нашей DLL во все GUI процессы
procedure SetWindowsHook(e:Boolean); stdcall;
var
M:THandle;
begin
if e then
begin
m:=CreateMutex(0,false,MutexName);
if m=0 then exit;
SH:=SetWindowsHookEx(WH_GETMESSAGE,@MsgProc,HInstance,0);
end
else
UnhookWindowsHookEx(sh);
end;
//главный библиотечный обработчик
procedure DLLEntryPoint(dwReason:DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
// StopProcess(GetCurrentProcessId);
SetWindowsHook(true);
SetProcedureHook(GetModuleHandle(’ntdll.dll’),’ZwQuerySystemInformation’,@NewSystemFunction,@SystemFunctionBridge);
// ResumeProcess(GetCurrentProcessId);
end;
DLL_PROCESS_DETACH:
begin
// StopProcess(GetCurrentProcessId);
SetWindowsHook(false);
UnHookCodeHook(@SystemFunctionBridge);
//ResumeProcess(GetCurrentProcessId);
end;
end;
end;
begin
DllProc:= @DLLEntryPoint; //устанавливаеем библиотечный обработчик
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Чтобы установить перехват на API функции во всех процессах (во всех GUI процессах) достаточно просто загрузить нашу DLL. Достаточно написать вот такой код:
LoadLibrary(pchar(ExtractFileDir(Application.ExeName)+’\’+’HideDLL.dll’));
В архиве с исходниками есть модуль с функциями перехвата API там есть все функции, которые я сегодня использовал и описывал.
Вот, пожалуй, и всё на сегодня. В архиве так же есть пример скрытия процесса lsass.exe.
Руслан Аблязов E-mail
1st
Янв
Базы данных в Delphi
Шумаков
Базы данных в среде Delphi 3. В книге будут рассматриваться: средства Delphi для разработки приложений, использующих базы данных, Delphi компоненты для работы с базами данных, построение отчетов, разработка систем принятия решений, построение приложений баз данных в архитектуре “клиент-сервер”, свойства, методы, события.
От автора:
Без баз данных сегодня невозможно представить работу большинства финансовых, промышленных, торговых и прочих организации. Потоки информации, циркулирующие в мире, который нас окружает, огромны. Во времени они имеют тенденцию к увеличению. Не будь баз данных, мы давно захлебнулись бы в информационной лавине. Базы данных позволяют информацию структурировать, хранить и извлекать оптимальным для пользователя образом.
Поскольку использование баз данных является одним из краеугольных камней, на которых построено существование различных организаций, пристальное внимание разработчиков приложений баз данных вызывают инструменты, при помощи которых такие приложения можно было бы создавать. Выдвигаемые к ним требования в общем виде можно сформулировать как: “быстрота, простота, эффективность, надежность”.
В основе такой общепризнанной популярности Delphi лежит тот факт, что Delphi, как никакая другая система программирования, удовлетворяет изложенным выше требованиям. Действительно, приложения с помощью Delphi разрабатываются быстро, причем взаимодействие разработчика с интерактивной средой Delphi не вызывает внутреннего отторжения, а наоборот, оставляет ощущение комфорта. Delphi-приложения эффективны, если разработчик соблюдает определенные правила (и часто – если не соблюдает). Эти приложения надежны и при эксплуатации обладают предсказуемым поведением.
Но вот проста ли Delphi? И да, и нет. Она лишь кажется простой, поскольку многие “подводные камни” скрыты от разработчика. Однако чем больше изучаешь ее, тем больше становится ясной ее глубина, которая одновременно и вызывает уважение, и пугает. Лишь со временем приходит понимание того, что для написания действительно мощных и функциональных приложений требуется постоянное изучение Delphi.
В книге вы узнаете:
4. Компоненты для работы с базами данных
5. Работа с утилитой BDE Administrator
6. Работа с полями – компонент TField
7. Общие принципы работы с наборами данных
8. Работа с компонентом ТТаblе
9. Работа с компонентом TQuery
10. Использование компонента TDBGrid
11. Визуальные компоненты для работы с текущей записью набора данных
12. Компонент TSession
13. Построение графиков. Компонент TDBChart
14. Введение в построение отчетов
15. Введение в разработку систем принятия решений
16.Построение приложений баз данных в архитектуре “клиент-сервер”
17. Пример создания удаленной БД и приложения
18. Работа с утилитой Windows Interactive SQL (WISQL)
19. Создание базы данных
20. Типы столбцов таблиц БД
21. Создание доменов
22. Создание таблиц
23. Работа с индексами
25. Оператор SELECT
26. Добавление, изменение, удаление записей
27. Работа с просмотрами VIEW
28. Работа с хранимыми процедурами
29. Работа с триггерами
30. Использование генераторов
31. Использование утилиты Database Explorer
32. Транзакции
33. Кэшированные изменения
34.Работа с событиями
35. Функции, определяемые пользователем
36. Определение бизнес-правил
37. Оптимизация работы с БД
38. Работа с утилитой InterBase Server Manager
39. Установка привилегий доступа. Свойства, методы, события. Формат SQL-операторов (СУБД InterBase)
31st
Дек
Модуль архивации – создание и использование Delphi
как пользоваться библиотекой ZLib которая начала поставляться с Delphi начиная с версии 7. Конечно, её можно было использовать и в предыдущих версиях, но для правильного функционирования программы нужно было всё время таскать вместе с программой библиотеку ZLib.dll. В седьмой версии всё стало проще, Delphi внедряла прямо в программу этот модуль с максимальной оптимизацией. Поэтому нам можно не думать о том, как программе носить с собой библиотеку ZLib.dll.
29th
Авг
Загадочный тип PCHAR (delphi)
Здравствуйте, дельфисты! Сегодня вам поведую, что это за тип PCHAR. И как его корректно использовать. Этот тип упоминается во всех API функциях, которые принимают в качестве параметра какое-либо строковое значение.
Облако меток
css реестр ассемблер timer SaveToFile ShellExecute программы массив советы word MySQL SQL ListView pos random компоненты дата LoadFromFile form база данных сеть html php RichEdit indy строки Win Api tstringlist Image мысли макросы Edit ListBox office C/C++ memo графика StringGrid canvas поиск файл Pascal форма Файлы интернет Microsoft Office Excel excel winapi журнал ПРОграммист DelphiКупить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)