Автор: | Sh [AHTeam] |
Уровень: | Для опытных |
Программа: | Любая программа, защищенная FlexLM |
Тип защиты: | FlexLM |
Инструменты: | Ida Pro 4.5, Soft-Ice, Ida2Sice, FlexLM SDK 7.2f |
Это моя первая краткая статья по менеджеру лицензий FlexLM. Базируется на статье by Nolan Blender и его замечательных тулзах Calcseed и Vendor Key Generator (540 Kb). Ссылка на calcseed дана с любезного разрешения автора - он обещал выкладывать свежие версии :)
Итак, мы имеем прогу и просроченный лицензионный файл такого вида:
---license.lic--- ## (c) 2002, XXX Software ## Product Name: TargetXXX ## Product Version: 9.3 ## Licence Type: Standalone ## HostName: vasya ## HostID: 00023f39df58 ## Number of Users: 1 ## Expiry Date: 23-mar-2004 ## Licence File Version: 1.0 ## For Customer Name: Vasily ## For Company Name: Firma
SERVER vasya 00023f39df58 VENDOR xxxslm USE_SERVER PACKAGE TargetName xxxslm 2002.1 COMPONENTS="Component1 \ Component2 ... Component25" SIGN=5CE4BB78EC52 INCREMENT TargetName xxxslm 2002.1 23-mar-2004 1 HOSTID=00023f39df58 \ SIGN=E244707E3D6F
---license.lic--- Запускаем прогу. Видим окно запроса файла сервера лицензии. Пытаемся подсунуть наш файл, прога ругается "Security failed". Запускаем поиск в каталоге с программой. Ищем файлы, содержащие строку "FlexLM". Приятным сюрпризом для нас становится факт, что 25(!) *.dll содержат строку:
(#) FLEXlm v7.2a (liblmgr.a), Copyright (C) 1988-2000 Globetrotter Software, Inc.
Делаем сигнатуру из SDK при помощи FLAIR - метод описан в статье на wasm.ru. Либо берем готовую в сети - сигнатур для FlexLM 7.2 наделано предостаточно. Для лентяев прилагается небольшая подборка сигнатур, flex_sig.zip (115 Kb), собранная из разных источников. В принципе, легко можно запатчить по одному шаблону все 25 библиотек - и даже написать универсальный патч. Сначала я так и сделал, и прога заработала великолепно. Но потом мне стало очень интересно разобраться, как же сгенерить лицензию самому. После кучи прочитанных статей на woodmann.net, я понял, что нужно подобрать значения в lm_code.h и скомпилировать SDK. Далее лицензии будут генериться неотличимым от вендора способом :)
Итак, lm_code.h из поставки FlexLM SDK:
/******************************************************************************
Module: $Id: blank_lm_code.h,v 1.2.2.1 2000/12/19 19:13:17 jwong Exp $
COPYRIGHT (c) 1990, 2000 by Globetrotter Software Inc. This software has been provided pursuant to a License Agreement containing restrictions on its use. This software contains valuable trade secrets and proprietary information of Globetrotter Software Inc and is protected by law. It may not be copied or distributed in any form or medium, disclosed to third parties, reverse engineered or used in any manner not provided for in said License Agreement except with the prior written authorization from Globetrotter Software Inc.
*****************************************************************************/ /* * * Description: Used to generate lm_new.o/.obj and by license- * generators. * * Once the kit is "built" (using make or nmake) * this file is no longer needed, but should be * stored somewhere safe. * * Set the following values: * LM_STRENGTH * If using public-key, set to desired length * ENCRYPTION_SEED1-4 * Make up 4 32-bit numbers, keep secret, safe, * and never change. * VENDOR_NAME * If not evaluating, set to vendor name. * VENDOR_KEY1-5 * Provided by Globetrotter. * */
#ifndef LM_CODE_H #define LM_CODE_H #include "lm_cro.h"
/* * Pick an LM_STRENGTH. * * If you're not using CRO public-key, then leave this as * LM_STRENGTH_DEFAULT. * If you're upgrading from pre-v7.1, and want no changes, * set this to LM_STRENGTH_LICENSE_KEY. */
#define LM_STRENGTH LM_STRENGTH_DEFAULT
/* * LM_STRENGTH Options are * LM_STRENGTH_DEFAULT Public key protection unused * Use SIGN= attribute * sign length = 12 * Public key: * LM_STRENGTH_113BIT, LOW sign length = 58 chars * LM_STRENGTH_163BIT, MEDIUM sign length = 84 chars * LM_STRENGTH_239BIT, HIGH sign length = 120 chars * * Use pre-v7.1, non-CRO * LM_STRENGTH_LICENSE_KEY Use pre-v7.1 license-keys. * Doesn't use SIGN= attribute. */
/* * Vendor's private seeds, -- replace with 32-bit numbers that * you make up. */
#define ENCRYPTION_SEED1 0x87654321 #define ENCRYPTION_SEED2 0x12345678
#define ENCRYPTION_SEED3 0x11223344 #define ENCRYPTION_SEED4 0x55667788
/* * FLEXlm vendor keys -- enter as received from Globetrotter. * Changing these keys has NO impact on license files (unlike * the ENCRYPTION_SEEDs). */ /*- * Generate these keys with: lmvkey -v demo -d (+3 months) -p ALL -c DEMO * (Use a date approx 3 months out) */
#define VENDOR_KEY1 0x0 #define VENDOR_KEY2 0x0 #define VENDOR_KEY3 0x0 #define VENDOR_KEY4 0x0 #define VENDOR_KEY5 0x0 #define CRO_KEY1 0x0 /* Used to enable CRO -- turned off by default */ #define CRO_KEY2 0x0 /* Be sure to reset LM_STRENGTH above if CRO_KEY is non-zero */
/* * FLEXlm vendor name. Leave as "demo" if evaluating FLEXlm. Otherwise * set to your vendor daemon name. */
#define VENDOR_NAME "demo"
/* * Older customers with newer versions may want to set * behavior defaults to previous version, though this is usually * discouraged. Behaviors can be changed individually using * LM_A_xxx in the flexible API. New customers should use the * current default, as set below * * Valid settings include: * LM_BEHAVIOR_V2, _V3, _V4, _V5, _V5_1, _V6, _V7, _V7_1 */
#define LM_VER_BEHAVIOR LM_BEHAVIOR_V7_1
#endif /* LM_CODE_H */ Мы видим, что по любезному совету парней из Globetrotter нам нужно подобрать свои значения вместо дефолтных:
#define ENCRYPTION_SEED1 0x87654321 #define ENCRYPTION_SEED2 0x12345678
#define ENCRYPTION_SEED3 0x11223344 #define ENCRYPTION_SEED4 0x55667788 #define VENDOR_KEY1 0x0 #define VENDOR_KEY2 0x0 #define VENDOR_KEY3 0x0 #define VENDOR_KEY4 0x0 #define VENDOR_KEY5 0x0 #define VENDOR_NAME "demo" Значение #define CRO_KEY1 0x0 нам в данный момент не нужно. CRO - это покупаемая за отдельные большие деньги мощная крипто-опция (Counterfeit Resistant Option), в нашем таргете не используемая. Если эта опция используется, то подписи получаются устрашающей длины, а не 12 символов, как в нашем случае. Более того, при генерации лицензии нам нужны только ENCRYPTION_SEED1 и ENCRYPTION_SEED2. Начнем с самого простого - VENDOR_NAME. Его мы можем увидеть прямо в лицензионном файле (VENDOR xxxslm) или по имени сервера лицензий (установившегося в Program Files\XXX\FlexLM\Bin). Там лежат lmgrd.exe и xxxslm.exe. Вводим имя вендора xxxslm в упомянутый PCG FLEXlm Vendor Key Generator. Получаем
/* Version 7 keys */ #define VENDOR_KEY1 0xcbd2f45c #define VENDOR_KEY2 0x951dfed2 #define VENDOR_KEY3 0x889ad6c8 #define VENDOR_KEY4 0xffe2bfdf #define VENDOR_KEY5 0x625dc1e0 #define CRO_KEY1 0xcff2f654 #define CRO_KEY2 0xd33f9c54
#define VENDOR_NAME "xxxslm" В принципе, как мы увидели, эти значения не имеют особой важности. но для корректной сборки SDK они необходимы (вообще-то вопрос спорный). Гораздо интереснее ENCRYPTION_SEED1 и ENCRYPTION_SEED2. Вся защита базируется на них. Как их найти, подробно расписано все в той же статье by Nolan Blender. У меня это получилось так: Загружаем менеджер лицензий xxxslm.exe в IDA, применяем сигнатуру (File - Load file - FLIRT signature file). Находим процедуру _time. На нее идет куча ссылок из одной процедуры:
.text:00454380 _time proc near ; CODE XREF: sub_40D495+5Bp .text:00454380 ; sub_40D495+77p .text:00454380 ; sub_40D495+90p .text:00454380 ; sub_40D495+ACp .text:00454380 ; sub_40D495+C5p .text:00454380 ; sub_40D495+E1p .text:00454380 ; sub_40D495+FAp .text:00454380 ; sub_40D495+116p .text:00454380 ; sub_40D495+12Dp .text:00454380 ; sub_40D495+149p ... Забегая вперед, скажу, что эта процедура 40D495 выполняет нужную нам обработку ENCRYPTION SEDDS. Смотрим начало процедуры
.text:0040D495 sub_40D495 proc near ; DATA XREF: sub_401000+E7 ; 401000+E7 получается 4010E7 Используется косвенная адресация. Взглянем поближе:
.text:004010E7 push offset sub_40D495 ; адрес процедуры обработки .text:004010EC call _l_x77_buf ; _l_x77_buf = 40EB60 И что же эта _l_x77_buf делает с нашим адресом? Приведем ее код полностью:
.text:0040EB60 _l_x77_buf proc near ; CODE XREF: sub_401000+ECp .text:0040EB60 .text:0040EB60 arg_0 = dword ptr 8 .text:0040EB60 .text:0040EB60 push ebp .text:0040EB61 mov ebp, esp .text:0040EB63 cmp dword_49A31C, 0 .text:0040EB6A jnz short loc_40EB74 .text:0040EB6C mov eax, [ebp+arg_0] .text:0040EB6F mov dword_49A31C, eax .text:0040EB74 .text:0040EB74 loc_40EB74: ; CODE XREF: _l_x77_buf+Aj .text:0040EB74 pop ebp .text:0040EB75 retn .text:0040EB75 _l_x77_buf endp Ага, адрес процедуры sub_40D495 заносится в dword_49A31C. Смотрим, что происходит с этим dword_49A31C по XREF:
.data:0049A31C dword_49A31C dd ? ; DATA XREF: _l_x77_buf+3r .data:0049A31C ; _l_x77_buf+Fw .data:0049A31C ; _l_sg+2Ar _l_sg+3Fr Либо по XREF, либо брякнувшись в айсе по адресу 40D495 и один раз нажав F12, мы видим, откуда вызывается наша процедура 40D495:
.text:00413D5A cmp dword_49A31C, 0 .text:00413D61 jz short loc_413D7D
.text:00413D63 mov eax, [ebp+arg_8] ; EAX содержит указатель на .text:00413D66 push eax ; vendorcode structure
.text:00413D67 mov ecx, [ebp+arg_4] ; ECX содержит указатель на .text:00413D6A push ecx ; строку VENDOR_NAME
.text:00413D6B mov edx, [ebp+arg_0] ; EDX содержит указатель .text:00413D6E push edx ; на job structure
.text:00413D6F call dword_49A31C ; call 40D495. Bingo! Здесь ловим .text:00413D75 add esp, 0Ch ; нужные нам поля структур!
.text:00413D78 jmp loc_413E90 Это и есть наш самый важный кусок кода. Перед call по адресу 413d6f EAX содержит указатель на vendorcode structure, ECX содержит указатель на строку VENDOR_NAME (мы видим там все тот же xxxslm ;) и EDX содержит указатель на job structure. Эти параметры передаются в call - процедуру расшифровки. В айсе наберем bpx 413d6f. Когда брякнемся - dd eax+4. В окне данных находятся нули. Пройдем call по trace over. Видим, что в EAX+4 появились два dword вместо бывших там нулей. Процедура 40D495 добросовестно заселила нули нужными нам данными. Запишем их на бумажку :) - это будут значения data[0] и data[1] для calcseed. Опять прервемся в айсе перед call и посмотрим dd edx+8. Опять нули. После trace over там появятся 3 dword`a – это и есть значения job+08, job+0c и job+10 для calcseed. Записывать все значения нужно одновременно, т.к. при каждом запуске проги они получаются разные. Итак, мы записали data[0],[1], job+8,c,10, vendor name. Вводим это все в calcseed и получаем Derived encryption seeds! Подставляем их в lm_code.h:
#define ENCRYPTION_SEED1 0xda61fc28 #define ENCRYPTION_SEED2 0x42bd719e Компилируем SDK. Получаем lmcrypt.exe. Берем оригинальный файл лицензии. Ставим в нем оба значения SIGN=0, и сохраняем например как template.txt. Запускаем lmcrypt –i template.txt –o license.lic Есть контакт! Полученные на выходе в license.lic значения SIGN полностью совпадают с оригинальными – т.е. наш подписывальщик lmcrypt полностью аналогичен тому, который находится у вендора. Снова берем оригинальный файл лицензии. Выставляем в нем нужный нам HOSTID, Hostname, Server, нужную нам дату (2050 год), подписываем lmcrypt`ом. Сервер лицензий принимает наш файл, говорит что все FEATURE включены и могут быть “checked up”. Запускаем прогу. Прога не работает :) Странно, мы ведь все сделали правильно. Лезем глубже в процедуру проверки лицензии и смотрим, какое значение ошибки возвращается в EAX. EAX получается равным -77. По этому вопросу SDK любезно сообщает нам:
---lmclient.h--- #define LM_BAD_VERSION -77 /* Version number must be string of dec float */ Откуда же может взяться несовпадение версии? Трассируем внимательно и видим, что версия 9.3 преобразовалась к виду 9,300000. Процедура пытается найти в этой дроби точку (9.300000) и находит вместо нее запятую. Откуда может взяться в дробной записи числа запятая вместо точки? Правильно, из региональных установок винды. Выставляем в региональных настройках США, и вуаля, прога заработала прекрасно. Выводы: если не используются дополнительные фильтры, то весь FlexLM базируется на ENCRYPTION_SEED 1,2, которые мы с успехом восстановили.
Приветствия: моей команде ahteam.org, reversing.net, www.woodmann.net.
|
|