需要的工具
Debugger (SICE, OllyDbg--非常棒的东东),Wadsm或者IDA,Flexlm SDK 7.2或者更高版本(非必须),一些最近的信息(从Pilgrim, Nolan Blender或其他的地方得到)。
目标位置(对付得东东是个CAD软件,叫做Solidedge。)
http://www.ugsolutions.com
http://www.solid-edge.com
正文
经过最初的嗅听之后,发现了读取license文件(selicense.dat)的DLL。也许我们并没有创建License文件,所以License Key也没有,它是这样的:
FEATURE SOLIDEDGECLASSIC sedemon 11.0 permanent uncounted /
123456789ABC HOSTID=ANY ISSUER="I don’t know"
我们的ugflex.dll被jutil.dll替换。还有个MAP文件,格式如下:
Address Publics by Value Rva+Base Lib:Object
0001:00000010 _JSetVACallback@4 5a001010 f auto.obj
0001:00000040 ?IsAutomationEnabled@@YAHXZ 5a001040 f auto.obj
0001:00000050 ?IsLicenceValidForAutomation@@YAHXZ 5a001050 auto.obj
为了与idasym.exe文件一起使用这个MAP文件,将Rva+Base还有Lib:Object列删除。然
后将创建的sym文件与symbol loader一起使用(设断点易如反掌,接着往下看就明白了)
由经验得知,实际上对于License的检查是在LC_CHECKOUT进行的(摘自flexlm手册)
lc_checkout()
SYNTAX status = lc_checkout( job ,feature ,version ,num_lic ,flag ,code , dup_group )
说明:查出一个或多个具体的feature(不好翻译,姑且用e文)。如果调用lc_checkout()的程序存在,那么check出的license将返回供另一用户使用。
如果将上面函数中的flag设置成LM_CO_WAIT,那么这个程序将等待,一直到达到这个feature需要的license数目。License文件的版本必须等于或高于lc_checkout调用中的version参数。
If the license file is counted, that is, if the number of users specified on the FEATURE line is non-zero, l
c_checkout() will request the license from alicense server. If the number of users on the FEATURE line is uncounted
, it will grant permission based on
the contents of the license file onlyŠhostid,version, expiration date, etc.(感觉没什么用,没翻译)
在5a04cf70 处的_lc_checkout是设断点的好地方!找到了FEATURE名后,就可以按照上面的格式建立自己的license文件了^_^。为了保证正确性,给出所有的FEATURE名:SOLIDEDGECLASSIC, SOLIDEDGEADVANCEDPAR, SOLIDEDGEXPRESROUTE, SOLIDEDGEFEATURERECO, SOLIDEDGEXPAND3D,
SEWEBPUBLISHER, SOLIDEDGEHANDBOOK, SOLIDEDGEMANAGER(note:有些feature如expand3d要在别的可执行程序中采用的到,以后再说^_^)
再来看l_good_lic_key函数。_lc_checkout命中三次而_l_good_lic_key只有一次。挺败吧?下面是程序片断:
5A04DA6C loc_5A04DA6C: ;CODE XREF _lm_start_real+343j
5A04DA6C mov edx, [ebp+arg_14]
5A04DA6F push edx ; vendorcode 结构(这次有所改进-加密了)
5A04DA70 mov eax, [ebp+var_20]
5A04DA73 push eax
5A04DA74 mov ecx, [ebp+arg_0] ;我们的license information
5A04DA77 push ecx
5A04DA78 call _l_good_lic_key ;检查license
5A04DA7D add esp, 0Ch
5A04DA80 test eax, eax
5A04DA82 jnz short loc_5A04DA89 ;这个你应该很熟悉了吧:-)
如果运行part.exe而没有反应,可能是应为你没有运行seiges.exe。part.exe中有些反debug的代码的部分。运行seiges.exe并将eax置成非零,将得到status=OK.但是仅仅有patch并不能让人满意,所以我们接着往下看^_^
5A04E995 add edx, 54h
.
.
5A04E99C push eax
5A04E99D call _l_extract_date
.
.
5A04E9B1 push ecx ;我们的vendorcode structure
5A04E9B2 mov edx, [ebp+var_CC]
5A04E9B8 push edx ;feature(特征名)
5A04E9B9 mov eax, [ebp+arg_4]
5A04E9BC push eax
5A04E9BD mov ecx, [ebp+arg_0]
5A04E9C0 push ecx
5A04E9C1 call _l_ckout_crypt
跟踪上面的代码我们发现_l_ckout_crypt做了一些重要的工作。这里只改变了seed的值而没有改变key的值。由于key的值没有改变,我们姑且认为他们已经被解密了,但seed的值仍然隐藏着!继续追踪,_real_crypt出现了(败了,这么个败名字)
5A050B44 mov eax, [ebp+arg_0]
5A050B47 push eax
5A050B48 call _real_crypt
5A050B4D add esp, 10h
下面是_real_crypt的代码片断:
.
.
5A050ECB push ecx
5A050ECC call _l_getattr ;取得license attributes
.
.
5A05106A push eax
5A05106B call _l_good_bin_date ; date
.
.
5A0510DA mov edx, [ebp+arg_0]
5A0510DD push edx
5A0510DE call _move_in_hostid ; 从license文件里获取hostid
.
.
5A051456 push offset aDup_group ; "DUP_GROUP" ;DUP_GROUP=UHD意味着可能的分组为(DUP_USER|DUP_HOST|DUP_DISPLAY),
所以对于用户在一台主机上,另外的对于feature的使用不会销毁另外的licenses. (看不太懂哦:( )
5A05145B mov eax, [ebp+arg_4]
5A05145E mov ecx, [eax+94h]
5A051464 push ecx
5A051465 call _addi ;把这个加到license中
.
.
5A051855 push ecx
5A051856 call _l_ckout_string_key ;这个怎样?
5A05185B add esp, 18h
_l_ckout_string_key值得注意!
5A052902 _l_ckout_string_key proc near ; CODE XREF: _real_crypt+AD1p
5A052902 push ebp
5A052903 mov ebp, esp
5A052905 sub esp, 1E4h
.
.
.
5A053755 call _our_encrypt2 5A05375A add esp, 4
5A05375D jmp short loc_5A05376C
5A05375F ; ΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖ
5A05375F
5A05375F loc_5A05375F: ; CODE XREF: _l_ckout_string_key+E43j
5A05375F ; _l_ckout_string_key+E4Cj
5A05375F push offset byte_5A0C5820
5A053764 call _our_encrypt ;the second encrypt
.
.
.
5A05384B mov ecx, [ebp+var_188]
5A053851 add ecx, 1
5A053854 mov [ebp+var_188], ecx
5A05385A
5A05385A loc_5A05385A: ; CODE XREF: _l_ckout_string_key+F47j
5A05385A mov edx, [ebp+var_188]
5A053860 cmp edx, [ebp+var_18C]
5A053866 jge loc_5A0539E0
5A05386C mov eax, [ebp+var_188]
5A053872 mov cl, [ebp+eax*2+var_168]
5A053879 mov [ebp+var_1CC], cl
5A05387F call ds:__p___mb_cur_max
5A053885 cmp dword ptr [eax], 1
.
.
.
5A0539CB xor eax, eax
5A0539CD mov al, byte_5A0C5820[edx] ; 最终 - 比较license
5A0539D3 cmp ecx, eax
5A0539D5 jz short loc_5A0539DB ;比较下一个byte
5A0539D7 xor eax, eax ;错误的key
5A0539D9 jmp short loc_5A053A01
5A0539DB ; ΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖ
5A0539DB
5A0539DB loc_5A0539DB: ; CODE XREF: _l_ckout_string_key+10D3j
5A0539DB jmp loc_5A05384B ;loop back
上面的循环与版本7中的有些类似(现在是7.2)。5A0C5820是产生真正的key的地方!这里有必要说明一下key的产生:如果没有license key,我们的license(格式正确)是混乱的,两者好像是通过addi function函数联系到一起的。所以现在程序的任务就是计算vendorseed,并在4个vendorkey的帮助下同混乱的license混合(可能是做某种运算^_^)。上面说得工作将在5A0C5820处完成。在5A0C5820处bpm,我们得到:
.
.
5A053334 mov byte_5A0C5820[ecx], al ;here we go
5A05333A jmp short loc_5A0532F9
5A05333C loc_5A05333C: ; CODE XREF: _l_ckout_string_key+A0Dj
5A05333C cmp [ebp+var_188], 0
从5A05333C处开始追踪,我们发现了计算seed的代码:
5A0533EA xor eax, ebx ;计算正确的seed
5A0533EC push eax ;入栈
5A0533ED call sub_5A053AD3
5A0533F2 add esp, 4
5A0533F5 mov [ebp+seed_one], eax
5A0533FB mov edx, [ebp+seed_one]
5A053401 and edx, 0FFh
.
.
5A0534C9 add eax, 1
5A0534CC mov [ebp+var_10], eax
5A0534CF mov [ebp+seed_one], 3D4DA1D6h ;隐藏seed
.
.
5A053548 push eax ;第二个seed入栈
5A053549 call sub_5A053AD3
5A05354E add esp, 4
5A053551 mov [ebp+seed_two], eax
5A053557 mov edx, [ebp+seed_two]
.
.
5A053628 mov [ebp+var_10], eax
5A05362B mov [ebp+seed_two], 3D4DA1D6h ;隐藏5A053635 jmp loc_5A053735
将seed隐藏能很好的防止内存dump工具将seed解出来。解seed的过程只能在特定位置并且是运行时才可以!
总结:
LC_CHECKOUT ---
|
|
_l_good_lic_key— /*加密的keys*/
|
|
_l_ckout_crypt---/*解密的keys*/
|
|
_real_crypt---
|
|
_l_ckout_string_key---
|
|
5A0533EA /*计算第一个seed*/
|
|
5A053547 /*计算第二个seed*/
|
|
5A0539DB <-
|
|
5A0539CD--- /*license比较*/
现在我们可以修改lm_code.h并且编译lmcrypt。使用3D4DA1D6h这样的字节模式,我们在AddInlm.dll中找类似的位置。其实我们只需要LC_CHECKOUT作为feature名。使用其他的模式能得到相应的位置(对于没有flexlm SDK的朋友来说,比较有用):
jutil.dll AddInlm.dll Selicwiz.exe
5A0533EC 046CAEDC 00428C6C
.
5A0539CD 046CB4BD 0042924D
The origin of the above code is the object lm_ckout.obj winthin the lmgr.lib library.(大体意思是上面的代码从那里来的)
|
|
5A0533EA /*计算第一个seed*/
|
5A053547 /*计算第二个seed*/
|
5A0539DB <-
| |
5A0539CD--- /*license比较*/
|
--
翻译得不好,大虾莫笑:P