Проблемы с патчами.

Тема в разделе "WASM.BEGINNERS", создана пользователем Clerk, 30 июл 2010.

  1. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    В данном топике будут рассматриваться всевозможные патчи кода, как частный случай это хотпатч и сплайсинг. Все вопросы по патчам задаются теперь именно тут и нигде больше, не зависимо от имён апи, мода и пр.
    -
    В данном случае патч - изменение кода в памяти в пределах кодовых секций модулей(R/E). Далее краткое описание.
    1. Защита.
    Обычно кодосекции защишены от записи. В юзермоде используется сервис NtProtectVirtualMemory, либо обёртка для него VirtualProtect():
    Код (Text):
    1. push esp           ;адрес переменной, в нее возвращается "старый" режим доступа
    2. push 40h           ;режим доступа (нам нужен 40h)
    3. push 2000h        ;размер области памяти в байтах
    4. push eax           ;адрес области памяти, чьи атрибуты страниц нужно изменить
    5. call VirtualProtect
    Второй способ это замена страниц на R/W проекцию, но это большинству не нужно. В ядре возможности гораздо большие - можно отключить защиту записи сбросом бита WP(10000000000000000B) в регистре управления Cr0:
    Код (Text):
    1. mov eax, cr0
    2. mov ebx, eax           ;сохраняем начальное значение WP
    3. and eax,0xFFFEFFFF ;сбрасываем WP
    4. mov cr0, eax           ;загружаем в CR0
    Можно изменить флаг RW в PTE. Легальный и надёжный способ - описать регион через MDL и изменить его атрибуты посредством MmProtectMdlSystemAddress. Также можно создать вторую PTE для физической страницы и писать во вторую проекцию.

    2. Хотпатч. Большинство функций имеют в своём начале двубайтную холостую инструкцию(mov edi,edi), перед которой имеется 5 инструкций nop(0x90). Вначале на место нопов записывается безусловное ветвление(может быть процедурным), после этого в пролог записывается короткое безусловное ветвление(2 байта) на место первой инструкции. Это поддерживает ядро. http://www.codebreakers-journal.com/content/view/113/27/
    В общем случае это запись короткого безусловного ветвления(мост) на ветвление на хэндлер(near, far) в пределах +/-127 байт.
    o Как сделать такое же в своем модуле?
    Ключ компилятора cl: /hotpatch (генерит mov edi,edi)
    Ключ линкера ms link: /functionpadmin[:space], где space - минимальное число нопов между функциями.

    3. Сплайсинг. Записывается в начало процедуры, либо в необходимое место кода ветвление на хэндлер. При этом возникают проблемы потоками. Если ветвление занимает размер болеший чем размер изменяемой инструкции, то изза изменённых следующих инструкций потоки прерванные на них далее отработают не корректно. Чтобы избежать этой ситуации используется енум всех потоков процесса(U-mode) и поправка их Ip. Потоки енумяться и Ip каждого проверяется на вхождение в изменяемый диапазон кода. Далее можно поступить несколькими способами:
    o Отпустить поток и выполнить не большую задержку.
    o Скопировать оригинальный код в буфер и при вхождении Ip в изменяемый диапазон выполнять редирект потока на буфер. Тоесть просто прибавить к Ip разность базы буфера и целевой процедуры.
    http://www.wasm.ru/article.php?article=apihook_1

    4. Останов потоков и их енум. Для останова можно использовать два сервиса - NtSuspendThread(апи SuspendThread()) и NtSuspendProcess. Первый сервис замораживает поток, второй все потоки в процессе. Для разморозки соответственно *Resume. Для перечисления потоков используются слепки.
    http://msdn.microsoft.com/en-us/library/ms686832(v=VS.85).aspx

    5. Ветвление. Можно записать инструкцию Jmp или Call. Во втором случае обработчик получит адрес, откуда он был вызван. Необходимо если например хэндлер общий у разных процедур.

    6. Брейки. Однобайтные инструкции генерирующие исключения. Хэндлер является диспетчером исключений.

    http://www.wasm.ru/article.php?article=user-mode-exceptions
    http://www.wasm.ru/series.php?sid=7
    http://www.wasm.ru/article.php?article=veh
    http://www.wasm.ru/forum/viewtopic.php?pid=381157#p381157

    7. Дизассемблер длин используется для енума инструкций, лучший этот:
    http://www.eof-project.net/sources/Malum/VirXasm32_v1.5adv/src/VirXasm32b.asm
    http://files.virustech.org/indy/Code/XcptIp/VirXasm32b.asm

    8. Использование стековых фреймов. В начале процедуры может не быть например инструкции подходящей для записи ветвления. При этом оно записывается выше(глубже в процедуре). Параметры процедуры и локальные переменные адресуются обычно регистром Ebp. Он адресует цепочку стековых фреймов и не меняется в пределах процедуры, таким образом доступ к параметрам процедуры выполняется через него. Например структура, которую будет адресовать регистр Ebp в любом месте процедуры LdrGetDllHandleEx():
    Код (Text):
    1. NTSTATUS
    2. NTAPI
    3. LdrGetDllHandleEx(
    4.     IN ULONG Flags,
    5.     IN PCWSTR DllPath OPTIONAL,
    6.     IN PULONG DllCharacteristics OPTIONAL,
    7.     IN PCUNICODE_STRING DllName,
    8.     OUT PVOID *DllHandle OPTIONAL
    9.     );
    Код (Text):
    1. STACK_FRAME struct
    2. Next        PVOID ? ; Следующий фрейм.
    3. Ip      PVOID ? ; Адрес возврата из процедуры.
    4. STACK_FRAME ends
    5.  
    6. FN struct
    7. Frame           STACK_FRAME <>
    8. Flags           ULONG ?
    9. DllPath         PCWSTR ?
    10. DllCharacteristics  PULONG ?
    11. DllName         PCUNICODE_STRING ?
    12. DllHandle       PVOID ?
    13. FN ends
    9. Атомарность. Запись выполняется не побайтно, а сразу 4 или 8 байт изменяются посредством инструкций cmpxchg и cmpxchg8b.
    http://www.intel.com/Assets/PDF/manual/253666.pdf

    Используете поиск тут по словам "сплайсинг", "патч".
     
  2. Medstrax

    Medstrax Забанен

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    673
    Как быть с контролем целостности? Пусть один поток выполняет некий код, другой поток (не обязательно этого же процесса) контролирует целостность этого кода.
     
  3. Clerk

    Clerk Забанен

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

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    А как-нибуть еще можно изменять атрибуты памяти кроме как через NtProtectVirtualMemory?
    Можно-вить "пересобрать" секцию ZwCreateSection/ZwMapViewOfSection где находится нужный нам адрес, и прям в вышеупомянутых апи уже задать нужные атрибуты?
     
  5. Clerk

    Clerk Забанен

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

    Zlyden New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2008
    Сообщения:
    49
    Перехватываю функцию в DLL. Нашел точный адрес функции, имею ее исходный код. Но т.к. функция static, компилятор ее оптимизировал. Вот изначальная функция.
    Код (Text):
    1. static void HookCG_RGBForSaberColor( saber_colors_t color, vec3_t rgb )
    2. {
    3.     switch( color )
    4.     {
    5.         case SABER_RED:
    6.             VectorSet( rgb, 1.0f, 0.2f, 0.2f );
    7.             break;
    8.         case SABER_ORANGE:
    9.             VectorSet( rgb, 1.0f, 0.5f, 0.1f );
    10.             break;
    11.         case SABER_YELLOW:
    12.             VectorSet( rgb, 1.0f, 1.0f, 0.2f );
    13.             break;
    14.         case SABER_GREEN:
    15.             VectorSet( rgb, 0.2f, 1.0f, 0.2f );
    16.             break;
    17.         case SABER_BLUE:
    18.             VectorSet( rgb, 0.2f, 0.4f, 1.0f );
    19.             break;
    20.         case SABER_PURPLE:
    21.             VectorSet( rgb, 0.9f, 0.2f, 1.0f );
    22.             break;
    23.     }
    24. }
    saber_colors_t = int, vec3_t = float[3]. Как видно, функция возвращает цвет (почему-то в массиве float). Моя задача - добавить еще один вариант.
    Вот как она выглядит в дизассемблированном виде от IDA.
    Код (Text):
    1. _text:20136500 CG_RGBForSaberColor proc near           ; CODE XREF: sub_0_201365A0+D0p
    2. _text:20136500                                         ; CG_DoSaber+E3p
    3. _text:20136500                 cmp     ecx, 5          ; switch 6 cases
    4. _text:20136503                 ja      short locret_0_20136583 ; default
    5. _text:20136505                 jmp     ds:off_0_20136584[ecx*4] ; switch jump
    6. _text:2013650C
    7. _text:2013650C loc_0_2013650C:                         ; DATA XREF: _text:off_0_20136584o
    8. _text:2013650C                 mov     ecx, 2.0e-1     ; jumptable 20136505 case 0
    9. _text:20136511                 mov     dword ptr [eax], 1.0
    10. _text:20136517                 mov     [eax+4], ecx
    11. _text:2013651A                 mov     [eax+8], ecx
    12. _text:2013651D                 retn
    13. _text:2013651E ; ---------------------------------------------------------------------------
    14. _text:2013651E
    15. _text:2013651E loc_0_2013651E:                         ; CODE XREF: CG_RGBForSaberColor+5j
    16. _text:2013651E                                         ; DATA XREF: _text:off_0_20136584o
    17. _text:2013651E                 mov     dword ptr [eax], 1.0 ; jumptable 20136505 case 1
    18. _text:20136524                 mov     dword ptr [eax+4], 5.0e-1
    19. _text:2013652B                 mov     dword ptr [eax+8], 1.0e-1
    20. _text:20136532                 retn
    21. _text:20136533 ; ---------------------------------------------------------------------------
    22. _text:20136533
    23. _text:20136533 loc_0_20136533:                         ; CODE XREF: CG_RGBForSaberColor+5j
    24. _text:20136533                                         ; DATA XREF: _text:off_0_20136584o
    25. _text:20136533                 mov     dword ptr [eax], 1.0 ; jumptable 20136505 case 2
    26. _text:20136539                 mov     dword ptr [eax+4], 1.0
    27. _text:20136540                 mov     dword ptr [eax+8], 2.0e-1
    28. _text:20136547                 retn
    29. _text:20136548 ; ---------------------------------------------------------------------------
    30. _text:20136548
    31. _text:20136548 loc_0_20136548:                         ; CODE XREF: CG_RGBForSaberColor+5j
    32. _text:20136548                                         ; DATA XREF: _text:off_0_20136584o
    33. _text:20136548                 mov     ecx, 2.0e-1     ; jumptable 20136505 case 3
    34. _text:2013654D                 mov     [eax], ecx
    35. _text:2013654F                 mov     dword ptr [eax+4], 1.0
    36. _text:20136556                 mov     [eax+8], ecx
    37. _text:20136559                 retn
    38. _text:2013655A ; ---------------------------------------------------------------------------
    39. _text:2013655A
    40. _text:2013655A loc_0_2013655A:                         ; CODE XREF: CG_RGBForSaberColor+5j
    41. _text:2013655A                                         ; DATA XREF: _text:off_0_20136584o
    42. _text:2013655A                 mov     dword ptr [eax], 2.0e-1 ; jumptable 20136505 case 4
    43. _text:20136560                 mov     dword ptr [eax+4], 4.0000001e-1
    44. _text:20136567                 mov     dword ptr [eax+8], 1.0
    45. _text:2013656E                 retn
    46. _text:2013656F ; ---------------------------------------------------------------------------
    47. _text:2013656F
    48. _text:2013656F loc_0_2013656F:                         ; CODE XREF: CG_RGBForSaberColor+5j
    49. _text:2013656F                                         ; DATA XREF: _text:off_0_20136584o
    50. _text:2013656F                 mov     dword ptr [eax], 8.9999998e-1 ; jumptable 20136505 case 5
    51. _text:20136575                 mov     dword ptr [eax+4], 2.0e-1
    52. _text:2013657C                 mov     dword ptr [eax+8], 1.0
    53. _text:20136583
    54. _text:20136583 locret_0_20136583:                      ; CODE XREF: CG_RGBForSaberColor+3j
    55. _text:20136583                 retn                    ; default
    56. _text:20136583 CG_RGBForSaberColor endp
    Как мне объяснили, функция получает значения через регистры, color через ecx, rgb через eax. Поэтому я сделал заголовок новой фунции как void __fastcall HookCG_RGBForSaberColor( saber_colors_t color, int, vec3_t rgb ), в итоге программа начала глючить конкретно, притом вне зависимости от порядка значений. Перехват осуществляется при помощи подгруженной DLL. Вот ее исходный код.
    Код (Text):
    1. enum
    2. {
    3.     SABER_RED,
    4.     SABER_ORANGE,
    5.     SABER_YELLOW,
    6.     SABER_GREEN,
    7.     SABER_BLUE,
    8.     SABER_PURPLE,
    9.     SABER_RGB,
    10.     NUM_SABER_COLORS
    11. };
    12. typedef int saber_colors_t;
    13. typedef float vec_t;
    14. typedef vec_t vec2_t[2];
    15. typedef vec_t vec3_t[3];
    16. typedef vec_t vec4_t[4];
    17. typedef vec_t vec5_t[5];
    18. #undef QDECL
    19. #define QDECL   __cdecl
    20. #pragma pack (push,1)
    21. struct jmp_far{
    22.   BYTE instr_push;  //здесь будет код инструкции push
    23.   DWORD arg;        //аргумент push
    24.   BYTE  instr_ret;  //здесь будет код инструкции ret
    25. };
    26. #pragma pack (pop)
    27. BYTE old[6],oldCG_RGBForSaberColor[6];          //область для хранения 6-ти затираемых байт начала функции
    28. const DWORD adr_Sys_LoadDll = 0x440250, adr_CG_RGBForSaberColor=0x20136500;
    29. DWORD written;          //вспомогательная переменная
    30. jmp_far jump,jumpCG_RGBForSaberColor;           //здесь будет машинный код инструкции перехода
    31. #define VectorSet(v, x, y, z)   ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z))
    32.  
    33. #ifdef _MANAGED
    34. #pragma managed(push, off)
    35. #endif
    36. //void * QDECL OrigSys_LoadDll( const char *name, char *fqpath , int (QDECL **entryPoint)(int, ...),
    37. //                           int (QDECL *systemcalls)(int, ...) );
    38. //&OrigSys_LoadDll=adr_Sys_LoadDll;
    39.  
    40. //static void HookCG_RGBForSaberColor( saber_colors_t color, vec3_t rgb )
    41. void __fastcall HookCG_RGBForSaberColor( saber_colors_t color, int, vec3_t rgb )
    42. {
    43.     switch( color )
    44.     {
    45.         case SABER_RED:
    46.             VectorSet( rgb, 0.2f, 1.0f, 0.5f );
    47.             break;
    48.         case SABER_ORANGE:
    49.             VectorSet( rgb, 1.0f, 0.2f, 0.6f );
    50.             break;
    51.         case SABER_YELLOW:
    52.             VectorSet( rgb, 1.0f, 1.0f, 0.2f );
    53.             break;
    54.         case SABER_GREEN:
    55.             VectorSet( rgb, 0.2f, 1.0f, 0.2f );
    56.             break;
    57.         case SABER_BLUE:
    58.             VectorSet( rgb, 0.2f, 0.4f, 1.0f );
    59.             break;
    60.         case SABER_PURPLE:
    61.             VectorSet( rgb, 0.9f, 0.2f, 1.0f );
    62.             break;
    63.     }
    64. }
    65.  
    66. //Собственно подмена функций в dll
    67. void InterceptFunctions(void){
    68.     jumpCG_RGBForSaberColor.instr_push = 0x68;
    69.     jumpCG_RGBForSaberColor.arg = (DWORD)&HookCG_RGBForSaberColor;
    70.     jumpCG_RGBForSaberColor.instr_ret = 0xC3;
    71.     WriteProcessMemory(GetCurrentProcess(), (void*)adr_CG_RGBForSaberColor,
    72.         (void*)&jumpCG_RGBForSaberColor, sizeof(jmp_far), &written);
    73.  
    74. }
     
  7. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Zlyden
    Тоесть вам нужно увеличить на 1 это значение:
    Код (Text):
    1. _text:20136500                 cmp     ecx, 5          ; switch 6 cases
    и добавить хэндлер в таблицу 0x20136584, всё это делается атомарно, в отличие от сплайсинга(4). Не понятно для чехо сохранять пролог, если вы заменяете функцию полностью. Скорее всего откуда происходит вызов этой функи известен, тогда достаточно изменить ссылку на процедуру.
    Это не описание проблемы. Вероятно не верная модель вызова.
     
  8. RET

    RET Well-Known Member

    Публикаций:
    17
    Регистрация:
    5 янв 2008
    Сообщения:
    789
    Адрес:
    Jabber: darksys@sj.ms
    Уважаемый тов. Clerk так какой метод наиболее продвинут, о котором естественно наверняка тут не указано ( ;) ) ?
     
  9. Zlyden

    Zlyden New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2008
    Сообщения:
    49
    Clerk
    Спасибо, но я еще вчера разобрался. И пост вроде бы отредактировал, написал, что разобрался и помощь больше не нужна, но тут все как было. Решил проблему так - убрал у функции арги вообще. Вместо этого я создал локальные переменные int color, float * rgb, затем при помощи ассемблерной вставки вытащил их значения из регистров. Теперь работает. Перехват конкретно этой функции предпочтителен, т.к. над ней еще предстоит поработать. Хотя мне еще предстоит сделать перехват похожего ветвления внутри функции.
    Вообще, у меня возникла новая проблема. Я тружусь над перехватом другой функции. Собственно, заменять ее мне не нужно, мне нужны две переменные из ее стека. Вот как выглядит перехват:
    Код (Text):
    1. void HookCG_AddSaberBlade( int one, int two, int three, int four, int five, int six,
    2.     int saberNum, int bladeNum )
    3. {
    4.     //Восстановление первых вшестии байт
    5.     WriteProcessMemory(GetCurrentProcess(), (void*)adr_CG_AddSaberBlade,
    6.         (void*)oldCG_AddSaberBlade, 6, &written);
    7.     bnum=bladeNum;
    8.     snum=saberNum;
    9.     //Вызов функции с теми же переменными
    10.     ((void (__cdecl*)( int, int, int, int, int, int, int, int )
    11.         adr_CG_AddSaberBlade)( one, two, three, four, five, six, saberNum, bladeNum);
    12.     //Возвращаем хук
    13.     WriteProcessMemory(GetCurrentProcess(), (void*)adr_CG_AddSaberBlade,
    14.         (void*)&jumpCG_AddSaberBlade, sizeof(jmp_far), &written);
    15. }
    Функция несколько другая, чем я ожидал. Нужные мне переменные содержаться в последних двух аргументах, остальные - четырехбайтные переменные, для чего нужны, точно не знаю. Полагаю, в основном это указатели на объекты классов, three всегда 0, в функции не используется. В общем, я их получаю и передаю дальше как int, процессору вроде как нет разницы. Но почему-то вызываемая функция работает некорректно. По идее она отвечает за прорисовку лезвия меча, но после перехвата не рисует, появляются глюки в атаке.
    Функция вызывается из двух мест.
    Код (Text):
    1. mov     ecx, [esp+430h+var_420]
    2. push    ecx
    3. mov     ecx, [esi+1C4h]
    4. push    edi
    5. lea     edx, [esp+438h+var_418]
    6. push    edx
    7. mov     edx, [esp+43Ch+var_3F0]
    8. lea     eax, [esp+43Ch+var_3B0]
    9. push    eax
    10. movsx   eax, word ptr [ecx+3E4h]
    11. push    edx
    12. push    0
    13. push    esi
    14. push    esi
    15. call    CG_AddSaberBlade
    16. add     esp, 20h
    17. jmp     loc_0_2013FCE8
    Код (Text):
    1. mov     edx, [esp+430h+var_420]
    2. push    edx
    3. mov     edx, [esi+1C4h]
    4. push    edi
    5. lea     eax, [esp+438h+var_418]
    6. push    eax
    7. movsx   eax, word ptr [edx+3E2h]
    8. lea     ecx, [esp+43Ch+var_3B0]
    9. push    ecx
    10. mov     ecx, [esp+440h+var_3F0]
    11. push    ecx
    12. push    edi
    13. push    esi
    14. push    esi
    15. call    CG_AddSaberBlade
    16. add     esp, 20h
    17. jmp     short loc_0_2013FCE8
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Zlyden
    Их не нужно восстанавливать, а следует записать в конец буфера ветвление на код, после вашего джампа. При наличии ветвлений в начале процедуры их нужно поправить в буфере, например так http://www.wasm.ru/forum/viewtopic.php?pid=385497#p385497. Также лучше использовать не пару push/ret, а Jmp near, так как он короче на 1 байт. Тоесть в случае с вашим первым кодом исходная функа:
    Код (Text):
    1. CG_RGBForSaberColor:
    2. x00:
    3.     cmp ecx,5
    4. x03:
    5.     ja short loc_x83
    6. x05:
    7.     ...
    8. xXX:
    9.     ...
    Перехваченная:
    Код (Text):
    1. CG_RGBForSaberColor:
    2.     push offset HookCG_RGBForSaberColor
    3.     retn
    4.     ...
    5. xXX:
    И хэндлер:
    Код (Text):
    1. HookCG_RGBForSaberColor:
    2. x00:
    3.     cmp ecx,5
    4. x03:
    5.     ja CG_RGBForSaberColor.x83
    6. x05:
    7.     ...
    8. xXX:
    9.     push offset CG_RGBForSaberColor.xXX
    10.     ret
     
  11. Zlyden

    Zlyden New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2008
    Сообщения:
    49
    Clerk
    Наверно, вы меня не поняли, но CG_RGBForSaberColor я уже удачно перехватил, а восстанавливаю первые шесть байт совершенно другой функции, с ней возникли проблемы при заборе данных из стека. Насчет того, что jmp_near лучше jmp_far, не уверен. Я уже разок решил использовать ее вместо jmp_far, сделал все по инструкции, из адреса цели вычел адрес функции, добавил пять, получил бсод. Тогда я решил, что это наверняка из-за того, что функция-цель находится до перехватываемой функции, а jmp_near не воспринимает отрицательные значения (не знаю точно, но уверен). В общем, с тех пор только push/ret
     
  12. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Zlyden
    Это вы не поняли. У вас не корректный подход к решению задачи. Код CG_RGBForSaberColor был примером.
     
  13. Zlyden

    Zlyden New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2008
    Сообщения:
    49
    Clerk
    А, спасибо, теперь понял. Ваш метод опробую, у меня еще предстоит одно ветвление заменить.
    А с CG_AddSaberBlade разобрался. В чем ошибка, не нашел, зато нашел, где хранятся все эти уже извлеченные данные стека .
     
  14. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Zlyden
    Учтите что стек ниже Esp не ваш.
     
  15. SZ

    SZ New Member

    Публикаций:
    0
    Регистрация:
    19 авг 2010
    Сообщения:
    30
    а перехват функи на её возврате где-то обсуждался ?
     
  16. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    SZ
    Да, в #8. Что вам не понятно из этого ?
     
  17. SZ

    SZ New Member

    Публикаций:
    0
    Регистрация:
    19 авг 2010
    Сообщения:
    30
    Clerk
    Мне не понятно куда можно сохранить действительный адрес возврата в многопоточном приложении.
    Алгоритм вкратце:
    1. При инжекте: в начало перехватываемой функции вставляю jmp на свою функцию подмены адреса возврата.
    2. В функции подмены: меняю в стеке действительный адрес возврата на адрес моей функции перехватчика.
    и вот тут действительный адрес нужно куда-то сохранить чтоб им можно было воспользоваться в функе перехвата для передачи управления вызывающему коду после отработки перехвата. Если я ложу адрес в глобальную переменную, то каждый новый поток которому понадобилась перехватываемая функа приходит со своим адресом возврата и соотв. в переменной остаётся адрес последнего вызывающего потока. и получается сколько бы потоков не вошло в функцию, все они будут возвращаться по адресу последнего вошедшего.
    А как дотянуться до локальной переменной из другой функции я не представляю.

    Тогда я попробовал сохранять этот адрес относительно ESP. Ониже не могут быть равны у разных потоков ?
    mov [esp-12364],eax
    Смещение 12364, почти от фонаря, просто в отладчике подсмотрел что эта область заполнена нулями и никаких следов её использования не обнаружил. Работает. Но очень не устойчиво. Я вобще не уверен что туда можно чтото писать.
     
  18. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    SZ
    А почему не сделать просто call внутри своей функции, с дублированием фрейма стека? Или Вам нужен перехват функций с неизвестным кол-вом параметров? Тогда можно просто дублировать достаточно большой кусок, чтобы фрейма точно хватило.
     
  19. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    SZ
    #14.
    Можно использовать следующие способы:
    o TLS. Это инфа связанная с потоком. Может быть локальной или глобальной. Если локальна, то используется тот факт, что регистр Fs адресует сегмент уникальный для потока с его окружением(TEB). Во втором способе создаётся список, в котором сохраняются описатели поток-ссылка(адрес возврата). Это решение требует использование нотификаторов, при первом вызове кода описатель сохраняется в список, затем извлекается. Память выделяется при создании потока или первом вызове кода, освобождается при завершении потока или когда выполняется возврат на оригинальный код.
    o Использование контекста, который передаётся в хэндлер. Это например свободные поля в стековых фреймах. Не универсально.
    o Использование дна стека. Эта часть стека не используется. Например я использовал следующее макро:
    Код (Text):
    1. $GET_ENVIRONMENT macro Reg32
    2.     mov Reg32,fs:[TEB.Tib.StackBase]
    3.     mov Reg32,dword ptr [Reg32 - 4]
    4. endm
    o Механизм исключений. Универсально. Старший бит ссылки взводится. Это приведёт к возникновению исключения при возврате, так как выход за пределы сегмента/U-space. Диспетчер исключений сбрасывает старший бит ссылки и выполняет возврат.
    o Использование переменных ядра. Это конфиг связанный с текущим обьектом(ETHREAD), например ThreadQuerySetWin32StartAddress, проецирование ядерной памяти и пр. Крайне не желательно для применения.
     
  20. SZ

    SZ New Member

    Публикаций:
    0
    Регистрация:
    19 авг 2010
    Сообщения:
    30
    Booster
    Вот произошёл вызов перехватываемой функи
    [esp]=Адрес возврата
    позади (esp+), дыра в 1028 байт оставленная прологом функи для буфера(?)
    впереди (esp-), место для функций которые будут вызываться из перехватываемой.
    Вот я и не понимаю как тут воткнуться чтоб мне не испортили мои данные (esp-) или я не испортил чужие (esp+).

    Clerk
    Из перечисленных вами способов мне наверное подойдут
    "TLS" и "дно стека". Но вряд ли с TLS получиться, мне это не осилить.
    На всякий случай запощу проблемный кодес
    Код (Text):
    1. NAKED void HookRecv()
    2. {
    3.     __asm
    4.     {
    5.     __emit  0x8B
    6.     __emit  0x41
    7.     __emit  0x08
    8.     jmp     [pPreHookRecv]  ; для вставки: прыжок на пресплайс.
    9.     __emit  0xCC
    10. ;................           ; Перехватчик   
    11.                             ; После отработки целевой функции управление передаётся сюда, адрес в pofHookRecv.
    12.     push    [esp-12364-4]   ; Замена подставного на действительный адрес возврата.   
    13.     pushad                  ; Сохранение контекста
    14.     mov     eax,[esp+32+4]  ; Берём адрес возвращённых данных,
    15.     mov     pData, eax      ; сохраняем.
    16.  
    17.     mov     eax,[eax]
    18.     cmp     al,0x38         ; а что там ?
    19.     je      skiprecv        ; если '8' пропустить
    20.     }
    21. //................          полезная нагрузка, работа с данными *pData
    22.  
    23. //................
    24.     __asm
    25.     {
    26. skiprecv:
    27.     popad       ; Восстановление контекста
    28.     ret         ; возврат
    29.     }
    30. }
    31. //=================================================================================
    32. NAKED void PreHookRecv()        //  Пресплайс
    33. {
    34.     __asm
    35.     {
    36.     pushad                      //  Произошёл вызов перехватываемой функции, её адрес в eax.
    37.    
    38.     mov     eax,pofHookRecv     //  Загрузка адреса перехватчика:=>pofHookRecv
    39.     xchg    eax,[esp+32+0]      //  Меняем местами: подставной<===>действительный, +32 поправка на pushad
    40.     mov     [esp+32-12364],eax  //  Сохранение действительного адреса возврата
    41.  
    42.     popad
    43.     jmp     eax                 // Передача управления целевой функции
    44.     }
    45. }
    буду с макросом разбираться.