Finding the Winlicense Is_Registered dwords and patching them in Winlicense 2.0.6.5. by quosego/snd
//////////////////////////////////////////////////////////////////////////
///////----翻译:nevsayno
///////----时间:2010.5.18
//////----翻译的不好,请各位方家斧正。
//////////////////////////////////////////////////////////////////////////
介绍:
大多数依靠winlicnse保护的应用程序仅仅是依靠winlicnse提供的选项进行保护,选项通常是用了 WL API保护和偶尔有些用了自定义的宏保护。所以你可以很简单的修改这些api的返回值为1或者以这种方式实现,但是这种方法通常不不能修复宏保护或者其他自定义的检查和序列号保护。

但是我们仍然可以对其进行补丁,而且我经常这么做。

经过分析可以得出,winlicnse仅仅对两个dword值进行了检测是否为注册版,所以我们只需要找到这两个正确的dword值进行补丁就可以了。

更新说明;
Oreans 已经更新了这两个dword值,而且坦诚的说并不像其他公司那么的业余。所以这次我将引导你去找到这个正确的值。因为她们现在不再是固定的或者说不可能用通常的做法进行修复了。
不过呢,不用担心,这个过程不会很痛苦的。

查找dwords;
这里没有太多的更新,运行程序,在winlicnse区块中查找以下的字符串:
1)
B8 01 00 00 00 89 85 ?? ?? ?? ?? C7 85 

发现以下代码;  
MOV EAX,1                        // 不重要
MOV DWORD PTR SS:[EBP+xxxxxxxx],EAX            // 不重要
MOV DWORD PTR SS:[EBP+xxxxxxxx], {Variable_1)    // EBP+xxxxxxxx 记下这个值

(这个第三行的EBP+xxxxxxxx 是我们定位的第一个is_registered dword。)

Variable_1 是一个随机值,wl就是通过检查这个值进行判断是否注册的,不过判断这个正确的值不是0和1两种情况,而是随机值。如果Variable_1等于已经存储的值,那么wl则将其通过注册。

2)
00 00 00 00 00 00 00 00 81 BD 

发现以下代码;
CMP DWORD PTR SS:[EBP+xxxxxxxx],{Variable_2)
EBP+xxxxxxxx是第二个判断是否注册的is_registered dword值。

Variable_2 也是通过注册的必须的值,同样的,如果他等于已经存储的值,那就可以通过注册。

在已经找到的地方下硬件之行断点,然后重新加载程序,下一步要做的就是在内存中找到这两个值对比的地方或者写入值的地方,这些地方就是存储的is_registered dwords的地方。

补丁the dwords;
在之前的版本中is_registered dwords的值是固定的,但是她们现在是随机的生成,而且虽然会用到上面所讨论的代码,但这段代码你仅仅知道他的第二个的值。就像第一个,你虽然可以知道他的错误的值,但知道了这个值一点用没有。

下面我将给你讲解如何追踪Oreans虚拟机的得到第一个正确的值。可能你已经知道了是哪两个虚拟机,就是Risc和 Cisc嘛。因为他们有不同的复杂程度和执行的方法,所以我已经做了两个教程去查找第一个is_registered dword值。为了利用正确的值得到正确的虚拟机,一个简单的规则就是如果其地址定位在在wl区段,那就是cisc,定位在其他区段就是risc。

WL第二次进行访问对比第一is_registered dword的值和存储的正确的值会发生在VM代码段,所以在第一个值上设置硬件访问断点。然后,重新载入,shift+f9,一直到写入Variable_1的地方,然后按F9,你将会停在第一次访问vm 的地方,然后再次f9,你会停到第二次访问的地方。之后,is_registered dword就会和已经存储的值进行对比。现在,你可以选择读cisc还是risc的教程进行下一步了~~。

Cisc虚拟机对比:

- 按F7到达主检测句柄处,这时你在堆栈窗口可以看到ariable_1。
- 此处下断点,直到在寄存器ecx中看到variable_1的值。
- 现在,eax的值就是正确的值。存储这个值到第一个is_registered dword后。你的程序就会顺利通过注册,倒过来也可以。

现在你可能会想,这样子挺好,不过,你最好是告诉我这该死的vm是怎么计算的。Ok,那就简单看一下在cisc里面对比这两个值的明确的代码吧。
POP EAX
POP ECX
CMP ECX,EAX
PUSHFD
JMP {Main_Handler)  
                      // 所有的句柄都返回到这里

尽管你的Variable_1被会先被压入ecx,而且eax必须包含和他对比的值。但Junk VM代码从不写堆栈的值到eax或ecx里面去,所以variable_1也不会在ecx里面,除非是他的扩展。(上面的句柄很明显,但是如果你打算自己跟踪得到他那将会是一个宏大的工程)

Risc虚拟机中的对比;

- 跟踪variable_1一直到第二个值可以在堆栈中定位,最多20次吧。
00391FF8              7EAC5730    <--压入 is_registered dword {Variable_1)
00391FFC              00000000    <--堆栈开始

-在堆栈地址下硬件访问断点,运行,当中断的时候就是正确的is_registered dword了。和上面的步骤一样把值保存,你就可以通过注册了

-你可能会又一次问为什么这么做?你一旦明白了这些不模糊的代码,一切就豁然开朗了
MOV ECX,DWORD PTR DS:[ESI]      <-- 得到{Variable_1)
MOV EBX,DWORD PTR DS:[ESI-4]    <-- 得到正确的值
PUSH DWORD PTR DS:[EDI+70]
POPFD
CMP ECX,EBX  
            <-- 对比
PUSHFD

好了,就这些,在你脱壳之后,你只需要每次重新设置这些值就可以了,或者做一个补丁。

附注;
当有key的时候,wl会阻止写入这两个值,这些不能被解密而且会失败,获取api当然也会失败了!
尽管没有注册用户名,你仍可以添加一个返回值,多数程序是可以实现的,或者你可以做个补丁让他返回用户名。

祝大家玩的高兴!

PS: @Oreans, Your VM are belong to us!! ;)

Thnx to a certain provider of executables.

------------------------------------------


欢迎各位和我交流,Email:nevsayno@163.com