首页
社区
课程
招聘
[旧帖] [原创]麦克疯 简单破解过程 [申请邀请码] 0.00雪花
发表于: 2010-4-3 05:05 2382

[旧帖] [原创]麦克疯 简单破解过程 [申请邀请码] 0.00雪花

2010-4-3 05:05
2382
【原创】麦克疯  简单破解过程 【申请邀请码】

-------------------------------
软件名称: 麦克疯
版本号:   官方版本号 v6 下载日期 3.18 2010
下载地址: http://51mike.com
发布日期: 4.2.2010
作者        sippey
Email   sippey@163.com
目的   : GF的要求。。。 汗
破解目标: 免插播广告,破解45秒拨号限制,解密被加密的WMV文件
工具软件: OllyDBG (很老的版本)
        IDA  
        Winhex
        FileMon       
        Reshacker
-------------------------------------

麦克疯是一个用于网络K歌的软件。比起其他的单机版K歌软件的优点在于
歌库可以从网上下载,不需要花钱或者让朋友copy歌库,而且歌库也能常用
常新。MTV的视频质量比单机版的差一点,不过自己用用也可以了,尤其是接在
电视上面,基本看不出来。 至于用户上传自己作品之类的功能,感觉没什么用。

没有破解的时候,注册的免费用户只能点播部分免费曲目,其他的大部分会在歌曲
之间插播广告。而且会有45秒播放限制,还有banner提示45秒显示。播放到45秒自动停止播放,提示是否要
注册VIP用户。简单的用FileMon探测,发现缓冲的文件存放在
%USERPROFILE%\Local Settings\Application Data\KaraKing\MediaCache (好像因版本不同而异)处,
文件类型WMV(据说还可能有其他格式 不过我没下载几首所以没有找到)。

使用暴风影音播放文件,提示文件损坏。 Winhex 打开缓存的WMV,发现文件头非标准WMV文件头,
怀疑加密。

PEID 查看主程序GameHall.exe, VC6编译,没壳。 哈哈,比较熟。

运行程序,用Spy++看一下,发现很多都是用网页控件搞定的,视频播放功能是用WMP和Flash的控件。
事实上整个程序就是IE控件嵌入到EXE里面,怀疑作者一开始想用Web搞定所有东东,弄纯网页版。
后来出现技术或安全等方面的考虑,就转而改用EXE。另外一种可能性就是作者是做网页功夫不错,想法也很奇特,所以
剑走偏锋就写出这样的程序。

主观分析到此结束。开工。

既然文件缓存是加密的,想要播放必然有两种可能。 1.播放时解密到一个临时文件,再播放。2.另一种是
直接写个自己的DShow filter,抢在WMV decoder filter之前先把文件流解密。

第一种方法简单,不过在运行过程中文件系统里会有完全解密的文件,第二种比较复杂,不过感觉加密效果比较
好。先猜作者用的第一种。

思路很简单,OllyDBG启动程序,注意要忽略所有的内存异常,直接加到调试设置中的忽略选项里面。
待程序已经准备好,并且下载完成一首MTV之后。bp CreateFileA/W,点击播放列表里面一个已经
缓冲好的mtv。 这样会断下几次,因为程序使用了IE控件,所以会有读网页缓存,cookie之类的操作。直到断在
一个MTV缓存文件夹中的文件。这个时候,程序已经准备好打开加密的文件并解密了。查看Call Stack
调用堆栈

ESP      返回地址                  例程 / 参数                                                                                                                                      调用来自                  Frame
00FA80C4  0053279C              kernel32.CreateFileA                                                                                                                             GameHall.00532796         00FA810C
00FA80C8  02FADE81                FileName = "c:\documents and settings\xxxxx\local settings\application data\karaking\mediacache\1000025726noedxa.wmv"
00FA80CC  80000000                Access = GENERIC_READ
00FA80D0  00000003                ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
00FA80D4  00FA80F0                pSecurity = 00FA80F0
00FA80D8  00000003                Mode = OPEN_EXISTING
00FA80DC  00000080                Attributes = NORMAL
00FA80E0  00000000                hTemplateFile = NULL
00FA8110  0052C2DC              ? GameHall.005325E3                                                                                                                              GameHall.0052C2D7
00FA813C  00524662              GameHall.0052C198                                                                                                                                GameHall.0052465D         00FA8138
00FA8158  00524681              GameHall.00524641                                                                                                                                GameHall.fopen+0A
00FA8168  00502758              00524672 <GameHall.fopen>                                                                                                                                 GameHall.00502753
00FA816C  02FADE81                path = "c:\documents and settings\xxxxx\local settings\application data\karaking\mediacache\1000025726noedxa.wmv"
00FA8170  005C7CF4                mode = "rb"
00FA8278  005020C1              GameHall.005026B0                                                                                                                                GameHall.ReadAndDecryptW
00FA827C  00FA82B0                Arg1 = 00FA82B0
00FA8280  01029490                Arg2 = 01029490
00FA8284  00FA82C0                Arg3 = 00FA82C0
00FA8288  00FA82C4                Arg4 = 00FA82C4
01029388  00501EA6              <GameHall.ReadAndDecrypt>  502000                                                                                                                   GameHall.00501EA1
0102944C  004715A3              GameHall.00501DB0                                                                                                                                GameHall.0047159E
01029450  01029490                Arg1 = 01029490
01029454  01029470                Arg2 = 01029470
010294AC  004DE4FE              <GameHall.DecryptB1>                                                                                                                             GameHall.004DE4F9
01029504  004DA039              GameHall.004DE320                                                                                                                                GameHall.004DA034
01029518  0044D9DB              GameHall.004DA020                                                                                                                                GameHall.0044D9D6
010295E0  0046F2EA              GameHall.0044D790                                                                                                                                GameHall.0046F2E5
01029604  00561D62              包含 GameHall.0046F2EA                                                                                                                             GameHall.00561D60
01029610  005612A7              GameHall.00561D52                                                                                                                                GameHall.005612A2
01029688  00522C1A              ? GameHall.00561184                                                                                                                              GameHall.00522C15
010296F0  0051C1C6              GameHall.00522A7F                                                                                                                                GameHall.0051C1C1         010296EC
01029700  00549D72              包含 GameHall.0051C1C6                                                                                                                             GameHall.00549D6F         01029720
01029724  0054A209              GameHall.00549D46                                                                                                                                GameHall.0054A204         01029720
01029728  0000046D                Arg1 = 0000046D
0102972C  FFFFFFFE                Arg2 = FFFFFFFE
01029730  0102976C                Arg3 = 0102976C
01029734  00000000                Arg4 = 00000000
01029748  0051ED8B              GameHall.0054A1EE                                                                                                                                GameHall.0051ED88         01029744
0102974C  0000046D                Arg1 = 0000046D
01029750  FFFFFFFE                Arg2 = FFFFFFFE
01029754  0102976C                Arg3 = 0102976C
01029758  00000000                Arg4 = 00000000
01029760  0051FCDF              GameHall.0051ED52                                                                                                                                GameHall.0051FCDA         01029790
01029794  3E25EDF2              Maybe GameHall.0051FCA0                                                                                                                          ieframe.3E25EDEF          01029790
...
                                                                                                                        mshtml.3DABFE4A           01029EEC

堆栈里面的地址已经有我的一些标号了。到这里的基本思路就是把几级的Call都F2设断。然后F9让程序跑飞,回去在点击
播放重来一次。 分析调用关系。 这时候也可以用IDA静态分析,我知道IDA也有debugger不过还是OllyDBG用着舒服,
所以只能两个程序切来切去。

IDA说00502753是调用 fopen所以我们只考虑它之前的调用。 几次试验后发现在004DA020的Call,应该是关键
的一个调用。它之后调用了 004DE320。

004DE320用IDA 分析一下,用F5功能出来源码。IDA 并没有猜出来一些CString的函数,可能是部分设置有问题,
所以我自己对着这汇编的大概给他们命了名,这样就能看出来不少了。

分析代码 基本就是先确定临时文件路径然后调用DecryptB1_471500去解密。调用的参数分别是源文件的地址
和解密后文件的临时地址。

DecryptB1_471500 (471500是函数地址)
IDA看出来里面竟然用了好多std::string的东西,看来不像是一个人写的。至少不是一个
时间写的。 IDA已经分析出来大部分string函数的名称,只需回到VC的include里面找到xstring文件
看看他们到底是干什么的就行了。不是我不熟悉std::string的函数,只是这些函数很多是private的,
实在是没有见过啊。

用OllyDbg进入471500后下断 WriteFile和WriteFileEx。 F9几次,直到发现在写那个新建的临时文件。
怎么判断是否是写那个文件?CreateFileA断下的时候记得先运行到返回看看hFile的数字,也就是eax的值。
把文件名和对应的handle记下来。如果你忘了记得话,Ctrl+F2重新运行程序吧。

此时堆栈中找到501DB0。501DB0也被DecryptB1调用。看看501DB0, 发现没什么特殊,只是有一个关键的调用
call 502000。跟进。

502000一开始用_alloc_probe在stack里面分配了5xxK的内存,看样子应该是作者在函数体里面定义了缓存区。
IDA看一下502000,结构比较清楚:

1 变量初始化
2 call 5026B0  获取文件头信息
3 call 483A40  判断两种解密算法
算法1
4 打开文件
5 call 502D30  继续准备解密key
6 然后就开始循环解密 貌似我这里只会解密前一部分(256KB) 使用的解密函数是5038F0 之后就直接写到文件了。
算法2
4 打开文件
5 call 502D30  继续准备解密key
6 然后就开始循环解密 call 5038F0

中间的一些SendMessage猜想是因为这段程序跑在主线程里面,如果不这样界面可能会卡掉。

本来打算写出解密算法的,无奈算法复杂,跟了一会儿没有耐心了。 于是开始看是否有对应的加密部分,如果没有,说明
文件是在服务器端被加密的(这样想要得到原始WMV文件就要看懂解密算法),如果有说明是在客户端被加密的。

点击下载一个MTV,然后等文件快下载完的时候,设断CreateFileA/W,跟踪堆栈,这个时候很容易让OllyDBG卡死。
后来分析原因是此处断在一个下载线程里面。我的做法是迅速截下调用堆栈的图 然后慢慢分析。

更有意思的是,这个CreateFileA/W 断下的地方可以找到一个可以播放的WMV,证明服务器没有加密。 这样就好办了。

在堆栈中找到关键的一个Call, 503BA0。 用IDA分析内容
char __stdcall EnCrypt1(int strDecryptedFilename, int strEncryptedFName)
{
  int v3; // edx@1
  char v4; // ST23_1@1
  int v5; // [sp+1Ch] [bp-98h]@1
  char v6; // [sp+20h] [bp-94h]@1
  int (__stdcall **v7)(char); // [sp+74h] [bp-40h]@1
  int v8; // [sp+B0h] [bp-4h]@1

  v8 = 0;
  v5 = (int)&unk_58B950;
  sub_49C510(&v7);
  v7 = &off_58B94C;
  v3 = *((_DWORD *)&unk_58B950 + 1);
  LOBYTE(v8) = 1;
  *(int *)((char *)&v5 + v3) = (int)&off_58B93C;
  std__basic_ios_char_std__char_traits_char____init(&v6, 0);
  v8 = 3;
  StlLibFunction2_49D8A0(0);
  *(int *)((char *)&v5 + *(_DWORD *)(v5 + 4)) = (int)&off_58B944;
  LOBYTE(v8) = 4;
  v4 = EncryptMaybe_503CF0(strEncryptedFName, strDecryptedFilename, 1, strEncryptedFName, (int)&v5, 1, 0, 524288);
  *(int *)((char *)&v5 + *(_DWORD *)(v5 + 4)) = (int)&off_58B944;
  LOBYTE(v8) = 5;
  sub_49CA80(&v6);
  LOBYTE(v8) = 0;
  *(int *)((char *)&v5 + *(_DWORD *)(v5 + 4)) = (int)&off_58B93C;
  v7 = &off_58B94C;
  std__ios_base___ios_base(&v7);
  return v4;
}

可以发现他会调用503CF0。 503CF0很长,基本上可以确定是加密部分了。不过我们已经不再关心这一点。因为我们可以直接用copyfile代替加密和解密,这样不加密的
WMV文件会保存在缓存文件夹里面。以后想拿来这些MTV做其他用途也比较方便。

分别修改471500和503BA0处的代码。 让他们等价于CopyFile.

00471500 <>   /E9 09341100            jmp 0058490E                         ;  original : push -1; push 572088
00471505      |90                     nop
00471506      |90                     nop

00503BA0 <>   /E9 3A0D0800            jmp 005848DF                           ;  original : push -1;push 581B89
00503BA5      |90                     nop
00503BA6      |90                     nop

这里是Patch 代码,放在text段最后没有用到得地方
005848DF <>    60                     pushad
005848E0       56                     push esi
005848E1       57                     push edi
005848E2       54                     push esp
005848E3       55                     push ebp
005848E4       8B5C24 34              mov ebx,dword ptr ss:[esp+34]                           ;  un crypted file
005848E8       8B4B 04                mov ecx,dword ptr ds:[ebx+4]
005848EB       90                     nop
005848EC       90                     nop
005848ED       90                     nop
005848EE       90                     nop
005848EF       90                     nop
005848F0       90                     nop
005848F1       90                     nop
005848F2       90                     nop
005848F3       90                     nop
005848F4       8B5C24 38              mov ebx,dword ptr ss:[esp+38]
005848F8       8B53 04                mov edx,dword ptr ds:[ebx+4]
005848FB       6A 00                  push 0                                                  ; /FailIfExists = FALSE
005848FD       52                     push edx                                                ; |NewFileName
005848FE       51                     push ecx                                                ; |ExistingFileName
005848FF       FF15 80535800          call dword ptr ds:[<&KERNEL32.CopyFileA>]               ; \CopyFileA
00584905       5D                     pop ebp
00584906       5C                     pop esp
00584907       5F                     pop edi
00584908       5E                     pop esi
00584909       61                     popad
0058490A       C2 0800                retn 8
0058490D       90                     nop

0058490E <>    60                     pushad
0058490F       55                     push ebp
00584910       56                     push esi
00584911       57                     push edi
00584912       8B5424 30              mov edx,dword ptr ss:[esp+30]
00584916       8B4C24 34              mov ecx,dword ptr ss:[esp+34]
0058491A       6A 00                  push 0                                                  ; /FailIfExists = FALSE
0058491C       51                     push ecx                                                ; |NewFileName
0058491D       52                     push edx                                                ; |ExistingFileName
0058491E       FF15 80535800          call dword ptr ds:[<&KERNEL32.CopyFileA>]               ; \CopyFileA
00584924       5F                     pop edi
00584925       5E                     pop esi
00584926       5D                     pop ebp
00584927       61                     popad
00584928       33C0                   xor eax,eax
0058492A       40                     inc eax
0058492B       C2 0800                retn 8

复制到可执行文件,保存。
然后记着删掉已经缓存的文件,执行修改后exe。以后缓存的文件就都不是加密的了,哈哈。可以在WMP或者暴风里面直接播放。

虽然破掉了加密,但是还是有45秒播放的限制。这里我是这样想的,播放结束之后,程序会把解密的WMV文件删掉,于是我等播放到35秒左右的时候 bp DeleteFileA,嘿嘿果然断下来了。
查看调用堆栈以后,发现大概最终是在在窗口消息处理函数中调用的。

跟到消息处理里面,

004551B5     .  8BCE                   mov ecx,esi                                             ;  switch 9
004551B7     .  E8 345F0300            call GameHall.0048B0F0
004551BC     .  894424 20              mov dword ptr ss:[esp+20],eax
004551C0     .  8B85 40340000          mov eax,dword ptr ss:[ebp+3440]
004551C6     .  DB4424 20              fild dword ptr ss:[esp+20]
004551CA     .  3D D9040000            cmp eax,4D9
004551CF     .  D95C24 2C              fstp dword ptr ss:[esp+2C]

....

00455426     . /74 1B                  je short GameHall.00455443
00455428     . |D94424 2C              fld dword ptr ss:[esp+2C]
0045542C     . |D80D F0B05800          fmul dword ptr ds:[58B0F0]
00455432     . |D81D ECB05800          fcomp dword ptr ds:[58B0EC]                                ;45.0
00455438     . |DFE0                   fstsw ax
0045543A     . |F6C4 41                test ah,41
0045543D     . |75 04                  jnz short GameHall.00455443
0045543F     . |B3 01                  mov bl,1
00455441     . /EB 02                  jmp short GameHall.00455445
00455443     > |32DB                   xor bl,bl
00455445     > \8D8C24 14010000        lea ecx,dword ptr ss:[esp+114]
0045544C     .  E8 928C0F00            call <GameHall.DerefCString>
00455451     .  8D8C24 1C010000        lea ecx,dword ptr ss:[esp+11C]
00455458     .  C78424 2C040000 FFFFFF>mov dword ptr ss:[esp+42C],-1
00455463     .  E8 7B8C0F00            call <GameHall.DerefCString>
00455468     .  84DB                   test bl,bl
0045546A     .  0F84 29070000          je GameHall.00455B99
00455470     .  8BCD                   mov ecx,ebp
00455472     .  E8 99CB0200            call <GameHall.StopPlayDeleteFile>                //这里就停掉了并且删除临时文件
00455477     .  E9 1D070000            jmp GameHall.00455B99                                // 跳走
0045547C     >  8B95 D0330000          mov edx,dword ptr ss:[ebp+33D0]                         ;  Case 7 of switch 00452F5F
00455482     .  42                     inc edx
00455483     .  8BC2                   mov eax,edx

怎么能够跳过 call <GameHall.StopPlayDeleteFile>?

0045546A     .  0F84 29070000          je GameHall.00455B99
这里和后边的jmp位置相同,

在浮点运算之前有一些可以跳过检测45秒的,猜想基本上就是检测是否是VIP(vIP不会停止),是否付费(缴费以后也不会停止)。

找一个最早的检测
004553C0     .  83C4 08                add esp,8
004553C3     .  85C0                   test eax,eax
004553C5        75 7C                  jnz short GameHall.00455443
这里, 直接爆破将jnz改完jmp

复制修改到可执行文件,保存。 运行发现没有问题了。

但因为是爆破的,有些地方处理的不好,比如还是有一个提示试看45秒的banner,很心烦。 直接打开reshacker找到那个图(在位图段里面)
看出来黄色的地方是透明的。 将这个位图导出,用mspaint修改为全黄~色~图。再重新导入,覆盖原有位图。 保存。

插播广告的问题的解决途径比较诡异,因为程序很多地方基于网络,想到可能会判断字串之类的。打开字符参考,果然如此,

很多xxxx=的字串,猜想是判断返回字串的值。
断下一个与ad有关的然后跟进去
00477A29     .  68 74595C00            push offset <GameHall.str_AndMark>
00477A2E     .  E8 1E670D00            call <GameHall.CStrLoadString>
00477A33     .  51                     push ecx
00477A34     .  C64424 68 05           mov byte ptr ss:[esp+68],5
00477A39     .  8BCC                   mov ecx,esp
00477A3B     .  896424 58              mov dword ptr ss:[esp+58],esp
00477A3F     .  68 6CBA5C00            push GameHall.005CBA6C                                  ;  ASCII "noadstate="
00477A44     .  E8 08670D00            call <GameHall.CStrLoadString>
00477A49     .  51                     push ecx
00477A4A     .  8D4424 78              lea eax,dword ptr ss:[esp+78]
00477A4E     .  8BCC                   mov ecx,esp
00477A50     .  896424 58              mov dword ptr ss:[esp+58],esp
00477A54     .  50                     push eax
00477A55     .  C64424 70 06           mov byte ptr ss:[esp+70],6
00477A5A     .  E8 F9630D00            call <GameHall.CStringOpEq>
00477A5F     .  8D4C24 2C              lea ecx,dword ptr ss:[esp+2C]
00477A63     .  C64424 6C 04           mov byte ptr ss:[esp+6C],4
00477A68     .  51                     push ecx
00477A69     .  E8 42A80300            call <GameHall.GetNamedStr>
00477A6E        83C4 10                add esp,10
00477A71        50                     push eax
00477A72        8D4C24 6C              lea ecx,dword ptr ss:[esp+6C]
00477A76     .  C64424 64 07           mov byte ptr ss:[esp+64],7
00477A7B     .  E8 9C670D00            call <GameHall.AssignStr>
00477A80     .  8D4C24 20              lea ecx,dword ptr ss:[esp+20]
00477A84     .  C64424 60 04           mov byte ptr ss:[esp+60],4
00477A89     .  E8 55660D00            call <GameHall.DerefCString>
00477A8E     .  8B5424 68              mov edx,dword ptr ss:[esp+68]
00477A92     .  52                     push edx
00477A93        E8 6DC80A00            call <GameHall.atoi>
00477A98     .  8BCC                   mov ecx,esp
00477A9A     .  896424 58              mov dword ptr ss:[esp+58],esp
00477A9E     .  68 74595C00            push offset <GameHall.str_AndMark>
00477AA3     .  8986 84010000          mov dword ptr ds:[esi+184],eax
00477AA9     .  E8 A3660D00            call <GameHall.CStrLoadString>
00477AAE     .  51                     push ecx
00477AAF     .  C64424 68 08           mov byte ptr ss:[esp+68],8
00477AB4     .  8BCC                   mov ecx,esp
00477AB6     .  896424 58              mov dword ptr ss:[esp+58],esp

这段基本是找到字串里面的..noadstate=x&..
将x 提取出来,用atoi转换为数字,然后存在一个变量里面。
将00477A93        E8 6DC80A00            call <GameHall.atoi>
改为
00477A93        33C0                   xor eax,eax
00477A95        40                     inc eax
00477A96        90                     nop
00477A97        90                     nop

得到的值将永远为1

保存到exe。

修改了这些基本就可以正常用了。只需要免费注册一个账户就可以玩了。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费
支持
分享
最新回复 (10)
雪    币: 12
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
说的很详细,很好,支持
2010-4-3 07:59
0
雪    币: 10
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
要是能把破解的文件发一个给大家就更好了
2010-4-3 08:14
0
雪    币: 1849
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
厉害,这个思路清晰
2010-4-3 08:55
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
楼主   思想有多远  就能走多远
2010-4-3 09:05
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
新手,学习一下!
2010-4-3 09:16
0
雪    币: 7
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
新手,眼花了什么看也不懂
2010-4-3 11:03
0
雪    币: 705
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
不用申请了,多发些这样的优秀文章,Kx够了自己买个邀请码,搞定
2010-4-3 11:48
0
雪    币: 32
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
2010-4-3 12:36
0
雪    币: 2203
活跃值: (1021)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10

貌似很强大
2010-4-3 12:49
0
雪    币: 27
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
楼主很强大,我要努力学习娃哈哈。
2010-4-3 19:52
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册