Сплайсинг
Код внедряемой длл:
OldCode = packed record
One: dword;
two: word;
end;
far_jmp = packed record
PuhsOp: byte;
PushArg: pointer;
RetOp: byte;
end;
var
JmpMba: far_jmp;
OldMba: OldCode;
MbaAdr: pointer;
function NewMessageBox: Integer; stdcall;
var
Bytes: dword;
begin
WriteProcessMemory(INVALID_HANDLE_VALUE, MbaAdr, @OldMba, SizeOf(OldCode), Bytes);
asm
mov eax, dword ptr MbaAdr
add eax, 5
jmp eax
end;
end;
Procedure SetHook();
var
hUser32: dword;
Bytes,OldProtect: dword;
begin
hUser32 := GetModuleHandle('user32.dll');
MbaAdr := GetProcAddress(hUser32, 'MessageBoxExA');
ReadProcessMemory(INVALID_HANDLE_VALUE, MbaAdr, @OldMba, SizeOf(OldCode), Bytes);
VirtualProtect(MbaAdr,6,PAGE_EXECUTE_READWRITE,OldProtect);
JmpMba.PuhsOp :=$68;
JmpMba.PushArg := @NewMessageBox;
JmpMba.RetOp := $C3;
WriteProcessMemory(INVALID_HANDLE_VALUE, MbaAdr, @JmpMba, SizeOf(far_jmp), Bytes);
end;
.........
В идеале при перехвате происходит джамп на мою функцию NewMessageBox, затем восстанавливается затертый джампом участок памяти и джамп обратно.. и как следствие правильное выполнение функции MessageBoxExA. Фукция выполняется правильно, но после закрытия MessadgeBox'a закрывается почему-то и программа, его вызвавшая...
Кто-нибудь может подсказать, в чем проблема? Вобзможно в этом коде
add eax, 5
jmp eax
По коду у вас не восстанавливаются байты, после того, как MessageBox отработает и еще возможно, что компилятор вставляет фрейм в процедуру и выход из MsgBox будет не туда, куда надо. В дизасме или отладчике поглядите и поймете почему ошибка.
Почему не восстанавливаются? Я записываю созраненные 6 байт в начало перехватываемой функции. После этого выполняю на неё джамп. По-хорошему первоначальный вид перехватываемой функции в памяти не должен был измениться, разве не так?
вы восстановили ориг. байты функции, она отработала и после этого обычно снова патчат начало функции (конечно если не надо, чтобы хук только один раз отработал). к тому же у вас скорее всего в стеке лежат еще данные, например локальные переменные (var Bytes: dword), поэтому может стать так, что адрес возврата будет неправильный и приложение "упадет"
кстати сплайсинг плох тем, что потоконебозопасный. может быть имеет смысл юзать критические секции.
Иначе - это значит я не знаю, какую функцию перехватываю, а считываю её название из файла. Поэтому не могу написать что-то типо result:=MessageBoxExA (...);
Я должен совершить джамп обратно,чтобы вынкция выполнилась.
к тому же у вас скорее всего в стеке лежат еще данные, например локальные переменные (var Bytes: dword), поэтому может стать так, что адрес возврата будет неправильный и приложение "упадет"
А как решить эту проблему? Удалить Bytes из стека?
Только если заменить user32.dll на kernel32.dll, а MessageBoxA на CreateFileA, то вылетает ошибка :(
У меня главная задача - возможность перехвата любой функции...
И вам не кажется, что вы это сделали как-то сложно? Неужели нельзя проще?
Например вот так http://hellknights.void.ru/articles/cch-hotpatching.txt
Вот только если я заменяю MessageBoxA на CreateFileA,а user32 на kernel32,
то программа выдает ошибку.. У меня главная задача, чтобы прога могла перехватывать любые АПИ функции по их названию и названию библиотеки.
И вам не кажется, что вы сделали слишком сложно? Разве нельзя было проще? Например вот так ?
add eax, 5
jmp eax
Не, ну вообще забавно. Из NewMessageBox, где стек уже искажен локальной переменной Bytes, и может быть, прочей чепухой сразу брать тай переходить джампом на адрес в другой функции... аяяй. Нехорошо. Ну а смысл записать оригинальные байты и перейти на +5 байт вперед - ето что шутка? Если подумать, то 0x68 + DWORD + 0xc3 == 6 байт, ну может я чего не понял. 5 или 6 - какая разница. Главное что ети байты что-то в оригинальной функции делают, а ты их просто взял и пропустил. То что ор. функция отрабатывает правильно - ето чудо.
Короче. Как надо делать :):
1) Читаем оригинальные байты (чтобы не прогадать с количеством нужен дисассемблер длин инструкций).
2) Строим код перехода:
ret
3) Строим мост:
push АдресФункции
add [esp],ДлинаЗатертыхИнструкций
ret
4) На место оригинальных байт ставим код перехода на новый обработчик.
// шото делаем...
push args
call мост
}
Следует сказать о многопоточности. Приведенный мною метод вроде безопасен в етом плане (сам не проверял).