+ Reply to Thread
Results 1 to 2 of 2

Thread: Решение крякми написанного на Qt

  1. #1

    Default Решение крякми написанного на Qt

    Доброго времени суток.

    Само крякми: http://forum.reverse4you.org/attachm...0&d=1358541694

    Сегодня рассмотрим решение крякмиса, с которого мы сможем вынести информацию о том как класс Qt QString хранит внутри себя данные.

    Собственно, посмотрим на то с чем мы будем иметь дело. Видим, что программа написана на С++ с использованием фреймворка Qt. Запустим ее и попробуем ввести что-то в поле Login и нажав кнопку Enter видим, что никаких окошек не всплывает. А жаль... Очень жаль.... Но не будем долго печалиться и начнем как-то выкручиваться с этой ситуации.

    Для начала посмотрим, что используется в данном приложении. Для этого зайдем в IDA и нажмем View->Open subview->Names window. Немного посмотрев, меня очень сильно заинтересовал класс QlineEdit. Вбив в гугле, нашел интересную функцию у этого класса под названием text(), которая возвращает Qstring, где хранится введенная нами строка. Т.к. Введеная нами строка вероятно где-то должна сравниваться, то попробуем найти в окне Names window класс Qstring и посмотрем, какие операторы его используются. Видим, что используется Qstring::operator==(QString const &). Нажимаем на ней 2 раза и видим, что наша строка сравнивается дважды по адресам 0х00401341 и 0х004013F2. Поставим на этих адресах сразу бряки. Теперь проанализируем, что находится возле этих адресов. Начнем с адреса 0х00401341:
    PHP Code:
    .text:00401329                 cmp     byte ptr [esi+24h], 1
    .text:0040132D                 mov     edids:??8QString@@QBE_NABV0@@QString::operator==(QString const &)
    .
    text:00401333                 jnz     loc_4013E4
    .text:00401339                 lea     eax, [esi+20h]
    .
    text:0040133C                 push    eax
    .text:0040133D                 lea     ecx, [esp+60h+var_40]
    .
    text:00401341                 call    edi QString::operator==(QString const &) ; QString::operator==(QString const &)
    .
    text:00401343                 test    alal
    .text:00401345                 jz      loc_4013E4
    .text:0040134B                 push    0FFFFFFFFh
    .text:0040134D                 push    offset aYouVeBrokenMe "You' ve broken me!"
    .text:00401352                 call    ds:?fromAscii_helper@QString@@CAPAUData@1@PBDH@QString::fromAscii_helper(char const *,int)
    .
    text:00401358                 mov     [esp+64h+var_38], eax
    .text:0040135C                 push    0FFFFFFFFh
    .text:0040135E                 mov     bl9
    .text:00401360                 push    offset aCongratulation "Congratulation"
    .text:00401365                 mov     byte ptr [esp+6Ch+var_4], bl
    .text:00401369                 call    ds:?fromAscii_helper@QString@@CAPAUData@1@PBDH@QString::fromAscii_helper(char const *,int
    Ура, мы видим нужные для нас сообщения вида «You' ve broken me!» и «Congratulation». Они не могу не радовать, но давайте попробуем понять, что должно произойти, что бы мы туда попали. Исходя из листинга выше, можно сделать вывод, что для этого должны выполниться следующие условия: 1. по адресу esi+24h, мы должны получить значение 1 ( похоже на флажок) и 2. какие-то две строки, можно предположить, что это введенная нами строка и правильная, должны быть равны.
    Если мы запустим приложение, введем какое-то значение и нажмем кнопку Enter, то попадем на оператор сравнения, который находится по адресу 0х004013F2. Почему же мы не попали на оператор сравнения описанный выше? Наверно, все из-за того, флажок оказался равным 0. Это мы можем легко проверить, если поставим бряк на строчке и посмотрев, что находится по адресу esi+24h:
    HTML Code:
    .text:00401329                 cmp     byte ptr [esi+24h], 1
    Т.к. мы попали на 2й оператор сравнения, то давайте проанализируем код, который находится вокруг него:
    PHP Code:
    .text:004013EA                 lea     eax, [esi+1Ch]
    .
    text:004013ED                 push    eax
    .text:004013EE                 lea     ecx, [esp+60h+var_40]
    .
    text:004013F2                 call    edi QString::operator==(QString const &) ; QString::operator==(QString const &)
    .
    text:004013F4                 test    alal
    .text:004013F6                 jz      short loc_401448
    .text:004013F8                 push    0FFFFFFFFh
    .text:004013FA                 push    offset aPassword "Password:"
    .text:004013FF                 call    ds:?fromAscii_helper@QString@@CAPAUData@1@PBDH@QString::fromAscii_helper(char const *,int)
    .
    text:00401405                 add     esp8
    .text:00401408                 mov     [esp+5Ch+var_38], eax
    .text:0040140C                 lea     ecx, [esp+5Ch+var_38]
    .
    text:00401410                 push    ecx
    .text:00401411                 mov     ecx, [esi+18h]
    .
    text:00401414                 mov     byte ptr [esp+60h+var_4], 0Bh
    .text:00401419                 call    ds:?setText@QLabel@@QAEXABVQString@@@QLabel::setText(QString const &)
    .
    text:0040141F                 mov     edx, [esp+5Ch+var_38]
    .
    text:00401423                 mov     byte ptr [esp+5Ch+var_4], 6
    .text:00401428                 or      eax0FFFFFFFFh
    .text:0040142B                 lock xadd [edx], eax
    .text:0040142F                 jnz     short loc_40143B
    .text:00401431                 mov     ecx, [esp+5Ch+var_38]
    .
    text:00401435                 push    ecx
    .text:00401436                 call    ebx QString::free(QString::Data *) ; QString::free(QString::Data *)
    .
    text:00401438                 add     esp4
    .text:0040143B
    .text:0040143B loc_40143B:                             ; CODE XREFsub_401140+2EF#j
    .text:0040143B                 mov     ecx, [esi+14h]
    .
    text:0040143E                 call    ds:?clear@QLineEdit@@QAEXXZ QLineEdit::clear(void)
    .
    text:00401444                 mov     byte ptr [esi+24h], 
    В этом листинге можем видеть, что если 2 строки равны, то Qlabel с текущим текстом «Login» поменяется на Passoword и флажок, к-ый мы упоминали выше, установится в 1! Исходя из всего можем сделать вывод, что по адресу 0x004013F2 у нас проверяется правильность логина, а по адресу 00401341 — правильность пароля. И для того, что бы это проверить нам надо разобраться, как QString хранит строки. Посмотрим какой код находится внутри функции Qstring::operator==(QStting const &):

    PHP Code:
    QtCore4.dll:6705BFD0 qtcore4_??8QString@@QBE_NABV0@@Z:
    QtCore4.dll:6705BFD0 mov     eax, [esp+4]
    QtCore4.dll:6705BFD4 mov     edx, [ecx]
    QtCore4.dll:6705BFD6 mov     eax, [eax]
    QtCore4.dll:6705BFD8 mov     ecx, [edx+8]
    QtCore4.dll:6705BFDB cmp     ecx, [eax+8]
    QtCore4.dll:6705BFDE jz      short loc_6705BFE5
    QtCore4
    .dll:6705BFE0 xor     alal
    QtCore4
    .dll:6705BFE2 retn    4
    QtCore4
    .dll:6705BFE5 ; ---------------------------------------------------------------------------
    QtCore4.dll:6705BFE5
    QtCore4
    .dll:6705BFE5 loc_6705BFE5:                           ; CODE XREFQtCore4.dll:qtcore4_??8QString@@QBE_NABV0@@Z+E#j
    QtCore4.dll:6705BFE5 push    ecx
    QtCore4
    .dll:6705BFE6 mov     ecx, [eax+0Ch]
    QtCore4.dll:6705BFE9 mov     eax, [edx+0Ch]
    QtCore4.dll:6705BFEC call    near ptr unk_6705BB20
    QtCore4
    .dll:6705BFF1 add     esp4
    QtCore4
    .dll:6705BFF4 retn    4 
    С этого листинга, можно заключить, что [esp+4] содержит указатель на объект Qstring, a [ecx] — this. Далее проверяется не равны ли указатели объектов и если не равны, то получаем указатели сравниваемых строк: [*QString+0Ch] и [*this + 0Сh]
    . Соответственно, если к тому что передается в функцию сравнения прибавить 0Ch, то увидим указатель на введенную и верную строки. Проверим это.

    Перезапускаем программу, вводим логин, нажимает кнопку Enter. И смотрим, что передается функции operator==. Посмотрим, какая строка передается оператору сравнения:
    PHP Code:
    debug035:00A16E58 db    1
    debug035
    :00A16E59 db    0
    debug035
    :00A16E5A db    0
    debug035
    :00A16E5B db    0
    debug035
    :00A16E5C db  0Ah
    debug035
    :00A16E5D db    0
    debug035
    :00A16E5E db    0
    debug035
    :00A16E5F db    0
    debug035
    :00A16E60 db    8
    debug035
    :00A16E61 db    0
    debug035
    :00A16E62 db    0
    debug035
    :00A16E63 db    0
    debug035
    :00A16E64 db  6Ah j
    debug035
    :00A16E65 db  6Eh n
    debug035
    :00A16E66 db 0A1h 
    debug035
    :00A16E67 db    0
    debug035
    :00A16E68 db    0
    debug035
    :00A16E69 db 0F0h 
    debug035
    :00A16E6A db  2Eh ; .
    debug035:00A16E6B db    0
    debug035
    :00A16E6C db  29h ; )
    debug035:00A16E6D db    0
    debug035
    :00A16E6E db  2Eh ; .
    debug035:00A16E6F db    0
    debug035
    :00A16E70 db  34h 4
    debug035
    :00A16E71 db    0
    debug035
    :00A16E72 db  2Eh ; .
    debug035:00A16E73 db    0
    debug035
    :00A16E74 db  23h #
    debug035:00A16E75 db    0
    debug035
    :00A16E76 db  22h "
    debug035:00A16E77 db    0
    debug035:00A16E78 db  35h ; 5
    debug035:00A16E79 db    0
    debug035:00A16E7A db    0 
    Это строка 2Eh 29h 2eh 34h 2eh 34h 2eh 23h 22h 35h. Переводим это все в ASCII пробуем ввести в логин нажимает Enter и все равно видим, что наша программа не приняла логин, соответственно, что тут не так и по ходу логин тем или иным образом шифруется. Что бы это проверить давайте проанализируем функцию, в которой находится наши операторы сравнения. Посмотрим на ее начало ( что бы долго не капашиться, посмотрим на код в Hex-rays):
    PHP Code:
    v1 this;
      
    v25 this;
      
    enteredString QLineEdit::text(*(_DWORD *)(this 20), &v28);
      
    v32 0;
      
    v3 QString::toAscii(enteredString, &v27);
      
    LOBYTE(v32) = 1;
      
    QString::QString(&v21v3);
      
    LOBYTE(v32) = 3;
      if ( !
    _InterlockedExchangeAdd((signed __int32 *)v270xFFFFFFFFu) )
        
    qFree(v27);
      
    v4 QString::free;
      
    LOBYTE(v32) = 4;
      if ( !
    _InterlockedExchangeAdd(v280xFFFFFFFFu) )
        
    QString::free(v28);
      
    v22 = (signed __int32 *)QString::shared_null;
      
    _InterlockedExchangeAdd((signed __int32 *)QString::shared_null1u);
      
    LOBYTE(v32) = 5;
      
    v26 QString::fromAscii_helper("g", -1);
      
    v5 = *(_DWORD *)(v21 8) == 0;
      
    v6 = *(_DWORD *)(v21 8) < 0;
      
    LOBYTE(v32) = 6;
      
    v23 0;
      if ( !(
    v6 v5) )
      {
        do
        {
          
    v7 QString::toAscii(&v26, &v29);
          
    LOBYTE(v32) = 7;
          
    v8 QString::toAscii(&v21, &v24);
          
    LOBYTE(v32) = 8;
          
    v9 QByteArray::operator__(v7, &v300);
          
    v10 = **(_DWORD **)v9;
          
    v11 = *(_DWORD *)(v9 4);
          if ( 
    v11 >= *(_DWORD *)(v10 8) )
            
    v12 0;
          else
            
    v12 = *(_BYTE *)(v11 + *(_DWORD *)(v10 12));
          
    v13 QByteArray::operator__(v8, &v31v23);
          
    v14 = **(_DWORD **)v13;
          
    v15 = *(_DWORD *)(v13 4);
          if ( 
    v15 >= *(_DWORD *)(v14 8) )
            
    v16 0;
          else
            
    v16 = *(_BYTE *)(v15 + *(_DWORD *)(v14 12));
          
    LOBYTE(v32) = 7;
          
    v17 = (v12 v16) % 127;
          if ( !
    _InterlockedExchangeAdd((signed __int32 *)v240xFFFFFFFFu) )
            
    qFree((void *)v24);
          
    LOBYTE(v32) = 6;
          if ( !
    _InterlockedExchangeAdd((signed __int32 *)v290xFFFFFFFFu) )
            
    qFree(v29);
          if ( 
    v17 32 )
            
    v17 += 32;
          
    QString::operator__(&v22v17);
          
    v18 __OFSUB__(v23 1, *(_DWORD *)(v21 8));
          
    v6 v23++ + - *(_DWORD *)(v21 8) < 0;
        }
        while ( 
    v6 v18 );
        
    v1 v25;
        
    v4 QString::free;
      } 
    Видим, что вначале мы получаем исходную строку, и потом в цикле с каждым символом делаем операции: взять ASCII очередного введенного символа, сделать с ним операцию xor, резудьтат взять по модулю 127 и далее если получившиеся значение меньше 32 (20h), то добавить еще к нему 20h.
    Соответственно, что бы получить строку, к-ую мы должны ввести, нам надо поставить бряку на строчку, где xor'ся значения и получить ключ с которым происходит эта операция. Для этого анализируем ассемблерный код и ставим бряку в этой строчке:

    PHP Code:
    004012A0 xor     eaxedx 
    Запускаем программу, попадаем на эту точку и смотрим чему равно значение edx — это и есть наш ключ. Он у нас получается равным 67h.

    Т.к. У нас есть строка, к-ую мы должны были бы получить, то делаем обратные операции и получаем строку, к-ую мы должны ввести:

    Искомый символ = (Символ полученной строки) xor 0x67.

    Получаем строку, к-ую должны получить, как было описано выше:
    PHP Code:
    debug025:003DB040 db    1
    debug025
    :003DB041 db    0
    debug025
    :003DB042 db    0
    debug025
    :003DB043 db    0
    debug025
    :003DB044 db  0Dh
    debug025
    :003DB045 db    0
    debug025
    :003DB046 db    0
    debug025
    :003DB047 db    0
    debug025
    :003DB048 db  0Dh
    debug025
    :003DB049 db    0
    debug025
    :003DB04A db    0
    debug025
    :003DB04B db    0
    debug025
    :003DB04C db  52h R
    debug025
    :003DB04D db 0B0h ; -
    debug025:003DB04E db  3Dh ; =
    debug025:003DB04F db    0
    debug025
    :003DB050 db    0
    debug025
    :003DB051 db 0F0h 
    debug025
    :003DB052 db  37h 7
    debug025
    :003DB053 db    0
    debug025
    :003DB054 db  26h ; &
    debug025:003DB055 db    0
    debug025
    :003DB056 db  35h 5
    debug025
    :003DB057 db    0
    debug025
    :003DB058 db  26h ; &
    debug025:003DB059 db    0
    debug025
    :003DB05A db  23h #
    debug025:003DB05B db    0
    debug025
    :003DB05C db  2Eh ; .
    debug025:003DB05D db    0
    debug025
    :003DB05E db  34h 4
    debug025
    :003DB05F db    0
    debug025
    :003DB060 db  22h "
    debug025:003DB061 db    0
    debug025:003DB062 db  47h ; G
    debug025:003DB063 db    0
    debug025:003DB064 db  2Bh ; +
    debug025:003DB065 db    0
    debug025:003DB066 db  28h ; (
    debug025:003DB067 db    0
    debug025:003DB068 db  34h ; 4
    debug025:003DB069 db    0
    debug025:003DB06A db  33h ; 3
    debug025:003DB06B db    0 
    И начинаем восстанавливать исходную строку:
    X1 = ( 37h — 20h ) xor 67h = 70h = P
    X2 = (26h — 20h ) xor 67h = 61h = A

    Проделывая для всех символов — paradise lost. Проверяем этот логин, и смотрим о чудо, он подходит. Мы проходим проверку, которая находится сразу за оператором сравнения, находящийся по адресу 004013F2. Видим, что надпись Login поменяется на Password и наш флажок установится в 1.

    Теперь если мы введем какой либо пароль, то мы попадем на оператор сравнения, находящийся по адресу 00401341. Где скорее всего понятно, что мы не правильно ввели строку ;). Сразу смотрим чему должна быть равна правильная строка:
    PHP Code:
    debug024:003DB088 db    1
    debug024
    :003DB089 db    0
    debug024
    :003DB08A db    0
    debug024
    :003DB08B db    0
    debug024
    :003DB08C db  0Dh
    debug024
    :003DB08D db    0
    debug024
    :003DB08E db    0
    debug024
    :003DB08F db    0
    debug024
    :003DB090 db  0Dh
    debug024
    :003DB091 db    0
    debug024
    :003DB092 db    0
    debug024
    :003DB093 db    0
    debug024
    :003DB094 db  9Ah 
    debug024
    :003DB095 db 0B0h ; -
    debug024:003DB096 db  3Dh ; =
    debug024:003DB097 db    0
    debug024
    :003DB098 db    0
    debug024
    :003DB099 db 0F0h 
    debug024
    :003DB09A db  42h B
    debug024
    :003DB09B db    0
    debug024
    :003DB09C db  52h R
    debug024
    :003DB09D db    0
    debug024
    :003DB09E db  4Fh O
    debug024
    :003DB09F db    0
    debug024
    :003DB0A0 db  4Bh K
    debug024
    :003DB0A1 db    0
    debug024
    :003DB0A2 db  45h E
    debug024
    :003DB0A3 db    0
    debug024
    :003DB0A4 db  4Eh N
    debug024
    :003DB0A5 db    0
    debug024
    :003DB0A6 db  20h
    debug024
    :003DB0A7 db    0
    debug024
    :003DB0A8 db  44h D
    debug024
    :003DB0A9 db    0
    debug024
    :003DB0AA db  52h R
    debug024
    :003DB0AB db    0
    debug024
    :003DB0AC db  45h E
    debug024
    :003DB0AD db    0
    debug024
    :003DB0AE db  41h A
    debug024
    :003DB0AF db    0
    debug024
    :003DB0B0 db  4Dh M
    debug024
    :003DB0B1 db    0
    debug024
    :003DB0B2 db  53h S
    debug024
    :003DB0B3 db    0
    debug024
    :003DB0B4 db    0 
    Теперь по тому же принципу, что и с логином получаем правильный пароль. Он оказывается равным - %5(,")G#5"&*4

    Вот, собственно и все.
    Все, что хочется вынести с этого крякми, как это то, что если внимательно посмотреть на тот как хранятся строки в Qstring, то можно сделать вывод (испольую то, что писал root, очень хорошо написал ;) ):



    Code:
    [0xaaaabbbb] = 0x12345670
    
    0x12345670 struct {
                          0x0 reserved   <= *QString
                          0x8 pSize      <= *QString + 8 
                          0xC pString    <= *QString + C
    }
    
    QString = this(QString) = 0xaaaabbbb
    
    *QString = [QString]
    
    pSize = *QString + 8
    Size = [pSize]
    
    pString = *QString + C
    String = [pString]
    И также, хочется отметить, что каждый символы в QString хранится формате unicode.

    Вроде как все. Всем спасибо за внимание и всем кто помогал мне разбираться.

    Жду гневных отзывов, комментариев и критики по написанному.

    П.С.: может заняться исследованием типичных конструкций для ООП на языке С++ и как это все выглядит в дизасме? Кого-то такое заинтересует?

  2. 3 пользователя(ей) сказали cпасибо:
    korsader (27-01-2013) root (26-01-2013) ximera (26-01-2013)
  3. #2
    root's Avatar

    Default Re: Решение крякми написанного на Qt

    Советую пользоваться IDA Pro только по прямому на значению, так как отлаживать в ней кране не удобно. ИМХО.

    Далее проверяется не равны ли указатели объектов и если не равны, то получаем указатели сравниваемых строк:
    Я это сказал, не смотря в отладчик, а чисто исходя из логики, на самом деле там проверяются "размеры строк", а не идентичность объектов. Позже, на своем скриншоте, я это уточнил как size(this->text).

    Жду гневных отзывов, комментариев и критики по написанному.
    Сам же крякми решается намного быстрее, без всяких операций XOR. Нужно:

    1. Поставить бряк на operator == (адрес 0x6705BFD0)

    2. Подсмотреть сравниваемые строки, адреса 0x6705BFE6 и 0x6705BFE9. Понять, где твоя строка, а где Логин.
    3. Ввести найденый Логин. Увидеть, что он превратился в строку PARADISE LOST.
    4. Ввести полученную строку (PARADISE LOST) в качестве Логина.

    5. Тем же макаром, что и с Логином - подсмотреть строки для Пароля. Понять, где твоя строка, а где Пароль.
    6. Ввести найденый Пароль. Увидеть, что он превратился в строку %5(,")G#5"&*4.
    7. Ввести полученный строку (%5(,")G#5"&*4) в качестве Пароля.
    Last edited by root; 26-01-2013 at 23:27.
    Успех – это путь от провала до провала без потери энтузиазма. (В. Черчиль)

    Не бойся идти медленно, бойся остановиться. (Китайская пословица)

    When you lose fun and start doing things only for the payback, you're dead. (c) TCLH (Phrack 65, Intro)

  4. 3 пользователя(ей) сказали cпасибо:
    V3T (28-01-2013) coldfire (27-01-2013) korsader (27-01-2013)
+ Reply to Thread

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
All times are GMT. The time now is 01:34
vBulletin® Copyright ©2000 - 2018
www.reverse4you.org