Во первых объяви вот это:
type
///////////////////////////////////////////////////////////////////
PFunctionRestoreData = ^TFunctionRestoreData;
TFunctionRestoreData = packed record
Address: POINTER;
Val1: BYTE;
Val2: DWORD;
///////////////////////////////////////////////////////////////////
end;
// ФУНКЦИЯ ПЕРЕПИСЫВАЕТ ПЕРВЫЕ 5 БАЙТ У ПЕРЕХВАТЫВАЕМОЙ ФУНКЦИИ
// ЗАПИСЫВАЯ АДРЕС ФУНКЦИИ ОБРАБОТЧИКА
function RewriteFuncCode(CurFuncAddress, NewFuncAddress: POINTER; FuncRestoreData: PFunctionRestoreData): BOOL; stdcall;
var
OldProtect, JMPValue: CARDINAL;
begin
Result := FALSE;
if not VirtualProtect(CurFuncAddress, 5, PAGE_EXECUTE_READWRITE, OldProtect) then Exit;
JMPValue := CARDINAL(NewFuncAddress) - CARDINAL(CurFuncAddress) - 5;
FuncRestoreData^.Val1 := BYTE(CurFuncAddress^);
FuncRestoreData^.Val2 := CARDINAL(Pointer(DWORD(CurFuncAddress) + 1)^);
FuncRestoreData^.Address := CurFuncAddress;
BYTE(CurFuncAddress^) := $E9;
CARDINAL(Pointer(DWORD(CurFuncAddress)+1)^) := JMPValue;
Result := VirtualProtect(CurFuncAddress, 5, OldProtect, OldProtect);
end;
// ФУНКЦИЯ ВОССТАНАВЛИВАЕТ(ЗАПИСЫВАЕТ ИЗНАЧАЛЬНЫЕ)
// ПЕРВЫЕ 5 БАЙТ У ПЕРЕХВАЧЕННОЙ ФУНКЦИИ
function RestoreFuncCode(FuncRestoreData: PFunctionRestoreData): BOOL; stdcall;
var
ProcAddress: POINTER;
OldProtect, JMPValue: CARDINAL;
begin
Result:=False;
ProcAddress := FuncRestoreData^.Address;
if not VirtualProtect(ProcAddress, 5, PAGE_EXECUTE_READWRITE, OldProtect) then Exit;
Byte(ProcAddress^) := FuncRestoreData^.Val1;
CARDINAL(POINTER(CARDINAL(ProcAddress) + 1)^) := FuncRestoreData^.Val2;
Result := VirtualProtect(ProcAddress, 5, OldProtect, OldProtect);
end;
// ФУНКЦИЯ УСТАНАВЛИВАЕТ ПЕРЕХВАТ ВЫЗОВОВ API ФУНКЦИЙ
function SetFuncHook(ModuleHandle: CARDINAL; FuncName: PWideChar; NewFuncAddress: POINTER; FuncRestoreData: PFunctionRestoreData): BOOL; stdcall;
var
FuncAddress: POINTER;
begin
FuncAddress := GetProcAddress(ModuleHandle, FuncName);
Result := RewriteFuncCode(FuncAddress, NewFuncAddress, FuncRestoreData);
//RestoreFuncCode(FuncRestoreData);
end;
Перехват сохранения в файл
необходимо перехватить запись в файл.
пример, на рабочем столе есть текстовый файлик с текстом, после чего я его изменяю добавляя в него текст, и нажимаю сохранить..
как сделать перехват сохранения чтобы он сохранился не в старый уже существующий файлик а в новый файлик в другом месте?
заранее спасибо, обгуглился по горло ничего не нашёл, прошу вашей помощи товарищи!
а что нибудь конкретнееможно в студию?
Либо пишешь драйвер, либо dll, которая будет сплайсить вход в функцию WriteFile. Конкретней некуда.
Или ты думаешь, что это все в одну функцию делается и тут можно дать тебе код?
Вкратце, Вам нужно перехватить системную функцию WriteFileEx, причем перехватывать её надо не где-то там, а конкретно внутри процесса, который будет сохранять нужный Вам файл.
Такого можно добиться установив хук SetWindowsHookEx (погуглите). После этого Ваша dll будет находится почти во всех процессах, у которых есть интерфейс (GUI).
Еще посоветую Вам, чтобы не дербанить много материала по перехватам и прочей фигне, просто скачать библиотеку Microsoft Detours. Была там бесплатная для некоммерческого использования версия. Один минус - урезанный функционал (не сможете перехватывать в 64 разрядном процессе).
Лучше обе - и WriteFileEx, и WriteFile. Если не ошибаюсь, то это всё-таки разные функции с разными точкам входа.
Код:
// ФУНКЦИЯ ЗАГРУЖАЕТ ДЛЛ В УКАЗАННЫЙ ПРОЦЕСС
function InjectDLL(PId: CARDINAL; DllPath: WideString): BOOL; stdcall;
var
RemotePMem, StartAddress: POINTER;
LibPathLen, HProcess, RealWrite, MyTId, HThread: CARDINAL;
WriteProcess: BOOL;
begin
Result := FALSE;
LibPathLen := Length(DllPath)*2; // Вот тут осторожнее, у меня такой изврат пошёл из за юникода. Length подсчитывает количиство символов но не учитывает что они юникодовские(на этом месте я встрял на долго пока меня не осинило).
HProcess := OpenProcess(PROCESS_ALL_ACCESS, TRUE, PId);
if HProcess = 0 then
begin
ShowMessage('Не удалось получить доступ к процессу.');
Result := FALSE;
Exit;
end
else
RemotePMem := VirtualAllocEx(HProcess, NIL, LibPathLen, MEM_COMMIT, PAGE_READWRITE);
if not Assigned(RemotePMem) then
begin
ShowMessage('Ошибка выделения памяти в процессе "жертве".');
Result := FALSE;
CloseHandle(HProcess);
Exit;
end
else
StartAddress := GetProcAddress(GetModuleHandle('kernel32.dll'), 'LoadLibraryW'); // Вот я получаю юникод версию, т.к. сконвертить путь к длл юникод в анси так и не смог(там какая то чудовищная функция на понимание которой мне показалось уйдет пол жизни ( а аптечек нету, и до фантана пополняющего жизнь не добежать :-) )).
if not Assigned(StartAddress) then
begin
ShowMessage('Ошибка в получении адреса функции "LoadLibraryW".');
Result := FALSE;
CloseHandle(HProcess);
Exit;
end
else
WriteProcess := WriteProcessMemory(HProcess, RemotePMem, PWideChar(DllPath), LibPathLen, RealWrite);
if WriteProcess = FALSE then
begin
ShowMessage('Ошибка записи в память процесса.');
Result := FALSE;
CloseHandle(HProcess);
Exit;
end
else
HThread := CreateRemoteThread(HProcess, NIL, 0, StartAddress, RemotePMem, 0, MyTId);
if HThread = 0 then
begin
ShowMessage('Ошибка в создании удалённого потока.');
Result := FALSE;
CloseHandle(HProcess);
Exit;
end
else
CloseHandle(HProcess);
Result := TRUE;
end;
Если у тебя с анси всё норм тогда получай адреса анси версий и без всяких умножений на 2
function InjectDLL(PId: CARDINAL; DllPath: WideString): BOOL; stdcall;
var
RemotePMem, StartAddress: POINTER;
LibPathLen, HProcess, RealWrite, MyTId, HThread: CARDINAL;
WriteProcess: BOOL;
begin
Result := FALSE;
LibPathLen := Length(DllPath)*2; // Вот тут осторожнее, у меня такой изврат пошёл из за юникода. Length подсчитывает количиство символов но не учитывает что они юникодовские(на этом месте я встрял на долго пока меня не осинило).
HProcess := OpenProcess(PROCESS_ALL_ACCESS, TRUE, PId);
if HProcess = 0 then
begin
ShowMessage('Не удалось получить доступ к процессу.');
Result := FALSE;
Exit;
end
else
RemotePMem := VirtualAllocEx(HProcess, NIL, LibPathLen, MEM_COMMIT, PAGE_READWRITE);
if not Assigned(RemotePMem) then
begin
ShowMessage('Ошибка выделения памяти в процессе "жертве".');
Result := FALSE;
CloseHandle(HProcess);
Exit;
end
else
StartAddress := GetProcAddress(GetModuleHandle('kernel32.dll'), 'LoadLibraryW'); // Вот я получаю юникод версию, т.к. сконвертить путь к длл юникод в анси так и не смог(там какая то чудовищная функция на понимание которой мне показалось уйдет пол жизни ( а аптечек нету, и до фантана пополняющего жизнь не добежать :-) )).
if not Assigned(StartAddress) then
begin
ShowMessage('Ошибка в получении адреса функции "LoadLibraryW".');
Result := FALSE;
CloseHandle(HProcess);
Exit;
end
else
WriteProcess := WriteProcessMemory(HProcess, RemotePMem, PWideChar(DllPath), LibPathLen, RealWrite);
if WriteProcess = FALSE then
begin
ShowMessage('Ошибка записи в память процесса.');
Result := FALSE;
CloseHandle(HProcess);
Exit;
end
else
HThread := CreateRemoteThread(HProcess, NIL, 0, StartAddress, RemotePMem, 0, MyTId);
if HThread = 0 then
begin
ShowMessage('Ошибка в создании удалённого потока.');
Result := FALSE;
CloseHandle(HProcess);
Exit;
end
else
CloseHandle(HProcess);
Result := TRUE;
end;
Если у тебя с анси всё норм тогда получай адреса анси версий и без всяких умножений на 2
В своей длл которую будеш внедрятить добавь вот такие функции :
Код:
Вот тебе пример как я перехватывал разрушение окна:
Код:
Это всё там же в длл если кто не понял
// ФУНКЦИЯ ВЫЗЫВАЕМАЯ В ОТВЕТ НА ВЫЗОВ СТАНДАРТНОЙ DestroyWindow
// ПРИ ЗАКРЫТИИ ОКНА
function MyDestroyWindow(Handle: HWND): BOOL; stdcall; export;
var
DestroyWindowState: BOOL;
begin
RestoreFuncCode(Addr(DestroyWindowRestoreData));
// тут выполняем нужные нам действия
// перед убийством окна, я например проверял хендл переданный в функцию
// с имеющимся у меня и если они совпадают то я вообще больше не ставил хук
DestroyWindowState := DestroyWindow(Handle); // Обрати внимание, мы вызываем стандартную т.к её только что восстановили(она теперь как родненькая).
if Handle = ParentHandle then Exit; // Тут я уже не следил что будет возвращать функция т.к это уже был конец работы приложения.
SetFuncHook(User32Handle, 'DestroyWindow', MyDestroyWindowAddr, Addr(DestroyWindowRestoreData));
Result := DestroyWindowState;
end;
Хук должен быть установлен при загрузке длл, для чего мы пишем в самом низу длл:
begin
// получаем тут все пути, пиды, хендлы которые нам понадобятся и ставим перехват
SetFuncHook(User32Handle, 'DestroyWindow', MyDestroyWindowAddr, Addr(DestroyWindowRestoreData));
end.
// ФУНКЦИЯ ВЫЗЫВАЕМАЯ В ОТВЕТ НА ВЫЗОВ СТАНДАРТНОЙ DestroyWindow
// ПРИ ЗАКРЫТИИ ОКНА
function MyDestroyWindow(Handle: HWND): BOOL; stdcall; export;
var
DestroyWindowState: BOOL;
begin
RestoreFuncCode(Addr(DestroyWindowRestoreData));
// тут выполняем нужные нам действия
// перед убийством окна, я например проверял хендл переданный в функцию
// с имеющимся у меня и если они совпадают то я вообще больше не ставил хук
DestroyWindowState := DestroyWindow(Handle); // Обрати внимание, мы вызываем стандартную т.к её только что восстановили(она теперь как родненькая).
if Handle = ParentHandle then Exit; // Тут я уже не следил что будет возвращать функция т.к это уже был конец работы приложения.
SetFuncHook(User32Handle, 'DestroyWindow', MyDestroyWindowAddr, Addr(DestroyWindowRestoreData));
Result := DestroyWindowState;
end;
Хук должен быть установлен при загрузке длл, для чего мы пишем в самом низу длл:
begin
// получаем тут все пути, пиды, хендлы которые нам понадобятся и ставим перехват
SetFuncHook(User32Handle, 'DestroyWindow', MyDestroyWindowAddr, Addr(DestroyWindowRestoreData));
end.
Вот тебе и вторая половина дела, я недавно с этим занимался и с нуля конечно же тяжкое бремя.
Там тебе советовали с драйвером повозиться, как я понимаю нужно писать драйвер виртуального устройства но в твоём случае не считаю это хорошей идеей, тут будет достаточно обычного локального перехвата.
И ещё, чтоб понять какую именно функцию перехватывать тебе нужно использовать API Monitor, установиш хук в нём на тот процесс который занимается сохранением файла, и не забудь в фильтре убрать выделение со всех функций кроме предпологаемых к перехвату иначе там может появляться тысяча записей о перехватах в которых потом сложно разобраться.
Так ты увидиш какую именно вызывает твоя прога, она же не может при сохранении и ту и ту вызывать?