More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  信息产业部专业鉴定室PhotosProfileFriendsBlog Tools Explore the Spaces community

Blog

August 05

又被点名了

又被考察团团长点名了,而且问题多达三十八个,真三八啊。

没的说,捧场。

1.当你不高兴的时候,你喜欢做什么?
  开骂然后加仓。

2.最让你迷惘的事情是什么?
  为啥股市跌成这样嗫?

3.2008年最大的心愿是什么?
  风调雨顺国泰民安股市大涨买个破房。

4.你现在住在哪个城市,如果能够选择,你希望住在哪里?
  上海。布拉索夫。

5.如果现在可以让你随心所欲去旅行,你想去哪?
  也想去太空。

6.你相信命运么? 你会为了改变自己的命运抗争么?
  不可知论,也就没抗争的说法了。

7.最不喜欢什么类型的人?
  欠钱不还还大找借口的废话特多的男人。

8.会不会做饭?你希望你的伴侣会做饭吗?
  会。希望。

9.感触最深的一本书或影片的是?为什么?
  红楼梦

10.你会选择你爱的人还是爱你的人?为什么?
  选择两个行不?

11.当你遇到跟你很合不来的同事或者同学时(就是很不服你所做的事情和看法的那
种)而且你们还要经常在一起干活,你会怎样处理?
  一边合作一边鄙视它。

12.你最喜欢你伴侣的什么?如果没有,你希望你的伴侣具有什么品质。
  胸围。

13.给你一种能力去改变(或提升)自己,你选择什么?
  选择能给予提升能力的能力。

14.你会出于什么样的理由结婚? 或者是出于什么样的理由单身?
  八月十八星期八和九月九的酒。

15.和恋人分手了你会把对方的手机,MSN,QQ删掉么,如果删掉为什么?
  不会。

16.喜欢的人是谁?
  美女。

17.说说你童年的梦想和现在的理想。
  玩游戏机。玩模拟器。

18.你觉得,到目前为止,你在多大程度上对生活是满意的?
  除了钱不满意其他都满意。

19.你最欣赏的人是?为什么?
  芙蓉姐姐。她的勇气谁比的上?

20.你有非常非常贴心的朋友吗?
  有。

21.如果可以规划你的人生,你会选择去规划还是顺其自然?
  顺其自然地规划。

22.给你最深感动的一件事是什么?
  公元钟熄灭的那一刻……

23.喜欢孤单的感觉么?为何?
  不喜欢孤单也不喜欢嘈杂。

24.一年四季,你最喜欢哪个季节
  秋天。

25.喜欢养宠物么,如果有条件的话?
  不喜欢养只喜欢玩。

26.有的时候你非常想得到的东西,得不到,怎么想?
  使劲想。

27.对自己的缺点用不超过10个字总结一下
  一二三四五六七八九。

28.你最喜欢的明星是谁?
  现在没了。

29.用一种颜色来代表你现在的生活状态,那么它是哪种颜色呢?
  女色。
  
30.现在你最想做的一件事情是什么?
  马上治好口腔溃疡。

31.对自己的样貌作一个评价吧。
  玉树临疯。

32.喜欢苦的东西么,为什么?
  不喜欢。

33.民已食为天,你最喜欢的水果和菜是什么?
  西瓜。菜太多说不来。

34.最喜欢说的口头禅?它的典故或来源?
  tmd又跌了!来自最近一年的股市。

35.感觉自己最讨人喜欢的地方是?(不可以说你不讨人喜欢)
  BT+猥琐

36.当你心情低落时,是如何做调整的?
  疯狂加仓

37.下辈子想做什么?
  证监会主席

38.外面晴空万里,你想做点什么事情?
  下班回家睡觉。

July 31

乱捏联话之一

国画大师徐悲鸿当年曾在浙江丽水作画顺便寻访故人,后未逢而怅然远游。然故人亦病,后托信于徐,信辗转至藏外大吉岭,彼时大雪封山人难行,且信无地址,回复亦不能,唯无可奈何尔。
当时,好事者曾以“悲鸿绘丽水”出联,后闻大吉岭之事,遂对“喜马拉雅山”,无情流水,严丝合缝,真他妈的牛。
July 25

大饼油条四明治

三个角的是三明治,四个角的自然就是四明治了,但一个自产的四明治吃不饱,又补了一份大饼油条,然而后者吃着总没前者爽。早上七点提早起床折腾面包香肠榨菜黄瓜色拉酱凑成四明治,这样新奇的口味以前是没尝过的。人要会感恩会知足,要提前历练做房奴的穷困日子,早晚这四明治会被磨光棱角变成∞明治的。
June 30

周老虎终于被抓了

一副很牛很粗俗的对联:
 
顶叶纸虎啸山林,
卧槽泥马勒戈壁。
June 20

转贴:歪批《三国》

歪批《三国》

甲: 说相声的谈今论古,《三国演义》、“东、西汉”、“红楼”、“聊斋”。《水浒传》,什么书都看。
乙: 要提起“三国”,我可知道得最彻底。
甲: 你对“三国”有研究?请问你“三国”里头所有的人物,谁最有能耐?
乙: 能耐最大的就是诸葛亮。
甲: 诸葛亮有何能耐?
乙: 诸葛亮仰面知天文,俯察知地理,明阴阳,懂八卦,运筹帏幄之中,决胜千里之外。抱膝危坐,自比管仲、乐毅;笑做风月,未出茅庐就知有三分天下。诸葛亮乃一国军师,可称得起世之奇才!《三国》里就数诸葛亮能耐。
甲: 诸葛亮要是能耐大,七星灯借寿怎么会死到司马懿手里呢?
乙: 这个……那就是司马懿能耐。
甲: 司马懿有什么能耐?
乙: 司马懿乃是领兵大元帅,统带千军万马,执掌生杀之权,攻、杀、战、守,抽、撤、盘、环,无一不晓。就拿取街亭说吧,不用自己去,派张郃一战成功。司马懿多有能耐!
甲: 司马懿要是有能耐,得了街亭,怎么还叫赵云追得满市街乱跑?
乙: 那么这一说是赵云有能耐。
甲: 赵云有什么能耐?
乙: 赵云是常胜将军,百战百胜,长坂坡前一场大战,单枪独马,敌住曹操八十三万人马,闯出重围,救出阿斗。那是多大的能耐!
甲: 赵云要有能耐,到了当阳桥,为什么还让张飞给断后哪?
乙: 那是张飞有能耐。
甲: 张飞要有能耐,虎牢关战吕布,怎么哥儿仨打人家一个?
乙: 那是吕布有能耐。
甲: 吕布要是有能耐,在白门楼怎么会死在曹操手里?
乙: 那是曹操有能耐。
甲: 曹操有能耐,火烧战船,怎么把胡子都烧没啦?
乙: 要照你这么一说……
甲: 谁有能耐?
乙: 你有能耐。
甲: 我有什么能耐?
乙: 你把我问住了,还没有能耐吗?
甲: 你就知道看人家优点,你不知道人家的缺点。
乙: 缺点我也知道,就是不说。
甲: 为什么?
乙: 得罪那个人干什么?
甲: 你说这话不对,做事情要站稳立场,优点应该提出表扬,缺点应该提出批评。
乙: 噢,优点提出表扬,缺点提出批评,话虽然很对,可是我上哪儿找诸葛亮去呀?
甲: 我没让你找诸葛亮,我是说事情应该这样做。如此看来,你对《三国演义》还是没什么研究。请问你《三国演义》是谁作的?
乙: 罗贯中。
甲: 什么人批过?
乙: 有好几位哪,金批——金圣叹;御批——四帝乾隆;毛批——毛宗岗。
甲: 还有。
乙: 还有什么?
甲: 还有侯批!
乙: 什么侯批?是古人吗?
甲: 不,是今人。
乙: 姓什么叫什么?
甲: 侯宝林。
乙: 噢,就是你呀!
甲: 对啦!
乙: 金批,御批,毛批我全看过,您这侯批我可没看见过。
甲: 可以买一本看看。
乙: 书店有吗?
甲: 不好买。
乙: 缺货?
甲: 不,还没出版哪。
乙: 废话!没出版说它干什么!
甲: 我这可不敢说是批“三国”。
乙: 是什么?
甲: 我这叫与读者共同讨论。
乙: 怎么?
甲: 你也爱看“三国”,我也爱看“三国”,我们在“三国”里头提出点问题,互相研究研究,讨论讨论。
乙: 那好哇!“三国”里头有不知道的,你就问我。
甲: 噢!你都知道?我问你为什么叫“三国”?
乙: 北魏,西蜀,东吴,此为三国。
甲: 十八路诸侯讨董卓,为什么不叫十八国哪?
乙: 那个……他们都没成事。
甲: 三分归一统,为什么不叫一国?
乙: 那不是以后吗?我说的不对吗?那你说为什么叫“三国”?
甲: “三国”里带“三”的节目多,故此叫“三国”。
乙: 全有什么哪?
甲: 拿过来“三国”您看,头本第一回那个目录里头就有个三字。
乙: 有什么?
甲: “宴桃园豪杰三结义”,有三没有?
乙: 有啊!还有什么?
甲: 最后一回:“降孙皓三分归一统”,有三没有?
乙: 就两个三呀?
甲: 还有哪:“虎牢关三战吕布”、“屯土山关公约三事”、“刘玄德三顾茅庐”、“陶公祖三让徐州”、“荆州城公子三求计”、“袁曹各起马步三军”、“三江口曹操折兵”、“定三分隆中决策”、“三江口周瑜纵火”、“诸葛亮智取三城”、“三气周瑜”、“三擒孟获”……
乙: 七擒孟获!
甲: 三擒!
乙: 怎么是三擒哪?
甲: 先有三擒,然后才有七擒,你得经过三擒,才能到七擒哪,不能由二擒就蹦到四上去!
乙: 噢!这么个三擒哪?还有什么?
甲: 三出祁山!
乙: 六出祁山!
甲: 二三得六。
乙: 小九九哇!
甲: 三伐中原。
乙: 哎,九伐中原!
甲:、乙 三三见九。
乙: 我就知道嘛。
甲: 这是明三,“三国”里还有暗三。
乙: 什么叫暗三?
甲: “三国”里有三妻,三不明,三不知去向,三头驴,三张断三桥,文官三丑,武将三俊,三个不知道,还有三个做小买卖的。
乙: 你说这是什么呀?这么乱!你说这话我好有一比。
甲: 比从何来?
乙: 蛤蟆跳井——
甲: 怎么讲?
乙: 不懂(扑通)。
甲: 不懂不要紧,我可以给你讲。
乙: 我先问你什么叫三妻?
甲: 妻是夫妻的妻。头一个是猎户刘安杀妻供主。
乙: 第二个?
甲: 刘备抛妻。刘备要不抛妻,没有《回荆州》。
乙: 第三个?
甲: 吕布贪妻。吕布要不贪妻,没有《白门楼》。
乙: 什么叫三不明?
甲: “三国”里有三个人,他们的姓名不明。
乙: 头一个?
甲: 是有姓无名。
乙: 谁?
甲: 乔阁老。
乙: 噢,东吴的,他不是姓乔名阁老吗?
甲: 不对,阁老是皇亲,说白话就是老丈人,他就是有姓没名。
乙: 有名。
甲: 叫什么?
乙: 乔玄。
甲: 你是在“三国”里头看到的?
乙: 不是。
甲: 哪儿学来的?
乙: 听戏听来的,《甘露寺》里头有。
甲: 我早就知道你是听戏听来的。
乙: 怎么?
甲: 唱戏到台口要报名,就是介绍剧中人物。不能报乔阁老,阁老是老丈人。光报姓不报名也不好听,“老夫,乔——”乔什么呀?因此戏剧演员给他编出个名字叫乔玄。
乙: 他为什么叫乔玄哪?
甲: “三国”原文上没有,历史纲鉴上查不着,这个名字还在那悬(玄)着哪。
乙: 噢,这么个乔玄哪。第二个是谁?
甲: 第二个有名无姓——貂蝉。
乙: 哎,貂蝉有姓。
甲: 姓什么?
乙: 姓貂名蝉。
甲: 不对,她是王司徒的一个歌姬,原文上没姓,就叫貂蝉,是有名无姓。
乙: 第三个人是谁?
甲: 就是“张翼德怒鞭督邮”这是督邮无名无姓。
乙: 哎!那不是姓督名邮吗?
甲: 不对,督邮是当时的官衔,就相当于现在的税务局长。督邮是无姓无名,他刚一露头没等报名,就叫张飞给打回去了。以后再不提他了。我看这个人就是为挨打而来的。
乙: 噢,这是三不明。什么叫三不知去向呢?
甲: 对,有三不知去向,貂蝉不知去向,徐庶不知去向,督邮被打完了可也不知去向。
乙: 啊,还有什么三头驴?
甲: 对,“三国”里头有三头驴。
乙: 头一头?
甲: 吕伯奢骑驴沽酒。
乙: 哎,不错,有。第二头?
甲: 诸葛亮的岳父黄承彦有一头驴。
乙: 他哪有驴呀?
甲: 有啊,在三顾茅庐的时候,不是黄承彦骑驴过小桥吗!有一首《梁父吟》,那里就有一头驴。
乙: 在哪有?
甲: 我念念你听:“一夜北风寒,万里彤云厚,长空雪乱飘,改尽江山旧,仰面观太虚,疑是玉龙斗,纷纷鳞甲飞,顷刻遍字宇宙,骑驴过小桥,独叹梅花瘦。”这里边不是有头驴吗?
乙: 第三头?
甲: 诸葛亮有个哥哥诸葛瑾……
乙: 对!东吴的谋士,号叫子瑜。
甲: 他长的是什么相貌?
乙: 他长的是驴脸。
甲: 哎,长脸膛,大下巴,长得跟驴一样。哎,他,他,他就算一头驴。
乙: 啊?拿人比驴,这叫什么话呀!
甲: 哎!他是有一头驴。有一天东吴的孙权大宴群臣,内中就有诸葛子瑜,他是带他的儿子去的。他儿子叫诸葛恪,那年才七岁,一块儿去了。在赴宴的时候,文武百官跟诸葛子瑜开玩笑,一看他那脸长得跟驴脸似的,就拉过来一头驴,在那驴脑门上写了四个字:“诸葛子瑜”,大家一看,哄堂大笑。你说诸葛子瑜急又不能急,这是开玩笑;不急吧,当众受辱。正在难受的时候,他儿子诸葛恪一看,他爸爸面红耳赤,小孩子有办法,拿起笔在驴头上那四个字底下又添了两个字。
乙: 什么字?
甲: “之驴”这样一念就好听了:“诸葛子瑜之驴”,说明这头驴是他们家的。吃完喝完了,还把这头驴拉他们家去啦。
乙: 噢,这是三头驴。那三张断三桥哪?
甲: 第一,张飞喝断当阳桥。
乙: 二?
甲: 张任断过金雁桥。
乙: 三?
甲: 威镇逍遥津,张辽断过小石桥。
乙: 文官三丑?
甲: 夏侯敦是猴相,诸葛瑾是驴相,庞统是七孔朝天,这是文官三丑。
乙: 武将三俊哪?
甲: 吕布、赵云、周瑜,这是武将三俊。
乙: 还有什么?
甲: 还有三个不知道,问谁谁也不知道。
乙: 你不知道问我呀,我全知道。
甲: 你知道?我问你:周瑜他姥姥家姓什么?
乙: 不知道。
甲: 诸葛亮他姥姥家姓什么?
乙: 不知道。
甲: 张飞他姥姥家姓什么?
乙: 也不知道。
甲: 哎,这就是三不知道。你不知道,大家也不知道。
乙: 那你知道吗?
甲: 我当然知道。
乙: 周瑜他姥姥家姓什么?
甲: 姓纪。
乙: 诸葛亮他姥姥家姓什么?
甲: 姓何。
乙: 张飞他姥姥家姓什么?
甲: 姓吴。
乙: “三国”原文没有哇!
甲: 有,周瑜在临死的时候,仰面长叹,说了一句。
乙: 说什么?
甲: 说:“既生瑜而何生亮?”这就是说,纪氏老太太生的周瑜,何氏老太太生的诸葛亮。
乙: 哎,不对,人家是说既然生周瑜何必再生诸葛亮!
甲: 我就这么体会!
乙: 好,那张飞他姥姥家为什么姓吴哪?
甲: 你没看老太太管小孩儿,不是有那么一句话嘛:“你这个孩子,总出去惹祸!真是无(吴)事(氏)生非(飞)!”这就是吴氏老太太生的张飞!
乙: 噢,这么讲啊,像话吗!还有什么?
甲: 还有三个做小买卖的。
乙: 第一个?
甲: 刘备卖过草鞋。
乙: 不错,织席贩履嘛!第二个?
甲: 张飞卖肉。
乙: 对,屠户出身嘛。第三个?
甲: 你没听明白吗?刘备卖草鞋。
乙: 唉!我问你第三个?
甲: 啊!是啊!张飞卖肉。
乙: 哎!你等一等。第一个是刘备卖草鞋,第二个是张飞卖肉,这第三个哪?
甲: 啊,有啊,你别着急呀!
乙: 第三个?
甲: 第三个……哎,赵云……
乙: 赵云卖什么呀?
甲: 赵云卖年糕嘛!
乙: 赵云多会儿卖年糕?
甲: 你看过《天水关》这出戏吗?
乙: 看过呀!
甲: 《天水关》这出戏,姜维在校场一传令,那几句(流水板),就把赵云卖年糕给唱出来啦。
乙: 怎么唱的?
甲: (唱)“这一班五虎将俱都丧了,只剩下赵子龙老迈(卖)年(年)高(糕)。”他老卖年糕!
乙: 去你的吧!

June 02

诡异!

前段时间台式机出毛病了,偶尔跑着跑着就死机,死机的症状一般是硬盘灯持续亮着,然后就蓝屏。开始以为中毒了或者中木马了,杀了一回没见着。后来逐渐感觉到是进行比较大的硬盘操作时死机的概率大些,比如复制一电影等,便怀疑杀软的监视文件的功能有问题,于是卸掉卡巴裸奔,情况果然好些,但仍然会死。接着怀疑是硬盘文件系统坏了,用CHKDSK能查出几个问题,也能修复,但下回仍旧会死机。于是凄凉地怀疑硬盘可能坏了,只有凑合着继续用。终于有一次死机后Windows少了n多系统文件,CHKDSK也找不回来了,只有重装系统。重装后好了很多,但陆续装上一堆应用软件后,死机的概率越来越大,总怀疑有木马病毒,用IceSword查内核,有几个挂接NTDLL的,是DaemonTool虚拟光驱与360安全卫士。尝试着卸掉360再裸奔,果然几天不死机了,以为找到了原因,沾沾自喜的同时还很专业地抱怨360的内核驱动兼容性差。岂料过几天又开始死了,晕!再卸掉DaemonTool,又安静了几天,这回不敢乱抱怨了,还是静观其变为好。果然过了几天老毛病又开始犯,而且越来越厉害,大有又要重装之势。幸亏上回刚重装好一堆东西比较稳定时做了一个几个G的Ghost,花十几分钟恢复回来也不太费事。一恢复又好些,但跑着跑着又有老毛病重犯的趋势,又猜可能天热了CPU过热引发死机,下了个CPU COOL,看温度也不过20多度,不像,不过为保险起见还是拆开机箱拿风扇吹,但仍旧无效。快抓狂时在敞开的机箱里瞎捣腾,发现主板的串口硬盘线略有松动,难道是它???于是插紧了一下,重启,没死机;等了等,还没死;折腾折腾,仍然不死;陆续玩了半个月了,死机蓝屏的迹象一次都没复现。神啊,老子以后要是被查出有啥神经方面的毛病,就是这个硬盘线插头折腾的!
May 23

转贴韩寒的一段话

转贴。
“另外,我还想继续说一个事情,我依然坚持我的向有关部门捐款为0,这是我个人的选择。我也依然非常反对逼捐和搞捐款的排名,很多人在背后冷言冷语,有些个人和公司出于善心,追加了捐款,那些人就自以为是自己的功劳,并把这些钱下意识记在自己的账上。他们都是道德的小人,自己制定道德的准绳。在大家都忙着做善事没空的时候,他们闲着,指指点点,我朋友说,他发现这些人都喜欢重复发言,反复变换马甲,在各个地方说一样的风凉话,足以见得他们是闲到一种什么样的程度。他们体力和脑力都非常充沛活跃,网监部门应该把他们登记在案,以后有灾难的时候派他们上场。
前一阵子盛传的肯德基没捐款,麦当劳没捐款,我当时就和朋友说,首先,他们如果没捐款,也不应该受到指责,这是他们的权利,其次,肯德基可能是以百胜的名义捐的。因为这些我么熟知的国际快餐都属于百胜集团。事实证明,的确是以百胜集团的名义捐款了一千多万,而麦当劳也是。但是,一些丐帮人员居然在某一个城市,去肯德基麦当劳门前闹事,这才是添乱和丢脸。
一旦捐款变味,会让做善事者心里很不舒服。比如这次地震,第一批捐款的人应该是最积极的,但到最后,他们都会因为数额少而被人骂。很多人也会借机对自己不喜欢的人传播谣言,这些都是对好心人的打击。
做善事者,内心一定要得到宽慰,如果做了善事还要备受一些什么都没做的人的指责,好人会越来越少,做事会越来越谨慎。”
May 15

地震

川汶一震罢,烽烟满地愁。
丹景成绝景,泥流伴石流。
天道无刍狗,人伦有方舟。
勉尽些微事,来日祭荒丘。

April 25

Sparc 平台上的 FlexLM 7.0 用户滤波函数分析

Sparc 平台上的 FlexLM 7.0 用户滤波函数分析
 
作为一个比较老旧的保护工具,FlexLM的初级保护已经被分析的差不多了,默认情况下内存中能截到明文的签名,这点很多高手的文章中都有提到。但俺近日在分析一款SunOS Sparc平台下的FlexLM 7.0时遇上了 user_crypt_filter 机制,这种机制会对签名加以变形运算,导致内存中不会出现明文,给破解的捕获增加了一些难度。后来参考Nolan Blender大牛的文章,总算破掉了这个用户滤波函数的保护,在此写出来总结一下供有相同需要的朋友参考与讨论。
本文没有提到到具体的软件名称,也不涉及到Feature、Vendor与版本号的跟踪捕获,甚至也和抓取VendorKey和加密种子等没有关系。另外Sparc平台的汇编可能大伙都不熟悉,这儿尽量多加以解释。
工具:DDD+GDB、IDA
 
一、按传统方法定位明文比较处。
 
参考laoqian的《制作Flexlm license总结》的文章,以及laowanghai的《LabWindows CVI 8.0》中列出来的详尽x86汇编代码,通过在IDA中搜索常数66D8B337,可以定位到几个地方。以下是laowanghai的《LabWindows CVI 8.0》文章中列出的部分x86的代码供参考:
 
105C9CDB      894D F4                    mov dword ptr ss:[ebp-C],ecx
105C9CDE    ^ E9 EEFAFFFF                jmp CVI_1.105C97D1
105C9CE3      817D 18 37B3D866           cmp dword ptr ss:[ebp+18],66D8B337
105C9CEA      0F85 96000000              jnz CVI_1.105C9D86
105C9CF0      33D2                       xor edx,edx
……
105C9D86      C785 78FEFFFF 08000000     mov dword ptr ss:[ebp-188],8
105C9D90      817D 18 37B3D866           cmp dword ptr ss:[ebp+18],66D8B337
105C9D97      75 0F                      jnz short CVI_1.105C9DA8
……
105C9EB0      8B95 30FEFFFF              mov edx,dword ptr ss:[ebp-1D0]
105C9EB6      81E2 FF000000              and edx,0FF
105C9EBC      8B85 7CFEFFFF              mov eax,dword ptr ss:[ebp-184]
105C9EC2      33C9                       xor ecx,ecx
105C9EC4      8A88 98358A10              mov cl,byte ptr ds:[eax+108A3598]
105C9ECA      3BD1                       cmp edx,ecx                     ; 与正确SIGN逐字节的比较
 
这里,比较之处前面一个and edx,0FF比较的显目,可以作为一个小标志。
类似的,在我们对付的SPARC平台下的软件,其比较代码也类似:
 
 loc_3515CC:                             ! CODE XREF: sub_3508E4+6B0j
.text:003515CC                                         ! sub_3508E4+CE0j
.text:003515CC                 ld      [%fp+arg_54], %o5
.text:003515D0                 set     0x66D8B337, %o7 ! 绝对是这儿的常数
.text:003515D8                 cmp     %o5, %o7
.text:003515DC                 be      loc_3515EC
.text:003515E0                 nop
……
 loc_351684:                             ! CODE XREF: sub_3508E4+D00j
.text:00351684                 mov     8, %o7          ! 也是这儿的常数
.text:00351688                 st      %o7, [%fp+var_8]
.text:0035168C                 ld      [%fp+arg_54], %l0
.text:00351690                 set     0x66D8B337, %l1
.text:00351698                 cmp     %l0, %l1
.text:0035169C                 be      loc_3516AC
.text:003516A0                 nop
……
.text:003517F8 loc_3517F8:                             ! CODE XREF: sub_3508E4+EE0j
.text:003517F8                 ld      [%fp+var_4_idx], %o3
.text:003517FC                 set     byte_4DD515, %o4
.text:00351804                 ldub    [%o3+%o4], %o5  ! ldub取一位字节,相当于同时做了上面的and 0xff了
.text:00351808                 ldub    [%fp+var_180_oursign+3], %o7
.text:0035180C                 cmp     %o7, %o5        ! 是这儿的比较
.text:00351810                 bne     loc_351820
.text:00351814                 nop
.text:00351814
 
由x86与Sparc的汇编代码对比可以看出,.text:0035180C处确实是我们传入的伪造签名值(我传的是1234567890AB)与正确签名值的比较之处,byte_4DD515这个地址所指的一片内存区域,应该是我们需要的正确签名。于是在0035180C处下断,第一次来到此处时查看0x4DD515地址的内容,得到六个字节EEB53723B248。想当然地拿它放到license文件里头一试,很不幸,通不过。
于是开始了摸索,在0035180C之前下断,逐步来,发现0035180C之前有一处很关键的代码:
 
.text:003517CC loc_3517CC:                             ! CODE XREF: sub_3508E4+ED8j
.text:003517CC                 ld      [%fp+arg_44_job], %o0
.text:003517D0                 ld      [%o0+0x234], %g1 ! Job偏移234处是啥?原来是user_crypt_filter函数地址。
.text:003517D4                 ld      [%fp+var_4_idx], %o1
.text:003517D8                 set     byte_4DD515, %o2
.text:003517E0                 add     %o1, %o2, %o1   ! char*,指向正确的未filter的内容
.text:003517E4                 ldub    [%fp+var_180_oursign+3], %o3 ! 我们的sign的字符
.text:003517E8                 ld      [%fp+arg_44_job], %o0 ! Job!
.text:003517EC                 ld      [%fp+var_4_idx], %o2 ! Index?
.text:003517F0                 call    %g1             ! 3323a0,user_crypt_filter,结果放在o1指的内容
.text:003517F4                 nop
 
那个call %g1是对解出的明文密码进行的一次变换。刚才抓到的六个字节EEB53723B248,其中EE是已经经过了第一次变换的结果,变换出来的结果和我们传入的伪造签名的第一个字节12不一致,因此出错。如果在003517F0之前下断查看byte_4DD515的内容,则可得到未经变换的第一个字节值。抓出的初始的正确签名值是C1B53723B248,但如果拿这个签名值去license文件里头试的话仍然通不过,因为这串签名值还会经过一次变换,这个变换便是臭名昭著的user_crypt_filter:用户滤波函数。
 
二、分析用户滤波函数
 
查FlexLM的资料得知,user_crypt_filter是对签名字符进行的进一步可逆变换机制,包括生成时的user_crypt_filter解码函数和user_crypt_filter_gen编码函数。我们的任务,是根据user_crypt_filter函数的实现,反推出user_crypt_filter_gen函数来。
从代码中以及从大牛们的破解资料中可得知,user_crypt_filter 附近的调用机制基本上是:
 
for (i = 0; i < j; i++) /* compare user-input and real checksums */
{
  ......
  if (user_crypt_filter)
    (*user_crypt_filter)(job, &x, i, y[i]); // 使用了滤波函数进行进一步的对比!
   
  if (x != y[i])
    return 0;
}
 
而网上查到的很多中文文章中的FlexLM都是没用user_crypt_filter的,也就是user_crypt_filter为false而跳过(*user_crypt_filter)指针所指函数的变换,因此下面的x != y[i]便是正确签名字符与我们输入的伪造签名字符的明文比较。而我们碰到的情况是会调用user_crypt_filter的函数的。
 
user_crypt_filter 的函数原型为:
user_crypt_filter(job, char* KeySign, int index, char OurChar);
 
其中job在函数体内基本无用。KeySign为传入的未变换的签名的地址(下面称为原始签名),index为此字符在密文中的位置,如签名为1234567890AB,则12的index为0,34的为1,以此类推。
 
user_crypt_filter是逐个处理字符的,它根据未变换的原始签名字符、此字符的位置、以及我们传入的伪造签名字符进行一系列的运算返回一个字符,这个字符必须等于我们传入的伪造签名字符。这么说可能有点绕,换种说法就是:未变换的原始签名字符、此字符的位置、以及变换后的签名字符三者必须符合一定的运算法则,user_crypt_filter函数拿我们传入的伪造签名字符作为验证来和原始签名字符参与运算,如果运算通过,则表示伪造的签名字符是正确的变换后的签名字符,那么就将此正确的签名字符返回供上层代码(x != y[i])比较,其实此时已经无需比较了。
 
可以看出,user_crypt_filter函数中不会出现我们需要的正确签名字符,只有当我们传入的伪造签名字符等于正确签名字符时才会验证通过,才会返回正确签名字符。下面我们要搞清楚的是user_crypt_filter函数究竟对未变换的原始签名字符、此字符的位置、以及我们传入的伪造签名字符三者进行了怎样的变换,从而努力反推出来如何根据未变换的原始签名字符以及此字符的位置计算正确的签名字符。
 
user_crypt_filter函数非常长,从.text:003323A0 到.text:003374B8,反汇编代码有七千多行,很是吓人。不过经过大致浏览,可以看出它是根据传入的Idx的范围0到19有比较重复的20大段代码,20大段里头每大段会对字符进行异或并对其8位进行处理,共20加160处变换,搞明白了它做啥就好办了。
 
首先是将传入的字符异或,比如我们传入的Idx是0的话:
 
.text:003324E0                 ld      [$XADqrkBrM9j3y7__num0], %l0
.text:003324E4                 cmp     %l1, %l0
.text:003324E8                 bne     loc_332504
.text:003324EC                 nop
.text:003324EC
.text:003324F0                 ldub    [%fp+var_2_GoodChar_xor], %l2
.text:003324F4                 sethi   %hi(unk_496800), %l0
.text:003324F8                 ldub    [$XADqrkBrM9j3y7__x_0], %l1 !
// 取出num0对应的某常量值(x_0)和GoodChar一异或,存入局部变量 GoodChar_Xor。
.text:003324FC                 xor     %l2, %l1, %l0
.text:00332500                 stb     %l0, [%fp+var_2_GoodChar_xor]
根据传入的Idx的不同,将未变换的原始签名字符和某一值进行异或,得到临时变量GoodChar_xor。
然后启用另外一个Char变量,这里命名为TmpChar,用来挨个检查GoodChar_xor的位,比如这儿是检查其中一位:
 loc_332740:                             ! CODE XREF: user_crypt_filter+384j
.text:00332740                 ld      [%fp+arg_4C_Idx], %l1
.text:00332744                 sethi   %hi(unk_496800), %l0
.text:00332748                 ld      [$XADqrkBrM9j3y7__num8], %l0
.text:0033274C                 cmp     %l1, %l0
.text:00332750                 bne     loc_3327BC // 如果此字符的index是8,那么检查
.text:00332754                 nop
.text:00332754
.text:00332758                 ldub    [%fp+var_2_GoodChar_xor], %l2
.text:0033275C                 sethi   %hi(unk_496800), %l0
.text:00332760                 ld      [$XADqrkBrM9j3y7__bit3], %l1
.text:00332764                 andcc   %l2, %l1, %l0
.text:00332768                 be      loc_332784  // 如果异或后的字符的bit3位是1 则执行下面的,
.text:0033276C                 nop
.text:0033276C
.text:00332770                 ldub    [%fp+var_1_TmpChar], %l2
.text:00332774                 sethi   %hi(unk_496800), %l0
.text:00332778                 ld      [$XADqrkBrM9j3y7__bit4], %l1 
// 如果异或后的字符的bit3位是1,则将临时变量TmpChar的bit4置为1,
.text:0033277C                 or      %l2, %l1, %l0
.text:00332780                 stb     %l0, [%fp+var_1_TmpChar]
.text:00332780
.text:00332784
.text:00332784 loc_332784:                             ! CODE XREF: user_crypt_filter+3C8j
.text:00332784                 ldub    [%fp+var_1_TmpChar], %l1
.text:00332788                 sethi   %hi(unk_496800), %l0
.text:0033278C                 ld      [$XADqrkBrM9j3y7__bit4], %l2
.text:00332790                 and     %l1, %l2, %l1
.text:00332794                 ldub    [%fp+var_3_OurChar], %l0
.text:00332798                 and     %l0, %l2, %l0
.text:0033279C                 cmp     %l1, %l0
.text:003327A0                 be      loc_3327BC // 然后检查我们伪造的签名字符的bit4,和TmpChar的bit4是否相同。
.text:003327A4                 nop
.text:003327A4
.text:003327A8                 ld      [%fp+arg_48_charX], %l1
.text:003327AC                 ldsb    [%l1], %l0
.text:003327B0                 btog    -0x3E, %l0 // 在俩bit不同的情况下,返回垃圾值3E
.text:003327B4                 ba      locret_3374B8
.text:003327B8                 stb     %l0, [%l1]
.text:003327B8
 
以上是对Index为8时的未签名字符bit3位的判断检查过程:如果GoodChar_xor的bit3是1,则TmpChar的bit4也置一,因为TmpChar原始为0,因此bit4原始也为0,所以这一步就是把GoodChar_xor的bit3搬移到了TmpChar的bit4上。
然后TmpChar的bit4和我们传入的伪造签名字符OurChar的bit4进行比较,相同的话这位检查通过,继续检查下一位,否则返回一个垃圾值-0x3E用以迷惑俺们。总的来说,这步就是检查异或后的GoodChar_xor的bit3是否等于伪造签名字符的bit4,等的话才通过。
参考Nolan Blender的文章,这里检查一个bit的过程用C代码描述如下(这里是index为0时检查GoodChar_xor的bit2与TmpChar的bit5是否相等的情况):
 
if (idx == num0)
{
  if (GoodChar_xor & bit2) TmpChar |= bit5;
  // 如果inc_c的2置位,那么把另外一个C的5置位,相当于2位换到5位去
  if ((TmpChar & bit5) != (OurChar & bit5)) { *KeySign = 0xxx; return; // 不等则返回垃圾}
  // 其实就是GoodChar_xor的bit2要和输入签名字符的bit5相等。
}
 
以下还有很多类似的检验,对于每一个index,都要检查GoodChar_xor的8个bit和OurChar的8个bit是否相同,但这8个bit并不是顺序上一一对应,而是乱序(permute)了。比如GoodChar_xor的bit0应该等于OurChar的bit3、GoodChar_xor的bit2必须等于OurChar的bit7,等等。
 
由此可知,只要将GoodChar_xor按user_crypt_filter中特定的index处所指明的bit置换规则,把各个bit换一下,则可得到解密后的明文签名字符。这也就是说,如果我们在代码中找到了针对一个index的字符的八条位置换规则,如GoodChar_xor的bit0应该等于OurChar的bit3、GoodChar_xor的bit2应该等于OurChar的bit7等共八条,那么我们只要新起一个变量TmpChar,将GoodChar_xor的bit0放到变量TmpChar的bit3,GoodChar_xor的bit2换到TmpChar的bit7,换过8个bit后,这个TmpChar的每一位必然等于解密后的明文签名字符OurChar。这就是user_crypt_filter检查运算的逆运算!
 
三、编写逆运算程序
 
逆运算分析出来了,就可以写还原程序了。
这儿参考了Nolan Blender的思想,将0到19个index,每个index所对应的8位bit置换规则写成一个大数组,共一百六十项,从七千多行汇编代码中整理出来相当费力,但所幸只是体力活儿。而且如果是短的签名的话,只要搜集0到5的index所对应的四十八条bit置换规则即可。
 
以下代码用Delphi实现:
 
type
  TShiftVals = array[0..7] of Integer;
  TPermute = packed record
    shiftvals: TShiftVals;
  end;
 
PerTab: array[0..19] of TPermute = // 搜集得到的位置换规则数组
(           // BIT  0 1 2 3 4 5 6 7
       (shiftvals: (0,4,5,3,1,2,6,7)), // idx 00 //
       (shiftvals: (4,0,5,2,1,3,6,7)), // idx 01 //
       (shiftvals: (7,1,3,4,0,5,2,6)), // idx 02 //
       (shiftvals: (4,7,3,6,1,5,2,0)), // idx 03 //
       (shiftvals: (0,3,7,4,2,5,6,1)), // idx 04 //
       (shiftvals: (4,3,5,6,7,0,1,2)), // idx 05 //
       (shiftvals: (2,7,4,0,6,5,3,1)), // idx 06 //
       (shiftvals: (4,5,1,7,0,3,6,2)), // idx 07 //
       (shiftvals: (1,0,5,4,3,6,7,2)), // idx 08 //
       (shiftvals: (2,7,5,3,0,6,1,4)), // idx 09 //
       (shiftvals: (3,5,7,0,6,4,2,1)), // idx 10 //
       (shiftvals: (7,6,5,0,4,3,2,1)), // idx 11 //
       (shiftvals: (3,4,5,6,0,2,1,7)), // idx 12 //
       (shiftvals: (0,4,6,3,5,2,1,7)), // idx 13 //
       (shiftvals: (1,5,0,2,6,3,4,7)), // idx 14 //
       (shiftvals: (2,6,5,7,4,3,1,0)), // idx 15 //
       (shiftvals: (2,3,0,5,1,7,6,4)), // idx 16 //
       (shiftvals: (1,7,4,2,3,0,6,5)), // idx 17 //
       (shiftvals: (1,5,2,3,4,7,6,0)), // idx 18 //
       (shiftvals: (3,0,6,7,4,5,2,1))  // idx 19 //
);
 
如 (shiftvals: (0,4,5,3,1,2,6,7)), // idx 00 //,表示对于index为0的字符,其bit0位置换到bit0位(两位可以相同),bit1置换到bit4,bit2置换到bit5,等等以此类推。
 
另外还有一次异或,此异或的数字也是常数,根据index不同而不同,是上文代码中的x_0等形式的变量。总结得出一个异或数组:
 
var
  xorvals: array[0..19] of Integer =
  (
    $1E, $16, $3E, $24,
    $04, $1E, $1E, $13,
    $15, $0C, $2D, $33,
    $3D, $21, $26, $2E,
    $12, $34, $01, $2B
  );
 
然后写一个解密函数与bit置换函数(参考了:Nolan Blender的思想)
 
// 传入计算来的原始的签名字符与位置,返回变换后的正确签名字符
function user_crypt_filter_gen(inchar: Char; idx: Integer): Char;
var
  tmpchr: Char;
begin
  tmpchr := Chr(Ord(inchar) xor xorvals[idx]); // 先异或还原
  Result := Permute(tmpchr, PerTab[idx].shiftvals); // 再置换位置
end;
 
// 将传入字符按大数组表内的规则进行置换位置
function permute(inchar: Char; shiftvals: TShiftVals): Char;
var
  outval: Integer;
  i: Integer;
  shbit: Integer; // Test bit */
begin
  outval := 0;
  shbit := 1;
  for i := 0 to 7 do
  begin
    if ((Ord(inchar) and shbit) <> 0) then
    begin
      outval := outval or (1 shl (shiftvals[i]));
    end;
    shbit := shbit shl 1;
  end;
  Result := Chr(outval and $FF);
end;
 
然后,利用上面两个写好的函数对抓出的未变换签名值C1B53723B248进行运算:
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit1.Text := IntToHex(Ord(user_crypt_filter_gen(#$C1, 0)), 2)+
    IntToHex(Ord(user_crypt_filter_gen(#$B5, 1)), 2) +
    IntToHex(Ord(user_crypt_filter_gen(#$37, 2)), 2) +
    IntToHex(Ord(user_crypt_filter_gen(#$23, 3)), 2) +
    IntToHex(Ord(user_crypt_filter_gen(#$B2, 4)), 2) +
    IntToHex(Ord(user_crypt_filter_gen(#$48, 5)), 2);
end;
 
运行程序后,Edit1.Text中得到生成的正确签名值FB999098AEAA。拿这串签名填入license文件中,测试通过。
 
再次跟踪user_crypt_filter可知,比如对index为0的情况,传入原始字符C1与index 0,C1与1E异或后的值经过八次位置换得到FB,和我们传入的FB相等,因此通过,返回FB(只要有一位不等,就会返回垃圾值,外部的比较必然通不过)。user_crypt_filter外部再用返回的FB与我们传入的FB比较,自然相等,也就通过了。
 
四、总结
 
user_crypt_filter的核心是字符的位置换规则,需要通篇阅读代码以总结出一百六十个位置换规则来,这一点比较的耗体力并且不能出错,否则通不过的情况下再次调试就需要跟入七千多行的user_crypt_filter以找到出错点,这体力耗费的就不是总结位置换规则所能比的了。俺在总结过程中还好没在位置换规则中出错,但搞错了一位xorvals中的异或值,事后查起来也耗了一点力气,等到所幸最后还是找出来的时候已经快累趴下了。
 
参考资料:
http://www.woodmann.com/crackz/Tutorials/Nbufilt.htm
laoqian的《制作Flexlm license总结》的文章
laowanghai的《LabWindows CVI 8.0》
其他看雪论坛的精华文章
http://www-curri.u-strasbg.fr/documentation/calcul/doc/ProPack/3SP1/docs/doc/lmsgi-9.2.3/flexref/chap21.htm
April 23

骂一通无知的粪青和无耻的冷漠者

 
最近网络不平静的很,垃圾消息充斥着QQ与MSN,一群群粪青的本性在垃圾中暴露无遗:冲动、无知、排异、意淫。喊抵制是弱者的叫嚣,比弱者的叫嚣更可悲的是认识不到自己是弱者。敏感的自尊受了刺激却又找不到藏独分子出气,于是拿一家本地化已经相当严重的超市开刀,且不说打砸抢的提议本身就可笑,即使有那么一批稍许清醒的人提倡静静的抵制,这种提议也被淹没在积极购物不付款等损毁性的馊主意中。随着恶意降临的还有无知与意淫,什么捏造的令人呕吐的李白的诗,什么法国政府拨款二千万美金,无数缺乏起码思考能力的粪青们被利用了还不自知,还在积极无偿地宣传家乐福的五一促销活动。更无知的还有老一套的网站攻击,先是南联盟时期发动网民Ping美国,再是现在发动网民刷新CNN网站,中国那点儿可怜的出口带宽被挤得一塌糊涂,只平白无故替对手增加了访问量,没准其Alexa排名还会因此上升。——我们的网民啊,我们的年轻人啊,我们什么时候才能冷静一点地思考?有些人MSN/QQ好友栏里头明明没一个外国人,却叫嚣着改昵称改头像让全世界看华人的团结?中国在世界上的地位很低四处是敌,要获得敌人的尊重比从敌人处得到嘲弄和蔑视难得多。现在的闹剧,你们以为得到的是什么?一盘散沙是粪青的最大特征,从来没法凝聚起来做实事,从来以为一时的口眼之快就是爱国。中国这位母亲需要的是每一个位儿女的踏实奉献,而不是粉墨登场地——事实上,登场的档次根本算不上,除非真去打砸抢——出演让国内外都感到可笑的闹剧。一边体育不要和政治挂钩,一边经济和政治又在挂钩,中国是美国国债的第二大股东,中东地区有没闹着抵制俺们的加班中兴与跳楼华为?如果你说抵制日货是习惯没法改了,那么以前为抵制日货而买美法等货的人怎么现在也成了粪青的眼中钉人中奸?和自己的切身利益无关的人容易跟着瞎起哄,起哄完毕一转身继续屁颠屁颠地照样吃吃买买地亲美亲法,这就是俺们的抵制?
 
第二类该骂的是那些貌似冷静实则冷漠的无耻者。国家不关你的事,民族不关你的事,奥运不关你的事,就钱关你的事。如果您是低保户无法糊口,这种现象俺能理解,可你丫还不是装白领上班上网玩MSN?你可以问国家民族是什么,可以问如果是一块面包它有多大,也可以问如果是一件衣服它有多暖和,更可以问如果是一间房子能不能为我们挡住风雨,但你又是什么?你是游荡的无业民?你是吃喝的啃老族?还是说你是只会索取不会奉献的寄生虫?一个国家不能只靠雇佣军战斗,一个青年也不能只靠冷漠来活着。别告诉你丫不想做青年,五四歇半天丫还不是屁颠屁颠地羡慕得捶胸顿足?死水一样的冷漠者和洪水一样的粪青同样可恶,后者是无知,前者则是无耻。不是一般的无耻,还是很黄很暴力很傻很天真很不和谐的无耻!
 
骂完了,该干啥还干啥。请随便对号入座来着。
April 16

早晨路上联诗

笑死俺了,原来室友们都这么有才:
 
上海四月雨茫茫,
吃喝嫖赌诸事忙。
三把小伞上班去,
到了路上变色狼。
牛仔包臀弹性好,
黑发披肩瀑布长。
两只手套玩细腻,
一根宽粉笑疯狂。
April 02

迎风喝豆花的恶果

近日早餐比较喜欢吃摊韭菜煎蛋饼与咸豆腐花,时常伙同俩室友晚起坐在那儿饕餮而不管是否迟到。只是卖豆花的老板不知道没钱租场地了还是怎么的,原先的店面愣是锁着空着,只在外头路边摆下一长条木桌供人挤坐着匆忙地吃。这天一早风很大,照例俺们仨挤在桌子角边,吃得差不多时,对面的一女的没吃完就不厚道的起身离开,那挡风的身板一走,她没喝完的豆花碗被风一吹哗啦就朝这边盖过来洒了俺们一腿,我靠!悻悻然地放下餐具找纸来擦,刚放下,室友自己没喝完的豆花碗被风一吹哗啦又朝这边盖过来又洒了俺们一身!我靠!俺们赶紧站起身来胡乱擦,这时,第三个俺的没喝完的豆花碗被风一吹哗啦啦地又盖了过来……
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 的开发帮助:
 
这个对破解很有作用。
 
先恶补一下基础知识:
 
一、Sparc 平台的寄存器架构与汇编规则
 
Sparc 的 CPU 有很多寄存器,但针对任一进程的任一时刻来说只开放 32 个,以寄存器窗口的方式切换。一般它的寄存器可命名为 r0 到 r31,但一般以其别名来命名,如下:
1. 全局寄存器(8个) -对所有程序可见。命名为 %g0 ~ %g7 = %r0 ~ %r7
2. 输出寄存器(8个) -函数返回值,输出寄存器是下一个窗口的输入寄存器。命名为 %o0 ~ %o7,等同于 %r8 ~ %r15
3. 局部寄存器(8个) -仅本函数可见。命名为 %l0 ~ %l7,等同于 %r16 ~ %r23
4. 输入寄存器(8个) -本函数的输入参数,来自于上一窗口的输出寄存器。命名为 %i0 ~ %i7,等同于 %r24 ~ %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 命令有以下:
 
b main
b *0x27aaa
在某命名函数处或在某地址处设置断点。
 
bt
查看此刻的调用堆栈。
 
info reg o0
查看某寄存器值,如果只敲 info reg,则打印所有寄存器值。
 
stepi/nexti
单步执行机器代码。注意不是 step/next,后者是单步执行源码。
 
disable 1
禁用第一个断点。如只敲 disable 则禁用所有断点。
 
enable 1
使能第一个断点。如只敲 enable 则使能所有断点。
 
x /8xb 0x45678
从地址 0x45678 处开始查看 8 个 byte,以 HEx 的方式显示。
 
x /s $o1
查看 o1 寄存器内容所指内存处的内容,以字符串方式显示。
 
set $o1=0
将寄存器 o1 值设置为 0。
 
r、c、k
这三个命令的功能分别为:运行被调试程序、中断后继续运行、中止被调试程序。
三、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 的解密文章,l