Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вычисление relative address для jmp, call

15K
19 марта 2008 года
hel
78 / / 10.11.2007
Извините если не туда запостил, не нашел больше никаких разделов посвящённых Assembler'у.

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

Как он должен работать?
К программе-жертве аттачится DLL (с помощью PETools например).
Запускаем программу, DLL начинает делать своё дело:
1. Устанавливает права на участок памяти в code-секции программы жертвы, с помощью winapi-функции "VirtualProtect()".
2. Заменяет инструкцию (размер 5 байт вместе с операндом) по заданному адресу инструкцией jmp (E9 xxxxxxxx) или call (E8 xxxxxxxx), адрес которой должен указывать на нашу функцию по обработке перехваченной функции.
3. Возвращает обратно старые права на участок памяти winapi функцией "VirtualProtect()".

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

Суть проблемы.
Нужно вычислить relative address (относительный адрес), чтобы записанные в программу-жертву call или jmp указывали на правильный адрес обработчика бажной функции (обработчик сидит в подгруженной DLL).

Инструкции типа FF (JMP FAR и CALL FAR с абсолютными адресами) мне непонятны, они по размеру уж точно более 5 байт. В этом случае участок кода в программе-жертве превратится в мусор, который еще и надо вычислять, сколькими nop'ами забивать, что мне пока не под силу.

Пример кода DLL, добавил комменты:
Код:
.386
.model flat, stdcall

include WINDOWS.INC
include kernel32.inc
include user32.inc
includelib KERNEL32.LIB
includelib USER32.LIB

TestHook proto
ProcessHook proto

.const
    msgCaption db "Hooktest DLL", 0h
    msgHooking db "Hooking called...", 0h
    msgHookDone db "Hooking done...", 0h
    msgHooked db "Hooked successfully...", 0h

.data
    TestHookAddr dd 0040100Fh ; пишем call сюда
    HookCallData db 0E8h ; опкод call'а
   
.data?
    oldProtect dd ? ; тут копия старых прав
    bytesWritten dd ? ; сколько байт записано
    ProcId dd ? ; текущий PID проги
    hProc dd ? ; хендл управления процессом

.code
    LibMain proc hInstDLL:DWORD, reason:DWORD, unused:DWORD
        cmp reason, DLL_PROCESS_ATTACH
        jnz NotAttach
        invoke TestHook ; if reason==DLL_PROCESS_ATTACH call TestHook
      NotAttach:
        mov eax, TRUE
        ret
    LibMain endp
   
    TestHook proc
        invoke GetCurrentProcessId
            mov ProcId, eax
        invoke OpenProcess, PROCESS_ALL_ACCESS, FALSE, ProcId
            mov hProc, eax
        invoke MessageBox, NULL, ADDR msgHooking, ADDR msgCaption, MB_OK
        invoke VirtualProtect, TestHookAddr, 5, PAGE_EXECUTE_READWRITE, oldProtect ; выставляем права
        invoke WriteProcessMemory, hProc, TestHookAddr, ADDR HookCallData, 1, bytesWritten
        inc TestHookAddr ; инкрементим TestHookAddr на 1
        ; invoke WriteProcessMemory, hProc, TestHookAddr, ProcessHook, 4, bytesWritten ; ошибка тут, ProcessHook проверял, вроде передает правильный адрес, но он абсолютный. Как узнать относительный?
        invoke VirtualProtect, TestHookAddr-1, 5, oldProtect, oldProtect ; возвращаем старые права
        invoke MessageBox, NULL, ADDR msgHookDone, ADDR msgCaption, MB_OK
        ret
    TestHook endp

    ProcessHook proc
        invoke MessageBox, NULL, ADDR msgHooked, ADDR msgCaption, MB_OK ; Оповещение, что обработчик успешно вызван.
        ret
    ProcessHook endp

end LibMain
5.1K
19 марта 2008 года
12345678
93 / / 16.12.2006
Неее, сложноватую задачу ты перед собой поставил :) Точнее не задачну, а подход к ее решению. Можно и по-проще:

первые байти оригинальной функции заменяем на свои, предварительно сохранив оригинал где нить в памяти (ну ето само собой понятно). Потом, вместо того чтобы вычислять E8XXXXXXXX или чё там ещё можно просто засунуть адрес в eax например, а потом его оттуда вызвать:

 
Код:
db 0xB8          ;mov eax,
  func_addr dd ? ;addr
  jmp eax


func_addr - адрес функции в твоей dll. Узнать его можно с помощью GetProcAddress.

Но если тебе приспичило ломать голову то, насколько я знаю для того что бы вычислить относительный адрес чего то там, то надо знать RVA того места откуда идёт вызов:

 
Код:
00401000                    start:
00401000 E903000000             jmp     loc_00401008
00401005 90                     nop
00401006 90                     nop
00401007 90                     nop
00401008                    loc_00401008:
00401008 C3                     ret


Короче, как то так: E9 - опкод, 03000000 - операнд, обозначающий что надо перейти на три байта вперёд. Теоретично можно узнать адреса всего шо надо, но первый способ по-моему легче.
15K
19 марта 2008 года
hel
78 / / 10.11.2007
 
Код:
TestHookAddr dd 00401000h
HookCallData db 0B8h, 0ABh, 10h, 0h, 10h, 0FFh, 0D0h, 0C3h


 
Код:
invoke WriteProcessMemory, hProc, TestHookAddr, ADDR HookCallData, 8, bytesWritten


Результат (проверяю на тестовой проге):
 
Код:
00401000  /$ B8 AB100010    MOV EAX,100010AB
00401005  |. FFD0           CALL EAX
00401007  \. C3             RETN


Обработчик наконец-то нормально вызвался, чем оповестил мессаджбоксом!

Мегаспасибо, 12345678! :)
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог