我的一次Debug(续):音量调节函数浅析 (26千字)
我的一次Debug(续):音量调节函数浅析这篇文字希望能回答一些朋友所询问的关于音量调节的细节问题。上篇文章中我只贴出了最关键的设置代码,也没有进一步解释。
另外,宽河朋友跟踪一个类似出问题的软件后,也贴了一段代码。我看了后觉得有点眼熟耶~~~随后比较NewPlay 4.01相关代码,竟然一模一样:)这是怎么回事,我不太明白……
解释代码是件困难的事情,还是用程序来描述吧。下面用了“类Delphi”来描述,因为源程序可能是Delphi写的,但由于编译优化,有些只好用寄存器描述,goto语句还不能避免。有些习惯还保留,如16进制还是用h后缀。不当的地方请多多指教为谢!
最后,我在测试时发现,上篇似乎将左声道和右声道写反了:( 尽管这对找静音原因不是一个问题,却不希望误导,特此提出。
==================================================
这个函数(过程)设置音量,包括静音。分析一下,可以知道参数一共有5个,栈中push了3个,寄存器中放了2个(eax, ecx)。下面要进一步解释和了解这些参数的意义。为了叙述方便,把栈参数称param1、param2、param3,寄存器参数称regeax、regecx。
先把变量的相关资料总结在下面供查询:
参数:
regeax为指针,通过它取一个变量作为参数调用sub_00477588
regecx为一个32位integer,为一个正整数,或FFFFFFFF。在NewPlay中总是FFFFFFFF。
param1为静音与否Mute(=1静音,=0取消静音)
param2是左声道值leftValue
param3是右声道值rightValue
局部变量:
[ebp-4]=regeax。4pEax
[ebp-8]=regecx。8Ecx
[ebp-9]byte型的boolean。9bResult;函数的返回值
[ebp-10h]指针,通过sub_00477588返回的值。10p
[ebp-11]byte类型的boolean,如果leftValue=-1就等于为true,否则0。11bNoRightValue
[ebp-12]byte类型的boolean,如果Mute=-1就等于为true,否则0。12bNoMute
局部变量之MIXERCONTROLDETAILS结构
[ebp-18]=paDetails;(这个关键指针指向[ebp-150h])
[ebp-1c]=cbDetails;
[ebp-20]=hwndOwner or cMultipleItems;
[ebp-24]=cChannels;
[ebp-28]=dwControlID;
[ebp-2c]=cbStuct;
[ebp-2c]=&MIXERCONTROLDETAILS;
[ebp-150]=右声道数值(right)。或是否mute(此时要cChannels=1)
[ebp-14c]=左声道数值(left)
[ebp-2c]到[ebp-0D4]为一个32位整数数组。d4IntArray[1..2Ah]。其中[ebp-0B8](B8int)是cChannel的默认值2
==================================================
下面是程序分析,先逐行把汇编写成“类Delphi”语言,再把“类Delphi”代码合并起来,脉络就清晰多了
* Referenced by a CALL at Addresses:
|:004920CD , :0049A35D , :0049A3C5 , :0049A407 , :0049A48C
|:0049A5E9 , :0049A745 , :0049CCFC
|
:00477A24 55 push ebp
:00477A25 8BEC mov ebp, esp
:00477A27 81C4B0FEFFFF add esp, FFFFFEB0
上面三句大概是Borland的习惯吧。经过这样处理,栈具有一定的布局:
[ebp+8]为从栈传的第一个参数的位置,[ebp+c]为栈传的第二个参数的位置,类推。
[ebp-4]为第一个局部变量的位置(如果这个局部变量是32位的话),类推。
........——locVar2—locVar1—EBPvalue(EBP指向这里)—RetAddr—1stParam—2ndParam——......栈顶(ESP指向这里)
局部变量区 EBP值 返回地址 参数区 栈顶
:00477A2D 53 push ebx
:00477A2E 56 push esi
:00477A2F 57 push edi
压栈
:00477A30 894DF8 mov dword ptr [ebp-08], ecx
:00477A33 8945FC mov dword ptr [ebp-04], eax
:00477A36 C645F700 mov [ebp-09], 00
8Ecx:=ecx;
4pEax:=eax;
9bResult:=false;
:00477A3A 8B45FC mov eax, dword ptr [ebp-04]
:00477A3D 8B4028 mov eax, dword ptr [eax+28]
:00477A40 E843FBFFFF call 00477588
:00477A45 8945F0 mov dword ptr [ebp-10], eax
:00477A48 837DF000 cmp dword ptr [ebp-10], 00000000
:00477A4C 0F848D020000 je 00477CDF
10p:=sub_00477588( ^(4pEax+28h) );
if 10p=nil then
goto lblExit;
:00477A52 837DF8FF cmp dword ptr [ebp-08], FFFFFFFF
:00477A56 7520 jne 00477A78
:00477A58 8B45F0 mov eax, dword ptr [ebp-10]
:00477A5B 8BB8B0000000 mov edi, dword ptr [eax+000000B0]
:00477A61 8B45F0 mov eax, dword ptr [ebp-10]
:00477A64 57 push edi
:00477A65 8D7008 lea esi, dword ptr [eax+08]
:00477A68 8DBD2CFFFFFF lea edi, dword ptr [ebp+FFFFFF2C]
:00477A6E B92A000000 mov ecx, 0000002A
:00477A73 F3 repz
:00477A74 A5 movsd
:00477A75 5F pop edi
:00477A76 EB31 jmp 00477AA9
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477A56(C)
|
:00477A78 8B45F0 mov eax, dword ptr [ebp-10]
:00477A7B 8B80B4000000 mov eax, dword ptr [eax+000000B4]
:00477A81 8B55F8 mov edx, dword ptr [ebp-08]
:00477A84 E817F9FFFF call 004773A0
:00477A89 85C0 test eax, eax
:00477A8B 741A je 00477AA7
:00477A8D 8BB8B0000000 mov edi, dword ptr [eax+000000B0]
:00477A93 57 push edi
:00477A94 8D7008 lea esi, dword ptr [eax+08]
:00477A97 8DBD2CFFFFFF lea edi, dword ptr [ebp+FFFFFF2C]
:00477A9D B92A000000 mov ecx, 0000002A
:00477AA2 F3 repz
:00477AA3 A5 movsd
:00477AA4 5F pop edi
:00477AA5 EB02 jmp 00477AA9
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477A8B(C)
|
:00477AA7 33FF xor edi, edi
if 8Ecx=FFFFFFFFh then
begin
for i:=1 to 2Ah do
d4IntArray[i]:=^((10p+7)+i);
edi:=^(10p+B0h);
end
else
begin
eax:=sub_004773A0( ^(10p+B4h),8Ecx );
if eax<>0 then
begin
for i:=1 to 2Ah do
d4IntArray[i]:=^((eax+7)+i));
edi:=^(eax+B0h);
end
else
edi:=0;
end;
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00477A76(U), :00477AA5(U)
|
:00477AA9 85FF test edi, edi
:00477AAB 0F842E020000 je 00477CDF
if edi=0 then
goto lblExit;
:00477AB1 33F6 xor esi, esi
:00477AB3 837D10FF cmp dword ptr [ebp+10], FFFFFFFF
:00477AB7 0F9445EF sete byte ptr [ebp-11]
:00477ABB 837D08FF cmp dword ptr [ebp+08], FFFFFFFF
:00477ABF 0F9445EE sete byte ptr [ebp-12]
:00477AC3 C645F701 mov [ebp-09], 01
:00477AC7 E9DB000000 jmp 00477BA7
esi:=0;
if rightValue=FFFFFFFFh then
11bNoRightValue:=true;
if Mute=FFFFFFFFh then
12bNoMute:=true;
9bResult:=true;
goto lbl00477BA7;
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477BBC(C)
|
:00477ACC 8BD6 mov edx, esi
:00477ACE 8BC7 mov eax, edi
:00477AD0 E8EBF6FFFF call 004771C0
:00477AD5 8BD8 mov ebx, eax
:00477AD7 85DB test ebx, ebx
:00477AD9 0F84C7000000 je 00477BA6
lbl00477AAC:
ebx:=sub_004771C0(esi,edi);//返回值ebx是个指针,[ebx+4]是dwControlID,[ebx+0Ch]为cChannel
if ebx<>0 then
begin
:00477ADF 8B4308 mov eax, dword ptr [ebx+08]
:00477AE2 3D01000350 cmp eax, 50030001
:00477AE7 740B je 00477AF4
:00477AE9 3D02000120 cmp eax, 20010002
:00477AEE 0F85B2000000 jne 00477BA6
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477AE7(C)
|
:00477AF4 8B430C mov eax, dword ptr [ebx+0C]
:00477AF7 83E002 and eax, 00000002
:00477AFA 83F802 cmp eax, 00000002
:00477AFD 0F84A3000000 je 00477BA6
:00477B03 C745D418000000 mov [ebp-2C], 00000018
:00477B0A 8B4304 mov eax, dword ptr [ebx+04]
:00477B0D 8945D8 mov dword ptr [ebp-28], eax
:00477B10 F7430C01000000 test [ebx+0C], 00000001
:00477B17 7609 jbe 00477B22
:00477B19 C745DC01000000 mov [ebp-24], 00000001
:00477B20 EB09 jmp 00477B2B
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477B17(C)
|
:00477B22 8B8548FFFFFF mov eax, dword ptr [ebp+FFFFFF48]
:00477B28 8945DC mov dword ptr [ebp-24], eax
case ^(ebx+8) of
20010002,5003001:
begin
eax:=^(ebx+Ch);
if eax=00000002h then
goto lbl00477BA6;
cbStuct:=18h;
dwControlID:=^(ebx+4h);
if ^(ebx+Ch)>1 then
cChannels:=1
else
cChannels:=B8int;//=2
end;
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477B20(U)
|
:00477B2B 33C0 xor eax, eax
:00477B2D 8945E0 mov dword ptr [ebp-20], eax
:00477B30 C745E404000000 mov [ebp-1C], 00000004
:00477B37 8D85B0FEFFFF lea eax, dword ptr [ebp+FFFFFEB0]
:00477B3D 8945E8 mov dword ptr [ebp-18], eax
hwndOwner:=0;
cbDetails:=4;
paDetails:=@[ebp-150h];
:00477B40 817B0801000350 cmp dword ptr [ebx+08], 50030001
:00477B47 752F jne 00477B78
:00477B49 807DEF00 cmp byte ptr [ebp-11], 00
:00477B4D 7529 jne 00477B78
:00477B4F 8B4510 mov eax, dword ptr [ebp+10]
:00477B52 8985B0FEFFFF mov dword ptr [ebp+FFFFFEB0], eax
:00477B58 837D0CFF cmp dword ptr [ebp+0C], FFFFFFFF
:00477B5C 750B jne 00477B69
:00477B5E 8B4510 mov eax, dword ptr [ebp+10]
:00477B61 8985B4FEFFFF mov dword ptr [ebp+FFFFFEB4], eax
:00477B67 EB09 jmp 00477B72
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477B5C(C)
|
:00477B69 8B450C mov eax, dword ptr [ebp+0C]
:00477B6C 8985B4FEFFFF mov dword ptr [ebp+FFFFFEB4], eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477B67(U)
|
:00477B72 C645EF01 mov [ebp-11], 01
:00477B76 EB1C jmp 00477B94
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00477B47(C), :00477B4D(C)
|
:00477B78 817B0802000120 cmp dword ptr [ebx+08], 20010002
:00477B7F 7513 jne 00477B94
:00477B81 807DEE00 cmp byte ptr [ebp-12], 00
:00477B85 750D jne 00477B94
:00477B87 8B4508 mov eax, dword ptr [ebp+08]
:00477B8A 8985B4FEFFFF mov dword ptr [ebp+FFFFFEB0], eax
:00477B90 C645EE01 mov [ebp-12], 01
if [ebx+8]=50030001 then//50030001设置音量
begin
if not 11bNoRightValue then//如果右声道数据有定义(<>FFFFFFFFh)
begin
right:=rightValue;
if leftValue=FFFFFFFFh then
left:=rihtValue;
else
left:=leftValue;
11bNoRightValue:=true;
end
end
else
begin
if [ebx+8]=20010002 then//20010002设置静音
begin
if not 12bNoMute then
begin
right:=Mute;
12bNoMute:=true;
end;
end;
end;
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00477B76(U), :00477B7F(C), :00477B85(C)
|
: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
mixerSetControlDetails(^(4pEax+30h),@MIXERCONTROLDETAILS,0);
end;
else
begin
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00477AD9(C), :00477AEE(C), :00477AFD(C)
|
:00477BA6 46 inc esi
lbl00477BA6:
esi:=esi+1;
* 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
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477BAB(C)
|
:00477BB3 8BC7 mov eax, edi
:00477BB5 E812F6FFFF call 004771CC
:00477BBA 3BF0 cmp esi, eax
:00477BBC 0F8C0AFFFFFF jl 00477ACC
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477BB1(C)
|
:00477BC2 807DEE00 cmp byte ptr [ebp-12], 00
:00477BC6 0F8513010000 jne 00477CDF
:00477BCC 837DF8FF cmp dword ptr [ebp-08], FFFFFFFF
:00477BD0 0F8409010000 je 00477CDF
lbl00477BA7:
if 11NoRightValue then
if not 12bNoMute then
goto lb00477BC2;
if esi<sub_004771CC(edi) then
goto lbl00477ACC;
lbl00477BC2:
if not 12bNoMute then
goto lblExit;
if 8Ecx=FFFFFFFFh then
goto lblExit;
:00477BD6 8B45F0 mov eax, dword ptr [ebp-10]
:00477BD9 8BB8B0000000 mov edi, dword ptr [eax+000000B0]
:00477BDF 8B45F0 mov eax, dword ptr [ebp-10]
:00477BE2 57 push edi
:00477BE3 8D7008 lea esi, dword ptr [eax+08]
:00477BE6 8DBD2CFFFFFF lea edi, dword ptr [ebp+FFFFFF2C]
:00477BEC B92A000000 mov ecx, 0000002A
:00477BF1 F3 repz
:00477BF2 A5 movsd
:00477BF3 5F pop edi
:00477BF4 85FF test edi, edi
:00477BF6 0F84E3000000 je 00477CDF
:00477BFC 33F6 xor esi, esi
:00477BFE E9C7000000 jmp 00477CCA
for i:=1 to 2Ah do
d4IntArray[i]:=^((10p+7)+i));
edi:=^(10p+B0h);
if edi=0 then
goto lblExit;
esi:=0
goto lbl00477CCA;
end;
end;
end;
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477CD9(C)
|
:00477C03 8BD6 mov edx, esi
:00477C05 8BC7 mov eax, edi
:00477C07 E8B4F5FFFF call 004771C0
:00477C0C 8BD8 mov ebx, eax
:00477C0E 8B4308 mov eax, dword ptr [ebx+08]
:00477C11 3D01000171 cmp eax, 71010001
:00477C16 740B je 00477C23
:00477C18 3D01000170 cmp eax, 70010001
:00477C1D 0F85A6000000 jne 00477CC9
lbl00477C03;
ebx:=sub_4771C0(esi,edi);
case ^(ebx+8) of
7101001,70010001:
begin
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477C16(C)
|
:00477C23 C745D418000000 mov [ebp-2C], 00000018
:00477C2A 8B4304 mov eax, dword ptr [ebx+04]
:00477C2D 8945D8 mov dword ptr [ebp-28], eax
:00477C30 8B430C mov eax, dword ptr [ebx+0C]
:00477C33 F7C001000000 test eax, 00000001
:00477C39 7609 jbe 00477C44
:00477C3B C745DC01000000 mov [ebp-24], 00000001
:00477C42 EB09 jmp 00477C4D
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477C39(C)
|
:00477C44 8B9548FFFFFF mov edx, dword ptr [ebp+FFFFFF48]
:00477C4A 8955DC mov dword ptr [ebp-24], edx
cbStuct:=18h;
dwControlID:=^(ebx+4h);
eax:=^(ebx+Ch);
if eax>1 then
cChannels:=1
else
cChannels:=B8int;
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00477C42(U)
|
:00477C4D 83E002 and eax, 00000002
:00477C50 83F802 cmp eax, 00000002
:00477C53 7508 jne 00477C5D
:00477C55 8B4310 mov eax, dword ptr [ebx+10]
:00477C58 8945E0 mov dword ptr [ebp-20], eax
:00477C5B EB05 jmp 00477C62
