很多浏览器有这种功能,实现原理都是一样。发声源基本都来自Flash,比如Flash游戏啦,视频播放器啦等等
而Flash的发声都是通过winmm.dll::waveOutWrite函数来完成,所以,我们只要能“接管”这个函数就行了
下面的代码是以前写的一个模块,针对Flash的静音,代码写的比较粗糙 ^_^
注意,下面的代码仅仅针对Flash模块进行IAT Hook
XP测试通过
unit FlashMute;
interface
uses
Windows, SysUtils, Classes, StrUtils, TlHelp32, MMSystem;
type
TFlashMute = class
private
class var Flag: Boolean;
public
class function Modify_waveOutWrite: Boolean;
class procedure Enable;
class procedure Disable;
end;
implementation
function MywaveOutWrite(hWaveOut: HWAVEOUT; lpWaveOutHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
begin
if TFlashMute.Flag then
ZeroMemory(lpWaveOutHdr.lpData, lpWaveOutHdr.dwBufferLength);
Result := waveOutWrite(hWaveOut, lpWaveOutHdr, uSize);
end;
{ TFlashMute }
class procedure TFlashMute.Disable;
begin
TFlashMute.Flag := True;
end;
class procedure TFlashMute.Enable;
begin
TFlashMute.Flag := False;
end;
class function TFlashMute.Modify_waveOutWrite: Boolean;
var
hSnapshot: THandle;
ME32: TModuleEntry32;
Found: Boolean;
BaseAddr: DWORD;
DosHeader: PImageDosHeader;
NtHeader: PImageNtHeaders;
ImportDesc: PImageImportDescriptor;
ITD, ITD2: PImageThunkData;
IIBN: PImageImportByName;
mbi: TMemoryBasicInformation;
begin
Result := False;
// 枚举当前进程模块列表,找到Flash?.ocx
hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId);
if hSnapshot <> INVALID_HANDLE_VALUE then
begin
ME32.dwSize := SizeOf(TModuleEntry32);
Found := Module32First(hSnapshot, ME32);
while Found do
begin
if ContainsText(ME32.szModule, 'Flash') then
begin
if SameText(ExtractFileExt(ME32.szModule), '.ocx') then
begin
BaseAddr := DWORD(@ME32.modBaseAddr^);
DosHeader := @ME32.modBaseAddr^;
NtHeader := Ptr(BaseAddr + DosHeader^._lfanew);
// 遍历输入模块
ImportDesc := Ptr(BaseAddr + NtHeader.OptionalHeader.DataDirectory[1].VirtualAddress);
while ImportDesc^.Name <> 0 do
begin
ITD := PImageThunkData(BaseAddr + ImportDesc^.OriginalFirstThunk); // 指向函数名称RVA或函数序号
ITD2 := PImageThunkData(BaseAddr + ImportDesc^.FirstThunk); // 指向函数地址
// 遍历输入函数
while ITD^.AddressOfData <> 0 do
begin
// 按函数名方式导入的函数
if ITD^.AddressOfData and IMAGE_ORDINAL_FLAG <> IMAGE_ORDINAL_FLAG then
begin
IIBN := PImageImportByName(BaseAddr + ITD^.AddressOfData);
// 找出 winmm.dll::waveOutWrite
if SameText(string(PAnsiChar(@IIBN^.Name[0])), 'waveOutWrite') then
begin
if VirtualProtect(@ITD2^._Function, SizeOf(DWORD), PAGE_EXECUTE_READWRITE, @mbi.Protect) then
begin
ITD2^._Function := DWORD(@MywaveOutWrite);
Result := True;
end;
Break;
end;
end;
Inc(ITD);
Inc(ITD2);
end;
if Result then
Break;
Inc(ImportDesc);
end;
end;
end;
if Result then
Break;
Found := Module32Next(hSnapshot, ME32);
end;
CloseHandle(hSnapshot);
end;
end;