制作 GL Studio v3.02 的 license

按:好像没什么技术含量,仅供参考!

手头的这个软件,试用版license已经过期,故不得不自己动手找一个不过期的license。
license中签名的长度是12个字符,可断定没使用公钥保护,不需打补丁就可以找出关键
参数,做出正确的license。

1、确定版本号(用lmtools.exe或lmver.exe都可以)
FLEXlm v9.2.0 (lmgr.lib)

2、生成Vendor Key(用lmkg.exe)

/* Version 9 keys */
#define VENDOR_KEY1 0x109922eb
#define VENDOR_KEY2 0x9ca04eba
#define VENDOR_KEY3 0xc3934b79
#define VENDOR_KEY4 0xdbcfd49c
#define VENDOR_KEY5 0x623a63f1
#define CRO_KEY1 0x14b920e3
#define CRO_KEY2 0xda822c3c

#define VENDOR_NAME "DISTI"

3、找FEATURE
这个很好找,在试用版license里面就有。或者在IDA里面也能找到。有两个:
glStudio
glStudioRuntime

4、找ENCRYPTION_SEED

反汇编主程序glStudio.exe,其中有一段是进行license检查的代码:

.text:004642CA                 push    offset aAcquiringLicen ; "Acquiring License..."
.text:004642CF                 call    sub_476F60
.text:004642D4                 add     esp, 4
.text:004642D7
.text:004642D7 loc_4642D7:                             ; CODE XREF: _main+328j
.text:004642D7                 push    edi
.text:004642D8                 push    offset a3_0     ; "3.0"
.text:004642DD                 push    offset aGlstudio ; "glStudio"
.text:004642E2                 mov     ecx, offset unk_653090
.text:004642E7                 call    ds:?Checkout@License@disti@@QAEXPAD0_N@Z ; disti::License::Checkout(char *,char *,bool)
.text:004642ED                 mov     ecx, offset unk_653090
.text:004642F2                 call    ds:?Valid@License@disti@@QAE_NXZ ; disti::License::Valid(void)
.text:004642F8                 test    al, al
.text:004642FA                 jnz     short loc_46430A
.text:004642FC                 push    offset aGlStudioDevelo ; "GL Studio Development license not found"...
.text:00464301                 call    ds:?fl_message@@YAXPBDZZ ; fl_message(char const *,...)
.text:00464307                 add     esp, 4

上面这段代码调用了glstudio3_0_2_vc71.dll中的几个函数。

反汇编glstudio3_0_2_vc71.dll,寻找两个关键函数lc_checkout、l_sg。
这两个函数的原型(见lm_ckout.c):

API_ENTRY
lc_checkout(
  LM_HANDLE_PTR      job,    /* Current license job */
  const LM_CHAR_PTR    feature,  /* The feature to be checked in */
  const LM_CHAR_PTR    version,  /* Feature's version */
  int            nlic,    /* Number of licenses to checkout */
  int            flag,    /* Checkout flag */
  const VENDORCODE_PTR  key,    /* The vendor's key */
  int            dup_group)  /* Duplicate license grouping criteria */
{

void
l_sg(
  LM_HANDLE *    job,
  char *      vendor_id,
  VENDORCODE *  key) /*- l_sg means "signature vendor_key5" */

lc_checkout的定位比较简单,因为它有7个参数,在feature出现的地方就可以找到它。

.text:10079F20 _lc_checkout    proc near               ; CODE XREF: sub_10037C9A+54p
.text:10079F20                                         ; sub_10037C9A+A9p ...
.text:10079F20
.text:10079F20 var_8           = dword ptr -8
.text:10079F20 var_4           = dword ptr -4
.text:10079F20 arg_0           = dword ptr  8
.text:10079F20 arg_4           = dword ptr  0Ch
.text:10079F20 arg_8           = dword ptr  10h
.text:10079F20 arg_C           = dword ptr  14h
.text:10079F20 arg_10          = dword ptr  18h
.text:10079F20 arg_14          = dword ptr  1Ch
.text:10079F20 arg_18          = dword ptr  20h
.text:10079F20
.text:10079F20                 push    ebp
.text:10079F21                 mov     ebp, esp
.text:10079F23                 sub     esp, 8
.text:10079F26                 mov     [ebp+var_4], 0
.text:10079F2D                 mov     eax, [ebp+arg_0]
.text:10079F30                 push    eax
.text:10079F31                 call    sub_100862CE
.text:10079F36                 add     esp, 4
.text:10079F39                 mov     ecx, [ebp+arg_0]
.text:10079F3C                 mov     edx, [ecx+3FCh]
.text:10079F42                 or      dh, 40h
.text:10079F45                 mov     eax, [ebp+arg_0]
.text:10079F48                 mov     [eax+3FCh], edx
.text:10079F4E                 push    95h
.text:10079F53                 push    offset aLm_ckout_c ; "lm_ckout.c"      // 看看,多好的提示
.text:10079F58                 mov     ecx, [ebp+arg_0]
.text:10079F5B                 push    ecx
.text:10079F5C                 call    __initp_misc_winxfltr_0
.text:10079F61                 add     esp, 0Ch
.text:10079F64                 mov     edx, [ebp+arg_0]
.text:10079F67                 add     edx, 494h
.text:10079F6D                 push    0
.text:10079F6F                 push    edx
.text:10079F70                 call    _setjmp3
.text:10079F75                 add     esp, 8
.text:10079F78                 test    eax, eax
.text:10079F7A                 jz      short loc_10079F87
.text:10079F7C                 mov     eax, [ebp+arg_0]
.text:10079F7F                 mov     eax, [eax+14h]
.text:10079F82                 jmp     loc_1007A057


在IDA中搜索立即数0x6f7330b8,可找到l_sg。

.text:1007DABB _l_sg           proc near               ; CODE XREF: sub_10073B7E+C63p
.text:1007DABB                                         ; sub_1007BC9F+C4p ...
.text:1007DABB
.text:1007DABB var_24          = dword ptr -24h
.text:1007DABB var_20          = dword ptr -20h
.text:1007DABB var_1C          = dword ptr -1Ch
.text:1007DABB var_14          = byte ptr -14h
.text:1007DABB var_13          = word ptr -13h
.text:1007DABB var_11          = byte ptr -11h
.text:1007DABB var_10          = dword ptr -10h
.text:1007DABB var_C           = dword ptr -0Ch
.text:1007DABB var_8           = dword ptr -8
.text:1007DABB var_4           = dword ptr -4
.text:1007DABB arg_0           = dword ptr  8
.text:1007DABB arg_4           = dword ptr  0Ch
.text:1007DABB arg_8           = dword ptr  10h
.text:1007DABB
.text:1007DABB                 push    ebp
.text:1007DABC                 mov     ebp, esp
.text:1007DABE                 sub     esp, 24h
.text:1007DAC1                 mov     [ebp+var_14], 0
.text:1007DAC5                 xor     eax, eax
.text:1007DAC7                 mov     [ebp+var_13], ax
.text:1007DACB                 mov     [ebp+var_11], al
.text:1007DACE                 mov     [ebp+var_C], 6F7330B8h    // 这个是比较重要的特征参数
.text:1007DAD5                 mov     [ebp+var_4], 0
.text:1007DADC                 mov     [ebp+var_8], 0
.text:1007DAE3                 mov     [ebp+var_10], 3
.text:1007DAEA                 mov     ecx, [ebp+arg_0]
.text:1007DAED                 mov     edx, [ecx+6Ch]
.text:1007DAF0                 mov     eax, [edx+0F54h]
.text:1007DAF6                 and     eax, 8000h
.text:1007DAFB                 test    eax, eax
.text:1007DAFD                 jz      short loc_1007DB22
.text:1007DAFF                 cmp     dword_10213CB4, 0
.text:1007DB06                 jz      short loc_1007DB22
.text:1007DB08                 mov     ecx, [ebp+arg_8]
.text:1007DB0B                 push    ecx
.text:1007DB0C                 mov     edx, [ebp+arg_4]
.text:1007DB0F                 push    edx
.text:1007DB10                 mov     eax, [ebp+arg_0]
.text:1007DB13                 push    eax
.text:1007DB14                 call    dword_10213CB4            // 在这个地方下断
.text:1007DB1A                 add     esp, 0Ch                  // 单步运行到这里


然后就是动态跟踪,找到以下参数:

输入dd [esp+8]
4D917F04               data[0]
4D9C696B               data[1]

输入dd [esp+4]
DISTI                  vendor_id

输入dd [esp]
341F91CA               job+08
00E80685               job+0c
004D0000               job+10

使用工具calcseed.exe,输入上述信息,可计算得到:
#define ENCRYPTION_SEED1 0x0000face
#define ENCRYPTION_SEED2 0x000deca1

ENCRYPTION_SEED3、ENCRYPTION_SEED4是SDK中的默认值,不需要改动,对计算license没有影响。

至此,分析已经基本完成,可以使用SDK计算license了。

5、写注册机

按照上面的信息,编辑lm_code.h,修改makefile,编译lmcrypt.c,大功告成!

注意:要将
#define ENCRYPTION_SEED1 0x0000face
#define ENCRYPTION_SEED2 0x000deca1
#define ENCRYPTION_SEED3 0x22334455
#define ENCRYPTION_SEED4 0x33221100
这几行放到lm_code.h文件中,
#define VENDOR_KEY5 。。。
后面即可。

后记:
第一次碰FlexLM,没想到运气真好,照着tulipfan[CCG]的大作
“制作Compuware.SoftIce.Driver.Suite.3.0.1.StinkyD的license”就轻松地搞定了它。
原计划花一个星期的时间,实际上只用了两天,总共10小时不到,还包括搜集资料和学习的
时间。
感谢tulipfan[CCG]!

--------------------------------------------------------------------------------

附录:FlexLM SDK 使用说明

以下以FLEXnet v10.1为例,简单介绍FlexLM SDK的使用流程。
这个流程也基本适用于 FlexLM SDK 的早期版本。

1、安装FlexLM SDK
   刚安装完的SDK肯定是不能用的。若不信可运行i86_n3\lmwin.exe看看,肯定一个
   feature都不能checkout,呵呵。
   
2、怎样才能让demo运行起来呢?
   首先用工具lmkg.exe计算出一组vendor key。以下是一个例子:   

/* Version 10 keys */
#define VENDOR_KEY1 0x321cd48b
#define VENDOR_KEY2 0xe6e4652c
#define VENDOR_KEY3 0x2076c1a2
#define VENDOR_KEY4 0xbbb34234
#define VENDOR_KEY5 0x0b165dca
#define CRO_KEY1 0x363cd683
#define CRO_KEY2 0xa0c607aa

#define VENDOR_NAME "demo"

   然后在命令行下运行i86_n3\lmrand1.exe,生成一组随机数种子。
   
#define LM_SEED1 0xcdfeb228
#define LM_SEED2 0x1b111a77
#define LM_SEED3 0xfe02cc3d

   最后修改 machind\m_code.h 中相应的行。
   (注意:如果VENDOR_NAME不是demo,还要修改makefile中相应行。)
   
注意:

A.从v10.0以后,CRO_KEY1、CRO_KEY2改名为TRL_KEY1、TRL_KEY1。

B.关于LM_STRENGTH的可能定义值
可根据需要定义以下之一,推荐使用公钥保护,强度更高。

不使用公钥保护
LM_STRENGTH_DEFAULT:  签名长 12 字符
使用公钥保护(ECC)
LM_STRENGTH_113BIT, LOW:     签名长  58 字符
LM_STRENGTH_163BIT, MEDIUM:  签名长  84 字符
LM_STRENGTH_239BIT, HIGH:    签名长 120 字符
兼容v7.1以前的版本(不做变动)
LM_STRENGTH_LICENSE_KEY


3、写一个调用Visual C++ 6.0的脚本编译SDK

@echo off
set MSVCDir="C:\Program Files\Microsoft Visual Studio\VC98"
set PATH=%MSVCDir%\Bin;%PATH%
@call vcvars32.bat
@call build.bat
echo ............. Done!
pause

4、生成licences

lmcrypt counted.lic
lmcrypt uncounted.lic
lmcrypt expired.lic
pause

注意:需要先修改lic文件中除签名字符串以外的其它各项,然后再用以上命令
生成新的lic文件。上面的命令只更改签名字符串。

5、测试lincense
   首先用i86_n3\lmtools.exe配置一个license server,可参考FlexLM编程指南。
   然后运行i86_n3\lmwin.exe,看看所有的feature是不是都能checkout。
   
   我这里是没有问题的,不知道你那里怎么样呢?

6、在自己的软件中调用FlexLM
   仿照lmvendor.c调用API即可,很简单了。