cdj68765 发表于 2015-5-29 19:06

水杉4 爆破过程

本帖最后由 cdj68765 于 2015-5-30 01:51 编辑

水杉4,在日本发售的一款建模软件,可以在官网下载到完整的源程序供安装试用,输入购买的激活码后,才能享受完整的功能,
该程序仅仅只用线下的用户名+序列号验证,验证过程并不需要联网,不过序列号验证过程会需要验证版本,一共五个版本,限期高级版和限期普通版,不限期高级版和普通版,以及试用版
该软件有64位以及32位版本,由于考虑到当前32位的动态调试技术比较成熟,而且估计作者并不会为了64位重新写一遍代码,而只会在原有代码的基础上,直接让IDE生成64位的程式,因此只要作者用的IDE是同一款,就可以保证汇编层面代码的相似性,所以本次就先突破32位程序,再突破64位的
32位下主要的动态调试工具还是OD,然后用IDA做辅助分析,哎,果然能直接保存修改结果的工具都是好工具啊,IDA你也学学,每次都让我用16位编辑修改程序,我会想死的。(别跟我提IDA6.0版本以后能直接保存修改结果的问题,我不想听QAQ)
64位使用X64dbg动态调试工具,根据32位的修改,修改相应的64位指令完成破解就行。

废话不多说,先从官网下载程式
然后第一件事情么,查壳

唔,然而并没有找到什么,两个可能性,未知壳,或者没壳
嘛,先不管了,直接载入OD吧,看OD怎么说

唔,没壳,而且注释巨详细无比,好像没啥挑战性的感觉,233
嘛,不管了,直接运行下,找下破解的线索呗

一运行,直接跳出一个框,要求你输入ID

按否的话,直接进入主程序并且是试用版的,按是的话,就是要求输入账号以及序列号的结构。
可以了,我们的线索已经找到,就从这个对话框入手,然后我们给MessageBox下断..下断,下毛断啊,这个明显不是系统的Wndows的API啊
来,我们换一套套路,右键 搜索字符串,看能不能从字符串下手,看能不能找到我感兴趣的东西

还真被我找到了,一个明显是注册表地址的东西,以及V4ID1和V4ID2,V4明显说的是版本4,ID1 2 就更不用说了。
我们双击进去看看
很长很长一段代码,不过不知道为什么,这个程序给的提示太明显

MQ就是水杉的简写,后面跟着一个英文字注册字样以及作用域符::外加一个清除密码的字样
嘛,我们在返回下一个断,然后运行看看

果真,一运行就直接断下来了,而且什么窗体都没有出现,估计这一块就是跟验证有关的过程,我们跟下去瞅瞅
首先我看到了

额,作用域后面写着检查注册证明..嘚,要不要这么为反汇编人员着想,把明显是编写人员写的函数名称展现给我看?

嘛,也不管吧,Ctrl+F9,跳转到函数的返回,下个断,然后跟下去看看
$ ==>    >call Metaseq.MQRegister::CheckRegistrat>
$+5      >mov ebx,dword ptr ds:[<&MTKit.MTDialog:>;MTKit.MTDialog::messageYesNoBox
$+B      >mov esi,dword ptr ds:[<&MLibs.MString::>;MLibs.MString::MString
$+11   >mov edi,dword ptr ds:[<&MLibs.MString::>;MLibs.MString::~MString
$+17   >add esp,0x4
$+1A   >mov dword ptr ss:,eax         ;把验证结果输入到该堆栈地址
$+1E   >cmp eax,0x3                           ;判断验证结果是否是3; Switch (cases 0..6)
$+21   >jnz XMetaseq.014696A9                   ;判断不通过则跳转
$+23   >push Metaseq.016A41BC                   ;Metasequoia; Case 3 of switch 01469641
$+28   >lea ecx,dword ptr ss:
$+2C   >call esi                              ;<&MLibs.MString::MString>
$+2E   >mov byte ptr ss:,0x1
$+36   >mov ecx,Metaseq.016A41E0                ;SerialTimeover

不知道各种有木有从这里看出什么没,
至少我这边看到,经过刚才那个叫做CheckRegistration的函数以后,后面紧跟着一个叫做MTDialog::messageYesNoBox的函数,看来程式一打开就显示的确认序列号窗口,就是这货了,只不过这里还没有call,只是把虚拟地址给了ebx寄存器,准备找个时机call ebx就行
后面一个选择跳转,然后又看到了SerialTimeover,估计是试用期限到了的意思
我们不管,直接F9,等待下一次断在CheckRegistration的地方
跳出来验证窗口,我不管,直接运行程序,然后程序又一次断下来了
再按下F9,然后程序直接运行了
好,以上都是收集线索的过程,接下来我们要开始调试了
首先我确认,CheckRegistration就是一个验证你注册与否的地方,也就是说,将来我要修改的地方指令,就在这里面,只不过现在这个函数对我来说,还是个黑匣子,我想从外部了解他


我们回到之前那个我看到MTKit.MTDialog::messageYesNoBox的地方,我认为,如果我们注册通过了,程序就不应该call这个函数的
于是我们跟踪下去
$-50   >test eax,eax                               ;经过CheckRegistration后,不久就跳到这里
$-4E   >je Metaseq.00F398F6                        ;确认是否跳过messageYesNoBox
...
...
...
$ ==>    >call ebx                                 ;call 了MTKit.MTDialog::messageYesNoBox

经过CheckRegistration以后很快就到了这里,用test进行对比rax寄存器的与操作,我们没有注册,所以这里的对比结果是真,因此后面的je不跳过
我把后面的je改成jne以后,再启动,messageYesNoBox窗口果然不见了,不过仅仅只是确认注册信息的窗口不见了而已,软件启动以后还是试用版


不过至少,我清楚了,经过CheckRegistration以后,会影响rax寄存器里面的数值,如果call这个函数以后,输出到rax里面的是1,就代表没有注册
于是我们回到CheckRegistration这个函数里面,现在开始,才认真观看这个函数到底干了什么
首先是一大段的初始化过程
$ ==>    >push ebp
$+1      >mov ebp,esp
$+3      >and esp,0xFFFFFFF8
$+6      >push -0x1
$+8      >push Metaseq.013E0352
$+D      >mov eax,dword ptr fs:
$+13   >push eax
$+14   >sub esp,0xA0
$+1A   >mov eax,dword ptr ds:
$+1F   >xor eax,esp
$+21   >mov dword ptr ss:,eax
$+28   >push ebx
$+29   >push esi
$+2A   >push edi
$+2B   >mov eax,dword ptr ds:
$+30   >xor eax,esp
$+32   >push eax
$+33   >lea eax,dword ptr ss:
$+3A   >mov dword ptr fs:,eax
$+40   >mov eax,
$+43   >mov edi,ecx
$+45   >xor ebx,ebx
$+47   >mov dword ptr ss:,ebx
$+4B   >mov esi,dword ptr ds:[<&MLibs.MString::MSt>;MLibs.MString::MString
$+51   >lea ecx,dword ptr ss:
$+55   >mov dword ptr ss:,eax
$+59   >mov dword ptr ss:,edi
$+5D   >call esi                                 ;<&MLibs.MString::MString>
$+5F   >lea ecx,dword ptr ss:
$+63   >mov dword ptr ss:,ebx
$+6A   >call esi
$+6C   >lea ecx,dword ptr ss:
$+73   >mov byte ptr ss:,0x1
$+7B   >call esi
$+7D   >mov byte ptr ss:,0x2
$+85   >mov dword ptr ss:,0x1
$+8D   >mov dword ptr ds:,-0x1
$+93   >mov byte ptr ds:,bl
$+99   >mov dword ptr ss:,ebx
$+9D   >mov dword ptr ss:,ebx
$+A1   >mov dword ptr ss:,ebx
$+A5   >mov byte ptr ss:,0x3
$+AD   >xor ecx,ecx
$+AF   >mov dword ptr ss:,0x7
$+BA   >mov dword ptr ss:,ebx
$+C1   >mov word ptr ss:,cx
$+C9   >lea ecx,dword ptr ss:
$+D0   >lea ebx,dword ptr ss:
$+D4   >mov byte ptr ss:,0x4
$+DC   >call Metaseq.std::vector<std::basic_string>
$+E1   >mov byte ptr ss:,0x3
$+E9   >cmp dword ptr ss:,0x8
$+F1   >jb XMetaseq.013B8524
$+F3   >mov edx,dword ptr ss:
$+FA   >push edx
$+FB   >call dword ptr ds:[<&MSVCR100.operator del>;msvcr100.operator delete
$+101    >add esp,0x4
$+104    >xor ebx,ebx
$+106    >xor eax,eax
$+108    >lea ecx,dword ptr ss:
$+10C    >mov dword ptr ss:,0x7
$+117    >mov dword ptr ss:,ebx
$+11E    >mov word ptr ss:,ax

初始化各种参数,我估计很多都是迷惑人的,
然后是从注册表获得激活码的过程
$+126    >call dword ptr ds:[<&MLibs.MRegistry::MReg>;MLibs.MRegistry::MRegistry
$+12C    >mov byte ptr ss:,0x5
$+134    >mov edi,dword ptr ds:[<&MLibs.MRegistry::O>;MLibs.MRegistry::Open
$+13A    >mov dword ptr ss:,ebx
$+13E    >mov edi,edi
$+140    >/cmp byte ptr ds:,0x0
$+147    >|jnz Metaseq.013B86E6
$+14D    >|mov esi,ebx
$+14F    >|neg esi
$+151    >|push 0x0
$+153    >|sbb esi,esi
$+155    >|push Metaseq.0144D460                     ;SOFTWARE\Tetraface\Metasequoia
$+15A    >|add esi,0x80000002
$+160    >|push esi
$+161    >|lea ecx,dword ptr ss:
$+165    >|call edi
$+167    >|test al,al
$+169    >|jnz XMetaseq.013B85A1
$+16B    >|push 0x1
$+16D    >|push Metaseq.0144D460                     ;SOFTWARE\Tetraface\Metasequoia
$+172    >|push esi
$+173    >|lea ecx,dword ptr ss:
$+177    >|call edi
$+179    >|test al,al
$+17B    >|je Metaseq.013B86B8
$+181    >|mov esi,dword ptr ds:[<&MLibs.MRegistry::>;MLibs.MRegistry::ReadString
$+187    >|lea ecx,dword ptr ss:
$+18B    >|push ecx
$+18C    >|push Metaseq.0144D4AC                     ;V4ID1
$+191    >|lea ecx,dword ptr ss:
$+195    >|call esi                                  ;<&MLibs.MRegistry::ReadString>
$+197    >|lea edx,dword ptr ss:
$+19B    >|push edx
$+19C    >|push Metaseq.0144D4B8                     ;V4ID2
$+1A1    >|lea ecx,dword ptr ss:
$+1A5    >|call esi
$+1A7    >|lea ecx,dword ptr ss:
$+1AB    >|call dword ptr ds:[<&MLibs.MRegistry::Clo>;MLibs.MRegistry::Close

到此为止,后面跟了一大片我看不懂的代码,很乱
$+2D0    >push 0x5                                             ; /maxlen = 0x5
$+2D2    >push Metaseq.0144D4C4                              ; |00000
$+2D7    >push ecx                                             ; |wstr1
$+2D8    >call esi                                             ; \wcsncmp
$+2DA    >add esp,0xC
$+2DD    >test eax,eax
$+2DF    >je Metaseq.013B87D3
$+2E5    >mov edx,dword ptr ss:
$+2E9    >push 0x4
$+2EB    >push Metaseq.0144D4D0                              ;1111
$+2F0    >push edx
$+2F1    >call esi
$+2F3    >add esp,0xC
$+2F6    >test eax,eax
$+2F8    >je Metaseq.013B87D3
$+2FE    >mov eax,dword ptr ss:
$+302    >push 0x5
$+304    >push Metaseq.0144D4DC                              ;12345

push了一个冒充是字符对比的函数,下面跟了一堆意义不明的字符串比如1111啊12345啊56789啊,等等字符串对比
我很清楚,这里都是迷惑我的,而且,你们知道这段指令多少长不?整整4789行啊,作者也是够无聊的
不过到这里,我确实没辙了,迷惑人的代码段太多,光靠OD没戏,我把程序载入了IDA,准备用F5功能直接看

IDA漫长的静态分析结束以后,我们点下功能窗口,既然在OD里面都把函数名一一显示了,那在IDA里面更是如此了,功能窗口里面,都是正儿八经的函数名,我们搜索下目标函数CheckRegistration

双击,什么都不想,直接F5,好吧,即便是把汇编变成了伪C语言代码,代码长度依旧是那么长,595行..
然后,通过之前的分析,我们知道,程序会返回一个数值,如果是0的话,验证不通过,于是我们看下返回那里

恩,程序最后,会返回v50这个变量,我们往上面翻翻,看哪里修改了v50这个变量(鼠标在这里点下V50就会高亮显示v50,往前面翻的时候,注意看高亮显示的地方就行,当然直接搜索V50也未尝不可以)
找到了

一共有三个地方会修改V50,一个是我之前将的初始化过程,会被v50初始化成1,然后如果期间都没有被修改,那初始化的结果1会被直接输出
第二处就是如图所示的这里,v50被改成了0,让我们回忆之前的一个地方,test rax,rax,用来判断是否显示验证窗口的地方,
显然v50被改成0就表示那里不会显示验证窗口,也就是说,改成0是正解
那么v50被改成3呢,记不记得我之前提到的试用期限到了?那么改成3,就是代码期限到了
然后我们可以注意到
sub_806C60(v8, v55, (char *)&v45 + 3)
很明显一个功能函数,而且IDA以及OD都没有给明该函数的名字,不过确确实实,是经过这个函数以后,程序才判断是否要改v50的值的,那么我们就可以很轻松的理解,该函数,是一个用来验证你输入账号密码是否正确的函数,当然,事情要是这么简单,我文章标题就不会写爆破,而是【水杉算法分析&kengen编写】
原因很简单,小的无能,实在没有能力解这个验证算法,即便有IDA的F5功能,能看到伪代码也不行,
有兴趣的童鞋可以下载个水杉,然后根据我这篇文章找到这个call然后分析下
我可以稍微提一下
   if ( !(unsigned __int8)((int (__thiscall *)(char *, int, _DWORD, _DWORD))v4)(
                           &v60,
                           -(v3 != 0) - 2147483646,
                           L"SOFTWARE\\Tetraface\\Metasequoia",
                           0)
      && !(unsigned __int8)((int (__thiscall *)(char *, int, _DWORD, signed int))v4)(
                           &v60,
                           -(v3 != 0) - 2147483646,
                           L"SOFTWARE\\Tetraface\\Metasequoia",
                           1) )
      goto LABEL_20;
    MRegistry::ReadString(&v60, L"V4ID1", &Str1);
    MRegistry::ReadString(&v60, L"V4ID2", &v58);
    MRegistry::Close(&v60);
    if ( !v47 || !v59 )
      goto LABEL_20;
    BYTE3(v45) = 0;
    MQRegister::UncryptPassword(&v55, &v58);
if ( (unsigned __int8)sub_806C60(v8, v55, (char *)&v45 + 3) )
    {
      v9 = Str1;
      v50 = 0;
      *(_DWORD *)v56 = v9;
      byte_921AC0 = 1;
      goto LABEL_19;
    }
简化一下过程,便是如你所见的这些代码
代码很简单,就是从注册表获得序列号后首先call一个叫MQRegister::UncryptPassword(&v55, &v58);的函数,根据名字我们知道,是加密密码后,得到一个处理后的加密码
然后call sub_806C60,这个函数会根据用户名以及处理后的加密码来验证,验证过程中甚至用到了本地时间
如果验证通过就开始赋值过程,而我们需要做的,就是让程序直接进入赋值的过程,不用管注册的正确与否,也就是所谓的爆破,
嘛,改代码的过程肯定要回到OD的,但是那将近5000行代码,让人找了头痛,我们该怎么定位呢,

看,点击右键,复制到汇编

这种汇编兼C语言代码的样子是不是很奇怪?
对照这里,就能很轻松找到OD里面的目标位置了
我也不啰嗦了
$ ==>    >|.FF15 >call dword ptr ds:[<&MLibs.MRegistry:>;准备获得验证信息
$+6      >|.C6842>mov byte ptr ss:,0x5
$+E      >|.8B3D >mov edi,dword ptr ds:[<&MLibs.MRegist>;MLibs.MRegistry::Open
$+14   >|.895C2>mov dword ptr ss:,ebx
$+18   >|.8BFFmov edi,edi
$+1A   >|>803D >/cmp byte ptr ds:,0x0
$+21   >|.0F85 >|jnz Metaseq.006F86E6
$+27   >|.8BF3|mov esi,ebx
$+29   >|.F7DE|neg esi
$+2B   >|.6A 00 |push 0x0
$+2D   >|.1BF6|sbb esi,esi
$+2F   >|.68 60>|push Metaseq.0078D460                ;输入注册表的地址
$+34   >|.81C6 >|add esi,0x80000002
$+3A   >|.56    |push esi
$+3B   >|.8D4C2>|lea ecx,dword ptr ss:
$+3F   >|.FFD7|call edi
$+41   >|.84C0|test al,al
$+43   >|.75 16 |jnz XMetaseq.006F85A1                ;判断是从注册表获得用户名密码的,还是键入的
$+45   >|.6A 01 |push 0x1
$+47   >|.68 60>|push Metaseq.0078D460                ;再次输入注册表地址
$+4C   >|.56    |push esi
$+4D   >|.8D4C2>|lea ecx,dword ptr ss:
$+51   >|.FFD7|call edi
$+53   >|.84C0|test al,al
$+55   >|.0F84 >|je Metaseq.006F86B8                  ;验证该注册表目录是否存在,不存在的话话,下面的验证全部跳过
$+5B   >|>8B35 >|mov esi,dword ptr ds:[<&MLibs.MRegis>;MLibs.MRegistry::ReadString
$+61   >|.8D4C2>|lea ecx,dword ptr ss:
$+65   >|.51    |push ecx
$+66   >|.68 AC>|push Metaseq.0078D4AC                ;V4ID1
$+6B   >|.8D4C2>|lea ecx,dword ptr ss:
$+6F   >|.FFD6|call esi                           ;读取用户名; <&MLibs.MRegistry::ReadString>
$+71   >|.8D542>|lea edx,dword ptr ss:
$+75   >|.52    |push edx
$+76   >|.68 B8>|push Metaseq.0078D4B8                ;V4ID2
$+7B   >|.8D4C2>|lea ecx,dword ptr ss:
$+7F   >|.FFD6|call esi                           ;读取密码
$+81   >|.8D4C2>|lea ecx,dword ptr ss:
$+85   >|.FF15 >|call dword ptr ds:[<&MLibs.MRegistry>;结束获得验证信息
$+8B   >|.837C2>|cmp dword ptr ss:,0x0
$+90   >|.0F84 >|je Metaseq.006F86B8                  ;验证V4ID1是否为空,空的话下面的验证全部跳过
$+96   >|.837C2>|cmp dword ptr ss:,0x0
$+9B   >|.0F84 >|je Metaseq.006F86B8                  ;验证V4ID2是否为空,空的话下面的验证全部跳过
$+A1   >|.8D442>|lea eax,dword ptr ss:
$+A5   >|.50    |push eax
$+A6   >|.8D4C2>|lea ecx,dword ptr ss:
$+AA   >|.51    |push ecx
$+AB   >|.C6442>|mov byte ptr ss:,0x0
$+B0   >|.E8 D5>|call Metaseq.MQRegister::UncryptPass>;call一个函数,加密获得的V4ID2
....
....
$+FE   >|.83F8 >||cmp eax,0x13
$+101    >|.75 25 ||jnz XMetaseq.006F866E               ;验证是否有资格进行序列号验证阶段
$+103    >|.8B442>||mov eax,dword ptr ss:
$+107    >|.8D542>||lea edx,dword ptr ss:
$+10B    >|.52    ||push edx
$+10C    >|.8B542>||mov edx,dword ptr ss:
$+110    >|.50    ||push eax
$+111    >|.57    ||push edi
$+112    >|.E8 03>||call Metaseq.006F6C60               ;调用序列号验证函数
$+117    >|.83C4 >||add esp,0xC
$+11A    >|.84C0||test al,al
$+11C    >|.75 11 ||jnz XMetaseq.006F8675               ;判定验证是否通过
$+11E    >|.38442>||cmp byte ptr ss:,al
$+122    >|.75 2A ||jnz XMetaseq.006F8694
$+124    >|.8B7C2>||mov edi,dword ptr ss:
$+128    >|>43    ||inc ebx
$+129    >|.3BDE||cmp ebx,esi
$+12B    >|.^ 72 BD |\jb XMetaseq.006F8630
$+12D    >|.EB 27 |jmp XMetaseq.006F869C
$+12F    >|>8B4C2>|mov ecx,dword ptr ss:      ;验证通过开始赋值
$+133    >|.0FB75>|movzx edx,word ptr ds:
$+137    >|.8B442>|mov eax,dword ptr ss:
$+13B    >|.C7442>|mov dword ptr ss:,0x0
$+143    >|.8910|mov dword ptr ds:,edx
$+145    >|.C605 >|mov byte ptr ds:,0x1       ;最重要的赋值,之后判断功能是否注册全部是验证该数值的
$+14C    >|.EB 08 |jmp XMetaseq.006F869C                ;强制跳走

好,分析过以后,只要修改几个跳转就行了,就是验证注册表是否为空,验证取得的字符串是否为空,判断验证是否通过,以及是否有资格进行验证
把这几个跳转修改以后,运行程序
很好,前面的序列号验证窗口完全不弹出来了,看来修改的地方没错,
然后看看功能实现呢

阿勒,一堆功能没法实现,这些暗灰色的图标无法点击,并且有小标,标着Std(standard)以及EX,猜测是需要什么版本才能用什么功能的意思

甚至还会出现,许可证错误的提示
好吧,果然没有那么简单就能破解啊

给CheckRegistration下断,然后再次运行程序,看都是哪里在验证许可证

一共也就这么些函数在call CheckRegistration
断在一个奇怪的地方,

OD显示,这一段函数的名字叫做getclass,得到等级/种类?心中大概猜到这里是什么了,

我单步跟踪,看看到底怎么一回事
$ ==>    >|.E8 E1>call Metaseq.MQRegister::CheckRegistr>
$+5      >|.83C4 >add esp,0x4
$+8      >|.85C0test eax,eax
$+A      >|.74 0D je XMetaseq.003B2A53                  ;判断CheckRegistration是否验证通过
$+C      >|.C746 >mov dword ptr ds:,0x0
$+13   >|.33C0xor eax,eax
$+15   >|.8BE5mov esp,ebp
$+17   >|.5D    pop ebp
$+18   >|.C3    retn
$+19   >|>8B45 >mov eax,
$+1C   >|.83F8 >cmp eax,0x45
$+1F   >|.74 20 je XMetaseq.003B2A7B                  ;如果是Ex版就跳转
$+21   >|.83F8 >cmp eax,0x54
$+24   >|.74 1B je XMetaseq.003B2A7B                  ;如果是Std版本就跳转
$+26   >|.83F8 >cmp eax,0x52
$+29   >|.74 16 je XMetaseq.003B2A7B                  ;如果是限期版的Ex就跳转
$+2B   >|.83F8 >cmp eax,0x53
$+2E   >|.74 05 je XMetaseq.003B2A6F                  ;如果是限期版的Std就跳转
$+30   >|.83F8 >cmp eax,0x55
$+33   >|.75 18 jnz XMetaseq.003B2A87               ;如果什么都不是,就跳转
$+35   >|>B8 10>mov eax,0x10
$+3A   >|.8946 >mov dword ptr ds:,eax
$+3D   >|.8BE5mov esp,ebp
$+3F   >|.5D    pop ebp
$+40   >|.C3    retn                                  ;赋值返回rax 10,代表Std版本
$+41   >|>B8 20>mov eax,0x20
$+46   >|.8946 >mov dword ptr ds:,eax
$+49   >|.8BE5mov esp,ebp
$+4B   >|.5D    pop ebp
$+4C   >|.C3    retn                                  ;赋值返回rax 20,代表Ex版本
$+4D   >|>8B46 >mov eax,dword ptr ds:
$+50   >|.8BE5mov esp,ebp
$+52   >|.5D    pop ebp
$+53   >\.C3    retn ; 赋值返回rax 0,代表试用版

聪明的看官们,如果是你们,应该会选择哪个版本强制跳转呢,233

很好,原来的暗灰色已经变成了可以点击的实色了,并且可以点击实现对应的功能了


看,虽然用户名,密码栏都是空的,但是版本显示却是EX
至此可以表示,水杉4 32位的破解已经完成
让我们转战64位的
================================================================================================================================
有了32位的破解基础,64位也就是找一个call,然后改跳转的节奏,当然,前提都要建立下32位和64位在汇编层面上,指令差不多的情况下
载入64位的程式到X64dbg,然后找CheckRegistration这个函数,怎么找?

在这个标志选项卡里面,选择载入的程式,右边的框里面,就会列出来所有的函数了,当然此方法并不是所有程序都适用就是了
然后搜索下CheckRegistration,很快就精确找到了,双击函数,跳到函数头
然后我们观察下和32位上的指令,有木有区别

一样的取得注册表地址,取得用户名和密码,除了指令表达上面不一样以外,执行的操作都是一模一样的,这样子就好办了
我们按照32位上的操作,如法炮制就行了
$ = | jnz metaseq.13FA4A95F               |
$+6 | mov eax,r13d                        |
$+9 | neg eax                               |
$+B | sbb rdi,rdi                           |
$+E | add rdi,FFFFFFFF80000002            |
$+1 | xor r9d,r9d                           |
$+1 | lea r8,qword ptr ds:[<`string'>]      | ;取得注册表地址所在地"SOFTWARE\\Tetraface\\Metasequoia"
$+1 | mov rdx,rdi                           |
$+2 | lea rcx,qword ptr ss:         |
$+2 | call qword ptr ds:[<__imp_?Open@MRegi | ;准备获得验证信息
$+2 | test al,al                            |
$+2 | jnz metaseq.13FA4A682               |
$+3 | mov cl,1                              |
$+3 | lea r8,qword ptr ds:[<`string'>]      | ;再次取得注册表地址所在地:L"SOFTWARE\\Tetraface\\Metasequoia"
$+3 | mov rdx,rdi                           |
$+3 | lea rcx,qword ptr ss:         |
$+4 | call qword ptr ds:[<__imp_?Open@MRegi |
$+4 | test al,al                            |
$+4 | je metaseq.13FA4A792                  | ;判断注册表是否为空,空的话就跳走,不进行注册码验证
$+4 | lea r8,qword ptr ss:          |
$+5 | lea rdx,qword ptr ds:[<`string'>]   | ;13FB20AD8:L"V4ID1"
$+5 | lea rcx,qword ptr ss:         |
$+5 | call qword ptr ds:[<__imp_?ReadString | ;取得用户名
$+6 | lea r8,qword ptr ss:          |
$+6 | lea rdx,qword ptr ds:[<`string'>]   | ;13FB20AE8:L"V4ID2"
$+7 | lea rcx,qword ptr ss:         |
$+7 | call qword ptr ds:[<__imp_?ReadString | ;取得密码
$+7 | lea rcx,qword ptr ss:         |
$+7 | call qword ptr ds:[<__imp_?Close@MReg | ;结束获得验证信息
$+8 | cmp qword ptr ss:,0         |
$+8 | je metaseq.13FA4A792                  | ;判断用户名是否为空
$+9 | cmp qword ptr ss:,0         |
$+9 | je metaseq.13FA4A792                  | ;判断密码是否为空
$+9 | mov byte ptr ss:,0            |
$+A | lea rdx,qword ptr ss:         |
$+A | lea rcx,qword ptr ss:         |
$+A | call <metaseq.class MString __cdecl M | ;加密取得的密码为加密码
...
...
$+E | cmp rcx,13                            |
$+F | jnz metaseq.13FA4A74C               | ;判断是否有资格进行验证码验证
$+F | mov r9,r14                            |
$+F | lea r8,qword ptr ss:          |
$+F | mov rdx,qword ptr ss:         |
$+1 | mov rcx,r10                           |
$+1 | call metaseq.13FA48770                | ;进行验证码验证
$+1 | test al,al                            |
$+1 | jnz metaseq.13FA4A760               | ;验证通过就跳转
$+1 | cmp byte ptr ss:,al         |
...
...
$+1 | xor esi,esi                           | ;开始验证通过的各参数赋值
$+1 | mov dword ptr ss:,esi         |
$+1 | mov rax,qword ptr ss:         |
$+1 | movzx ecx,word ptr ds:         |
$+1 | mov dword ptr ds:,ecx            |
$+1 | mov byte ptr ds:,1         | ;最重要的一个参数赋值
$+1 | jmp metaseq.13FA4A77D               | ;跳走
修改上述几个跳转以后就算通过验证了,
而验证通过以后就是版本选择阶段
000 | call <metaseq.enum MQRegister::REGINF |
000 | test eax,eax                        |
000 | je metaseq.13F3AC459                  | ;验证通过就跳转
000 | mov dword ptr ds:,0            |
000 | xor eax,eax                           |
000 | add rsp,20                            |
000 | pop rbx                               |
000 | ret                                 |
000 | mov eax,dword ptr ss:         |
000 | cmp eax,45                            |
000 | je metaseq.13F3AC488                  | ;是EX版就跳转
000 | cmp eax,54                            |
000 | je metaseq.13F3AC488                  | ;Std版就跳转
000 | cmp eax,52                            |
000 | je metaseq.13F3AC488                  | ;Ex限期版跳转
000 | cmp eax,53                            |
000 | je metaseq.13F3AC476                  | ;限期版Std就跳转
000 | cmp eax,55                            |
000 | jnz metaseq.13F3AC49A               | ;啥都不是就跳转
000 | mov dword ptr ds:,10         |
000 | mov eax,10                            |
000 | add rsp,20                            |
000 | pop rbx                               |
000 | ret                                 |
000 | mov dword ptr ds:,20         |
000 | mov eax,20                            |
000 | add rsp,20                            |
000 | pop rbx                               |
000 | ret                                 |
000 | mov eax,dword ptr ds:          |
000 | add rsp,20                            |
000 | pop rbx                               |
000 | ret                                 |
好,保存一下结果,64位也就顺势破解完毕了,简单吧

好吧,是这个软件给的提示,实在是太多了,函数连名字都明确告诉你了,再不能破解就真的醉了
不过即便如此,我这样做也只能算是爆破,要想真正的破解,还是需要分析验证算法的
不过本人能力有限,如果仅仅是用户名,密码的验证我还可以处理,不过这个验证是对输入的密码经过一次不明所以的加密以后再验证的,有点头大,以后有时间再慢慢分析,就这样,光速匿

rainfly-lee 发表于 2017-7-27 19:24

不好意思,今天 刚注册,不能在留言板里回复;关于你水杉4注册机源代码的算法,看了N遍你的贴子,也自己看了伪代码,但有个函数不知道怎么作用!如果有可能,可以帮我看下哪里有错吗?

rainfly-lee 发表于 2017-7-27 20:23

哈哈,忘记跟你说了,百度可以出来,有人已经把你那贴转出来了,我早做成PDF的放手机里了,现在我在学习你的源码!让你费心了!

今天你笑了吗 发表于 2015-5-29 19:15

segasonyn64 发表于 2015-5-30 00:04

不错,X64破解时亮点,感谢分享经验!!

yysniper 发表于 2015-5-30 00:44

其实日本人的软件不加壳是意料之中的,他们有付费的习惯

百家 发表于 2015-5-30 01:06

高手,各种羡慕

Hmily 发表于 2015-6-3 12:08

这帖子让我联想到破解Sublime Text和Beyond Compare的过程,都是先拿32位分析,64位就轻车熟路的搞了,赞一个!

tzxinqing 发表于 2015-6-3 15:21

竟然在前排发现了h大

lthink 发表于 2015-6-4 20:39

给发帖者最大的支持!

19nuclear91 发表于 2015-6-6 09:01

奈斯啊熊弟
支持一发

lbl紫夜 发表于 2015-6-7 07:15

学习啦 ~!谢谢~1
页: [1] 2 3
查看完整版本: 水杉4 爆破过程