Исключение простого ассемблерного кода в C без его присутствия в функции

#c #hook #inline-assembly

#c #перехват #встроенная сборка

Вопрос:

Я пытаюсь написать перехват батута для какой-либо функции win32 api, когда я пишу инструкцию JMP в начало исходной функции, я хочу, чтобы она переходила в кодовое хранилище вместо вызова функции.

Исходный запуск функции выглядит следующим образом в OllyDbg:

 PUSH 14
MOV EAX, 12345678
...
  

И я исправляю его, чтобы:

 JMP 87654321
NOP
NOP
  

Адрес следующей функции:

 int HookFunc(int param)
{
    DoStuff(param);
    return ExecuteOriginal(param);
}
  

ExceuteOriginal выглядит так:

 unsigned long address = AddressOfOriginalFunction   7;

int ExceuteOriginal(int param)
{
    __asm
    {
        PUSH 0x14
        MOV EAX, 0x12345678
        JMP address
    }
}
  

Который выполняет переопределенный код и переходит к исходной функции сразу после исправленного кода. Проблема в том, что, поскольку это функция, она испортит стек, потому что вызывающий должен его очистить, а функция вместо возврата переходит к коду другой функции. И я думаю, именно поэтому программа вылетает.

Есть ли способ с помощью компилятора Visual C поместить ассемблерный код в раздел кода программы, не помещая его внутри функции? Таким образом, я могу перейти туда, выполнить что угодно и вернуться обратно без риска испортить стек.

Ответ №1:

Решение: __declspec(naked)

Для функций, объявленных с атрибутом naked, компилятор генерирует код без кода prolog и epilog. Вы можете использовать эту функцию для написания собственных последовательностей кода prolog / epilog, используя встроенный ассемблерный код.

Пример:

 __declspec( naked ) int ExceuteOriginal(int param)
{
    __asm
    {
        PUSH 14
        MOV EAX, 0x12345678
        JMP address
    }
}
  

Комментарии:

1. Большое спасибо! Это именно то, что я искал! 1 для простого решения