Помогите пожалуйста с альтернативой CreateRemoteThread

Тема в разделе "WASM.BEGINNERS", создана пользователем Rel, 23 сен 2009.

  1. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.317
    у меня такая идея: цепляться к какой-нить часто-вызываемой API функции целевого процесса, сплайсингом делать трамплин на код (который вызовет необходимую функцию, уберет трамплин с начала API функции, и вызовет оригинал)... таким образом алгоритм сводится к следующему:
    - найти адрес часто-вызываемой API функции в контексте целевого процесса
    - сохранить первые 5 байт часто-вызываемой API функции в памяти целевого процесса
    - динамически сформировать внедряемый код
    - записать внедряемый код в целевой процесс
    - приостановить процесс, записать трамплин в начало API функции, возобновить процесс

    все нормально работает, кроме двух вещей)))
    1) как найти адрес ну допустим GetMessage в чужом процессе... можно канеш записать в чужой процесс GetProcAddress и ExitThread, затем выполнить их CreateRemoteThread'ом, но это - возвращение к тому, от чего я пытаюсь уйти...
    2) я довольно сильно туповат в ассемблере, поэтому не могу нормально сформировать код (который вызовет необходимую функцию, уберет трамплин с начала API функции, и вызовет оригинал)... сейчас я делаю так:

    Код (Text):
    1. // В заголовке файла
    2. // Опкоды некоторых команд ассемблера
    3. #define ASM_PUSH 0x68
    4. #define ASM_CALL 0x15FF
    5. #define ASM_RET  0xC3
    6.  
    7. // Структура для формирования кода
    8. typedef struct _INJECTOR_RUNFUNCEX
    9. {
    10.     BYTE  PushFuncCom; // Команда  - push (записать в стек адрес параметра)
    11.     DWORD PushFuncArg; // Параметр - адрес параметров функции
    12.     WORD  CallFuncCom; // Команда  - call (выполнить функцию с таким параметром)
    13.     DWORD CallFuncArg; // Параметр - адрес функции
    14.     // ВСТАВИТЬ ВОССТАНОВЛЕНИЕ ПЕРВЫХ 5 БАЙТ ОРИГИНАЛЬНОЙ ФУНКЦИИ
    15.     WORD  CallOrigCom; // Команда  - call (выполнить оригинальную функцию)
    16.     DWORD CallOrigArg; // Параметр - адрес функции
    17. } INJECTOR_RUNFUNCEX, *PINJECTOR_RUNFUNCEX;
    18.  
    19. // И уже в функции
    20. // Формируем внедряемый код
    21. INJECTOR_RUNFUNCEX InjData;
    22. InjData.PushFuncCom = ASM_PUSH;
    23. InjData.PushFuncArg = (DWORD)paramadr;
    24. InjData.CallFuncCom = ASM_CALL;
    25. InjData.CallFuncArg = (DWORD)funcadr;
    26.  
    27. InjData.CallOrigCom = ASM_CALL;
    28. InjData.CallFuncArg = (DWORD)target_adr;
    29.  
    30. // Записываем внедряемый код
    31. PVOID my_adr = InjectMemoryEx(hProc, &InjData, sizeof(INJECTOR_RUNFUNCEX));
    32. if(my_adr == NULL) { return false; } // Если не удалось внедрить код
    то есть к моему стыду я не знаю, как правильно (грамотно) восстановить эти первые 5 байт...

    всем заранее спасибо за ответы!

    ЗЫ просьба ногами не пинать))
    ЗЗЫ мне хотелось бы реализовать именно этот метод (делаю я это исключительно в самообразовательных целях), про всякие там GetThreadContext/SetThreadContext и другие альтернативы я в курсе...
     
  2. IceT

    IceT IceT

    Публикаций:
    0
    Регистрация:
    13 авг 2009
    Сообщения:
    233
    Адрес:
    RU
    Сохраняй их в шелл-коде, а писать просто (mov byte ptr[address],[byte]), ты же уже в контексте целевого процесса. На сях можно так: *(BYTE*)[указатель]=[byte], ну или массив байтеков создавай.
     
  3. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.317
    есть идея по поводу поиска адреса функции... загрузить нужную DLL себе, получить адрес функции у себя... вычесть из адреса функции адрес загрузки DLL, получить смещение... в чужом процессе уже оперировать со смещением относительно начала загрузки DLL... но возникает вопрос: как получить адрес загрузки DLL в чужом процессе... это видимо надо в заголовке секции экспорта копаться?
     
  4. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.317
    блин... это канеш отличная идея, но тк я не силен в ассемблере, шелл-коды остаются для меня загадочным понятием... то есть, я делаю так?

    Код (Text):
    1. BYTE Mov1Com = 0x"шелл-код команды mov" // Не подскажешь код этой команды
    2.  
    3. DWORD Mov1Arg1 = &target_adr[0]; // target_adr[0] - адрес 1ого байта API функции
    4.  
    5. BYTE Mov1Arg2 = byte5[0]; // Сохраненный первый байт
    и так для каждого из 5 байт?

    а не возникнет ли проблем с защитой страницы? всмыле не надо ли вызывать VirtualProtectEx перед записью?
     
  5. IceT

    IceT IceT

    Публикаций:
    0
    Регистрация:
    13 авг 2009
    Сообщения:
    233
    Адрес:
    RU
    Надо.

    Шеллкод должен сам находить нужные ему апи-функции. Стандартный способ - получение из PEB'а адресов загрузки ntdll и kernel32. Дальше уже используешь LoadLibrary и GetPrcoAddress(или свой аналог с парсером экспорта).
     
  6. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Rel
    [0x7FFE0304]
    Crc32
    o Peb.Ldr:PPEB_LDR_DATA
    o MemoryMappedFilenameInformation
    Перемап кодовой секции.
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Rel
    В своем процессе просто GetModuleHandle, т.к. хэндл модуля это и есть его базовый адрес. В чужом можно через toolhelp CreateToolhelp32Snapshot + Module32First\Next или psapi EnumProcessModules + GetModuleBaseName (+ GetModuleInformation до кучи)

    Причем если речь идет о user32.dll, то 1) скорее всего она грузится во все процессы по одному адресу, 2) по крайней мере в XP для всех популярных функций предусмотрен hot-patch, т.е. функция начинается с двухбайтового нопа mov edi,edi (для замены на короткий джамп), перед которым зарезервированы 5 нопов 90h для замены на длинный джамп. Это позволяет не сохранять и не восстанавливать исходные байты функции - просто делаешь двойной джамп на свою функ-у, которая делает свое "грязное дело" и передает управление на адрес исходной функ-и + 2 байта
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    leo
    На сколько помню слепки исполняются посредством RtlQueryProcessDebugInformation(), этот функционал использует удалённые потоки.
    Гарантировано. Ядро использует глобальные ссылки в этот модуль.
     
  9. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Clerk
    Утверждение кажется очень логичным, однако, например, в висте64 user32.dll может быть промаплена и по другому адресу (в отличие от ntdll.dll и kernel32.dll):
    Код (Text):
    1. >frilocs64.exe user32.dll
    2. WinVer: 6.0.6001  sp1, SuiteMask: 274, x64 process: 1, wow64: 0
    3.  
    4. Using base of [user32.dll] library as default ImageBase
    5.  
    6. Default ImageBase for test: 0000000077A60000
    7.  
    8. Current process:
    9.         Fixups applied: 1
    10.         ImageBase (default): 0000000140000000
    11.         ImageBase (actual):  000000013F190000
    12.  
    13.  
    14.  
    15. -------------------------------------------------------------------------------
    16. CASE 0:
    17.         IMAGE_FILE_RELOCS_STRIPPED = 0
    18.         Base Relocations Directory ZEROED = 0
    19. -------------------------------------------------------------------------------
    20.  
    21. Trying to create a child process... SUCCESS
    22. Listing currently mapped views:
    23.         0000000076F10000: 1\Users\John\AppData\Local\Temp\1\vuvetcwhrahsuhxb.exe
    24.         0000000077C60000: 1\Windows\System32\ntdll.dll
    25.         Total mapped views: 2
    26. Listing mapped views again:
    27.         0000000076F10000: 1\Users\John\AppData\Local\Temp\1\vuvetcwhrahsuhxb.exe
    28.         0000000077A60000: 1\Windows\System32\user32.dll
    29.         0000000077B30000: 1\Windows\System32\kernel32.dll
    30.         0000000077C60000: 1\Windows\System32\ntdll.dll
    31.     ...
    32.  
    33.  
    34. Child process exit status: 0x00000000
    35. Child process:
    36.         Fixups applied: 1
    37.         ImageBase (default): 0000000077A60000
    38.         ImageBase (actual):  0000000076F10000
    39.  
    40.  
    41.  
    42. -------------------------------------------------------------------------------
    43. CASE 1:
    44.         IMAGE_FILE_RELOCS_STRIPPED = 0
    45.         Base Relocations Directory ZEROED = 1
    46. -------------------------------------------------------------------------------
    47.  
    48. Trying to create a child process... SUCCESS
    49. Listing currently mapped views:
    50.         0000000077520000: 1\Users\John\AppData\Local\Temp\1\hcsgwadetehsdxtq.exe
    51.         0000000077C60000: 1\Windows\System32\ntdll.dll
    52.         Total mapped views: 2
    53. Listing mapped views again:
    54.         0000000077520000: 1\Users\John\AppData\Local\Temp\1\hcsgwadetehsdxtq.exe
    55.         0000000077A60000: 1\Windows\System32\user32.dll
    56.         0000000077B30000: 1\Windows\System32\kernel32.dll
    57.         0000000077C60000: 1\Windows\System32\ntdll.dll
    58.     ...
    59.  
    60. Child process exit status: 0x00000000
    61. Child process:
    62.         Fixups applied: 0
    63.         ImageBase (default): 0000000077A60000
    64.         ImageBase (actual):  0000000077520000
    65.  
    66.  
    67.  
    68. -------------------------------------------------------------------------------
    69. CASE 2:
    70.         IMAGE_FILE_RELOCS_STRIPPED = 1
    71.         Base Relocations Directory ZEROED = 0
    72. -------------------------------------------------------------------------------
    73.  
    74. Trying to create a child process... SUCCESS
    75. Listing currently mapped views:
    76.         0000000077A60000: 1\Users\John\AppData\Local\Temp\1\xbqqabexaqhudcxg.exe
    77.         0000000077C60000: 1\Windows\System32\ntdll.dll
    78.         Total mapped views: 2
    79. Listing mapped views again:
    80.         0000000000140000: 1\Windows\System32\user32.dll
    81.         0000000077A60000: 1\Users\John\AppData\Local\Temp\1\xbqqabexaqhudcxg.exe
    82.         0000000077B30000: 1\Windows\System32\kernel32.dll
    83.         0000000077C60000: 1\Windows\System32\ntdll.dll
    84.     ...
    85.  
    86. Child process exit status: 0x00000000
    87. Child process:
    88.         Fixups applied: 0
    89.         ImageBase (default): 0000000077A60000
    90.         ImageBase (actual):  0000000077A60000
    91.  
    92.  
    93.  
    94. -------------------------------------------------------------------------------
    95. CASE 3:
    96.         IMAGE_FILE_RELOCS_STRIPPED = 1
    97.         Base Relocations Directory ZEROED = 1
    98. -------------------------------------------------------------------------------
    99.  
    100. Trying to create a child process... SUCCESS
    101. Listing currently mapped views:
    102.         0000000077A60000: 1\Users\John\AppData\Local\Temp\1\qavcbsebetwwceed.exe
    103.         0000000077C60000: 1\Windows\System32\ntdll.dll
    104.         Total mapped views: 2
    105. Listing mapped views again:
    106.         0000000000680000: 1\Windows\System32\user32.dll
    107.         0000000077A60000: 1\Users\John\AppData\Local\Temp\1\qavcbsebetwwceed.exe
    108.         0000000077B30000: 1\Windows\System32\kernel32.dll
    109.         0000000077C60000: 1\Windows\System32\ntdll.dll
    110.     ...
    111.  
    112. Child process exit status: 0x00000000
    113. Child process:
    114.         Fixups applied: 0
    115.         ImageBase (default): 0000000077A60000
    116.         ImageBase (actual):  0000000077A60000
    (Один должен обращать внимание на два последних кейса).

    Конечно, если есть гарантия, что к моменту вызова ZwMapViewOfSection регион для отображения нужной длл свободен, то вполне можно посчитать, что длл промапится по тому же адресу, что и в другом процессе – ядро старается отображать такие регионы по одному и тому же адресу на время жизни секции (из-за неких сортов оптимизации?).

    Rel
    Можешь также взглянуть на пример того, как ^листать виды^. Там пара строчек всего.
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Sol_Ksacap
    Всё сказанное мной имеет смысл только для x32. Я не рассматриваю x64.
     
  11. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Переводил промптом?)
     
  12. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    "Не промтом. Я лингвист" – Sol.

    "Not промтом. I the linguist" – Promt.
     
  13. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.317
    спасибо большое а ответы! сейчас проблема больше в формировании внедряемого кода... сплайсинг проходит без проблем, поиск импортированной функции в другом процессе тоже (копаюсь в PE заголовке)... но код никак не хочет выполняться... пробывал так:
    1) просто "байпасить функцию":
    Код (Text):
    1. ret
    работает...
    2) выполнить другую функцию, вместо этой
    Код (Text):
    1. call funcadr
    2. ret
    вылезает косяк "эксесвайолейтинг" на чтение... по всей видимости закрадывается в стек какой-то косяк, в результате которого он пытается вернуть управление не туда... и я не могу понять почему... обе функции (и подменяемая и та, на которую подменяю: void и без параметров), вроде никаких изменений в стеке для вызова функции-подменки я производить не должен, но почему же тогда проблема в стеке возникает... загадка)))
     
  14. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Интересно, что скрывается за "call funcadr" ?
    Не забывай, что call м.б. либо относительным (E8) - тогда funcadr д.б. = смещению вызываемой функции относительно команды следующей за call.
    Либо прямым косвенным (FF 15) - тогда funcadr д.б. = адресу дворда, в котором записан адрес вызываемой функции. А ты небось напрямую адрес своей функции подставляешь
     
  15. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.317
    да... я именно так и делаю))) ну во всяком случае с кодом я угадал))) (FF 15)
    завтра попробую, это я чет в справочнике не доглядел(((( спасибо!
     
  16. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Rel
    Не нужен никакой поиск, сказал ведь [0x7FFE0304]. Посмотрите что по этому адресу.
     
  17. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.317
    ну все работает теперь)) правда ещё пришлось саму структуры взять в

    Код (Text):
    1. #pragma pack(push, 1)
    2.  
    3. . . .
    4.  
    5. #pragma pack(pop)
    так и не понял зачем и почему, но работает)))



    господа, а как мне правильно составить восстановление пяти первых байт? можно сделать так:

    Код (Text):
    1. mov <адрес начала функции>, <сохраненный байт1>
    2.  
    3. mov <адрес начала функции + 1>, <сохраненный байт2>
    4.  
    5. mov <адрес начала функции + 2>, <сохраненный байт3>
    6.  
    7. mov <адрес начала функции + 3>, <сохраненный байт4>
    8.  
    9. mov <адрес начала функции + 4>, <сохраненный байт5>
    или делать 1 mov с dword'ами и 1 mov с байтом... может есть лучше вариант?... но я чет никак не могу подобрать нужный опкод команды mov для этого... подскажите пожалуйста))) Virtual Protect'ом решил в своем процессе права на 5 байт не восстанавливать, чтобы во внедряемом коде два раза не вызывать эту функцию... то есть старые права на страницу будет восстанавливать именно внедренный код...
     
  18. IceT

    IceT IceT

    Публикаций:
    0
    Регистрация:
    13 авг 2009
    Сообщения:
    233
    Адрес:
    RU
    movsb и иже с ними
     
  19. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.317
    да... movsb - это канеш хорошо... но как мне записать в кодах вот это:

    Код (Text):
    1. mov ecx, 05h
    2.  
    3. mov esi, offset adr1
    4.  
    5. mov edi, offset adr2
    6.  
    7. rep movsb
    пытался накопать коды в справочниках, но чет не могу понять это(((



    http://faydoc.tripod.com/cpu/rep.htm
    допустим по данным этого справочника, чтобы выполнить rep movsb мне надо в структуру записать

    Код (Text):
    1. BYTE rep = 0xF3;
    2.  
    3. BYTE movsb = 0xA4
    это верно?))



    http://faydoc.tripod.com/cpu/mov.htm
    а как быть с командами mov, заполняющими регистры?
     
  20. IceT

    IceT IceT

    Публикаций:
    0
    Регистрация:
    13 авг 2009
    Сообщения:
    233
    Адрес:
    RU
    Ну е мае возьми ассемблер, скомпилируй свой шеллкод и посмотри что получится. Спрашивать тут опкоды каждой инструкции - это уже борщ (с фасолью).