| 鉴定主任's profile信息产业部专业鉴定室PhotosBlogLists | Help |
|
March 26 Sparc平台下的FlexLM 4.1明文比对破解网上关于破解 FlexLM 的文章大多是 Windows 平台的,而且版本很高。但近日俺碰到的一款 SunOS Sparc 平台上的软件也是 FlexLM 保护,这可是个希罕物件,又加上整个公司只买了 2 个 License,一块用的时候俺基本轮不上,于是就带着尝试的想法拿它开刀。IDA 反了反这个 ELF 格式的主程序文件,字符串中看见是 FlexLM 4.1 版的,而且程序的字符串块没被 strip 掉,FlexLM 的相关函数名居然都在,省掉了找 Unix 下的 FlexLM SDK 的Signature 的麻烦。而且,这个 4.1 的版本由于相当低,其密文字符串的对比居然是明码标价,实在不符合其商业产品的特性(不过这也是事后才知道的)。
工具:IDA,DDD/GDB;
方法:静态阅读+动态跟踪。 网上找不到 FlexLM 4.1 的 SDK,但能找到的比较全的 FlexLM 4.0 的开发帮助:
http://wwweic.eri.u-tokyo.ac.jp/computer/manual/lx/SGI_Developer/books/FLEXlm_PG/sgi_html/index.html 这个对破解很有作用。
先恶补一下基础知识:
一、Sparc 平台的寄存器架构与汇编规则
Sparc 的 CPU 有很多寄存器,但针对任一进程的任一时刻来说只开放 32 个,以寄存器窗口的方式切换。一般它的寄存器可命名为 r0 到 r31,但一般以其别名来命名,如下:
通过 call 指令进行函数调用时,函数开始可调用 save 指令分配相应的栈空间并进行窗口切换,这个窗口切换会将切换前的 o 系列寄存器映射为切换后的 i 系列寄存器,函数返回时通过 restore 指令切换回来。这条规则要记住,否则进入函数前后参数和返回值都不知道去哪儿找。
一般进入函数之前给 o0 到 o5 寄存器赋值作为传入参数(不够则用堆栈),进入函数之后访问对应的 i0 到 i5 便可访问对应的传入参数,函数内部给 o0 赋值可作为返回值使用。
此外 Sparc 还有一些其他特点:访存用 ld/st 指令,和寄存器之间操作数据不同;跳转指令是 b(ranch),后缀表示各种条件,和 80x86 平台下的 j 系列一样;call 与 b 跳转指令后都有一个 nop,估计是给 Sparc 的指令预取机制或者跳转预判断机制准备的。
二、GDB/DDD 常用命令:
Data Display Debugger(DDD)是 Unix 平台下基于 GDB 的一款图形化调试工具,虽然用起来没 OllyDbg 等方便,但毕竟比 gdb 的纯命令行好得多,至少不需要频繁敲 disas 命令来查看反汇编代码,而且还可方便设置多个 display 来查看寄存器值,也不需要频繁敲 info reg o0 之类的命令。因此凑合着用它了。
对调试汇编代码比较有用的 gdb 命令有以下:
三、FlexLM 解密过程
用 IDA 反汇编看,程序一开始经过必要的初始化后,便会调用 l_init 开始 FlexLM 的检查,此间暴露了 Vendor Name、Feature 名,版本号等(见下)。然后程序逐步会进入核心的 lc_checkout 函数。如需要爆破,则修改 lc_checkout 的返回值即可,但俺的目的是想获得真正能用的 License,因此继续。
.text:00017194 loc_17194: ! <suspicious> ! CODE XREF: main+5DCj
.text:00017194 sethi %hi(0x50800), %i0 ! <suspicious> .text:00017198 sethi %hi(0x50800), %i1 ! <suspicious> .text:0001719C st %g2, [prog] .text:000171A0 mov 1, %g2 .text:000171A4 sethi %hi(0x4C000), %o0 ! <suspicious> .text:000171A8 st %g2, [num_lic] .text:000171AC set lm_job, %l5 .text:000171B0 set s_Lic_sunw, %o1 ! "lic.SUNW" .text:000171B8 add %l5, 4, %o2 ! int .text:000171BC ld [lm_job], %o0 ! int .text:000171C0 call lc_init lc_init 函数调用前需要传入 Vendor Name,此处得知是“lic.SUNW”。
.text:0001732C loc_1732C: ! CODE XREF: main+714j
.text:0001732C ! main:loc_172D0j .text:0001732C st %g2, [%sp+0xB10+var_AB4] .text:00017330 set s_Stack_1, %o1 ! "STACK" .text:00017338 sethi %hi(sccsid_4), %g2 .text:0001733C ld [%l5], %o0 .text:00017340 set s_8_0, %o2 ! "8.0" .text:00017344 sethi %hi(0x4C000), %g2 ! <suspicious> .text:00017348 ld [%i1+0x13C], %o3 .text:0001734C set code, %o5 .text:00017350 call lc_checkout Feature 名是“STACK”,版本号(Version Number)是“8.0”。
然后可根据看到的 Feature 名、Vendor Name 和 Version Number 构造了一个就一行的 license.dat 文件: FEATURE STACK lic.SUNW 8.0 1-jan-0000 uncounted 1234567890ABCDEF HOSTID=ANY
构造此 license 文件的目的是构造针对此 Feature 的无时间限制、无数量限制、无运行主机限制的完全 license。当然,其中签名部分是瞎凑的,目的是为了跟踪到和正确签名的比对的部分。
构造完文件后,将环境变量 LM_LICENSE_FILE 指向此文件 /tmp/license.dat
export LM_LICENSE_FILE=/tmp/license.dat
根据网上翻译的 FlexLM 9.2 的解密文章,lc_checkout 内部最终会调用 l_string_key 函数来进行比较,但资料里说 9.2 版的 FlexLM SDK 已经在此函数上做了部分手脚,会用伪造的签名来蒙混跟踪者,只有无签名返回时才是正确的场合。根据此点,咱在 l_string_key 函数中还真绕了不少弯路(弯路部分略)。后来跟踪的事实证明,FlexLM 4.1 版本中还没有此狡猾的机制,而是非常直白的调用 l_string_key,并在 l_crypt_private 返回时便能生成正确的明文签名。获得 l_crypt_private 的结果后,上级的 good_lic_key 再调用 strncmp 进行比较,从而得到比对的结果,这就是 FlexLM 4.1 的核心对比。
FlexLM 9.2 或者其他版本估计是察觉到了此问题,便将比对隐藏起来了,但仍然保留着 strncmp 来混淆视听。 中断在 l_string_key 中时,用bt查看调用堆栈得到以下信息:
#0 0x000277d8 in l_string_key ()
#1 0x00027770 in l_crypt_private () #2 0x0001ce98 in good_lic_key () #3 0x0001c4a4 in lm_start_real () #4 0x0001b61c in lc_checkout () #5 0x00017358 in main () 在此,无需刻舟求剑地在 l_string_key 处直接下断以企图获取正确签名值,而应该返回至 l_crypt_private 被调用的地方:
.text:0001CE80 mov %o0, %o2
.text:0001CE84 add %fp, var_20, %o3 .text:0001CE88 ld [%fp+arg_48], %o1 .text:0001CE8C ld [%fp+arg_44], %o0 .text:0001CE90 call l_crypt_private .text:0001CE94 nop .text:0001CE94 .text:0001CE98 st %o0, [%fp+s1] .text:0001CE9C ld [%fp+arg_48], %o1 .text:0001CEA0 inc 0x48, %o1 ! s2 .text:0001CEA4 ld [%fp+s1], %o0 ! s1 .text:0001CEA8 mov 0x14, %o2 ! n .text:0001CEAC call _strncmp .text:0001CEB0 nop .text:0001CEB0 .text:0001CEB4 tst %o0 .text:0001CEB8 bne loc_1CEC8 .text:0001CEBC nop 这里,strncmp 的两个参数 s1 和 s2,一个是我们输入的错误 license,一个是它计算出来的正确 license。在 0001CEAC 处中断时用 GDB 的 x /s $o0 和 x /s $o1 命令可看到正确的签名值 8503E11B1950D9B5AA12。
最后,无限制的 License 文件生成如下:
FEATURE STACK lic.SUNW 8.0 1-jan-0000 uncounted 8503E11B1950D9B5AA12 HOSTID=ANY
保存此文件后退出 DDD,再次运行程序,一切 OK。
四、总结
FlexLM 4.1 的保护方式很薄弱,估计其低版本如 2.6 等也一样。如果 Unix 平台下编译的程序符号表还在的话,简直就是中门大开引狼入室。破解者无需 FlexLM 4.1 的 SDK,也不用寻找什么 seed 什么 key,找到 Feature、版本号和 Vendor Name 后就能在程序中直接跟踪到明文的签名,所以本文写到后来也就变成了初级水平了。 |
|
|