Sojang, для начала определитесь вообще, что Вы хотите, а не бездумно копируйте код)
jmp - безусловный переход и не более того.
push/ret - аналог jmp.
call - кидает на стек текущий адрес и прыгает на указанный адрес; если функция ret-ается, то у нас происходит возврат туда откуда был call (адрес caller'a на стеке же есть).
Для вызова оригинальной функции нужно выполнить, то что было затерто переходом (jmp/push-ret/call), обычно это
пролог функции по какому-нибудь calling conventions, а-ля, stdcall для win32. При вызове оригинальной функции, мы смещаемся на то количество байтов, которое мы перетерли.
Пример: адрес функции 0x1000, мы переписали первые 5 байт на jmp, значит мы реализуем перетертые 5 байт и делаем переход на 0x1005, грубо говоря.
Если затерто было БОЛЬШЕ пролога, да и вообще чето как-то получилось, то что размер перетертых команд не совпадает с размером команд, которыми мы заменили, то пишем дизассемблер длин, нопим кривые куски команд и делаем все то же самое, но реализовывать обратный переход надо уже с учетом того, что мы нопнули.
Можно конечно оботись костылем такого вида: если у нас перехваченная функция гарантированно дергается в один поток, то можно просто снимать хук, когда мы хотим перейти назад и ставить его опять, после того, как мы получим результат работы функции. Главное не забыть сбросить instruction cache, иначе ничего не поменяется