сплайсинг в нутри самого процесса

Тема в разделе "WASM.WIN32", создана пользователем wsd, 9 ноя 2008.

  1. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Код (Text):
    1. #include "stdafx.h"
    2.  
    3. typedef
    4. //NTSYSAPI
    5. NTSTATUS
    6. (NTAPI *Zwf)
    7. (
    8.  OUT PHANDLE ,
    9.  IN ACCESS_MASK ,
    10.  IN POBJECT_ATTRIBUTES ,
    11.  OUT PIO_STATUS_BLOCK ,
    12.  IN PLARGE_INTEGER ,
    13.  IN ULONG ,
    14.  IN ULONG ,
    15.  IN ULONG ,
    16.  IN ULONG ,
    17.  IN PVOID ,
    18.  IN ULONG );
    19.  
    20.  
    21. char testrstr[] = "777";
    22.  
    23. //NTSYSAPI
    24. NTSTATUS
    25. NTAPI  my_f(OUT PHANDLE FileHandle,
    26.             IN ACCESS_MASK DesiredAccess,
    27.             IN POBJECT_ATTRIBUTES ObjectAttributes,
    28.             OUT PIO_STATUS_BLOCK IoStatusBlock,
    29.             IN PLARGE_INTEGER AllocationSize OPTIONAL,
    30.             IN ULONG FileAttributes,
    31.             IN ULONG ShareAccess,
    32.             IN ULONG CreateDisposition,
    33.             IN ULONG CreateOptions,
    34.             IN PVOID EaBuffer OPTIONAL,
    35.             IN ULONG EaLength)
    36. {
    37.     //[b]puts( testrstr);[/b]
    38.     __asm mov   eax, -1;
    39.     __asm ret   02ch ;
    40.     return 0;
    41. }
    42.  
    43. int _tmain(int argc, _TCHAR* argv[])
    44. {
    45.  
    46.     HMODULE hm = GetModuleHandle(_T("ntdll.dll"));
    47.     Zwf _Zwf = (Zwf)(GetProcAddress( hm, "ZwCreateFile"));
    48.     DWORD lpflOldProtect;
    49.     VirtualProtect(_Zwf, 5, PAGE_EXECUTE_READWRITE, &lpflOldProtect);
    50.    
    51.     __asm
    52.     {
    53.         mov eax, _Zwf
    54.         mov  byte ptr [eax], 0e9h
    55.         mov edx, my_f
    56.         sub edx, eax
    57.         mov dword ptr [eax+1], edx
    58.     }
    59.     CreateFile(_T("new.txt"), 0, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
    60.    
    61.     getch();
    62.     return 0;
    63. }
    перехват выполняется и отрабатывает нормально,
    но если раскомментировать puts( testrstr); , то вылазиет это
    Unhandled exception at 0x0012ff5c in nat2.exe: 0xC0000005: Access violation writing location 0x7817a99b.

    наверно какая-то глупая ошибка у меня
     
  2. Freeman

    Freeman New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    1.385
    Адрес:
    Ukraine
    не правильно расчитываешь переход. должно получится
    Код (Text):
    1. db 0e9h
    2. dd куда-(откуда+5)
    3. а у тебя
    4. db 0e9h
    5. dd куда-откуда
     
  3. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Freeman
    спс
     
  4. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Зачем выполнять сплайсинг заглушки(причём процессор может не поддерживать cmpxchg8b), тогда все потоки суспендить придётся, если можно атомарно(xchg) четыре байта - указатель на UsSystemCall заменить в инструкции mov edx,7FFE0300(для SP1 немного иначе вызов).
     
  5. Freeman

    Freeman New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    1.385
    Адрес:
    Ukraine
    наверно потому-что этот способ не описывается в статьях рема :)
     
  6. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    А что будет если во время cmpxchg8b какой нибудь поток выполнял начало заменяемых байт и был прерван? Что он будет выполнять после получения процессорного времени?

    Всмысле переключение контекста произошло во время того, как какой-нибудь поток выполнял заменяемый код, код заменился, управление потом возвращается тому потоку и он будет выполнять уже левые инструкшены или вобще не пойми что?
     
  7. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    В ТС-вском случае, может вместо сплайсинга ZwCreateFile подредактировать IAT kernel32, чтобы вместо ZwCreateFile вызывался обработчик, а тот в свою очередь ZwCreateFile?
     
  8. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Это не возможно. Процессор не может быть прерван пока не закончит исполнять инструкцию.
    Для юзермода все ZwXX экспорты являются заглушками в ntdll для соответствующих сервисов.
    А в общем бесполезно хукать юзермодные стубы и KiFastSystemCallRet, ибо поток может заюзать сервис посредством прерывания.
     
  9. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    CrystalIC
    Ну я невнятно выразился. Поток начал выполнять первые байты из тех, которые будут заменены. Тут произошло переключение контекста, поток остановлен посреди тех байт. Другой поток делает cmpxchg8b. Когда снова начнет выполнятся первый поток, он будет исполнять уже не те инструкции.
     
  10. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    K10
    Ты ошибыешся, если думаешь что процессор считает операнд из инструкции, переключится на другой поток, потом восстановит состояние и продолжит исполнять инструкцию хех. Он её всю исполнит сразу, только потом будет может быть прерван.
     
  11. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    Ну это понятно, что лучше перехватывать все на уровне ядра.

    Часто бывает такая ситуация: Заранее известно, в каком приложении (приложениях) будет работать хукающий код. И если это приложение не юзает сервисы ядра путем прерываний и не вызывает native функции, а по честному использует kernel32.CreateFile, то имхо проще и безопаснее патчить IAT чтобы вместо соответствующих native api вызывались обработчики.
     
  12. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    Ну исполнил он всю сразу первую инструкцию вместе с операндом. Собирается исполнить следующую, и тут поток прервался...
     
  13. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    K10
    А следующая нам не нужна..
    Примеры в студию короче.
    В таком случае мы используем перехват KiFastSsystemCall/KiFastSystemCallRet, ибо если нужно перехватить несколько сервисов то незачем использовать сплайсинг множества функций, вызов/возврат любого стуба сходится в одной точке, а от туда и лучше всего выполнить обработку, в первом случае отфильтровать сервис по его номеру в регистре Eax, либо по адресу возврата в стеке.
     
  14. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    Эхх, неохота сочинять пример...

    Что-то типа этого (поправьте если где ошибусь)...

    Берем первую попавшуюся функцию: kernel32.AddAtomA
    начало:
    Код (Text):
    1. MOV   EDI, EDI    ; 88FF - 2 байта
    2. PUSH  EBP          ; 55    - 1 байт
    3. ... и т.д.
    Собираемся записать джамп на обработчик:
    Код (Text):
    1. JMP   ABCDEF00  ; E9 ABCDEF00 - 1 + 4 = 5 байт
    2. ...
    Какой нибудь поток выполняет начало AddAtomA: выполнил MOV EDI, EDI. Тут остановился. Когда он снова возобновится, то будет выполнять слудующую PUSH EBP. Но не тут то было - пока он стоял, другой поток переписал эти байты и теперь вместо
    Код (Text):
    1. PUSH  EBP          ; 55
    находится кусок из аргумента джампа:
    Код (Text):
    1. CDEF00 и прочий мусор...
    Примерно так, в общих чертах :)
     
  15. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Ну это конечно. Вроде про стуб речь шла, а не про любую последовательность инструкций. В твоём случае мы записываем Jmp_Near_Handler на пять байт ниже функции и атомарно заменяем пролог на короткий переход туда(0xF9EB).
     
  16. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    CrystalIC
    Опять же, запишем JMP, какой-то поток уже успел сделать MOV EDI, EDI; PUSH EBP, вместо короткого перехода, который еще не записан и будет сбитый стек. Либо поток остановлен на месте записываемого джампа.

    Вобщем, я так понимаю, проблема многопоточности в сплайсинге до сих пор не имеет решения... Даже если суспендить все потоки, нет гарантии, что какой-то из них не будет засуспенжен на заменяемом коде. Если только после суспенда проверять контексты всех потоков, но имхо геморно...

    А интересовало, чем cmpxchg8b лучше обычных MOV.
    К стате, на каких процах он поддерживается?
     
  17. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Внутри вместе пишется :)
     
  18. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    K10
    Какой есчо сбитый стек;
    Ты не понимаешь вообще как планирование исполняется. Две инструкции на одну не заменяются, иначе конечно придётся перечислять потоки, получать контексты, проверять не указывает ли Eip на вторую мод. инструкцию..
    В сплайсинге, где изменяемая инструкция имеет размер больший, либо равный инструкции перехода проблем нет.
    Тем что атомарно позволяет записать 8 байт. Если инструкция длиной больше 4 байт, то это единственный вариант атомарно изменить, 5 байт - опкод перехода(Jmp_Near_XXXX), остальные 3 - от оригинальной инструкции. Вобщем смотри в манах префикс Lock.
     
  19. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    Сорри, что немного оффтоп, но вроде бы это не совсем верно для многопроцессорной системы, хотя я сам не уверен, может кто-нибудь поправит/подтвердит?
     
  20. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Velheart
    Верь мне.)