Api Splacing

Тема в разделе "WASM.BEGINNERS", создана пользователем Yashin, 31 янв 2008.

  1. Yashin

    Yashin New Member

    Публикаций:
    0
    Регистрация:
    25 янв 2008
    Сообщения:
    19
    Вот прочитал статью MS-rem'a. Хочу сделать фильтр ZwQueryDirectoryFile. Замена нужна для однопоточного приложения. Мне не понятны пара моментов. Я раньше никогда ничего не писал на АСме(поэтому и пишу здесь), только на Делфе(rulezz). Опыт у меня достаточный, уже думаю пора взяться за асм'шку, тем более что подвернулась такая задача.
    Первое мое недопонимание относится к реализации метода. В статье он перед установкой хука останавливает все потоки, но когда вызывается реальная функция этого не делается, видимо решил сэкономить время. Но в тоже время, он восстанавливает начало функции при помощи Апи WriteMemory, на чем теряет дохера процессорного времени. Я в своей реализации хочу писать напрямую, для этого меняю защиту памяти VirtualProtect'ом.
    Второе... на Делфе я это реализовал, вполне сносно, работает. Но смысла писать в Делфи на асме я не вижу. В общем компилятор у меня MASM32. Я уже порядком замаялся, код не особо хочет переноситься, с BASM'а на MASM. Да и дебажить код при помощи Olly уже совсем не могу. Короче вот мой код. Моя проблема в том, что мало практики работы в асме и мне нужна подсказка, в правильном направлении я иду или нет.
    Да, и еще я решил сэкономить время на том, что использую предыдущее состояние стека и здесь мне пришлось изрядно помучаться, я потратил на это около 5 часов.
    Ms-Rem использовал структуру для инжекта (far_jmp в статье). Я изрядно намучался заполнять память при помощи асм'а ( по большей части из-за того, что где-то услышал, будто бы процессоры не любят не выровненную память, а прогеры обязаны угождать процессору), поэтому я прошу Масм, чтобы он сам создал для меня нужную структуру, вариант мне очень нравиться.

    Код (Text):
    1. .const
    2.     sLibName  db 'ntdll.dll',0
    3.     sProcName db 'ZwQueryDirectoryFile',0
    4.  
    5. .data?
    6.     QDFile dd ?                           ;Здесь адрес заменяемой функции
    7.     LastProtectMode dd ?             ;Защита памяти
    8.     OldCode dw ?,?,?,?                 ;Старое начало функции
    9.     RetPos  dd ?                          ;Временная переменная
    10.  
    11. .code
    12.  
    13.  
    14. MyFunc proc
    15.     push EDX     ; Запоминаем с чем пришли
    16.     ;=========================================
    17.     mov EAX, DWORD PTR OldCode         ; Восстанавливаем
    18.     mov DX,  OldCode+4         ; начальные байты
    19.     mov [QDFile],EAX           ; исходной
    20.     mov WORD PTR [QDFile+4],DX ; функции
    21.     ;=========================================
    22.     pop EDX  ; Я должен остаться незамеченным
    23.     pop RetPos
    24.     ;=========================================
    25.     call QDFile    ;Вызываем оригинальную функцию
    26.     ;=========================================
    27. ;Здесь я напишу фильтр, но это уже потом
    28.     push RetPos
    29.     push EAX
    30.     push EDX
    31.     ;=========================================
    32.     mov EAX, DWORD PTR [@ICode]    ; Ставим
    33.     mov DX,  WORD  PTR [@ICode+4]  ; обработчик
    34.     mov [[QDFile]],EAX
    35.     mov WORD PTR [QDFile]+4,DX
    36.     ;=========================================
    37.     pop EDX    ; Меня и вовсе тут и не было..
    38.     pop EAX
    39.    
    40. ;   mov EAX,0C000000Fh        ;Код не работает, иначе бы файлов на компе не было бы
    41.     ret
    42. MyFunc endp
    43.  
    44. ;Здесь новое начало функции с дальним джампом на мою функцию
    45. ;В асме я ничего не смыслю, поэтому использовал вариант Ms-Rem'а
    46. @ICode: push LROFFSET MyFunc
    47.         ret
    48.  
    49.  
    50. SetHook proc
    51.  
    52.     invoke GetModuleHandle,    OFFSET sLibName  
    53.     invoke GetProcAddress,EAX, OFFSET sProcName
    54.     mov QDFile, EAX
    55.    
    56.     invoke VirtualProtect,EAX, 6, PAGE_EXECUTE_READWRITE, OFFSET LastProtectMode
    57.  
    58. ;Как показал OllyDbg данные нормально создаются,
    59. ;но не передаются куда надо, следовательно ошибка тута
    60.     ;сохраняем старое начало функции
    61.     mov EAX,  [QDFile]
    62.     mov DX,   WORD PTR [QDFile+4]
    63.     mov DWORD PTR OldCode, EAX
    64.     mov OldCode+4, DX
    65.     ;записываем новое начало
    66.     mov EAX, DWORD PTR [@ICode]
    67.     mov DX,  WORD  PTR [@ICode+4]
    68.     mov [QDFile], EAX
    69.     mov WORD PTR [QDFile+4], DX
    70.    
    71.     ret
    72. SetHook endp
    73.  
    74. UnSetHook proc
    75.  
    76.     mov EAX, DWORD PTR OldCode
    77.     mov DX,  WORD  PTR OldCode+4
    78.     mov [QDFile], EAX
    79.     mov WORD PTR [QDFile+4],DX;
    80.    
    81.     invoke VirtualProtect,QDFile,6,LastProtectMode,OFFSET RetPos
    82.    
    83.     ret
    84.  
    85. UnSetHook endp
    Помогите кто может, направьте мой ум на путь истинный, читать я люблю, но общение более эффективно, в данном случае только чей-то огромный жизненный опыт сможет мне помочь, подсказать, где спрятана ошибка, и почему данные не передаются куда нужно. Любые подсказки насчет оптимизации жду.
     
  2. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    пишется splicing от слова splice.
    кошмар! в буффер копировать старые байты никак?
    ща найду код.. я писал давненько.. пгди
     
  3. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Код (Text):
    1. #include <windows.h>
    2. #include <stdio.h>
    3. #include "ldasm.h"
    4.  
    5. #define DPRINT(X) printf X
    6.  
    7. #pragma warning(disable:4311 4312)
    8.  
    9. char szF[]=" > NormalFunction( 0x%08x, 0x%08x )\n";
    10.  
    11. char blabla[] = "\xC3";
    12.  
    13. // Normal function
    14. VOID
    15. NormalFunction(
    16.     IN  ULONG   Argument1,
    17.     IN  ULONG   Argument2
    18.     )
    19. {
    20.     printf(szF, Argument1, Argument2);
    21. }
    22.  
    23. // Hook buffer
    24. ULONG HookBuffer[32];
    25. ULONG BufferWritten = 0;
    26.  
    27. // Hook
    28. VOID
    29. HookFunction(
    30.     IN  ULONG   Argument1,
    31.     IN  ULONG   Argument2
    32.     )
    33. {
    34.     DPRINT((" > HookFunction( 0x%08x, 0x%08x )\n", Argument1, Argument2));
    35.  
    36.     __asm {
    37.         leave
    38.         lea eax, HookBuffer
    39.         jmp eax
    40.     }
    41. }
    42.  
    43. //
    44. // Probe address for reading DWORD
    45. //
    46. void ProbeForReadUlong( PVOID Address )
    47. {
    48.     if( IsBadReadPtr( Address, 4 ) )
    49.         RaiseException( STATUS_ACCESS_VIOLATION, 0, 0, 0 );
    50. }
    51.  
    52. //
    53. // Probe region for writing
    54. //
    55. void ProbeForWriteRegion( PVOID Address, ULONG Length )
    56. {
    57.     if( IsBadWritePtr( Address, Length) )
    58.         RaiseException( STATUS_ACCESS_VIOLATION, 0, 0, 0 );
    59. }
    60.  
    61.  
    62. #define EmitJumpCommand( From, To ) \
    63.         { \
    64.             *(BYTE*)(From) = 0xE9; \
    65.             *(ULONG*)((ULONG)(From)+1) = (ULONG)(To) - (ULONG)(From) - 5; \
    66.         }
    67.  
    68. BOOLEAN
    69. SpliceFunctionStart(
    70.     IN  PVOID   OriginalAddress,
    71.     IN  PVOID   HookFunction,
    72.     OUT PVOID   SplicingBuffer,
    73.     IN  ULONG   MaxLength,
    74.     OUT PULONG  BytesWritten
    75.     )
    76. {
    77.     ULONG Len;
    78.     ULONG Ptr, NextAddress;
    79.     BOOLEAN Status = FALSE;
    80.  
    81.     DPRINT(("Entering SpliceFunctionStart( 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x )\n",
    82.         (ULONG)OriginalAddress,
    83.         (ULONG)HookFunction,
    84.         (ULONG)SplicingBuffer,
    85.         sizeof(MaxLength),
    86.         (ULONG)BytesWritten));
    87.  
    88.     //
    89.     // Probe arguments
    90.     //
    91.  
    92.     DPRINT(("Probing arguments\n"));
    93.  
    94.     __try {
    95.         ProbeForReadUlong( OriginalAddress );
    96.         ProbeForWriteRegion( SplicingBuffer, MaxLength );
    97.         ProbeForWriteRegion( BytesWritten, sizeof(ULONG) );
    98.     }
    99.     __except( EXCEPTION_EXECUTE_HANDLER ) {
    100.         DPRINT(("Arguments probing failed.\n"));
    101.         return 0;
    102.     }
    103.  
    104.     //
    105.     // Copy integer number of instructions to the buffer
    106.     //
    107.  
    108.     DPRINT(("Copying instructions\n"));
    109.     *BytesWritten = 0;
    110.     for( Ptr = (ULONG)OriginalAddress; Ptr < ((ULONG)OriginalAddress+5); Ptr+=Len )
    111.     {
    112.         Len = size_of_code( (BYTE*)Ptr );
    113.  
    114.         DPRINT(("Command decoded at address 0x%08x, length 0x%08x\n", Ptr, Len));
    115.  
    116.         if( Ptr < ((ULONG)OriginalAddress+5) )
    117.         {
    118.             if( (Ptr-(ULONG)OriginalAddress+5) >= MaxLength )
    119.             {
    120.                 DPRINT(("Error: buffer is too small\n"));
    121.                 Status = 0;
    122.                 goto _exit;
    123.             }
    124.  
    125.             memcpy( (PVOID)((ULONG)SplicingBuffer+(Ptr-(ULONG)OriginalAddress)), (PVOID)Ptr, Len );
    126.             *BytesWritten += Len;
    127.         }
    128.     }
    129.  
    130.  
    131.     NextAddress = Ptr;
    132.     Ptr += (ULONG)SplicingBuffer -(ULONG)OriginalAddress;
    133.  
    134.     DPRINT(("*BytesWritten = 0x%08x, Ptr = 0x%08x, NextAddress = 0x%08x\n", *BytesWritten, Ptr, NextAddress));
    135.  
    136.     DPRINT(("Generating splicing buffer\n"));
    137.  
    138.     //
    139.     // Emit splicing jump to the buffer
    140.     //
    141.  
    142.     DWORD Old;
    143.     VirtualProtect( OriginalAddress, 5, PAGE_READWRITE, &Old );
    144.  
    145.     EmitJumpCommand( OriginalAddress, HookFunction );
    146.  
    147.     VirtualProtect( OriginalAddress, 5, Old, &Old );
    148.  
    149.     DPRINT(("Original address bytes: %02x %02x %02x %02x %02x\n",
    150.         ((PBYTE)OriginalAddress)[0],
    151.         ((PBYTE)OriginalAddress)[1],
    152.         ((PBYTE)OriginalAddress)[2],
    153.         ((PBYTE)OriginalAddress)[3],
    154.         ((PBYTE)OriginalAddress)[4]
    155.         ));
    156.  
    157.     EmitJumpCommand( Ptr, NextAddress );
    158.  
    159.     Status = 1;
    160.  
    161. _exit:
    162.    
    163.     return Status;
    164. }
    165.  
    166. int main(int argc, CHAR* argv[])
    167. {
    168.     BOOLEAN Status;
    169.  
    170.     DPRINT(("Normal call:\n"));
    171.     NormalFunction( 0x12345678, 0xBAADFEED );
    172.  
    173.     Status = SpliceFunctionStart( &NormalFunction, &HookFunction, HookBuffer, sizeof(HookBuffer), &BufferWritten );
    174.     if( !Status ) {
    175.         DPRINT(("SpliceFunctionStart failed with status 0x%08x\n", Status));
    176.         return Status;
    177.     }
    178.  
    179. //  __try {__asm int 3;
    180. //  } __except( EXCEPTION_EXECUTE_HANDLER) { }
    181.  
    182.     DPRINT(("Spliced call:\n"));
    183.     NormalFunction( 0x12345678, 0xBAADFEED );
    184.  
    185.     return 0;
    186. }
    Копируются инструкции в буффер без изменения. По-хорошему, нужно их релокать на новый адрес.
     
  4. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    1. ОШИБКА РАЗ
    Код (Text):
    1.     pop RetPos       ;<------ПОМЕНЯТЬ МЕСТАМИ ЭТО и НИЖНЮЮ СТРОЧКУ (push)
    2.     ;=========================================
    3.     call QDFile    ;Вызываем оригинальную функцию
    4.     ;=========================================
    5. ;Здесь я напишу фильтр, но это уже потом
    6.     push RetPos
    2. ОШИБКА ДВА
    Код (Text):
    1. mov [[QDFile]],EAX
    Двойного вложения в асме нет
    вы вероятно имели ввиду это:
    Код (Text):
    1. mov ecx, dword ptr [QDFile]
    2. mov dword ptr [ecx], eax
    3. ОШИБКА ТРИ
    Код (Text):
    1. invoke GetModuleHandle,    OFFSET sLibName  
    2.     invoke GetProcAddress,EAX, OFFSET sProcName
    3.     mov QDFile, EAX
    4.    
    5.     invoke VirtualProtect,EAX, 6, PAGE_EXECUTE_READWRITE, OFFSET LastProtectMode
    6.  
    7. ;Как показал OllyDbg данные нормально создаются,
    8. ;но не передаются куда надо, следовательно ошибка тута
    9.     ;сохраняем старое начало функции
    10.     mov EAX,  [QDFile]
    11.     mov DX,   WORD PTR [QDFile+4]
    Та же ошибка. Двойного вложения в асме нет.

    Смотри

    Код (Text):
    1.     mov QDFile, EAX
    сохраняешь АДРЕС функции в переменную

    а чтобы сохранить первые байты этой функции нужно так
    Код (Text):
    1.     mov ecx, QDFile                     ;в есх загоняем адрес функции из переменной QDFile
    2.     mov eax, dword ptr [ecx]        ;считываем в еах - первые 4 байта
    3.     mov DX,   WORD PTR [ecx+4]  ;считываем в дх - еще 2 байта
    4.     mov DWORD PTR OldCode, EAX   ;сохраняем
    5.     mov OldCode+4, DX
    6.  
    7.     ;записываем новое начало
    8.     mov EAX, DWORD PTR [@ICode]
    9.     mov DX,  WORD  PTR [@ICode+4]
    10.     mov [ecx], EAX
    11.     mov WORD PTR [ecx+4], DX
    а ты записываешь не по адресу, куда указывает переменная, а в саму переменную
    Отсюда трабла

    Кстати, юзай вначале и вконце фунций pushad / popad - это сохраняет все регистры
     
  5. Yashin

    Yashin New Member

    Публикаций:
    0
    Регистрация:
    25 янв 2008
    Сообщения:
    19
    Спасибо, Great, только такое же я мог написан и на Делфи, мне нужен именно асм.
    Magnum, а вот это действительно то, что я искал. Делфовый ассемблятор умеет двигать mov [QDFile], EAX а этот почему то не умеет. А скажите, почему он делает длинный джамп как
    push Code
    ret
    а не как-нибудь там
    jmp Code
    ?
     
  6. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    Yashin
    И дельфийский и масмовский асм может "двигать"
    Двигать не умеешь ты

    В QDFile находится АДРЕС функции, а не тело функции.
    Чтобы достать первые байты из тела функции нужно:
    1. Достать адрес функции (mov ecx, [QDFile] )
    2. Достать первые байты, которые лежат по заданному адресу (mov eax, dword ptr [ecx])


    QDfile - ПЕРЕМЕННАЯ! где лежит АДРЕС функции.
    mov [QDFile], eax - ты перезаписываешь переменную!

    эммм.... Это вы где вычитали???
    jmp Code тоже можно использовать
    В общем, рано вы в сплайс полезли

    разберитесь сперва с основами ассемблера
     
  7. Yashin

    Yashin New Member

    Публикаций:
    0
    Регистрация:
    25 янв 2008
    Сообщения:
    19
    Мне кажется, чтоб инъекция была не столь заметной.

    Спасибо учту, тут пишут, что стоит Агнера почитать. Ладно не буду создавать очередное "Какие книжки почитать?" и скроюсь на недельку.
    Всем спасибо. Тему можете не закрывать, если что получится, сюда напишу о результатах.