|
|
|
yoda的壳与飞大侠的矛
惭愧,看来不管矛多么厉害,耍武器的笨人不会用也是空浪费了这一宝贝.是到了OEP......:) |
|
yoda的壳与飞大侠的矛
怕怕地:这样提问题不会被ban ID吧.记得我曾经有一个精华帖子,用之能否抵一次小命呢. |
|
翻译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->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在哪里? (待续。。。。。。) |
|
|
|
|
|
SWF播放器文件的加壳_好漂亮的一条鱼!
各位只要能将之exe件脱壳既可,可能是FI误报,是以前的UPx壳吧! |
|
|
|
|
|
请教如何去掉程序上的Demo水印的问题
这句话什么意思"用D2为键做立即数搜",这种搜索是IDA特有的方式?请问用win32dasm反编译后可以用此方法搜吗? 最初由 采臣・宁 发布 |
|
请教如何去掉程序上的Demo水印的问题
是一个位图,没找到Loadbitmap,有很多LoadImageA, 还请多多指教 |
|
请教U狗的有关信息
哈哈,有可能是指USB狗.好象彩虹天地也有USB狗吧! |
|
不一样的Armadillo3.00a的壳
谢谢!还是不太懂,如何进一步脱壳? |
|
|
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值