Выполнение системных функций в удалённом процессе

Тема в разделе "WASM.WIN32", создана пользователем d2k9, 25 мар 2010.

Статус темы:
Закрыта.
  1. d2k9

    d2k9 Алексей

    Публикаций:
    0
    Регистрация:
    14 сен 2008
    Сообщения:
    325
    Столкнулся с непонятной проблемой при попытке выполнения InternetSetOptionA(NULL, INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0) в чужом IE8 (реализовывать в виде отдельной либы и её грузить было лень да и некрасиво). Идея в том, что все системные либы мапятся по одному и тому же адресу, так что получив адреса нужных функций в своём процессе я могу выполнить их в удалённом по этим же адресам. В wininet.dll как и во всех системных WinAPI => stdcall, следовательно передаём-с аргументы задом наперёд. Выполнение кода реализовывается примитивным стартом удалённого потока с адресом начала шелкода в памяти осла.
    Прокоменченный шелкод таков:
    Код (Text):
    1. #pragma pack (push, 1)
    2.  
    3. typedef struct rem_code {
    4. //----------------------------------------------------//
    5.   BYTE instr_push4;  //здесь будет код инструкции push
    6.   DWORD arg4;         //аргумент push
    7. //----------------------------------------------------//
    8.   BYTE instr_push3;  //здесь будет код инструкции push
    9.   DWORD arg3;         //аргумент push
    10. //----------------------------------------------------//
    11.   BYTE instr_push2;  //здесь будет код инструкции push
    12.   DWORD arg2;         //аргумент push
    13. //----------------------------------------------------//
    14.   BYTE instr_push1;  //здесь будет код инструкции push
    15.   DWORD arg1;         //аргумент push
    16. //----------------------------------------------------//
    17.   WORD instr_call_func;  //здесь будет код инструкции call
    18.   DWORD arg_func;         //адрес InternetSetOptionA
    19. //----------------------------------------------------//
    20.   BYTE instr_push0;  //здесь будет код инструкции push
    21.   DWORD arg0;         //0 для выхода треда
    22. //----------------------------------------------------//
    23.   WORD instr_call_exit_thread;  //здесь будет код инструкции call
    24.   DWORD arg_exit_thread;         //адрес RtlExitUserThread
    25. } RemoteCode;
    26.  
    27. #pragma pack (pop)
    28.  
    29. /*адреса ф-ций получаем ессно так RemoteCode.arg_exit_thread=(DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"),"RtlExitUserThread");
    30. опкод кола 0x15FF
    31. опкод пуша 0x68
    32. */
    33. CreateRemoteThread(hProc, NULL, 0, callAddr, NULL, 0, NULL)
    наш шелкод в памяти осла
    Код (Text):
    1. 03380000   68 00000000      PUSH 0
    2. 03380005   68 00000000      PUSH 0
    3. 0338000A   68 2A000000      PUSH 2A
    4. 0338000F   68 00000000      PUSH 0
    5. 03380014   FF15 494DD374    CALL DWORD PTR DS:[WININET.InternetSetOptionA]
    6. 0338001A   68 00000000      PUSH 0
    7. 0338001F   FF15 7822F576    CALL DWORD PTR DS:[ntdll.RtlExitUserThread]
    Запускаем-с поток, и затем наступает песец, осёл вываливается, а в отладчике подключённом к нему видим мега жесть:
    Наш тред:
    Получаем вот етот бред, если в студии то выдаёт как dd KeServiceDescriptorTable, видимо в SSDT что-то не срастается, только как оно сюда относится...
    По тому адресу ессно пусто вот оно и бычарит. Регистры:
    Я в лёгком ступоре...
     
  2. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    d2k9
    Лично мне здесь видится несоответствие между:
    Код (Text):
    1.   WORD instr_call_func;  //здесь будет код инструкции call
    2.   DWORD arg_func;         //адрес InternetSetOptionA
    и
    Код (Text):
    1. FF15 494DD374    CALL DWORD PTR DS:[WININET.InternetSetOptionA]
    Подозреваю, что после FF 15 у вас указан адрес ф-ии InternetSetOptionA, а никак не адрес указателя на эту функцию.
     
  3. karabas_barabas

    karabas_barabas Member

    Публикаций:
    0
    Регистрация:
    9 авг 2009
    Сообщения:
    168
    недавно писал шеллкод не запомнил почему , но какая-то шняга была при call Adr , заменил на
    Код (Text):
    1. shc->movebp = 0x0BD;
    2. shc->adrcopyMemory = (DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"),"memcpy");
    3. shc->callebp = 0xD5FF;
    и все работает гуут
     
  4. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    d2k9
    Создаёте поток остановленным, получаете его контекст и на Ip ставите брейк, после чего отпусакете тред. Если изначально Ip валидный, то произойдёт останов. Если поток создан средствами kernel32!CreateRemoteThread(), то Ip = @kernel32!BaseThreadStartThunk(). Далее пройзойдёт переход на указанный стартуп код(рег. Eax для BaseThreadStartThunk()). Тогда вы можите потрейсить свой код и найти откуда выполняется джамп вникуда.
     
  5. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Clerk
    В данном случае и так понятно, откуда он выполняется: просто d2k9 не знает форматов инструкции call.
     
  6. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    l_inc
    Автор должен таким образом искать проблему. Этот код частный случай.
     
  7. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Clerk
    Согласен... Какая редкая неожиданность... :)
     
  8. d2k9

    d2k9 Алексей

    Публикаций:
    0
    Регистрация:
    14 сен 2008
    Сообщения:
    325
    Угу загнался вчера и то что вызов идёт по содержимому указателя не обратил внимания. Прикол-ка что call far opcode 9A не прокатывает. Спасибо karabas_barabas, сделаю как он подсказал. Тока для приличия думаю ebp надо сохранять:
    Код (Text):
    1. //вначале
    2. push ebp
    3. ...
    4. //в конце
    5. pop ebp
     
  9. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    у меня хедер, может кому пригодится:
    Код (Text):
    1. #ifndef _OPCODE_H_
    2. #define _OPCODE_H_
    3.  
    4. // Вызовы и инструкции переходов
    5. #define ASM_CALL      0x15FF
    6. #define ASM_CALL_OFS  0xE8
    7. #define ASM_CALL_EAX  0xD0FF
    8. #define ASM_RET       0xC3
    9. #define ASM_JMPFAR    0xE9
    10. #define ASM_JMPPTR    0x25FF
    11. #define ASM_JMPNEAR   0xEB
    12. // Логические операции
    13. #define ASM_XOR_EAX_X 0x35
    14. #define ASM_OR_EAX_X  0x0D
    15. #define ASM_AND_EAX_X 0x25
    16. #define ASM_AND_RAX_X 0x2548
    17.  
    18. // РАБОТА СО СТЕКОМ ------------------------------------------------------------------------------------------------
    19. // Работа со стеком x32
    20. #define ASM_PUSH     0x68
    21. #define ASM_PUSH_EAX 0x50
    22. #define ASM_PUSH_ECX 0x51
    23. #define ASM_PUSH_EDX 0x52
    24. #define ASM_PUSH_EBX 0x53
    25. #define ASM_PUSH_ESP 0x54
    26. #define ASM_PUSH_EBP 0x55
    27. #define ASM_PUSH_ESI 0x56
    28. #define ASM_PUSH_EDI 0x57
    29. #define ASM_POP_EAX  0x58
    30. #define ASM_POP_ECX  0x59
    31. #define ASM_POP_EDX  0x5A
    32. #define ASM_POP_EBX  0x5B
    33. #define ASM_POP_ESP  0x5C
    34. #define ASM_POP_EBP  0x5D
    35. #define ASM_POP_ESI  0x5E
    36. #define ASM_POP_EDI  0x5F
    37. // Работа со стеком x64
    38. #define ASM_PUSH_RAX 0x50
    39. #define ASM_PUSH_RCX 0x51
    40. #define ASM_PUSH_RSI 0x5640
    41. #define ASM_PUSH_RDI 0x57
    42. #define ASM_POP_RAX  0x58
    43. #define ASM_POP_RCX  0x59
    44. #define ASM_POP_RDI  0x5F
    45. #define ASM_POP_RSI  0x5E
    46. // ----------------------------------------------------------------------------------------------------------------
    47.  
    48. // ИНКРЕМЕНТ / ДЕКРИМЕНТ ------------------------------------------------------------------------------------------
    49. // Инкремент / Декримент x32
    50. #define ASM_INC_EAX 0x40
    51. #define ASM_INC_ECX 0x41
    52. #define ASM_INC_EDX 0x42
    53. #define ASM_INC_EBX 0x43
    54. #define ASM_INC_ESP 0x44
    55. #define ASM_INC_EBP 0x45
    56. #define ASM_INC_ESI 0x46
    57. #define ASM_INC_EDI 0x47
    58. #define ASM_DEC_EAX 0x48
    59. #define ASM_DEC_ECX 0x49
    60. #define ASM_DEC_EDX 0x4A
    61. #define ASM_DEC_EBX 0x4B
    62. #define ASM_DEC_ESP 0x4C
    63. #define ASM_DEC_EBP 0x4D
    64. #define ASM_DEC_ESI 0x4E
    65. #define ASM_DEC_EDI 0x4F
    66. // ----------------------------------------------------------------------------------------------------------------
    67.  
    68. // ПОЛОЖИТЬ ЗНАЧЕНИЕ В РЕГИСТР ------------------------------------------------------------------------------------
    69. // Положить значение в регистр x32
    70. #define ASM_MOV_EAX_X 0xB8
    71. #define ASM_MOV_ECX_X 0xB9
    72. #define ASM_MOV_EDX_X 0xBA
    73. #define ASM_MOV_EBX_X 0xBB
    74. #define ASM_MOV_ESP_X 0xBC
    75. #define ASM_MOV_EBP_X 0xBD
    76. #define ASM_MOV_ESI_X 0xBE
    77. #define ASM_MOV_EDI_X 0xBF
    78. // Положить значение в регистр x64
    79. #define ASM_MOV_RAX_X 0xB848
    80. #define ASM_MOV_RCX_X 0xB948
    81. #define ASM_MOV_RDX_X 0xBA48
    82. #define ASM_MOV_RBX_X 0xBB48
    83. #define ASM_MOV_RSP_X 0xBC48
    84. #define ASM_MOV_RBP_X 0xBD48
    85. #define ASM_MOV_RSI_X 0xBE48
    86. #define ASM_MOV_RDI_X 0xBF48
    87.  
    88. #define ASM_MOV_R8D_X 0xB841
    89. #define ASM_MOV_R9_X  0xB949
    90. #define ASM_MOV_R8_X  0xB849
    91. // ----------------------------------------------------------------------------------------------------------------
    92.  
    93. // РЕГИСТРЫ В ПАРАМЕТРАХ КОМАНД -----------------------------------------------------------------------------------
    94. #define ASM_EAX_EAX 0xC0
    95. #define ASM_EAX_ECX 0xC1
    96. #define ASM_EAX_EDX 0xC2
    97. #define ASM_EAX_EBX 0xC3
    98. #define ASM_EAX_ESP 0xC4
    99. #define ASM_EAX_EBP 0xC5
    100. #define ASM_EAX_ESI 0xC6
    101. #define ASM_EAX_EDI 0xC7
    102. #define ASM_ECX_EAX 0xC8
    103. #define ASM_ECX_ECX 0xC9
    104. #define ASM_ECX_EDX 0xCA
    105. #define ASM_ECX_EBX 0xCB
    106. #define ASM_ECX_ESP 0xCC
    107. #define ASM_ECX_EBP 0xCD
    108. #define ASM_ECX_ESI 0xCE
    109. #define ASM_ECX_EDI 0xCF
    110. #define ASM_EDX_EAX 0xD0
    111. #define ASM_EDX_ECX 0xD1
    112. #define ASM_EDX_EDX 0xD2
    113. #define ASM_EDX_EBX 0xD3
    114. #define ASM_EDX_ESP 0xD4
    115. #define ASM_EDX_EBP 0xD5
    116. #define ASM_EDX_ESI 0xD6
    117. #define ASM_EDX_EDI 0xD7
    118. #define ASM_EBX_EAX 0xD8
    119. #define ASM_EBX_ECX 0xD9
    120. #define ASM_EBX_EDX 0xDA
    121. #define ASM_EBX_EBX 0xDB
    122. #define ASM_EBX_ESP 0xDC
    123. #define ASM_EBX_EBP 0xDD
    124. #define ASM_EBX_ESI 0xDE
    125. #define ASM_EBX_EDI 0xDF
    126. #define ASM_ESP_EAX 0xE0
    127. #define ASM_ESP_ECX 0xE1
    128. #define ASM_ESP_EDX 0xE2
    129. #define ASM_ESP_EBX 0xE3
    130. #define ASM_ESP_ESP 0xE4
    131. #define ASM_ESP_EBP 0xE5
    132. #define ASM_ESP_ESI 0xE6
    133. #define ASM_ESP_EDI 0xE7
    134. #define ASM_EBP_EAX 0xE8
    135. #define ASM_EBP_ECX 0xE9
    136. #define ASM_EBP_EDX 0xEA
    137. #define ASM_EBP_EBX 0xEB
    138. #define ASM_EBP_ESP 0xEC
    139. #define ASM_EBP_EBP 0xED
    140. #define ASM_EBP_ESI 0xEE
    141. #define ASM_EBP_EDI 0xEF
    142. #define ASM_ESI_EAX 0xF1
    143. #define ASM_ESI_ECX 0xF2
    144. #define ASM_ESI_EDX 0xF3
    145. #define ASM_ESI_EBX 0xF4
    146. #define ASM_ESI_ESP 0xF5
    147. #define ASM_ESI_EBP 0xF6
    148. #define ASM_ESI_ESI 0xF7
    149. #define ASM_ESI_EDI 0xF8
    150. #define ASM_EDI_EAX 0xF8
    151. #define ASM_EDI_ECX 0xF9
    152. #define ASM_EDI_EDX 0xFA
    153. #define ASM_EDI_EBX 0xFB
    154. #define ASM_EDI_ESP 0xFC
    155. #define ASM_EDI_EBP 0xFD
    156. #define ASM_EDI_ESI 0xFE
    157. #define ASM_EDI_EDI 0xFF
    158. // ----------------------------------------------------------------------------------------------------------------
    159.  
    160. #define ASM_MOV   0x8B
    161. #define ASM_ADD   0x03;
    162. #define ASM_SUB   0x2B;
    163. #define ASM_XOR   0x33
    164. #define ASM_REP   0xF3
    165. #define ASM_MOVSB 0xA4
    166. #define ASM_NOP   0x90
    167.  
    168. #endif
     
  10. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    d2k9
    Это ужасно. Чем Вам E8 не угодил?
     
  11. Twister

    Twister New Member

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    720
    Адрес:
    Алматы
    Ну тогда уж push/ret используй (коли байтика не жаль), зачем такую ересь?
     
  12. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Twister
    А адрес возврата сохранить?
     
  13. Twister

    Twister New Member

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    720
    Адрес:
    Алматы
    Не совсем понял о чём речь.
     
  14. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Twister
    Если использовать push + ret для вызова API, то не сохраняется адрес возврата. Можно, конечно, извратиться чем-то в духе
    call $+5
    add dword[esp],6
    push API_Address
    ret
    Но смысл в этом, если есть E8? К тому же в этом случае речь будет о жалости явно не к одному байтику.
     
  15. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    P.S. Слегка прогнал... не учёл размер размер инструкции сложения... надо (хотя лучше сказать не надо :)) add dword[esp],10 .
     
  16. Twister

    Twister New Member

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    720
    Адрес:
    Алматы
    Хех. Ну это я слегка прогнал. Почему-то мне не показалось необходимым сразу вернуться в шеллкод :) Видать в голове вертелись обработчики хуков. Тут-то, конечно, жертвуется совсем не один байт.
     
  17. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Twister
    Ну формально в данном случае (когда поток вызывает только одну API) можно и не возвращаться в шеллкод. Для этого в самом начале потока нужно вытянуть куда-нибудь верхний dword, а перед передачей управления на API подсунуть его, как адрес возврата (использовать RtlExitUserThread, как это делает автор, в любом случае не имеет смысла). Поэтому для данного случая в принципе можно и потерять два байта, используя push/ret:
    pop eax
    push arg4
    push arg3
    push arg2
    push arg1
    push eax
    push InternetSetOptionA_Address
    ret
    Хотя сколько-нибудь значительной причины для этого я не вижу.
     
  18. Twister

    Twister New Member

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    720
    Адрес:
    Алматы
    Аналогично. Просто еще один способ передать управление, для общего развития автора, так сказать.
     
  19. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    d2k9
    Зачем какието опкоды забивать и смещения, если можно через дельту:
    Код (Text):
    1. $CALL macro Reference
    2. Local Dt
    3.     Call Dt
    4. Dt:
    5.     pop eax
    6.     Call dword ptr [eax + (offset Reference - offset Dt)]
    7. endm
    8.  
    9.     jmp @f
    10. pInternetSetOptionA     PVOID ?
    11. pRtlExitUserThread      PVOID ?
    12. @@:
    13.     push 0
    14.     push 0
    15.     push 2AH
    16.     push 0
    17.     $CALL pInternetSetOptionA
    18.     push 0
    19.     $CALL pRtlExitUserThread
     
  20. Twister

    Twister New Member

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    720
    Адрес:
    Алматы
    Лишние байтики, иногда для шеллкода критично :)
    А так хороший вариант в вирмейкеровском духе.
     
Статус темы:
Закрыта.