如果这个cm我有能力分析出算法的话,我还是希望能够把算法弄出来的。不过本人能力还是不够。唉,nooby牛之所以会被称为大牛,大概就是因为这些吧。
这个cm被编译为多个语言,既然如此,当然要选择最为简单的入手,去进行切入。这里我选择了APK的程序,当然,选择java的也是可以的。用解压软件解压APK后可以找到KeyGenMe.html文件,里面含有完整的keygen源代码。。。嘻嘻,开心了?且慢,先别那么高兴,既然大牛能够拿得出手,自然不会是那么简单的。
简单的分析了一下,发现这个程序是使用数据流来进行驱动的。数据代码被保存在数据 var mam数组中:var mem = new Array(0, 0,...),然后下面的驱动操作就只有3种:
具体如下
[JavaScript] 纯文本查看复制代码
function vrun(input_buffer) {
if (i == 0) {
input_buffer = '';
}
input_buffer = input_buffer.split('');
input_buffer.reverse();
var output_buffer = '';
while (i >= 0) {
var a = mem[i];
var b = mem[i + 1];
var c = mem[i + 2];
if (a < 0) {
if (input_buffer.length == 0) {
break;
}
mem[b] += input_buffer.pop().charCodeAt(0);
i += 3;
} else if (b < 0) {
output_buffer += String.fromCharCode(mem[a]);
i += 3;
} else {
if (mem[a] == undefined) {
mem[a] = 0;
}
if (mem[b] == undefined) {
mem[b] = 0;
}
mem[b] -= mem[a];
if (mem[b] < -2147483648) {
mem[b] += 4294967296;
} else if (mem[b] > 2147483647) {
mem[b] -= 4294967296;
}
if (mem[b] <= 0) {
i = c;
} else {
i += 3;
}
} if (i < 0) {
output_buffer += '\n(press ENTER to reset)\n';
break;
}
}
return output_buffer;
}
分别是 a < 0 , b < 0, 以及两者都不是。核心的算法就是数据的运算:
mem -= mem[a]
jmp c。
利用这个运算+data数据,就代替了mov,retn,call,jmp等等的功能。很厉害,这里我看到了新的vm思路了,而且这样进行vm的话,连所谓的vm分派啊,vm_pop, vm_retn 等等都找不到了,因为这些都完全成为数据流驱动的代码了。于是,你会发现,你将会在vRun这个函数里面反复的走来走去,弄得一塌糊涂。
弄不了了。。。弄不来了,难道就要这么放弃么?总不能就这样被大牛鄙视吧,就算要放弃也得努力一番,千万不能让大牛们看不起了。
首先来猜一下作者的想法吧,首先,他做了一个简单的小cm,然后利用新的vm程序来对这段代码进行加密,转为为数据流,最后把这段数据流复制进程序去,并且添加数据的处理方法。这样就完了。
这样简单的事情,我也可以做到,因此,我写了一个程序,来驱动他的数据,试图进行跟踪调试,果然的。。。调试起来变成了好几万步了。这样不行,不行的。
再换一个想法,既然是数据流,用来解析的话又是按照一定的方法的,我是不是可以弄个小程序来对这段数据进行翻译?这下不,一下子代码就清晰起来了: