Убираем баннеры в "Штирлице" или Баг в защите

Дата публикации 14 авг 2002

Убираем баннеры в "Штирлице" или Баг в защите — Архив WASM.RU

 

Штирлиц шел по лесу и напоролся на сук.
- "Шли бы вы домой, девочки, война все-таки!"

  Из личного дела:

Код (Text):
  1.  
  2. Имя:            Штирлиц 4.01
  3. Вес:            738 кило
  4. Дата рождения:  2001 год
  5. Отец:           Всеволод Лукьянин
  6.  

Prelude

  Наверное, нет такого человека, который никогда бы ничего не слышал о Штирлице. И речь в данной статье пойдет не о В. Тихонове, и не об анекдотах, а о лучшем в своем роде расшифровщике-трансляторе, вернее, о доведении оного до совершенства :smile3:.

  Любому из нас приходилось получать загадочные письма из сети, содержащие в себе прелюбопытные наборы значков и черточек. Разнообразие стандартов и кодировок породило на свет огромное количество перекодировщиков. Во всем этом безобразном разнообразии отчетливо обозначились несколько особо продвинутых программулин. Мне почему то особенно запомнились только две – Bred и Штирлиц. И если первая ничем не достает и не просит на "покушать", то вторая изрядно выводит из себя своим "рекламным окошком", которое по заявлению самого автора "не мешает работать программе" (Лукьянин вообще парень с юмором). Но, ближе к делу...

С чего начинается родина…

  Родина, безусловно, начинается с отладчика, и не с простого, а с большой буквы. Как вы уже догадались – это SoftIce, Многие из вас уже испугались и начали выводить кресты, однако я просто советую вам поставить на свою машину именно этот отладчик и пользуясь данным руководством в конце пути вы просто пожмете ему руку и... больше никуда не отпустите. Еще ОЧЕНЬ пригодится дизаcмер (я рекомендую ТОЛЬКО WDASM) и HIEW (который, как окажется в последствии, совершенно не понадобится, но в педагогических целях его неплохо бы заиметь).

  Больше нам реально ничего не понадобится... Ах да, разве что еще ваш любимый выходной набор "мозги + прямые руки". И конечно, листик с ручкой (запомните, ни один серьезный взлом не обходится без листика с ручкой, а еще лучше завести для этого дела специальную тетрадь, но это уже для извращенцев).

Go Go Go...!

  Итак, поехали! Запускаем Shtirlitz.exe для того чтобы окончательно понять, чего же мы все таки хотим. А хотим мы убрать этот чертов баннер, ато он $%@##$ уже достал внатуре !!!

  Где же он ?! Вот он, сидит себе в углу, моргает. Подожди же, зараза...

  SoftIce у нас уже конечно же запущен…

  Сразу же жмем ctrl-D, осмотримся, чего же у нас творится в данный момент... Оказавшись в любимом окне набиваем:

Код (Text):
  1.  
  2. addr
  3.  

  В ответ получим загадочную последовательность запущенных на данный момент процессов. Где-то в самом конце списка (на всякий случай, перемещение по списку – клавиши [вверх] и [вниз]) мы просто обязаны увидеть строку такого содержания:

Код (Text):
  1.  
  2.            Addr         PID     NAME
  3. …………    …………        ……      ……….
  4. xxxxxxxx    xxxxxxxx        xxxx        Shtirlitz
  5.  

  где вместо "х"-ов будут hex-цифры.

  Вот он, родимый!!! Привяжемся же к нему всей душой!!!

  Набиваем:

Код (Text):
  1.  
  2. addr xxxx
  3.  

  где вместо иксов подставляем соотв. значение из колонки PID.

  Теперь, повторно набрав в строке addr убеждаемся, что Штирлиц стал текущим процессом (т.е. голубым :smile3:.

  Далее. Добившись того, чтобы Shtirlitz стал текущим процессом, можно смело узнать про него много всего полезного. Набиваем:

Код (Text):
  1.  
  2. hwnd Shtirlitz
  3.  

  (Shtirlitz, кстати, в данном случае берется из колонки NAME)

  И что мы видим ? А видим мы длинный список инфы про нашего пациента. Чего мы вообще хотим? Убрать баннеры... Смотрим, чего тут можно нарыть по нашей проблеме... Ага!!! Вот оно!!! Первой же строкой!!! И не стыдно...?

  Shtirlitz.banner ... запомним.

  Теперь запускаем WDASM. Грузим Shtirlitz.exe. Пошарим по файлу (теперь мы знаем чего искать). В строке поиска пишем banner. Ждем... Вуаля!

Код (Text):
  1.  
  2. * Reference To: GDI32.GetStockObject, Ord:00FAh
  3.                                   |
  4. :00401B1C FF15B4E54400              Call dword ptr [0044E5B4]
  5. :00401B22 50                            push eax
  6. :00401B23 6800080000                push 00000800
  7.  
  8. * Possible StringData Ref from Data Obj ->"Shtirlitz.Banner"
  9.                                   |
  10. :00401B28 6804414400                push 00444104
  11. :00401B2D B938BA4400                mov ecx, 0044BA38
  12. :00401B32 E8BF6B0000                call 004086F6
  13. :00401B37 84C0                          test al, al
  14. :00401B39 7473                          je 00401BAE
  15. :00401B3B 57                            push edi
  16. :00401B3C 56                            push esi
  17. :00401B3D 8B742418                  mov esi, dword ptr [esp+18]
  18. :00401B41 53                            push ebx
  19. :00401B42 55                            push ebp
  20. :00401B43 6800004086                push 86400000
  21. :00401B48 56                            push esi
  22.  
  23. * Reference To: USER32.AdjustWindowRect, Ord:0001h
  24.                                   |
  25. :00401B49 FF156CE94400              Call dword ptr [0044E96C]
  26. :00401B4F 8B7E08                    mov edi, dword ptr [esi+08]
  27. :00401B52 8B5E0C                     mov ebx, dword ptr [esi+0C]
  28. :00401B55 2B3E                          sub edi, dword ptr [esi]
  29. :00401B57 2B5E04                    sub ebx, dword ptr [esi+04]
  30. :00401B5A 55                            push ebp
  31.  
  32. * Reference To: USER32.GetSystemMetrics, Ord:012Ch
  33.                                   |
  34. :00401B5B 8B2D64E94400              mov ebp, dword ptr [0044E964]
  35. :00401B61 FFD5                          call ebp
  36. :00401B63 83E814                    sub eax, 00000014
  37. :00401B66 6A01                          push 00000001
  38. :00401B68 894608                    mov dword ptr [esi+08], eax
  39. :00401B6B FFD5                      call ebp
  40. :00401B6D 8B4E08                    mov ecx, dword ptr [esi+08]
  41. :00401B70 83C0EC                    add eax, FFFFFFEC
  42. :00401B73 89460C                    mov dword ptr [esi+0C], eax
  43. :00401B76 2BCF                          sub ecx, edi
  44. :00401B78 2BC3                          sub eax, ebx
  45. :00401B7A 890E                          mov dword ptr [esi], ecx
  46. :00401B7C 894604                    mov dword ptr [esi+04], eax
  47.  
  48. * Reference To: KERNEL32.GetTickCount, Ord:0145h
  49.                                   |
  50. :00401B7F FF1598E74400              Call dword ptr [0044E798]
  51. :00401B85 8B4C2410                  mov ecx, dword ptr [esp+10]
  52. :00401B89 89415C                    mov dword ptr [ecx+5C], eax
  53. :00401B8C 33C0                          xor eax, eax
  54. :00401B8E 50                            push eax
  55. :00401B8F 50                            push eax
  56. :00401B90 50                            push eax
  57. :00401B91 56                            push esi
  58. :00401B92 6800004086                push 86400000
  59. :00401B97 68D8B64400                push 0044B6D8
  60.  
  61. * Possible StringData Ref from Data Obj ->"Shtirlitz.Banner"
  62.                                   |
  63. :00401B9C 6804414400                push 00444104
  64. :00401BA1 6888000000                push 00000088
  65. :00401BA6 E81D700000                call 00408BC8
  66. :00401BAB 5B                            pop ebx
  67. :00401BAC 5E                            pop esi
  68. :00401BAD 5F                            pop edi
  69.  
  70. * Referenced by a (U)nconditional or (C)onditional Jump at Address:
  71. |:00401B39(C)
  72. |
  73. :00401BAE 5D                            pop ebp
  74. :00401BAF 59                            pop ecx
  75. :00401BB0 C20800                    ret 0008
  76.  

  Всеволод Лукьянин не только с юмором, а еще и очень хитер! Видите, как ловко он вплел показ баннеров в код?! После непродолжительного разглядывания данного куска становиться очевидно :smile3:, что от результата, возвращаемого процедурой в строке

Код (Text):
  1.  
  2. :00401B32 E8BF6B0000     call 004086F6
  3.  

  зависит относится ли данный вызов непосредственно к показу рекламы или нет (если нет, то возвращаемый результат равен 0, и соответственно после

Код (Text):
  1.  
  2. :00401B37 84C0           test al, al
  3.  

  мы перепрыгиваем "через овечку" прямо в конец куска (перелетаем полностью через весь показ баннеров). Сам переход происходит в строке

Код (Text):
  1.  
  2. :00401B39 7473           je 00401BAE
  3.  

  Записывай пока на бумажку адрес 00401B39.

  Теперь напряжемся и вместе подумаем: как же сделать так, чтобы "перелет через показ баннера" происходил в любом случае? Выхода здесь два: либо загружать al перед je нулем посредством xor-а (mov не меняет флаги), либо просто изменить "74 на EB" (74 – код команды je, EB – код команды jmp; эти коды, наряду с CD (int) и др. кодами ты должен знать как "отче наш").

  Конечно же, мы выбираем второй вариант...

  Где наш HIEW? Вот и он. Запускаем. Ищем и меняем байт по адресу 00401B39h. Кстати, небольшое...

Лирическое отступление

  Для того, чтобы не бегать в HIEW по всему коду в поисках адреса 00401B39 мы в режиме decode (выбирается по F4) жмем F5 и набираем его в строке для быстрого перехода. Набрав 401B39 нас сразу же пошлют подальше, хотя реально это смещение в окне HIEW мы действительно можем наблюдать белым по синему. Так в чем же дело? А дело в том, что это не те смещения... :smile3: Все эти адреса генерятся из заголовка EXE файла, а РЕАЛЬНОЕ смещение в файле, как оно есть, можно увидеть, нажав в любимом HIEW-е комбинацию клавиш alt+F1. Все. Теперь все смещения – реальные, на любое из них можно прыгнуть по F5. Но куда же нам, все таки, in hell прыгать? Возвращаемся в любимый WDASM. Наводим курсор на строку

Код (Text):
  1.  
  2. 00401B39 7473     je 00401BAE
  3.  

  А вот внизу то что нам нада:

Код (Text):
  1.  
  2. Line:1734 Pg 35 and 36 of 2788 Code Data ... @offset 00000F39 in file...
  3.  

  Видишь @offset in file... ? Все. Теперь в HIEW прыгаем на F39 и меняем "74 на EB".

  ЗОЛОТОЕ ПРАВИЛО: всегда, перед тем как править файл в HIEW ВСЕГДА сохраняй его копию!

  И до чего же мы докатились ? Запускаем Shtirlitz, смотрим...

Вот зараза...

  Такой подлости мы явно не ожидали... "Файл поврежден, переустановите программу с дистрибутива". Что же произошло? А произошло то, что shtirlitz при загрузке проверяет сам себя на вшивость (или "на измену"). Как он это делает? А очень просто! Считывает сам себя в память (ф-ция ReadFile), затем с первого байта начинает сканировать сам себя, попутно манипулируя своим "телом" через регистры. Короче говоря, вычисляет контрольную сумму всех своих байт. (Контрольная сумма на деле оказывается не простой суммой, а результатом махинаций с регистрами, XOR-ами и MOV-ами). Вникать в алгоритм нет никакого желания да и не нужно нам это пока... Но запомните: взломать прогу "красиво" можно только полностью проникнувшись подобными алгоритмами.

  Итак, восстанавливаем из сохраненной копии Shtirlitz.exe и опять в SoftIce. Просто взять и установить бряк на ReadFile будет глупо, т.к. данная API-шка после запуска shtirlitz.exe вызывается тучу раз, и какой именно нужен нам – непонятно. Будем действовать старым дедовским методом. Лезем в WDASM. Смотрим, есть ли чего нить, что отвечает за загрузку файла. В строке поиска поочередно перебираем возможные варианты: сначала openfile. Найдено GetOpenFileName. Не то. CreateFile. О! То что нада! CreateFileA!

  Несколько слов по поводу данной апишки... Все что нам нужно знать про нее – это то, что перед ее вызовом последним в стек ляжет адрес на имя загружаемого файла. Вот его то нам и нужно отлавливать и контролировать, во избежание вызова "лже-CreateFile".

  Back to the SoftIce... Набиваем:

Код (Text):
  1.  
  2. bpx CreateFileA
  3.  

  Запускаем Штирлица и ждем срабатывания бряка... Есть! Смотрим, чего у нас лежит в стеке:

Код (Text):
  1.  
  2. dd esp
  3.  

  В окне данных видим:

Код (Text):
  1.  
  2. 00407289    00910BB0 ...
  3.  

  Когда SI отлавливает вызов API, управление передается на первую команду этой самой API, поэтому сейчас мы оказались на самом первом байте кода ф-ции CreateFile.

  Чего же это там у нас в окне данных... Ну первое число – понятно, откуда произошел вызов, оно нам не нада, а вот второе – это и есть указатель на имя открываемого файла (у вас это может быть другое число). Лезем по нему:

Код (Text):
  1.  
  2. d 00910BB0
  3.  

  Облом... Shtirlitz.loc какой то... А нам нужен Shtirlitz.exe. Но ничего! Ждем следующего вызова CreateFile… Жмем F5. И вот буквально тут же! Повторяем уже знакомые операции (dd esp), вот оно второе число: 00910910. Заглянем и туда (d 910910) – yes! Вот он, родимый! Shtirlitz.exe!!! Ну все!!! ВОТ ТЕПЕРЬ можно ставить бряк на ReadFile! НЕ ВЫХОДЯ ИЗ SI пишем:

Код (Text):
  1.  
  2. bpx ReadFile
  3.  

  Теперь жмем F5, ждем... Вот он долгожданный бряк по ReadFile! Смотрим стек (dd esp). Видим:

Код (Text):
  1.  
  2. 00405B00    00000060    00E90020    000A9400 ...
  3.  

  нас интересуют первые четыре числа. Первое число – адрес возврата (не нада), второе число – хэндл файла (не нужен), третье число – уже интереснее (адрес, куда надо считывать файл), четвертое – сколько байт нада считывать.

  Четвертое число вообще очень интересное... Кстати, ebx тоже равен этому же числу... Запомним это. Смотрим на калькуляторе: A9400h=693246d. А теперь угадай с трех раз, сколько весит файл Shtirlitz.exe? Теперь можно точно сказать, что происходит подсчет контрольной суммы ВСЕГО файла целиком... Но ты не сиди – записывай все числа на бумажку. С комментариями, ато потом заблудишься.

  Все. Пришло время заняться делом. Как только мы оказались в начале апишки ReadFile и посмотрели стек – жмем F12 (сам увидишь как это связано с первым числом). Теперь поехали трейсить! Запомни: видишь call – жми F10, чтобы не влезать в него. В других случаях – жмешь F8. Теперь главное вовремя остановиться... :smile3:. По ходу пьесы тебе часто придется вываливаться из SI, хотя бы даже для заглядывания в данную статью, поэтому перед выходом тебе ПРИДЕТСЯ набивать bc* (убрать все бряки). Так вот, для возврата тебе придется опять два раза отлавливать CreateFile, потом ReadFile... запаришься! Поэтому вспомни, что ebx был равен четвертому числу – а это ключ!!! Зная это, просто пишешь:

Код (Text):
  1.  
  2. bpx ReadFile if ebx==A9400
  3.  

  и ты в нужном месте в нужное время...!

  Итак, трейсим... через несколько F8 и парочки F10 мы попадаем в загадочную область:

Код (Text):
  1.  
  2. 00423B1E:   movzx...
  3.             ...
  4.             inc esi
  5.             cmp esi, ebx
  6.             mov [ebp-08], ecx
  7. 00423B5E:   jb 00423B1E
  8. 00423B60:   ...
  9.  

  Это какой то заговор... Обрати внимание на тот факт, что esi в начале цикла равен нулю, а ebx – A9400 (или размеру файла Штирлиц.exe); я нарочно выделил inc esi и последующее сравнение с ebx – тут даже койоту ясно, что идет подсчет контрольной суммы всего файла. Ну что ж, любители острых ощущений могут просидеть так пару дней, давя F8, я предпочитаю (и вам советую) сделать так:

Код (Text):
  1.  
  2. bpx 00423B60
  3.  

  Это есть бряк на следующую после jb команду, а сюда управление вернется только после того, как выполнится A9400 итераций. (вообще желательно выписать на бумажку значения ВСЕХ регистров и ячейки ebp-08 в этом месте, т.к. и ежу понятно – это единственные правильные значения, которые могут иметь место (ведь если бы мы "исправили" файл в HIEW, то значения регистров на выходе оказались бы совершенно иными). Вот значения регистров для "девственного" shtirlitz.exe:

Код (Text):
  1.  
  2. EAX=00000016
  3. ECX=000048D2
  4. EDX=00000020
  5. EDI=00E90020
  6. dword [ebp-08]=ECX=000048D2
  7.  

  Кстати, как многие уже догадались 48D2 – это и есть контрольная сумма, запомним это число.

  Что теперь? Пока ничего, трейсим дальше... :smile3: Здесь нам встретятся два call-а, перелетаем их. Ждем ret-а... И вот мы вернулись непонятно куда – на

Код (Text):
  1.  
  2. 00423744:       cmp ax,si
  3. 00423747:       jz  0042376A
  4.  

  Любознательные могут сами залезть в те два call-а, я же просто скажу: после того, как мы оказались на 00423744 в esi всегда будет лежать 48D2h (помните его?), а вот в ax – то, что получилось из нашего shtirlitz.exe, и если он только не равен 48D2... то... сами понимаете.

  Ну что, опять в 00423747 замена jz на jmp ? И сколько это будет продолжаться ? Пробуем... (00423747=22B47 in file)

  Запускаем... Ну вот!!! Теперь еще круче!!! Вообще ничего!!! Мда...

  Пришло время пораскинуть мозгами. Очевидно, что единственное, что поменялось в самом процессе работы программы – значение регистров после вычисления контрольной суммы. С одной стороны, весь цикл (00423B1E-00423B5E) можно заменить на код типа такого:

Код (Text):
  1.  
  2. mov ecx,48D2h
  3. mov edx,20h
  4. ...
  5.  

  т.е. галимо подогнать значения всех регистров, зная какими они выглядят в "девственном" Штирлице.exe. Но, во-первых, это уродливо, а во вторых - это нас не спасет... (можете попробовать). Стоит только отметить, что обращение к области памяти с E90020h (там, где лежит копия файла shtirlitz.exe) происходит еще минимум 4 раза!!! Разбираться и отлавливать их все нет никакого желания, Всеволод очень неплохо постарался...

  Поэтому пойдем по другому пути... Помнишь, в самом начале мы заменили по адресу

Код (Text):
  1.  
  2. :00401B39 7473      je 00401BAE
  3.  

  je на jmp ? Так вот, что если править код не в самом файле, а непосредственно в памяти??? Тогда никакой возни с контрольной суммой не возникнет!!! Отлично! Заодно можно проверить, по тому ли пути мы вообще идем... Итак, берем "девственный" shtirlitz.exe, ставим в SI бряк на readfile при ebx==A9400, запускаем shtirlitz.exe... Теперь, правим байт:

Код (Text):
  1.  
  2. eb 401B39 eb
  3.  

  Жмем F5 Yes! Никаких баннеров!!! Мы победили... Но... Не будем же мы в самом деле каждый раз при запуске Штирлица править байт в памяти !!!

  Но это уже и не нужно!!! Запустите shtirlitz.exe и убедитесь в этом сами!!! Вот он пресловутый "баг в защите"!!!

Postlude

  Существует еще как минимум два способа взлома данной программы. Сам автор на своем сайте в форуме признался, что если запустить Штирлица более 200 раз или с параметром –banoff в командной строке, то баннеры исчезнут... Но эти ли способы достойны настоящих хакеров?

  Вот как раз с первым способом (запустить 200 раз) и связан баг, который мы обнаружили.

FAQ

  - После того, как я пишу hwnd я ничего не вижу!
  А addr XXXX ты не забыл? Еще это может быть из за несовместимости версии SoftIce-а с установленной версией винды. Так, например, в SI из DriverStudio 2.5 в XP наблюдается именно этот баг, хотя по заявлениям SI 2.5 полностью поддерживает XP. В XP безгючно (почти!) работает ТОЛЬКО SI из DriverPack 2.6 (и вообще именно этот пак я и рекомендую всем)

  - Хочу исправить байт в HIEW, а оно ругается: "read-only mode".
  Закрой WDASM.

  - Теперь ругается SoftIce: Symbol not defined.
  Вот горе ты мое... Ищи файл winice.dat (в NT лежит он здесь: c:\windows\system32). Ищи строку: EXP=C:\WINDOWS\system32\comdlg32.dll. После нее дописывай таким же манером пути к нужным библиотекам (где лежат нужные API-шки). Какие это такие нужные библиотеки – см. в WDASM-е в самом начале идет список, впиши их все – не ошибешься. И будь внимателен с названием API-шек (SI различает CreateFile и CreateFileA)

  - Опять SoftIce пищит: Syntax error!
  Внимательно набирай команды!!! "bpx readfile if ebx=A9400" - ошибка!!! Должно быть два значка "=".

  Ломать – не строить!
  (C) Народная мудрость.
© Broken Sword


0 3.533
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532