2009年6月27日星期六

FLEXLM9.5该洗洗睡了吧---200水帖纪念

FLEXLM9.5该洗洗睡了吧---200水帖纪念

【郑重声明】:本文纯属技术交流,无其他目的。 请勿用于商业或其他非法用途,否则后果自负。转载需征得看雪论坛同意。
【软件名称】:Imaris 4.16版本,官方网站有DOWN。
【下载页面】:http://www1.skycn.com/soft/20059.html
【软件简介】:Flexlm9.5保护,医学用(汗,我不懂-:))
【调试环境】:XP、OLLYICE、PEID0.93、calcseed.exe、lmcryptgui.exe、SIG文件
不会写破文,发了199个水帖,一直潜水不敢再发。据说200帖就可以成为中级了,我汗---我这么菜水平的都成中级?细想一下,我想看雪上的级别资格更多的是给那些有所奉献的朋友吧,不完全代表水平,于是菜鸟我心释然。
论坛上有很多值得我尊敬的人:看雪、fly、一二三水(哈哈)、laoqian等,无私奉献技术,指导菜鸟提高。当然,我在学习FLEXLM的时候,请教时也曾遇到有人索要RMB的问题(至今心里忿然BS)。学CRACK仅仅是我的兴趣而非职业,是想了解别人的思想,因此绝不会靠CRACK去谋取一分钱,这也不是我学习的目的。
受大水写了第500帖纪念的启发,于是发第200水帖纪念,希望大锅们不要扁我哈。论坛上有很多水牛,发了那么多帖子,按说水平也该很高了,希望大家也能在整百帖的时候发帖纪念一下,总结一下自己的经验,共同提高!
转入正题:本文是学习CRACKZ的文章《FLEXlm latest information by CrackZ》后总结的。同样的软件,版本不同。

一、信息收集

1、-8,著名标志,许可证密码错误(0xFFFFFFF8 如果爆破的话,有用)
2、-5,著名标志,FEATURE名称错误
3、-2,许可证语法错误
4、验证逻辑:
如果许可证里面给的种子不对,做出的许可证即使过期了,也会提示-8错误,表示许可证密码无效。这说明是先进行种子参与的密码运算,接着进行密码验证;而后,才是进行日期检查。
如果给出的种子对了,而日期过期了,则会提示-10,表示FEATUER到期;也说明先进行密码检查,后进行日期检查。哈哈。
5、使用假的许可证,启动后出现提示-8提示,表示密码不正确
6、通过分析,比较容易发现VENDOR DAEMON是哪个可执行程序。
7、对于多进程情况,直接调试主干程序;如果调试创建进程的程序,则可能不中断,因为新进程在附加前已经完成了许可证检查
8、认真读看雪大锅的书,学习FLEXLM的基本知识。另外CRACKZ上也有不少好文章。

二、制作一个假的许可证FAKE.LIC

FEATURE feature_name vendor_name 1.000 permanent uncounted 123456654321\
HOSTID=ANY SIGN=123456789123
格式一定要正确。如果用lmcryptgui.exe检查许可证时提示格式错误,它会自动校正;将前面的错误信息删除,再检查一次,则会成功。

三、确定VEDNDOR NAME

目的:确定VENDOR NAME
方法:搜索字符串"DEMO",其前面的je跳转处会出现VENDOR NAME名称。(其实程序中多处出现,该步可略去)

006CE285 |. 05 0C030000 add eax, 30C
006CE28A |. 85C0 test eax, eax
006CE28C |. 74 2B je short 006CE2B9
确定VENDOR=bitplane
006CE28E |. B9 B8A28E00 mov ecx, 008EA2B8 ;
ASCII "demo"
006CE293 |. 85C9 test ecx, ecx
006CE295 |. 74 22 je short 006CE2B9
006CE297 |. 68 C0A28E00 push 008EA2C0 ;
/s2 = "demo"
006CE29C |. 8B95 6CFDFFFF mov edx, [ebp-294] ; |
006CE2A2 |. 81C2 0C030000 add edx, 30C ; |

四、定位_l_init()函数

函数目的:定位_l_init()函数可确定_l_sg函数,确定VENDOR NAME
方法:查找默认的种子0x12345678 & 0x87654321 可以确定_l_init() 函数

该函数调用时堆栈出现正确的VENDOR NAME;
006CE309 |. 51 push ecx ; |Arg2
006CE30A |. 8B95 6CFDFFFF mov edx, [ebp-294] ; |
006CE310 |. 52 push edx ;
|lc_init函数
006CE311 |. E8 453DFFFF call 006C205B ;
\调用_l_sg函数,F7跟进
006CE316 |. 83C4 0C add esp, 0C
006CE319 |. 81BD 84FDFFFF>cmp dword ptr [ebp-27C], 87654321 ;
默认的种子1,定位标志1
006CE323 |. 74 0C je short 006CE331
006CE325 |. 81BD 88FDFFFF>cmp dword ptr [ebp-278], 12345678 ;
默认的种子2,定位标志2
006CE32F |. 75 5D jnz short 006CE38E
006CE331 |> 8B85 6CFDFFFF mov eax, [ebp-294]
注意调用_l_sg函数完毕后不会填入正确的种子,因为在_l_sg函数中会提前跳转

五、定位_lc_checkout()函数以及对其的调用处

目的:确定FEATURE和产品版本号(不是FLEXLM的版本号)
方法:在字符串参考中查找'lm_ckout.c';总共也就出现几次,比较容易确定。一般是挨着的两个才是;另外有四个挨着的不是。
定位_lc_checkout()函数比较容易,可以执行到其返回,再F8,就可以确定主程序中对它的调用处。(直接查找可能有多处,运行一次找到)006BE4C0
/$ 55 push ebp
1、定位_lc_checkout函数
006BE4E8 |. 8990 FC030000 mov [eax+3FC], edx
006BE4EE |. 68 95000000 push 95 ;
/Arg3 = 00000095
006BE4F3 |. 68 8C9B8E00 push 008E9B8C ; |Arg2
= 008E9B8C ASCII "lm_ckout.c",确定标志1,
//堆栈和寄存器出现FEATURE
006BE4F8 |. 8B4D 08 mov ecx, [ebp+8] ; |
。。。。。
006BE543 |. E8 B3000000 call 006BE5FB ;
\堆栈出现产品版本和FEATUER名称
。。。。。
006BE5A6 |. E8 50000000 call 006BE5FB ;
\如果许可证密码错误,这里会间接调用_l_sg函数
(跟进发现有对l_valid_version 验证版本;lc_check_key 调用_l_sg函数等函数的调用)
(!!!注意:在这里初次不会调用该CALL。慢慢来,呵呵。我们在该函数里能得到FEATURE和版本号就足够了!)
。。。。。
006BE5DE |. 68 A6000000 push 0A6 ;
/Arg3 = 000000A6
006BE5E3 |. 68 989B8E00 push 008E9B98 ;
|Arg2 = 008E9B98 ASCII "lm_ckout.c 确定标志2
006BE5E8 |. 8B55 08 mov edx, [ebp+8] ; |
2、定位对其的调用
0041E785 . 51 push ecx
0041E786 . 53 push ebx
0041E787 . 52 push edx
0041E788 . E8 33FD2900 call 006BE4C0 ;
调用_l_checkout
0041E78D . 8BE8 mov ebp, eax ; |
0041E78F . 8B46 2C mov eax, [esi+2C] ; |
0041E792 . 53 push ebx ; |Arg2
0041E793 . 50 push eax ; |Arg1
0041E794 . E8 BDEC2900 call <_lc_hostid 009E:_l_hostid> ;
\堆栈出现产品版本号与FEATURE
0041E799 . 8B4E 08 mov ecx, [esi+8]
0041E79C . 83C4 24 add esp, 24
记录前面的版本号和FEATURE(有的软件可能有几个产品版本号)

六、修改假的许可证

为什么我们在前面不能再次调用_l_sg函数?这是因为FLEXLM的验证机制,如果FEATUER和产品号验证不正确,眼看要煮熟的鸭子_l_sg就直接飞了,就不会再断下来!
修改许可证,_l_sg函数就可以再次停下来了,这就相当于帅哥有钱,MM停下来;看来造假还是不好,来接近于真的:
FEATURE ImarisBase bitplane 4.1 permanent uncounted 123456654321\
HOSTID=ANY SIGN=123456789123

七、定位_l_sg函数及其返回

函数目的:_l_sg的意思是"签名vendor_key5",呵呵。其返回处是恢复加密种子的关键!
方法:搜索常量SEEDVAL,9.2版本的是6F7330B8;注意,有两个出现,其中一个是混淆函数_l_svk()里面的。可以在?_l_init函数里面通过F7跟进确定,也结合后面的固定结构
V7 glseed?=?0x788F71D2 seedval?=?0x7648B98E
V8 glseed?=?0x3CDE3EBF seedval?=?0x6F73330B8
V9 glseed?=?0x72346B53 seedval?=?0x6F7330B8
v10 glseed?=?0x5332322F seedval?=?0x6F7330B8
(seedval:用于确定_l_sg函数;glseed:可以用来确定vendor name,堆栈出现)
(这些值最早出现于WOODOOM网站,laoqian大锅的总结一文也提及了-惠及众生,爽)
可以执行到返回,然后用dd命令
1、定位函数
006C205B /$ 55 push ebp ; _l_sg函数
。。。。。
006C206B |. 8845 EF mov [ebp-11], al
006C206E |. C745 F4 B8307>mov dword ptr [ebp-C], 6F7330B8 ;
seedval 寻找L_SG,注意混淆函数
006C2075 |. C745 FC 00000>mov dword ptr [ebp-4], 0
。。。。。
006C21D7 |. 5D pop ebp ;
_l_sg函数返回

2、定位函数的返回:
006C02FF |. 8B45 08 mov eax, [ebp+8] ; |
006C0302 |. 50 push eax ; |Arg1
006C0303 |. E8 531D0000 call 006C205B ;
\调用_l_sg函数
006C0308 |. 83C4 0C add esp, 0C ;
返回到这里,该处下断,用dd [esp]和dd [esp+8]命令
006C030B |. 8B4D 08 mov ecx, [ebp+8]

八、追踪加密种子和许可证

方法:在调用_l_sg函数的返回处(后面一般是一个add…命令,就可以在add命令处下断,使用dd命令),用dd [esp] dd
[esp+8]命令查看内存中的内容。
dd [esp] 得到的是00000066。。。job[]结构内容
dd [esp+8] 得到的是00000004。。。data[]内容
如果是正确的许可证,与调用_l_sg函数的次数关系不大,除了_l_init函数不填充正确的job结构外,每一个FEATUER都要调用_l_sg函数一次;
其返回值将是正确的job和data结构数据;也就是说,每个FEATUER对应的job和data值不相等,但用它们算出的加密种子却一样。
1、追踪加密种子
在_l_sg函数的返回处,使用dd命令
006C0308 |. 83C4 0C add esp, 0C ;
返回到这里,该处下断,用dd [esp]和dd [esp+8]命令

dd [esp]
03A7C350 00000066
03A7C354 00000000
03A7C358 ******** job+08
03A7C35C ******** job+0c
03A7C360 ******** job+10
03A7C364 00000000

dd [esp+8]
0012F5CC 00000004
0012F5D0 ******** data[0]
0012F5D4 ******** data[1]
0012F5D8 18A011ED
0012F5DC 274BE197
0012F5E0 E26A21A8
0012F5E4 52580441
0012F5E8 00020009

用calcseed.exe计算加密种子
vendor=bitplane
enseed1=******* enseed2=******** 与VENDOR NAME的关系是仅仅与其第一个字母有关

vendor=Bitplane

追出的VENDOR NAME是小写:bitplane,算出的LIC正确;
而网上有DOWN的许可证,第一个字母是大写的VENDOR
NAME:Bitplane也正确。这里将VENDOR换成大、小写都没有关系,但用小写VENDOR计算的加密SEEDS。
2、做出许可证
用lmcryptgui.exe。具体方法参见laoqian大锅的文章。
用SDK也可以制作,只不过在lm_code.h中要添加一些信息,麻烦哦。我懒,如果你做好了,别忘了送我一份啊:)

后记:该文的方法对于7.2、8.0、9.2的版本都适用。7之前的版本应该也可以用该方法,因为FLEXLM的某些关键结构(哈哈)一直没有改变!这是通用的方法。
本想做个循序渐进册子,突然发现该方法其实对老版本的_l_init,_l_new_job等方法都包容了。
可以这样说,对于没有使用ECC等技术(需要PATCH,SIGN超过12位则使用了该技术,以后讨论)的情况,FLEXLM就像一张纸。
关键点:定位对_l_sg函数的调用返回处,逐步修改假许可证(格式正确)中的内容,就会在_l_sg函数处停下来恢复加密的种子。

感谢

CrackZ
Nolan Blender
tulipfan[CCG]
laoqian
看雪论坛上的朋友们!

附:一些常见问题的处理,希望大家补充:
1、FLEXLM追出了正确加密种子,7.2等SDK做不出正确的许可证?
如果能正确启动genlic32.exe,恭喜你找对了加密的种子,试试添加选项"advanced->Add Compatible License Key"
2、_l?_sg函数函数只调用一次,不来第二次?
CRACKZ的文章也曾提及,但没有说明原因和处理办法。常见处理:
A:许可证格式要正确
B:设置正确的环境变量,可在"我的电脑->属性"里面或者autoexec.bat里面设置
C:许可证里面逐步填入正确的VENDOR,FEATUER,产品版本号等
CRACKZ的另外一篇文章还提及了另外一种处理办法:终止DAEMON进程,在许可证里面加入UER_...信息,但我没有用它试验成功过。
3、如何让后台程序安息?
运行程序,会发现至少有三样不少:lmgrd.exe是一陪,vendor daemon是二陪,Cracker是"三陪",哈哈。
将许可证做成无任何限制的格式,前面两陪直接上床睡觉(进程不启动),晕吧。如果不知道什么是无任何限制的格式,赶快买看雪大锅的书看看(书店一般脱销,我托人才买到)。
4、有了正确的许可证,怎么找加密种子?
实在恭喜你,省事啊。VENDOR,FEATURE等等都不用找了。
一般情况了,有了正确的许可证,_l_sg函数会在每个FEATURE的验证后返回正确的值,用通用的种子恢复技术就可以了。
5、相互交流,才能共同提高!仅作技术交流,恳请不要用于非法用途!

2009年6月25日星期四

翻译FLEXlm9.2的破解教学六

  对于4个Vendor密钥,很明显它们是初始化时在l_n36_buf()中被模糊的,在l_xorname()中进行模糊逆向,l_xorname()未做别的仅进行了一些与或操作。我们都知道与或的特征:x ^ x = 0, x ^ 0 = x, x ^ 1 = ~x,因此进行两次相同的与或操作将相互取消。这个好特性将与或适用于编码和译码。如果我们的猜测对的话,那么l_n36_buf()将采用与 l_good_lic_key()相同的方式调用l_xorname()。因为l_n36_buf()驻留于lm_new.c,它由 lmnewgen.exe产生,因此直接检查lmnewgen.c更好。


#include "l_strkey.h"
... ...
int main(int argc, char **argv)
{
      ... ...
      strcpy(outfile, "lm_new.c");
      ... ...
/* 初始化工作,能报告错误并能退出 */
if (lc_init(0, vendor_name, &vendorkeys[0], &job))
      {  
fprintf(stderr, "lc_init failed: %s\n", lc_errstring(job));
         exit(1);
      }  
/* 通过sb_rngFIPS186Session()产生的随机数 */
l_genrand(job, lmseed1, lmseed2, lmseed3, NEWSEEDSIZ, newseeds);
      ... ... /* 把新种子转换为seed1 ? seed4,及其它*/
/* 把4个加密种子写进lmseeds.h */
if (!(ofp = fopen("lmseeds.h", "w")))
      {  
perror("Can't write lmseeds.h file, exiting");
         exit(1);
      }  
fprintf(ofp, "... ...", seed1, seed2, seed3, seed4);
      fclose(ofp);

/*现在是 lm_new.c */
if (!(ofp = fopen(outfile, "w")))
      {  
perror("Can't open output file, exiting");
         exit(1);
      }  
      ... ...
/* 确定缺省的和弱的种子被排除在外 */
if (!l_reasonable_seed(seed3) || !l_reasonable_seed(seed4) ||
         !l_reasonable_seed(lmseed1) || !l_reasonable_seed(lmseed2) ||
         !l_reasonable_seed(lmseed3))
      {  
         ... ...
         fprintf(stderr, "Existing.\n");
         exit(1);
      }  
      ... ...
      fputs("#include <time.h>\n", ofp);
      do_real(); /* 写lm_new.c 的主要内容*/
      fclose(ofp);
      return 0;
}

static void do_real()
{
      ... ... /* 产生随机的参数和函数名称 */
      while (!key5_uniqx)
      {  
key5_uniqx = our_rand(256) + (our_rand(256) << 8) +
                  (our_rand(256) << 16) + (our_rand(256) << 24);
      }  
      ... ... /* 产生随机的 key5_order[] */
for (i = 0; i < 200; i += 2)
         random_garbage();
      ... ... /* 更多的随机垃圾 */
for (counter=0; counter<keysize; counter++)/* 一般 keysize=1, 只有一个vendor */
      {  
         key5(&vendorkeys[counter]);  /* 模糊化vendorkeys->data[] */
         l_xorname(vname, &vendorkeys[counter]);/* 模糊化vendorkeys->keys[] */
/* 真正VENDORCODE的初始化 */
         do_ulong(vendorkeys[counter].data[0], "data[0]", counter);
         do_ulong(vendorkeys[counter].data[1], "data[1]", counter);
         do_ulong(vendorkeys[counter].keys[0], "keys[0]", counter);
         do_ulong(vendorkeys[counter].keys[1], "keys[1]", counter);
         do_ulong(vendorkeys[counter].keys[2], "keys[2]", counter);
         do_ulong(vendorkeys[counter].keys[3], "keys[3]", counter);
         ... ...
      }  
      l_puts_rand(ofp, fpVar, numvars); /* 以随机的顺序输出行 */
      fflush(ofp);
      uniqcode(); /* 输出lm_new.c!l_n36_buff()的源代码 */
      fflush(ofp);
      ... ...
}

static void do_ulong(unsigned long ul, char *varname, int counter)
{
      ... ...
randvarname(b1, "b1"); bnames[0] = b1; /* 产生混乱的参数名称 */
randvarname(b2, "b2"); bnames[1] = b2;
randvarname(b3, "b3"); bnames[2] = b3;
randvarname(b4, "b4"); bnames[3] = b4;

for (i = 0; i < 4; i++)
      {  
shift = i * 8;

         CLEARV; /* 把ul分成4 字节并且把它们指派为4个糊乱命名的参数 */
sprintf(vBuf, "static unsigned int %s = %d;\n",
bnames[i], (ul & (0xff << shift)) >> shift );
         fwrite(vBuf, sizeof(char), sizeof(vBuf), fpVar);

         CLEARF; /* 重新组装回4个参数,使v->varname = ul */
sprintf(fBuf, "\tif (%s == %d) v->%s += (%s << %d);\n",
               countervar, counter, varname, bnames[i], shift);
         fwrite(fBuf, sizeof(char), sizeof(fBuf), fpFunc);
      }  
}

static void uniqcode()
{
      ... ...
int idx = *vendor_name % XOR_SEEDS_ARRAY_SIZ; /* idx = V % 20 = 86 % 20 = 6 */
      XOR_SEEDS_INIT_ARRAY(xor_arr) /* l_strkey.h */

fprintf(ofp, "static void %s(job, vendor_id, key) \n\
            ... ...
unsigned long x = 0x%x; \n\
struct s_tmp {int i; char *cp; unsigned char a[12];} *t, t2; \n\
if (job) t = (struct s_tmp *)job; \n\
               else t = &t2; \n\
            ... ...", key5_fname, key5_uniqx); /* key5_fname 和key5_uniqx都是随机数*/
for(i = 0; i < SEEDS_XOR_NUM; i++) /* 解码 t->a[], i.e. job->mem_ptr2_bytes[] */
      {  
         unsigned char num;
         cpp[i] = cp;
sprintf(cp, "t->cp=(char *)(((long)t->cp) ^ (time(0) ^ ((0x%x << 16) + 0x%x)));\n\
t->a[%d] = (time(0) & 0xff) ^ 0x%x;\n", /* 运行时随机化 */
               our_rand(0xff), our_rand(0xff), i, our_rand(0xff));
cp += strlen(cp) + 1;
      }  
      l_puts_rand1(ofp, SEEDS_XOR_NUM, cpp); /* 以随机的顺序输出行*/

fprintf(ofp, "for (i = 0; i < %d; i++) \n\
            { \n\
               if (sig[i%%SIGSIZE] != vendor_id[i%%len]) \n\
                  sig[i%%SIGSIZE] ^= vendor_id[i%%len]; \n\
            } \n\
unsigned long y = ((((long)sig[0] << %d) \n\
| ((long)sig[1] << %d) \n\
   | ((long)sig[2] << %d) \n\
| ((long)sig[3] << %d)) \n\
^ ((long)(t->a[%d]) <<  0) \n\
^ ((long)(t->a[%d]) <<  8) \n\
^ ((long)(t->a[%d]) << 16) \n\
^ ((long)(t->a[%d]) << 24) \n\
^ x \n\
^ key->keys[0] \n\
^ key->keys[1]) & 0xffffffff; \n\
key->data[0] ^= y; \n\
key->data[1] ^= y; \n\
      ... ...", MAX_DAEMON_NAME, /* MAX_DAEMON_NAME = 10 在lmclient.h中定义 */
key5_order[0], key5_order[1], key5_order[2], key5_order[3],
xor_arr[idx][0], xor_arr[idx][1], xor_arr[idx][2], xor_arr[idx][3]));
}

static void key5(VENDORCODE *k) /* 模糊化加密种子, 即 k->data[] */
{
      ... ...
/* 和uniqcode()中相同的key5_uniqx, key5_order[], sig[]和MAX_DAEMON_NAME*/
for (i = 0; i < MAX_DAEMON_NAME; i++)
      {  
if (sig[i%SIGSIZE] != vname[i % len])
            sig[i%SIGSIZE] ^= vname[i % len];
      }  
y = ((((long)sig[0] << key5_order[0])
         | ((long)sig[1] << key5_order[1])
         | ((long)sig[2] << key5_order[2])
         | ((long)sig[3] << key5_order[3]))
         ^ key5_uniqx
         ^ k->keys[0]
         ^ k->keys[1]) & 0xffffffff;
      k->data[0] ^= y; /* k->data[0] = 加密种子SEED1 ^ y */
      k->data[1] ^= y; /* k->data[1] = 加密种子SEED2 ^ y */
}


  源码有点长,但是它的结构一旦被我们揭开就不再非常难懂。主要的过程在lmseeds.h中花费大量时间,并且lm_new.c主要是在 do_real()中产生的。在几个子程序的帮助下,do_real()本身是在制造l_n36_buf(),它把l_n36_buff()留给 uniqcode()。那么l_xorname()干什么用呢? 它虽然没有出现在l_n36_buf()中,但是在do_real()中出现了。因此这种说法是正确的:4个vendor key在不同的位置被同一个异或操作来进行加密和解密,它们分别是 do_real() / l_n36_buf() 和l_good_lic_key() 
  注意lm_new.c本身被高度模糊化:这里有大量完全无用的垃圾代码, 标识符是随机、无任何意义的, 真代码和垃圾代码看上去相似并且混在一起,真代码的行顺序被打乱……。很明显,它以这种方式设计的目的是用来迷惑读者,并且它成功了,因为理解C源码几乎是不可能的,更不用说反编译码了。这正是我们为什么要把注意力放在它的起源lmnewgen.c上的原因, 因为后者能给我们更多提示。例如,l_xorname()在do_real()中被调用,而不是l_n36_buf()。这意味着密钥的模糊化是在vendor site的内部进行的,并且加密后的密钥被链接到传送到终端用户的目标中,然后它们在l_good_lic_key()中被实时解码。这种方案是为了最小化真实密钥的暴露。
  但是,我们对加密种子(encryption seeds)比vendor key更感兴趣。回想一下,job->mem_ptr2_bytes[] 和code->data[] 在验证和密钥产生的过程中是不一样的。很可能 FLEXlm 也使用了异或进行种子加密,但是远不止这些,因为我们在运行时看到它是随机的。我们将逐步分析。
  恰好在do_real()->l_xorname()前面一行,这儿有一处对key5()的调用, 它在vendor那边对原有的加密种子进行模糊化 (在工作结构上没做任何事情). vendor key 的经验告诉我们它们一定在用户方的某个地方进行了反向模糊。这时从事这项工作的不再是 l_good_lic_key(), 而是l_n36_buff(). 它在lm_new.c中的源码是可读的,但我们仍然依然顷向于研究它的产生器 uniqcode()。不多久我们发现l_n36_buff()对一些和key5()中一样的参数进行了异或, 并加上额外的t->a[]。那么它又是什么东西呢?t->a[]正是job->mem_ptr2_bytes[]的另外一个名称. 怎样去解决那些额外的异或呢?让我们翻回去几页…,噢,在l_string_key()中宏L_MOVELONG()处,正好在散列(hashing)开始之前。
  现在我们看到种子加密/解密在两个步骤中完成, l_n36_buf()/l_n36_buff() 和 l_n36_buff() / l_string_key()。在相应函数中的xor代码相互镜像,从而保证清除掉所有的干扰。l_n36_buff()中的time(0)因子引入了运行时的随机性,它同时影响了我们在l_string_key()中看到的code->data[]和 job->mem_ptr2_bytes[] . 确实,与vendor keys相对而言,FLEXlm以一种更加模糊的方式隐藏了加密种子。我们现在知道了lm_new.c中两个名字神秘的函数的意义(事实上只有两个): l_n36_buf() ? 初始化VENDORCODE 、加密种子和密钥;l_n36_buff() ? 解开 l_n36_buf(),并进行第二步加密。
  我们需要强调模糊化只用于checkout过程。在keygen过程中lmcrypt.exe并不调用 l_n36_buf()、 l_n36_buff(),或者 l_good_lic_key(),并且L_MOVELONG对原始种子无任何影响,因为 job->mem_ptr2_bytes[]总是0。在checkout 的加密/解密过程中,xor操作涉及了众多的常数、变量和数组。它们常被放置在两个地方,一个用于编码,另一个用于解码。为了方便,下表对它们进行了概括。



  相关的对象  编码  解码
VENDOR_KEY  l_xorname(),
VENDORNAME,  do_real(), l_n36_buf()  l_good_lic_key()
ENCRYPTION_SEED,步骤1
  VENDORMAGIC_V7  do_real(),key5(), l_n36_buf()  uniqcode(), l_n36_buff()
ENCRYPTION_SEED,步骤2  x = key5_uniqx, 
key5_order[], 
sig[], MAX_DAEMON_NAME
idx, xor_arr  uniqcode(), l_n36_buff()  L_MOVELONG(), l_string_key()

  现在是我们从cmath.exe中找回真正的加密种子的时候了。真正的种子作为L_MOVELONG()的第一个参数被恢复。使用idx=6,和前面所述的置换表 xor_arr[],xor操作数包含 4 字节,,在job->mem_ptr2_bytes[]中被编址在7、3、5、11。经过汇编后是00A0A000.因此, ENCRYPTION_SEED1 =  code-> data[0] ^ 00A0A000 = 52ED15B8 ^ 00A0A000 = 524DB5B8,ENCRYPTION_SEED2 =  code-& gt;data[1] ^ 00A0A000 = 75CF780F ^ 00A0A000 = 756FD80F。
  在lmseeds.h中试用它们.呜呼! lmcrypt.exe产生了亲爱的6D5C01FD71C9。改变版本号为5.0,我们得到 3F23BE3056E4, 又是正确的鉴名档! 这无疑确定我们已经获得Visual Numerics的可信的加密种子 (encryption seeds)和vendor keys。 最终,我们能生成任何我们所想要的VNI license keys, 可以应用于其它的版本, 其它的features,其它的产品…只要FLEXLM没做重大的修改, 它应能够正常工作而不会有任何故障发生.

F:\flexlm>type license.dat
FEATURE CMATH VNI 5.0 permanent uncounted 0 HOSTID=ANY
FEATURE CSTAT VNI 5.0 permanent uncounted 0 HOSTID=ANY
FEATURE CMATH VNI 5.5 permanent uncounted 0 HOSTID=ANY
FEATURE CSTAT VNI 5.5 permanent uncounted 0 HOSTID=ANY
FEATURE CMATH VNI 7.1 permanent uncounted 0 HOSTID=ANY
FEATURE CSTAT VNI 8.3 permanent uncounted 0 HOSTID=ANY
FEATURE Hello VNI 2.9 permanent uncounted 0 HOSTID=ANY
FEATURE cRaCk VNI 4.0 permanent uncounted 0 HOSTID=ANY
FEATURE CMATH VNI 5.5 permanent uncounted HOSTID=ANY SIGN=0

E:\flexlm>utils\lmcrypt -i license.dat
FEATURE CMATH VNI 5.0 permanent uncounted 3F23BE3056E4 HOSTID=ANY
FEATURE CSTAT VNI 5.0 permanent uncounted 2C60CD4570B0 HOSTID=ANY
FEATURE CMATH VNI 5.5 permanent uncounted 6D5C01FD71C9 HOSTID=ANY
FEATURE CSTAT VNI 5.5 permanent uncounted 369B56AC8B35 HOSTID=ANY
FEATURE CMATH VNI 7.1 permanent uncounted F218B30D7129 HOSTID=ANY
FEATURE CSTAT VNI 8.3 permanent uncounted CC5FA3C48B85 HOSTID=ANY
FEATURE Hello VNI 2.9 permanent uncounted 505E4E243D1B HOSTID=ANY
FEATURE cRaCk VNI 4.0 permanent uncounted 93D0E20E2D20 HOSTID=ANY
FEATURE CMATH VNI 5.5 permanent uncounted HOSTID=ANY \
        SIGN=B5E1542279DC

进一步的讨论

尽管我们已经对FLEXLM保护系统进行了完全的反向工程,这里仍有许多东西值得讨论. 最显著的一个是, VENDOR_KEY5在哪里?

(待续。。。。。。)

http://bbs.pediy.com/archive/index.php?t-32787.html

准备工作:

1. 用 w32dasm89 反汇编 vendor daemon 程序
按照下面的说明找到 "FLEXwrap" 前面的地址,
和相应的算法地址,为下一步设置断点做准备.

2. 假的格式正确的 license, 一定要有 SERVER 和 DAEMON 或者 VENDOR 这两行.

SERVER this_host ANY 2080
DAEMMON vendor_name

FEATURE feature_name vendor_name 1.000 permanent uncounted 123456654321 \
HOSTID=ANY

3. 常用工具:
calcseed.exe ---------- 用 job 和 data 计算种子,这种方法可以不用.
lmkg.exe (v4.x-11.x) -- 计算 vendor key 包括 CRO 和 TRL
lmcryptgui.exe ------- 用找到的种子和 vendor name 生成 lmcryptxxxx.exe 文件
相当于 FlexLM SDK 中的 lmcrypt.exe, 但是不适用带 ECC 的 license.
FlexLM SDK ------------ 用计算的种子和 vendor keys 修改 lm_code.h
方法按 laoqian 提供的.
softice --------------- 加载 vendor daemon 程序用.

开始工作:

1. 启动 softice, 用 Symbol Loader 加载 vendor daemon 程序 vendor?.exe
再用 lmtools 启动 server, 会在下面设置的断点出停下. 然后, .....

2. 寻找标志代码段 "FLEXwrap" 并且设置断点
在 "FLEXwrap" 之前的第一个 CALL xxxxxxx
前面的 :004ABDDE push ecx 出设置断点, 一定会停.
这时可设置内存断点 bpm ds:ecx+2 是 feature 名的内存地址

:004ABDC3 8B4DF4 mov ecx, dword ptr [ebp-0C]
:004ABDC6 33D2 xor edx, edx
:004ABDC8 8A9118030000 mov dl, byte ptr [ecx+00000318]
:004ABDCE 83FA04 cmp edx, 00000004
:004ABDD1 0F8451010000 je 004ABF28
:004ABDD7 8B450C mov eax, dword ptr [ebp+0C]
:004ABDDA 50 push eax
:004ABDDB 8B4DF4 mov ecx, dword ptr [ebp-0C] ;
:004ABDDE 51 push ecx ;设置断点,一定会停
:004ABDDF 8B15A83A5100 mov edx, dword ptr [00513AA8] ;
:004ABDE5 52 push edx ;bpm ds:ecx+2 是 feature 名
:004ABDE6 E821190000 call 004AD70C ;
:004ABDEB 83C40C add esp, 0000000C
:004ABDEE 85C0 test eax, eax
:004ABDF0 0F8532010000 jne 004ABF28

* Possible StringData Ref from Data Obj ->"FLEXwrap"
|
:004ABDF6 6814FF4F00 push 004FFF14
:004ABDFB 8B4508 mov eax, dword ptr [ebp+08]
:004ABDFE 50 push eax
:004ABDFF E88A7DF6FF Call 00413B8E
:004ABE04 83C408 add esp, 00000008
:004ABE07 894594 mov dword ptr [ebp-6C], eax
:004ABE0A 837D9400 cmp dword ptr [ebp-6C], 00000000
:004ABE0E 7414 je 004ABE24

* Possible StringData Ref from Data Obj ->"SAMwrap"
|
:004ABE10 6820FF4F00 push 004FFF20
:004ABE15 8B4D08 mov ecx, dword ptr [ebp+08]
:004ABE18 51 push ecx
:004ABE19 E8707DF6FF Call 00413B8E
:004ABE1E 83C408 add esp, 00000008
:004ABE21 894594 mov dword ptr [ebp-6C], eax
:004ABE24 833DD8FD4F0000 cmp dword ptr [004FFDD8], 00000000
:004ABE2B 7409 je 004ABE36
:004ABE2D 833DDCFD4F0000 cmp dword ptr [004FFDDC], 00000000

3. 寻找算法代码 83BD90FEFFFF08 是 FlexLM v10.x 以后的
83BD74FEFFFF08 是 FlexLM v9.x 以前的
个别版本需要自己验证,是这种代码 83BDxxFEFFFF08
在它的前面一定有一个 add ecx, 00000001
在地址 004CB131 处设置断点, 如果停了,大功告成,往下马上就可以找到种子
如果不停,还请 marstj 给出具体解决方案.

4. 接下来是找种子:
(i)在地址 004CB25A 设置断点,在 eax 直接得到种子 seed1,不需计算.
(ii)在地址 004CB422 设置断点,在 eax 直接得到种子 seed2,不需计算.

5. 注意代码中这个参数 3D4DA1D6 是清除种子的缺省值
:004CB367 mov dword ptr [ebp+FFFFFE70], 3D4DA1D6
在这里也可以直接得到种子 seed1 = [ebp+FFFFFE70]
:004CB52E mov dword ptr [ebp+FFFFFE6C], 3D4DA1D6
在这里也可以直接得到种子 seed2 = [ebp+FFFFFE6C]

=====================================================================
:004CB122 8B8D90FEFFFF mov ecx, dword ptr [ebp+FFFFFE90] ;算法的特征代码
:004CB128 83C101 add ecx, 00000001 ;83BDxxFEFFFF08
:004CB12B 898D90FEFFFF mov dword ptr [ebp+FFFFFE90], ecx ;注意:前面的 add
ecx, 00000001
:004CB131 83BD90FEFFFF08 cmp dword ptr [ebp+FFFFFE90], 00000008 ;是重要的判断标志
:004CB138 7D2B jge 004CB165 ;
:004CB13A 8B55F4 mov edx, dword ptr [ebp-0C]
:004CB13D 039590FEFFFF add edx, dword ptr [ebp+FFFFFE90]
:004CB143 33C0 xor eax, eax
:004CB145 8A02 mov al, byte ptr [edx]
:004CB147 8B8D90FEFFFF mov ecx, dword ptr [ebp+FFFFFE90]
:004CB14D 33D2 xor edx, edx
:004CB14F 8A919CEE5000 mov dl, byte ptr [ecx+0050EE9C]
:004CB155 33C2 xor eax, edx
:004CB157 8B8D90FEFFFF mov ecx, dword ptr [ebp+FFFFFE90]
:004CB15D 88819CEE5000 mov byte ptr [ecx+0050EE9C], al ;
:004CB163 EBBD jmp 004CB122
:004CB165 83BD94FEFFFF00 cmp dword ptr [ebp+FFFFFE94], 00000000
:004CB16C 0F85D6040000 jne 004CB648
:004CB172 83BDA4FEFFFF00 cmp dword ptr [ebp+FFFFFEA4], 00000000
:004CB179 0F85BE030000 jne 004CB53D
:004CB17F 837DFC00 cmp dword ptr [ebp-04], 00000000
:004CB183 0F85B4030000 jne 004CB53D
:004CB189 6A01 push 00000001
:004CB18B 8B5508 mov edx, dword ptr [ebp+08]
:004CB18E 52 push edx
:004CB18F E8C916F7FF call 0043C85D
:004CB194 83C408 add esp, 00000008
:004CB197 85C0 test eax, eax
:004CB199 0F849E030000 je 004CB53D
:004CB19F C78574FEFFFF9CEE5000 mov dword ptr [ebp+FFFFFE74], 0050EE9C
:004CB1A9 8B4508 mov eax, dword ptr [ebp+08]
:004CB1AC 8B889C010000 mov ecx, dword ptr [eax+0000019C]
:004CB1B2 8B91E81C0000 mov edx, dword ptr [ecx+00001CE8]
:004CB1B8 8B45F8 mov eax, dword ptr [ebp-08]
:004CB1BB C1E004 shl eax, 04
:004CB1BE 8B8C05B0FEFFFF mov ecx, dword ptr [ebp+eax-00000150]
:004CB1C5 33C0 xor eax, eax
:004CB1C7 8A840A38050000 mov al, byte ptr [edx+ecx+00000538]
:004CB1CE 8B4D14 mov ecx, dword ptr [ebp+14]
:004CB1D1 8B5104 mov edx, dword ptr [ecx+04]
:004CB1D4 33D0 xor edx, eax
:004CB1D6 8B4508 mov eax, dword ptr [ebp+08]
:004CB1D9 8B889C010000 mov ecx, dword ptr [eax+0000019C]
:004CB1DF 8B81E81C0000 mov eax, dword ptr [ecx+00001CE8]
:004CB1E5 8B4DF8 mov ecx, dword ptr [ebp-08]
:004CB1E8 C1E104 shl ecx, 04
:004CB1EB 8B8C0DB4FEFFFF mov ecx, dword ptr [ebp+ecx-0000014C]
:004CB1F2 33DB xor ebx, ebx
:004CB1F4 8A9C0838050000 mov bl, byte ptr [eax+ecx+00000538]
:004CB1FB C1E308 shl ebx, 08
:004CB1FE 33D3 xor edx, ebx
:004CB200 8B4508 mov eax, dword ptr [ebp+08]
:004CB203 8B889C010000 mov ecx, dword ptr [eax+0000019C]
:004CB209 8B81E81C0000 mov eax, dword ptr [ecx+00001CE8]
:004CB20F 8B4DF8 mov ecx, dword ptr [ebp-08]
:004CB212 C1E104 shl ecx, 04
:004CB215 8B8C0DB8FEFFFF mov ecx, dword ptr [ebp+ecx-00000148]
:004CB21C 33DB xor ebx, ebx
:004CB21E 8A9C0838050000 mov bl, byte ptr [eax+ecx+00000538]
:004CB225 C1E310 shl ebx, 10
:004CB228 33D3 xor edx, ebx
:004CB22A 8B4508 mov eax, dword ptr [ebp+08]
:004CB22D 8B889C010000 mov ecx, dword ptr [eax+0000019C]
:004CB233 8B81E81C0000 mov eax, dword ptr [ecx+00001CE8]
:004CB239 8B4DF8 mov ecx, dword ptr [ebp-08]
:004CB23C C1E104 shl ecx, 04
:004CB23F 8B8C0DBCFEFFFF mov ecx, dword ptr [ebp+ecx-00000144]
:004CB246 33DB xor ebx, ebx
:004CB248 8A9C0838050000 mov bl, byte ptr [eax+ecx+00000538]
:004CB24F C1E318 shl ebx, 18
:004CB252 33D3 xor edx, ebx
:004CB254 52 push edx
:004CB255 E86D050000 call 004CB7C7 ;
:004CB25A 83C404 add esp, 00000004 ;seed1 = eax 直接得到种子 seed1
:004CB25D 898570FEFFFF mov dword ptr [ebp+FFFFFE70], eax ;
:004CB263 8B9570FEFFFF mov edx, dword ptr [ebp+FFFFFE70]
:004CB269 81E2FF000000 and edx, 000000FF
:004CB26F 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB275 8A08 mov cl, byte ptr [eax]
:004CB277 32CA xor cl, dl
:004CB279 8B9574FEFFFF mov edx, dword ptr [ebp+FFFFFE74]
:004CB27F 880A mov byte ptr [edx], cl
:004CB281 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB287 83C001 add eax, 00000001
:004CB28A 898574FEFFFF mov dword ptr [ebp+FFFFFE74], eax
:004CB290 81BD70FEFFFFFF000000 cmp dword ptr [ebp+FFFFFE70], 000000FF
:004CB29A 7F0C jg 004CB2A8
:004CB29C 81BD70FEFFFF00FFFFFF cmp dword ptr [ebp+FFFFFE70], FFFFFF00
:004CB2A6 7D30 jge 004CB2D8
:004CB2A8 8B8D70FEFFFF mov ecx, dword ptr [ebp+FFFFFE70]
:004CB2AE C1F908 sar ecx, 08
:004CB2B1 81E1FF000000 and ecx, 000000FF
:004CB2B7 8B9574FEFFFF mov edx, dword ptr [ebp+FFFFFE74]
:004CB2BD 8A02 mov al, byte ptr [edx]
:004CB2BF 32C1 xor al, cl
:004CB2C1 8B8D74FEFFFF mov ecx, dword ptr [ebp+FFFFFE74]
:004CB2C7 8801 mov byte ptr [ecx], al
:004CB2C9 8B9574FEFFFF mov edx, dword ptr [ebp+FFFFFE74]
:004CB2CF 83C201 add edx, 00000001
:004CB2D2 899574FEFFFF mov dword ptr [ebp+FFFFFE74], edx
:004CB2D8 81BD70FEFFFF007D0000 cmp dword ptr [ebp+FFFFFE70], 00007D00
:004CB2E2 7F0C jg 004CB2F0
:004CB2E4 81BD70FEFFFF0083FFFF cmp dword ptr [ebp+FFFFFE70], FFFF8300
:004CB2EE 7D2F jge 004CB31F
:004CB2F0 8B8570FEFFFF mov eax, dword ptr [ebp+FFFFFE70]
:004CB2F6 C1F810 sar eax, 10
:004CB2F9 25FF000000 and eax, 000000FF
:004CB2FE 8B8D74FEFFFF mov ecx, dword ptr [ebp+FFFFFE74]
:004CB304 8A11 mov dl, byte ptr [ecx]
:004CB306 32D0 xor dl, al
:004CB308 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB30E 8810 mov byte ptr [eax], dl
:004CB310 8B8D74FEFFFF mov ecx, dword ptr [ebp+FFFFFE74]
:004CB316 83C101 add ecx, 00000001
:004CB319 898D74FEFFFF mov dword ptr [ebp+FFFFFE74], ecx
:004CB31F 81BD70FEFFFF0024F400 cmp dword ptr [ebp+FFFFFE70], 00F42400
:004CB329 7F0C jg 004CB337
:004CB32B 81BD70FEFFFF00DC0BFF cmp dword ptr [ebp+FFFFFE70], FF0BDC00
:004CB335 7D30 jge 004CB367
:004CB337 8B9570FEFFFF mov edx, dword ptr [ebp+FFFFFE70]
:004CB33D C1FA18 sar edx, 18
:004CB340 81E2FF000000 and edx, 000000FF
:004CB346 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB34C 8A08 mov cl, byte ptr [eax]
:004CB34E 32CA xor cl, dl
:004CB350 8B9574FEFFFF mov edx, dword ptr [ebp+FFFFFE74]
:004CB356 880A mov byte ptr [edx], cl
:004CB358 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB35E 83C001 add eax, 00000001 ;3D4DA1D6 是清除种子的缺省值
:004CB361 898574FEFFFF mov dword ptr [ebp+FFFFFE74], eax ;
:004CB367 C78570FEFFFFD6A14D3D mov dword ptr [ebp+FFFFFE70], 3D4DA1D6
;seed1 = [ebp+FFFFFE70]
:004CB371 8B4D08 mov ecx, dword ptr [ebp+08] ;
:004CB374 8B919C010000 mov edx, dword ptr [ecx+0000019C] ;[ebp+xxxxxxxx]是种子seed1
:004CB37A 8B82E81C0000 mov eax, dword ptr [edx+00001CE8]
:004CB380 8B4DF8 mov ecx, dword ptr [ebp-08]
:004CB383 C1E104 shl ecx, 04
:004CB386 8B940DB0FEFFFF mov edx, dword ptr [ebp+ecx-00000150]
:004CB38D 33C9 xor ecx, ecx
:004CB38F 8A8C1038050000 mov cl, byte ptr [eax+edx+00000538]
:004CB396 8B5514 mov edx, dword ptr [ebp+14]
:004CB399 8B4208 mov eax, dword ptr [edx+08]
:004CB39C 33C1 xor eax, ecx
:004CB39E 8B4D08 mov ecx, dword ptr [ebp+08]
:004CB3A1 8B919C010000 mov edx, dword ptr [ecx+0000019C]
:004CB3A7 8B8AE81C0000 mov ecx, dword ptr [edx+00001CE8]
:004CB3AD 8B55F8 mov edx, dword ptr [ebp-08]
:004CB3B0 C1E204 shl edx, 04
:004CB3B3 8B9415B4FEFFFF mov edx, dword ptr [ebp+edx-0000014C]
:004CB3BA 33DB xor ebx, ebx
:004CB3BC 8A9C1138050000 mov bl, byte ptr [ecx+edx+00000538]
:004CB3C3 C1E308 shl ebx, 08
:004CB3C6 33C3 xor eax, ebx
:004CB3C8 8B4D08 mov ecx, dword ptr [ebp+08]
:004CB3CB 8B919C010000 mov edx, dword ptr [ecx+0000019C]
:004CB3D1 8B8AE81C0000 mov ecx, dword ptr [edx+00001CE8]
:004CB3D7 8B55F8 mov edx, dword ptr [ebp-08]
:004CB3DA C1E204 shl edx, 04
:004CB3DD 8B9415B8FEFFFF mov edx, dword ptr [ebp+edx-00000148]
:004CB3E4 33DB xor ebx, ebx
:004CB3E6 8A9C1138050000 mov bl, byte ptr [ecx+edx+00000538]
:004CB3ED C1E310 shl ebx, 10
:004CB3F0 33C3 xor eax, ebx
:004CB3F2 8B4D08 mov ecx, dword ptr [ebp+08]
:004CB3F5 8B919C010000 mov edx, dword ptr [ecx+0000019C]
:004CB3FB 8B8AE81C0000 mov ecx, dword ptr [edx+00001CE8]
:004CB401 8B55F8 mov edx, dword ptr [ebp-08]
:004CB404 C1E204 shl edx, 04
:004CB407 8B9415BCFEFFFF mov edx, dword ptr [ebp+edx-00000144]
:004CB40E 33DB xor ebx, ebx
:004CB410 8A9C1138050000 mov bl, byte ptr [ecx+edx+00000538]
:004CB417 C1E318 shl ebx, 18
:004CB41A 33C3 xor eax, ebx
:004CB41C 50 push eax
:004CB41D E8A5030000 call 004CB7C7 ;
:004CB422 83C404 add esp, 00000004 ;seed2 = eax 直接得到种子 seed2
:004CB425 89856CFEFFFF mov dword ptr [ebp+FFFFFE6C], eax ;
:004CB42B 8B856CFEFFFF mov eax, dword ptr [ebp+FFFFFE6C]
:004CB431 25FF000000 and eax, 000000FF
:004CB436 8B8D74FEFFFF mov ecx, dword ptr [ebp+FFFFFE74]
:004CB43C 8A11 mov dl, byte ptr [ecx]
:004CB43E 32D0 xor dl, al
:004CB440 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB446 8810 mov byte ptr [eax], dl
:004CB448 8B8D74FEFFFF mov ecx, dword ptr [ebp+FFFFFE74]
:004CB44E 83C101 add ecx, 00000001
:004CB451 898D74FEFFFF mov dword ptr [ebp+FFFFFE74], ecx
:004CB457 81BD6CFEFFFFFF000000 cmp dword ptr [ebp+FFFFFE6C], 000000FF
:004CB461 7F0C jg 004CB46F
:004CB463 81BD6CFEFFFF00FFFFFF cmp dword ptr [ebp+FFFFFE6C], FFFFFF00
:004CB46D 7D30 jge 004CB49F
:004CB46F 8B956CFEFFFF mov edx, dword ptr [ebp+FFFFFE6C]
:004CB475 C1FA08 sar edx, 08
:004CB478 81E2FF000000 and edx, 000000FF
:004CB47E 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB484 8A08 mov cl, byte ptr [eax]
:004CB486 32CA xor cl, dl
:004CB488 8B9574FEFFFF mov edx, dword ptr [ebp+FFFFFE74]
:004CB48E 880A mov byte ptr [edx], cl
:004CB490 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB496 83C001 add eax, 00000001
:004CB499 898574FEFFFF mov dword ptr [ebp+FFFFFE74], eax
:004CB49F 81BD6CFEFFFF007D0000 cmp dword ptr [ebp+FFFFFE6C], 00007D00
:004CB4A9 7F0C jg 004CB4B7
:004CB4AB 81BD6CFEFFFF0083FFFF cmp dword ptr [ebp+FFFFFE6C], FFFF8300
:004CB4B5 7D30 jge 004CB4E7
:004CB4B7 8B8D6CFEFFFF mov ecx, dword ptr [ebp+FFFFFE6C]
:004CB4BD C1F910 sar ecx, 10
:004CB4C0 81E1FF000000 and ecx, 000000FF
:004CB4C6 8B9574FEFFFF mov edx, dword ptr [ebp+FFFFFE74]
:004CB4CC 8A02 mov al, byte ptr [edx]
:004CB4CE 32C1 xor al, cl
:004CB4D0 8B8D74FEFFFF mov ecx, dword ptr [ebp+FFFFFE74]
:004CB4D6 8801 mov byte ptr [ecx], al
:004CB4D8 8B9574FEFFFF mov edx, dword ptr [ebp+FFFFFE74]
:004CB4DE 83C201 add edx, 00000001
:004CB4E1 899574FEFFFF mov dword ptr [ebp+FFFFFE74], edx
:004CB4E7 81BD6CFEFFFF0024F400 cmp dword ptr [ebp+FFFFFE6C], 00F42400
:004CB4F1 7F0C jg 004CB4FF
:004CB4F3 81BD6CFEFFFF00DC0BFF cmp dword ptr [ebp+FFFFFE6C], FF0BDC00
:004CB4FD 7D2F jge 004CB52E
:004CB4FF 8B856CFEFFFF mov eax, dword ptr [ebp+FFFFFE6C]
:004CB505 C1F818 sar eax, 18
:004CB508 25FF000000 and eax, 000000FF
:004CB50D 8B8D74FEFFFF mov ecx, dword ptr [ebp+FFFFFE74]
:004CB513 8A11 mov dl, byte ptr [ecx]
:004CB515 32D0 xor dl, al
:004CB517 8B8574FEFFFF mov eax, dword ptr [ebp+FFFFFE74]
:004CB51D 8810 mov byte ptr [eax], dl
:004CB51F 8B8D74FEFFFF mov ecx, dword ptr [ebp+FFFFFE74]
:004CB525 83C101 add ecx, 00000001 ;3D4DA1D6 是清除种子的缺省值
:004CB528 898D74FEFFFF mov dword ptr [ebp+FFFFFE74], ecx ;
:004CB52E C7856CFEFFFFD6A14D3D mov dword ptr [ebp+FFFFFE6C], 3D4DA1D6
;seed2 = [ebp+FFFFFE6C]
:004CB538 E90B010000 jmp 004CB648 ;
:004CB53D C78568FEFFFF00000000 mov dword ptr [ebp+FFFFFE68], 00000000
;[ebp+xxxxxxxx]是种子 seed2
:004CB547 EB0F jmp 004CB558
:004CB549 8B9568FEFFFF mov edx, dword ptr [ebp+FFFFFE68]
:004CB54F 83C201 add edx, 00000001
:004CB552 899568FEFFFF mov dword ptr [ebp+FFFFFE68], edx
:004CB558 83BD68FEFFFF08 cmp dword ptr [ebp+FFFFFE68], 00000008
:004CB55F 0F8DE3000000 jnl 004CB648
:004CB565 8B8568FEFFFF mov eax, dword ptr [ebp+FFFFFE68]
:004CB56B 2503000080 and eax, 80000003
:004CB570 7905 jns 004CB577
:004CB572 48 dec eax
:004CB573 83C8FC or eax, FFFFFFFC
:004CB576 40 inc eax
:004CB577 C1E003 shl eax, 03
:004CB57A 898564FEFFFF mov dword ptr [ebp+FFFFFE64], eax
..............
:004CB7AC 50 push eax
:004CB7AD E81D000000 call 004CB7CF
:004CB7B2 83C40C add esp, 0000000C
:004CB7B5 8985A0FEFFFF mov dword ptr [ebp+FFFFFEA0], eax
:004CB7BB 8B85A0FEFFFF mov eax, dword ptr [ebp+FFFFFEA0]
:004CB7C1 5E pop esi
:004CB7C2 5B pop ebx
:004CB7C3 8BE5 mov esp, ebp
:004CB7C5 5D pop ebp
:004CB7C6 C3 ret
=====================================================================

2009年6月23日星期二

汇编指令


        不知哪位大哥总结的,先借来用一下,免得老是翻书^_^ 
附一个汇编的在线学习网站

数据传输指令
───────────────────────────────────────
它们在存贮器和寄存器、寄存器和输入输出端口之间传送数据.
1. 通用数据传送指令.
MOV 传送字或字节.
MOVSX 先符号扩展,再传送.
MOVZX 先零扩展,再传送.
PUSH 把字压入堆栈.
POP 把字弹出堆栈.
PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈.
POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.
PUSHAD 把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
POPAD 把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈.
BSWAP 交换32位寄存器里字节的顺序
XCHG 交换字或字节.( 至少有一个操作数为寄存器,段寄存器不可作为操作数)
CMPXCHG 比较并交换操作数.( 第二个操作数必须为累加器AL/AX/EAX )
XADD 先交换再累加.( 结果在第一个操作数里 )
XLAT 字节查表转换.
── BX 指向一张 256 字节的表的起点, AL 为表的索引值 (0-255,即
0-FFH); 返回 AL 为查表结果. ( [BX+AL]->AL )
2. 输入输出端口传送指令.
IN I/O端口输入. ( 语法: IN 累加器, {端口号│DX} )
OUT I/O端口输出. ( 语法: OUT {端口号│DX},累加器 )
输入输出端口由立即方式指定时, 其范围是 0-255; 由寄存器 DX 指定时,
其范围是 0-65535.
3. 目的地址传送指令.
LEA 装入有效地址.
例: LEA DX,string ;把偏移地址存到DX.
LDS 传送目标指针,把指针内容装入DS.
例: LDS SI,string ;把段地址:偏移地址存到DS:SI.
LES 传送目标指针,把指针内容装入ES.
例: LES DI,string ;把段地址:偏移地址存到ES:DI.
LFS 传送目标指针,把指针内容装入FS.
例: LFS DI,string ;把段地址:偏移地址存到FS:DI.
LGS 传送目标指针,把指针内容装入GS.
例: LGS DI,string ;把段地址:偏移地址存到GS:DI.
LSS 传送目标指针,把指针内容装入SS.
例: LSS DI,string ;把段地址:偏移地址存到SS:DI.
4. 标志传送指令.
LAHF 标志寄存器传送,把标志装入AH.
SAHF 标志寄存器传送,把AH内容装入标志寄存器.
PUSHF 标志入栈.
POPF 标志出栈.
PUSHD 32位标志入栈.
POPD 32位标志出栈.

二、算术运算指令
───────────────────────────────────────
ADD 加法.
ADC 带进位加法.
INC 加 1.
AAA 加法的ASCII码调整.
DAA 加法的十进制调整.
SUB 减法.
SBB 带借位减法.
DEC 减 1.
NEC 求反(以 0 减之).
CMP 比较.(两操作数作减法,仅修改标志位,不回送结果).
AAS 减法的ASCII码调整.
DAS 减法的十进制调整.
MUL 无符号乘法.
IMUL 整数乘法.
以上两条,结果回送AH和AL(字节运算),或DX和AX(字运算),
AAM 乘法的ASCII码调整.
DIV 无符号除法.
IDIV 整数除法.
以上两条,结果回送:
商回送AL,余数回送AH, (字节运算);
或 商回送AX,余数回送DX, (字运算).
AAD 除法的ASCII码调整.
CBW 字节转换为字. (把AL中字节的符号扩展到AH中去)
CWD 字转换为双字. (把AX中的字的符号扩展到DX中去)
CWDE 字转换为双字. (把AX中的字符号扩展到EAX中去)
CDQ 双字扩展. (把EAX中的字的符号扩展到EDX中去)

三、逻辑运算指令
───────────────────────────────────────
AND 与运算.
OR 或运算.
XOR 异或运算.
NOT 取反.
TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果).
SHL 逻辑左移.
SAL 算术左移.(=SHL)
SHR 逻辑右移.
SAR 算术右移.(=SHR)  当值为负时,高位补 1 ;当值为正时,高位补 0
ROL 循环左移.
ROR 循环右移.
RCL 通过进位的循环左移.
RCR 通过进位的循环右移.
以上八种移位指令,其移位次数可达255次.
移位一次时, 可直接用操作码. 如 SHL AX,1.
移位>1次时, 则由寄存器CL给出移位次数.
如 MOV CL,04
SHL AX,CL

四、串指令
───────────────────────────────────────
DS:SI 源串段寄存器 :源串变址.
ES:DI 目标串段寄存器:目标串变址.
CX 重复次数计数器.
AL/AX 扫描值.
D标志 0表示重复操作中SI和DI应自动增量; 1表示应自动减量.
Z标志 用来控制扫描或比较操作的结束.
MOVS 串传送.
( MOVSB 传送字符. MOVSW 传送字. MOVSD 传送双字. )
CMPS 串比较.
( CMPSB 比较字符. CMPSW 比较字. )
SCAS 串扫描.
把AL或AX的内容与目标串作比较,比较结果反映在标志位.
LODS 装入串.
把源串中的元素(字或字节)逐一装入AL或AX中.
( LODSB 传送字符. LODSW 传送字. LODSD 传送双字. )
STOS 保存串.
是LODS的逆过程.
REP 当CX/ECX<>0时重复.
REPE/REPZ 当ZF=1或比较结果相等,且CX/ECX<>0时重复.
REPNE/REPNZ 当ZF=0或比较结果不相等,且CX/ECX<>0时重复.
REPC 当CF=1且CX/ECX<>0时重复.
REPNC 当CF=0且CX/ECX<>0时重复.

五、程序转移指令
───────────────────────────────────────
1>无条件转移指令 (长转移)
JMP 无条件转移指令
CALL 过程调用
RET/RETF过程返回.
2>条件转移指令 (短转移,-128到+127的距离内)
( 当且仅当(SF XOR OF)=1时,OP1 JA/JNBE 不小于或不等于时转移.
JAE/JNB 大于或等于转移.
JB/JNAE 小于转移.
JBE/JNA 小于或等于转移.
以上四条,测试无符号整数运算的结果(标志C和Z).
JG/JNLE 大于转移.
JGE/JNL 大于或等于转移.
JL/JNGE 小于转移.
JLE/JNG 小于或等于转移.
以上四条,测试带符号整数运算的结果(标志S,O和Z).
JE/JZ 等于转移.
JNE/JNZ 不等于时转移.
JC 有进位时转移.
JNC 无进位时转移.
JNO 不溢出时转移.
JNP/JPO 奇偶性为奇数时转移.
JNS 符号位为 "0" 时转移.
JO 溢出转移.
JP/JPE 奇偶性为偶数时转移.
JS 符号位为 "1" 时转移.
3>循环控制指令(短转移)
LOOP CX不为零时循环.
LOOPE/LOOPZ CX不为零且标志Z=1时循环.
LOOPNE/LOOPNZ CX不为零且标志Z=0时循环.
JCXZ CX为零时转移.
JECXZ ECX为零时转移.
4>中断指令
INT 中断指令
INTO 溢出中断
IRET 中断返回
5>处理器控制指令
HLT 处理器暂停, 直到出现中断或复位信号才继续.
WAIT 当芯片引线TEST为高电平时使CPU进入等待状态.
ESC 转换到外处理器.
LOCK 封锁总线.
NOP 空操作.
STC 置进位标志位.
CLC 清进位标志位.
CMC 进位标志取反.
STD 置方向标志位.
CLD 清方向标志位.
STI 置中断允许位.
CLI 清中断允许位.

六、伪指令
─────────────────────────────────────
DW 定义字(2字节).
PROC 定义过程.
ENDP 过程结束.
SEGMENT 定义段.
ASSUME 建立段寄存器寻址.
ENDS 段结束.
END 程序结束.