GetThreadContext/SetThreadContext & Entry point

Тема в разделе "WASM.WIN32", создана пользователем gribodemon, 17 дек 2009.

  1. gribodemon

    gribodemon New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    138
    Доброго времени суток!
    В качестве метода проникновения в новосозданный процесс, я использую сплайсинг точки входа (как альтернатива хуку NtResumeThread). Да-да, я уже прекрасно осознаю недостатки сплайсинга и вообще, работы в usermode, но, просто, хочется доделать до конца.
    Поэтому мне нужен совет.
    Ситуация такая.
    Я описал функцию, в которой я в первую очередь выполняю Unhook точки входа (т.к. изначально, на Entry point стоит Relative JMP на мой код), затем делаю PUSH/RET снова на точку входа (схему с bridge я использую как запасной вариант ... не суть). Выполняя свой код, соотв., я добавляю новые данные в стек, работаю с регистрами и пр. Некоторые главные функции программ сконструированы таким образом, что в их конце стоит не вызов, скажем, kernel32!ExitProcess, а что-то вроде RETN. Вот, в этом случае, адрес для перехода на "деструктор" программы (ntdll!RtlCreateUserThread & ntdll!RtlExitUserProcess и пр.) хранится в стеке, который, я, соответственно, "испортил" своим кодом.
    Возникла мысль - использовать GetThreadContext(GetCurrentThread(), ...) в начале своего кода, чтобы за'backup'ить стек и регистры, а затем, вернуть их с помощью SetThreadContext уже в конце выполнения кода, перед PUSH/RET.
    Однако, я взглянул на ASM-код своей функции, куда попадаю после Reletive JMP'а и увидел след.:

    Код (Text):
    1. ; 369  : VOID xEntryPoint () {
    2.  
    3.   00000 55       push    ebp
    4.   00001 8b ec        mov     ebp, esp
    5.   00003 81 ec e0 02 00
    6.     00       sub     esp, 736       ; 000002e0H
    7.   00009 56       push    esi
    8.   0000a 57       push    edi
    9. ; ...
    10. ; 373  :
    11. ; 374  :    HANDLE hThread = GetCurrentThread();
    12.  
    13.   0000e ff 15 00 00 00
    14.     00       call    DWORD PTR __imp__GetCurrentThread@0
    15.   00014 8b f8        mov     edi, eax
    16.  
    17. ; 375  :    CONTEXT ct;
    18. ; 376  :    GetThreadContext(hThread, &ct);
    19.  
    20.   00016 8d 85 20 fd ff
    21.     ff       lea     eax, DWORD PTR _ct$[ebp]
    22.   0001c 50       push    eax
    23.   0001d 57       push    edi
    24.   0001e ff 15 00 00 00
    25.     00       call    DWORD PTR __imp__GetThreadContext@8
    Т.е. ещё до того, как начнёт выполняться мой код в моей функции, я не смогу получить "слепок" с пом. GetThreadContext.

    Хм... теперь на мысль приходит использование мини-дизасма, чтобы восстановить слепок регистров и стэка до момента входа в фукнцию xEntryPoint.
    Ещё можно вместо первого JMP'а внедрить вызов GetThreadContext, хотя, не хотелось бы переписывать модуль сплайсинга.

    И вообще, я бы хотел спросить - если мы вызываем GetThreadContext из текущего потока, то мы "во время вызова" функции уже изменяем стек (для передачи аргументов функции) ... хотя, впринципе, сразу же после вызова можно восстановить, ... вроде, нужно будет только ESP поправить?

    В общем, прошу совета по решению проблемы. Подскажите: "Как грамотно сплайснуть точку входа?"
     
  2. gribodemon

    gribodemon New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    138
    Оу. Кажется, __declspec(naked) решает проблему лишнего кода вначале функции.
     
  3. gribodemon

    gribodemon New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    138
    В общем, похоже, проблема решена. Всего пару строк кода.
    В моём случае, видимо, будет достаточно восстановить стэк (ESP).
    Поэтому вот что я сделал:

    Объявил naked-функцию и использовал её в качестве переходника на основную.
    Т.е. сначала Relative JMP с просплайсеной функции попадает на naked-функцию, затем, она передаёт управление на основную (на xEntryPoint()).

    Код (Text):
    1. VOID xEntryPoint ();
    2. /* Naked function as bridge (just for getting ESP) */
    3. DWORD dwESP;
    4. VOID __declspec(naked) xEntryPointNaked ()
    5. {
    6.     __asm mov   dwESP, esp
    7.    
    8.     __asm push  xEntryPoint
    9.     __asm ret
    10. }
    Ну а дальше, переход на unhook'нутую точку входа:

    Код (Text):
    1. VOID xEntryPoint () {
    2.     /* some evil code here*/
    3.  
    4.     __asm mov   esp, dwESP
    5.  
    6.     __asm push  dwEntryPoint
    7.     __asm ret
    8. }
    Какие ещё подводные камни могут быть в таком подходе?
     
  4. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    ..w2k\private\windows\base\client\process.c
    Код (Text):
    1. CreateProcessW:
    2. ..
    3.  
    4.         //
    5.         // Create a section object backed by the file
    6.         //
    7.  
    8.         Status = NtCreateSection(
    9.                     &SectionHandle,
    10.                     SECTION_ALL_ACCESS,
    11.                     NULL,
    12.                     NULL,
    13.                     PAGE_EXECUTE,
    14.                     SEC_IMAGE,
    15.                     FileHandle
    16.                     );
    17. ..
    18.         //
    19.         // Query the section to determine the stack parameters and
    20.         // image entrypoint.
    21.         //
    22.  
    23.         Status = NtQuerySection(
    24.                     SectionHandle,
    25.                     SectionImageInformation,
    26.                     &ImageInformation,
    27.                     sizeof( ImageInformation ),
    28.                     NULL
    29.                     );
    30. ..
    31.         //
    32.         // Create an initial context for the new thread.
    33.         //
    34.  
    35.         BaseInitializeContext(
    36.             &ThreadContext,
    37.             Peb,
    38.             ImageInformation.TransferAddress,
    39.             InitialTeb.StackBase,
    40.             BaseContextTypeProcess
    41.             );
    42.  
    43.         //
    44.         // Create the actual thread object
    45.         //
    46.  
    47.         pObja = BaseFormatObjectAttributes(&Obja,lpThreadAttributes,NULL);
    48.  
    49.         Status = NtCreateThread(
    50.                     &ThreadHandle,
    51.                     THREAD_ALL_ACCESS,
    52.                     pObja,
    53.                     ProcessHandle,
    54.                     &ClientId,
    55.                     &ThreadContext,
    56.                     &InitialTeb,
    57.                     TRUE
    58.                     );
    59. ..
    Так сложно хоть раз в сурцы залезть или пройти дебугом чтоб поверхностно осознать как процесс создаётся ?
    -
    http://wasm.ru/forum/viewtopic.php?pid=284176#p284176
    Там опечатка, BaseProcessStartThunk() принимает только один параметр в Eax. Вызвано тем, что процедура которую вызывает первый поток в процессе, это та из опционального заголовка образа не имеет параметров, а процедура которую вызывают остальные потоки имеет один параметр. Короче в контексте будет:
    Eip @BaseProcessStartThunk()
    Eax @OEP
    -
    Ну и зачем изменять код, если можно выполнить с контекстом манипуляции ?
    Зациклился на сплайсе, какбудто ничего другого нет %..
    Инфа для размышления по теме. Кошерный способ не должен использовать очевидные фичи. Можно использовать синхроный доступ к обьекту для захвата треда, как частный случай ввод потока в состояние ожидания освобождения критической секции. Тогда мы можем получить контекст ждущего потока, выполнить бактрейс, в нужном стековом фрейме заменить адрес возврата. После чего тред может быть отпущен сигнализацией обьекта, вручную или выходом первого потока из критической секции. Вобщем вот пример(это не пройдёт для захвата потока на этапе инициализации ресурсов) http://paste.org.ru/?j7n4in
    бу: кнопка для выделения отвалилась :dntknw:
     
  5. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    ему уже сто раз писали про eax и т.д., он игнорит и делат такой тупизм дальше...