第一次发文章。很浅。不过还详细。仅供大家一笑。有错漏之处请指教为谢!
去年(好象很遥远,其实是2个月前)我下载了一个多媒体播放软件NewPlay 4.01,看看介绍好象不错,但NewPlay每次启动后就自动将系统设置为静音,菜单里的“静音”选项一点不起作用,而且一调节音量系统也自动没了声音。程序出了这么大的问题还放出来?给作者发封e-mail抱怨(当然写的很客气的啦):
“昨天我在上海热线的下载频道上看到您的软件(第一次)介绍,觉得功能比winamp好,所以下载一个试用。装好后启动就没了声音,发现tray里面的音量被静掉了,我没在意,消了静音,放了几个avi、wma、mp3、realplay文件后觉得还不错,随后我关掉了NewPlay,在资源管理器双击一个mp3文件,它启动了NewPlay播放,却没声音,我向tray里一看,又被静音了。然后我消静音,能听见声音了,于是我调节NewPlay上的音量和平衡,无论动哪一个,都会立刻静音。我向您发了e-mail咨询。……”
才半天时间工夫,就收到了作者的回复(好快):
“您好!
您的问题我们非常重视。……(嘿嘿,客气话)
我们之所以对你所提出的这个“静音问题”比较关注,是因为我们的一位国外用户也曾经提到过类似问题。看来问题是的确存在的。只是“静音问题”看来的确很奇怪。因为我们在很多不同的操作系统上都做过了非常仔细的测试,当然包括了不同版本的
Windows XP,只是都没有出现问题。但到目前为止,加上你,总共有两位用户向我们反应过,这说明有若干XP 版本可能存在问题。……”
好家伙,只有两个用户存在问题,我就是其中一个,怎么这么不幸!@#$%^&*
看来作者是没机会解决了(问题无法重复),很巧那几天我心情稍微好一点,就帮他看看吧。
启动Softice,加载主程序NewPlay.exe,先从调节静音的菜单出招:
bpx CheckMenuItem
很快找到了这段子程序:
:00435424 53
push ebx
:00435425 56
push esi
:00435426 57
push edi
:00435427 8BDA
mov ebx, edx
:00435429 8BF0
mov esi, eax
:0043542B 3A5E2C
cmp bl, byte ptr [esi+2C]
:0043542E
7442 je 00435472
:00435430 885E2C
mov byte ptr [esi+2C], bl
:00435433 8B7E58
mov edi, dword ptr [esi+58]
:00435436 85FF
test edi, edi
:00435438 7427
je 00435461
:0043543A F6462002
test [esi+20], 02
:0043543E 7521
jne 00435461
:00435440 33C0
xor eax, eax
:00435442
8AC3 mov
al, bl
:00435444 8B0485D4074A00 mov eax,
dword ptr [4*eax+004A07D4]
:0043544B 83C800
or eax, 00000000
:0043544E 50
push eax
:0043544F
0FB74644 movzx eax, word
ptr [esi+44]
:00435453 50
push eax
:00435454 8BC7
mov eax, edi
:00435456 E871F4FFFF
call 004348CC
:0043545B 50
push eax
* Reference To: user32.CheckMenuItem, Ord:0000h
|
:0043545C E86F16FDFF
Call 00406AD0
* Referenced by a (U)nconditional or (C)onditional
Jump at Addresses:
|:00435438(C), :0043543E(C)
|
:00435461 84DB
test bl, bl
:00435463 740D
je 00435472
:00435465 807E2F00
cmp byte ptr [esi+2F], 00
:00435469 7407
je 00435472
:0043546B 8BC6
mov eax, esi
:0043546D E86AFFFFFF call 004353DC
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0043542E(C), :00435463(C), :00435469(C)
|
:00435472 5F
pop edi
:00435473 5E
pop esi
:00435474 5B
pop ebx
:00435475 C3
ret
测试一下就知道,这段子程序的入口参数:DL=1的话,就将“静音”菜单打个勾,DL=0则将去掉勾。
这的、是一段公用代码,对于“静音”选项来说,由00490DBF调用的:
:00490DA9 833DD88E4B0001
cmp dword ptr [004B8ED8], 00000001
:00490DB0
7514 jne
00490DC6
:00490DB2 A1808E4B00
mov eax, dword ptr [004B8E80]
:00490DB7 8B80A4030000
mov eax, dword ptr [eax+000003A4]
:00490DBD B201
mov dl, 01
:00490DBF E86046FAFF call 00435424
:00490DC4 5A
pop edx
:00490DC5 C3
ret
这里有个分支,在于那句比较代码:
cmp
dword ptr [004B8ED8], 00000001
而
:00490DBD B201
mov dl, 01
:00490DBF E86046FAFF
call 00435424
就是用DL=1来调用菜单check的子程序了。
如此看来,只要地址[004B8ED8]为1的话,菜单的“静音”选项就要打勾,为0的话就否,这是个boolean信号变量。
下一步就是要找到为什么[004B8ED8]数值会为1,这正是问题的核心所在。
有了[004B8ED8]这个信号,就逆着往上追……
:004778C7 83BDB4FEFFFF00
cmp dword ptr [ebp+FFFFFEB4], 00000000
:004778CE 740B
je 004778DB
:004778D0 8B4510
mov eax, dword ptr [ebp+10]
:004778D3 C70001000000
mov dword ptr [eax], 00000001
:004778D9 EB07
jmp 004778E2
动态追踪中发现,这里eax=004B8ED8,正好是设置地址[004B8ED8]为1嘛,再看看前面的条件:
cmp dword ptr [ebp+FFFFFEB4], 00000000
看来是因为[ebp+FFFFFEB4]等于0的缘故了。看看[ebp+FFFFFEB4]的数值:0012F370。
目标改变,需要追踪[0012F370]地址了……
来招乾坤大挪移:bpm 12F370
于是我们来到了
:0047782E 33C0
xor eax, eax
:00477830 8945E4
mov dword ptr [ebp-1C], eax
:00477833 C745E804000000
mov [ebp-18], 00000004
:0047783A 8D85B4FEFFFF
lea eax, dword ptr [ebp+FFFFFEB4]
:00477840
8945EC mov dword
ptr [ebp-14], eax
:00477843 6A00
push 00000000
:00477845 8D45D8
lea eax, dword ptr [ebp-28]
:00477848
50
push eax
:00477849 8B45FC
mov eax, dword ptr [ebp-04]
:0047784C 8B4030
mov eax, dword ptr [eax+30]
:0047784F
50
push eax
* Reference To: winmm.mixerGetControlDetailsA, Ord:0000h
|
:00477850 E873F3FFFF
Call 00476BC8
:00477855 85C0
test eax, eax
:00477857
0F8585000000 jne 004778E2
:0047785D
817B0801000350 cmp dword ptr [ebx+08], 50030001
:00477864 753B
jne 004778A1
:00477866 8B4518
mov eax, dword ptr [ebp+18]
:00477869 8338FF
cmp dword ptr [eax], FFFFFFFF
:0047786C 7533
jne 004778A1
:0047786E F7430C00000080
test [ebx+0C], 80000000
:00477875 8B450C
mov eax, dword ptr [ebp+0C]
:00477878 0F9700
seta byte ptr [eax]
:0047787B 8B450C
mov eax, dword ptr [ebp+0C]
:0047787E 803800
cmp byte ptr [eax], 00
:00477881 755F
jne 004778E2
:00477883
8B4518 mov eax,
dword ptr [ebp+18]
:00477886 8B95B4FEFFFF
mov edx, dword ptr [ebp+FFFFFEB4]
:0047788C 8910
mov dword ptr [eax], edx
:0047788E 837DE001 cmp
dword ptr [ebp-20], 00000001
:00477892 764E
jbe 004778E2
:00477894 8B4514
mov eax, dword ptr [ebp+14]
:00477897 8B95B8FEFFFF mov edx, dword
ptr [ebp+FFFFFEB8]
:0047789D 8910
mov dword ptr [eax], edx
:0047789F EB41
jmp 004778E2
呵呵,程序调用了win美眉库的mixerGetControlDetail来取得当前音量设置,如果是静音,就将这个可爱的信号[0012F370]置0。
终于找到菜单的“静音”选项似乎看起来不起作用的原因了——其实还是有动作,不过因为设置失败,所以一直不能改变状态。
所以事情还远远没有结束,我们还没找到为何设置取消“静音”无效的原因。
很容易想到,程序可能会调用win美眉库的mixerSetControlDetail来设置音量,那就找找mm吧。
bpx winmm.mixerSetControlDetail
gogogo!
:00477B94 6A00
push 00000000
:00477B96 8D45D4
lea eax, dword ptr [ebp-2C]
:00477B99
50
push eax
:00477B9A 8B45FC
mov eax, dword ptr [ebp-04]
:00477B9D 8B4030
mov eax, dword ptr [eax+30]
:00477BA0
50
push eax
* Reference To: winmm.mixerSetControlDetails, Ord:0000h
|
:00477BA1 E852F0FFFF
Call 00476BF8
* Referenced by a (U)nconditional
or (C)onditional Jump at Addresses:
|:00477AD9(C), :00477AEE(C), :00477AFD(C)
|
:00477BA6 46
inc esi
* Referenced by a (U)nconditional or (C)onditional
Jump at Address:
|:00477AC7(U)
|
:00477BA7 807DEF00
cmp byte ptr [ebp-11], 00
:00477BAB
7406 je 00477BB3
:00477BAD 807DEE00
cmp byte ptr [ebp-12], 00
:00477BB1 750F
jne 00477BC2
看来这是设置音量、静音的代码了。需要追踪一下函数参数,才会明白为什么设置取消静音无效了。
参数颇为复杂,我是弄不懂的,看了老半天的API帮助,才知道那个cbDetailSize和paDetail指针还有点用,看看:
cbDetailSize=4,paDetail=12F8EC,好啊,就守株待兔,看看[12F8EC]用了什么值设置音量。
另外cChannels=2,说明是设置了两个声道的。
左声道=0,右声道=00000C78。
奇怪,为什么作者不把右声道设置为0呢?在其它系统中音量调节既然是正常的,那只有一种解释:系统中有一个是主声道,可能是左、可能是右,只要将此主声道音量设置为0时,系统认为取消两个声道的静音了。那么,我的系统中的主声道应该是右。
好了,改改参数试试吧。将右声道的值改为0,运行之后,果然“静音”被取消掉了。
再回溯调用程序,左声道*paDetail的值是从这里设置的:
:00477B87 8B4508
mov eax, dword ptr [ebp+08]
:00477B8A 8985B4FEFFFF
mov dword ptr [ebp+FFFFFEB4], eax
但找不到设置右声道的代码,看来是作者遗漏掉了。
修正这个问题可以令cCannel=1,不过这段代码设置音量也在用,此方法不行。那就将左右两声道同时都设置为0,就万无一失了!
好了,问题解决了,回信~~~~~~
“您好!
这个(静音)问题我已经解决了。从二进制代码分析颇为困难,费了两天时间,刚刚才弄出来。
问题出在对静音的设置上。文件定位:NewPlay.exe。
NewPlay.exe里面有一个过程,类似这样(名字是我自己取的,和源程序中的名字不同。省略号代表其它参数):
procedure ChangeVolumn(mute: interger......);
第一个参数是静音标志,当mute=1的时候就静音,mute=0的时候就取消静音。
这个过程的功能比较复杂,可以设置音量大小、平衡左右声道、是否静音。我们只关心静音问题,看看静音是如何设置的。
……
Channel:=2;
……(设置其它参数,略)
left:=mute;
MIXSETCONTROLDETAILS(...);
……
非常明显,程序假设左声道(left)是主音道,设置主音道的mute后,次音道(右音道right)被自动mute,所以不用设置。
不幸的是,我的系统右声道(right)才是主音道,所以对左声道设置mute对系统毫无影响。
解决上面的问题就必须这样写:
left:=mute;
right:=mute;
MIXSETCONTROLDETAILS(...);
两个音道都设置mute值才万无一失。
我改了NewPlay.exe文件,本想插一句right:=mute;进去,无奈代码太紧凑,插不进,想改Channel值,好象这个值别的功能也在用,没办法,只好改成适应我的系统:
right:=mute;
MIXSETCONTROLDETAILS(...);
改过的NewPlay.exe在我的系统中运行完全正常,但估计在你的系统中会出现静音问题:)
我要吃晚饭了,饥寒交迫中。”
这次收到了作者的感谢:
" 没想到你能帮我们把这个困扰我们多时的问题给解决了。
实在是我自己的疏忽,写程序时太想当然了。现在依照你的思路
问题已经解决。:-)
谢谢。"
另外作者答应:
“你可以永远得到 NewPlay 的注册码,即便是以后改变了注册方式。”
以前破解别人的软件,收山后,现在总算做了一件好事。
作者也很快推出了4.02升级版,正是目前上海热线上提供下载的版本。
- 标 题:我的一次debug(10千字)
- 作 者:stuman
- 时 间:2003-1-2 11:50:51
- 链 接:http://bbs.pediy.com