Вызовите оригинальную функцию после подключенной функции

0

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

Моя программа просто ждет любой ключ и печатает текст.

Мой крючок (DLL):

#include <windows.h>
#include <stdio.h>

void WriteMem(DWORD dwAddr, BYTE *dwNew, int Size);

void MyPrintf(char *text)
{
    printf("\n Original message: %s\n", buff);
}

void WriteMem(DWORD dwAddr, BYTE *dwNew, int Size)
{
    DWORD OldProt;
    VirtualProtect((void*)dwAddr, Size, PAGE_EXECUTE_READWRITE, &OldProt);
    memset((void*)(dwAddr), 0x90, Size);
    memcpy((void*)(dwAddr), (void*)(dwNew), Size);
    VirtualProtect((void*)(dwAddr), Size, OldProt, &OldProt);
}

void SetJMP(INT32 dwOld, LPVOID dwNew, INT32 Size)
{
    BYTE dwNewBytes[5] = {0xE9, 0x00, 0x00, 0x00, 0x00};
    DWORD calc = ((DWORD)dwNew - dwOld - 5); 
    memcpy(&dwNewBytes[1], &calc, 4);
    WriteMem(dwOld, dwNewBytes, Size);
}

int SetIntercepet()
{   // 0x40102A printf address
    SetJMP(0x40102A, MyPrintf, 7);
    return 0;
}


BOOL APIENTRY DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
{
    switch(fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        SetIntercepet();           
        break;
    }

    return TRUE;
}

Моя тестовая программа (C):

#include <stdio.h>
#include <windows.h>

int main()
{
    while (1)
    {
        system("pause");
        printf("ORIGINAL\n");
    }
}

часть программы тестирования декомпилирована:

00401000  /$ 55             PUSH EBP
00401001  |. 8BEC           MOV EBP,ESP
00401003  |> B8 01000000    /MOV EAX,1
00401008  |. 85C0           |TEST EAX,EAX
0040100A  |. 74 1C          |JE SHORT test.00401028
0040100C  |. 68 00E04000    |PUSH test.0040E000                      ;  ASCII "pause"
00401011  |. E8 D9000000    |CALL test.004010EF
00401016  |. 83C4 04        |ADD ESP,4
00401019  |. 68 08E04000    |PUSH test.0040E008                      ;  ASCII "ORIGINAL"
0040101E  |. E8 07000000    |CALL test.0040102A
00401023  |. 83C4 04        |ADD ESP,4
00401026  |.^EB DB          \JMP SHORT test.00401003
00401028  |> 5D             POP EBP
00401029  \. C3             RETN

0040102A  /$ 6A 0C          PUSH 0C
0040102C  |. 68 50D44000    PUSH test.0040D450
00401031  |. E8 52140000    CALL test.00402488
00401036  |. 33C0           XOR EAX,EAX
00401038  |. 33F6           XOR ESI,ESI
0040103A  |. 3975 08        CMP DWORD PTR SS:[EBP+8],ESI
  • 0
    Расположение функции не обязательно будет одинаковым между сборками. Вы должны устранить этот недостаток, прежде чем двигаться вперед.
Теги:
dll
hook

1 ответ

1

Поскольку вы перезаписываете фактическую функцию printf, вам придется скопировать инструкции там, а затем выполнить соответствующую "исправление", чтобы заставить ее работать в новом месте, а также вернуться к "после вашего исправления". Это будет либо подразумевать точное знание исходного кода (другими словами, push 0c, push test.0040d450), либо понимание достаточного количества машинного кода для разделения инструкций на их границах.

Другим, гораздо более простым способом было бы заменить исходное словосочетание новым кодом. Итак, вместо исправления кода в 0x40102a вы исправляете свой код в 40101E, сохраняя 40102a от исходной точки вызова, и как только вы сделали то, что вам нужно сделать, вы перезвоните в 40102a.

Что-то вроде этого сделало бы это:

void* origPrintf;

void MyPrintf(char *text)
{
    void (*orig)(char *text) = reinterpret_cast<void (*)(char *text)>(origPrintf);
    printf("\n Original message: %s\n", buff);

    orig(text);
}

void WriteMem(DWORD dwAddr, BYTE *dwNew, int Size, void &*oldCall)
{
    DWORD OldProt;
    int offset;
    VirtualProtect((void*)dwAddr, Size, PAGE_EXECUTE_READWRITE, &OldProt);
    memcpy(offset, (void*)(dwAddr + 1), sizeof(offset)); 
    oldCall = (void*)dwAddr + 5 + offset;   // 5 byte call instruction assumed.
    memset((void*)(dwAddr), 0x90, Size);
    memcpy((void*)(dwAddr), (void*)(dwNew), Size);
    VirtualProtect((void*)(dwAddr), Size, OldProt, &OldProt);
}

void SetJMP(INT32 dwOld, LPVOID dwNew, INT32 Size, void&*oldCall)
{
    BYTE dwNewBytes[5] = {0xE9, 0x00, 0x00, 0x00, 0x00};
    DWORD calc = ((DWORD)dwNew - dwOld - 5); 
    memcpy(&dwNewBytes[1], &calc, 4);
    WriteMem(dwOld, dwNewBytes, Size, oldCall);
}


int SetIntercepet()
{   // 0x40102A printf address
    SetJMP(0x40102A, MyPrintf, 7);
    return 0;
}

[Я не могу проверить код, так как я уверен, что на моей 64-разрядной машине Linux довольно разные адреса, но он должен дать разумный принцип]

  • 0
    Этот ответ такой плохой, и код везде нарушен. Я знаю, вы упомянули, что не могли это проверить. Но приходите к общим синтаксическим ошибкам void&* и SetJMP(4 parameters) называемым SetJMP(3 arguments) .
  • 0
    Я исправил общие проблемы, но это ничего не изменило. Это вызывает очевидный сбой системы при попытке вызвать исходную функцию из подключенной функции.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню