void WINAPI SetHook(HWND hWnd)
{
if (!g_hhHook)
{
g_hhHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)HookProc, hInst, 0);
}
}
* This source code was highlighted with Source Code Highlighter .
LRESULT WINAPI HookProc( int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
{
return CallNextHookEx(g_hhHook, nCode, wParam, lParam);
}
// - , -
return CallNextHookEx(g_hhHook, nCode, wParam, lParam);
}
* This source code was highlighted with Source Code Highlighter .
IDirectDrawSurface
object (also IDirectDrawSurface
as the “DirectDraw-surface”), which was created with the DDSCAPS_OVERLAY
flag. The transfer of the image to the screen, simply speaking, is the method IDirectDrawSurface::Flip
. So, by intercepting the call to this method, you can access the data with the image of the video frame. Much has been said about call interception, for example . At one time, I used method number one of this article as the simplest. The only obstacle is that getting the address of the COM object method by calling GetProcAddress
will fail. This is not so scary, because you can create a DirectDraw-surface, and find out the position of the Flip
method relative to the base address of the executable file into which the embedding was performed. You can do this as follows:// IDirectDraw
LPDIRECTDRAW pDirectDraw;
hr = DirectDrawCreate(NULL, (&pDirectDraw), NULL);
hr = pDirectDraw->SetCooperativeLevel(NULL, DDSCL_NORMAL);
DDSURFACEDESC desc = {0};
desc.dwSize = sizeof (desc);
desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
desc.dwWidth = 100;
desc.dwHeight = 100;
// IDirectDrawSurface
LPDIRECTDRAWSURFACE Surf;
hr = pDirectDraw->CreateSurface(&desc, &Surf, NULL);
void *pFlip = (*reinterpret_cast< void ***>(Surf))[11]; // 11 - IDirectDrawSurface::Flip vtable
ptrdiff_t pDDSFlipDiff = reinterpret_cast<ptrdiff_t>(pFlip) - reinterpret_cast<ptrdiff_t>(GetModuleHandle(_T( "ddraw.dll" )));
* This source code was highlighted with Source Code Highlighter .
IDirectDrawSurface::UpdateOverlay
, which has method number 33.Flip
and UpdateOverlay
methods by specifying the addresses of the original and modified methods in the installation procedure of the interceptor. The prototype methods look like this:typedef HRESULT (WINAPI *FUNC_IDIRECTDRAWSURFACEFLIP)(IDirectDrawSurface *This, LPDIRECTDRAWSURFACE lpDDSurfTargetOverride, DWORD dwFlags);
typedef HRESULT (WINAPI *FUNC_IDIRECTDRAWSURFACEUPDATEOVERLAY)(IDirectDrawSurface *This, LPRECT lpSrcRect, LPDIRECTDRAWSURFACE lpDDDestSurface, LPRECT lpDestRect, DWORD dwFlags, LPDDOVERLAYFX lpDDOverlayFx);
* This source code was highlighted with Source Code Highlighter .
Flip
and UpdateOverlay
in prototypes, the first in the list of arguments is a pointer to the COM object containing this method. This is due to the fact that the methods of COM objects have the type of call thiscall
.IDirectDrawSurface7::Flip
and IDirectDrawSurface7::UpdateOverlay
, since some renderers use interfaces of the seventh version of DirectDraw.UpdateOverlay
function, since it can be used to extract a lot of useful information.HRESULT WINAPI Patch_UO(IDirectDrawSurface *This, LPRECT lpSrcRect, LPDIRECTDRAWSURFACE lpDDDestSurface, LPRECT lpDestRect, DWORD dwFlags, LPDDOVERLAYFX lpDDOverlayFx)
{
DetourRestore(True_UO); //
HRESULT res = True_UO(This, lpSrcRect, lpDDDestSurface, lpDestRect, dwFlags, lpDDOverlayFx);
DetourRenew(True_UO); //
DDCOLORKEY ck = {0};
if (dwFlags & DDOVER_KEYDEST) //
{
DDCOLORKEY ck2 = {0};
lpDDDestSurface->GetColorKey(DDCKEY_DESTOVERLAY, &ck2);
g_ColorKey = ck2.dwColorSpaceHighValue;
}
if (dwFlags & DDOVER_KEYDESTOVERRIDE) //
{
if (lpDDOverlayFx != NULL)
{
ck = lpDDOverlayFx->dckDestColorkey;
g_ColorKey = ck.dwColorSpaceHighValue;
}
}
if (lpDestRect != NULL)
{
CopyMemory(&g_OverlayRect, lpDestRect, sizeof (RECT));
}
return res;
}
* This source code was highlighted with Source Code Highlighter .
HRESULT WINAPI Patch_Flip(IDirectDrawSurface *This, LPDIRECTDRAWSURFACE lpDDSurfTargetOverride, DWORD dwFlags)
{
DDSURFACEDESC desc = {0};
desc.dwSize = sizeof (desc);
This->GetSurfaceDesc(&desc);
// ,
if ((desc.ddsCaps.dwCaps & DDSCAPS_OVERLAY) > 0)
{
lpOverlaySurf = This;
}
// ,
if (lpOverlaySurf != NULL)
{
GetPic();
}
//
DetourRestore(True_Flip);
// ,
HRESULT res = True_Flip(This, lpDDSurfTargetOverride, dwFlags);
//
DetourRenew(True_Flip);
return res;
}
* This source code was highlighted with Source Code Highlighter .
GetPic()
function deals with this, which in the shortened version looks like this:void WINAPI GetPic( void )
{
DDSURFACEDESC2 desc = {0};
desc.dwSize = sizeof (desc);
DDSURFACEDESC desc1 = {0};
desc1.dwSize = sizeof (desc1);
// Lock ,
((LPDIRECTDRAWSURFACE)lpOverlaySurf)->Lock(NULL, &desc1, DDLOCK_WAIT | DDLOCK_READONLY | DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK, NULL);
desc.ddsCaps.dwCaps = desc1.ddsCaps.dwCaps;
desc.lpSurface = desc1.lpSurface;
desc.dwWidth = desc1.dwWidth;
desc.dwHeight = desc1.dwHeight;
desc.lPitch = desc1.lPitch;
desc.ddpfPixelFormat = desc1.ddpfPixelFormat;
desc.ddckCKDestOverlay = desc1.ddckCKDestOverlay;
desc.ddckCKSrcOverlay = desc1.ddckCKSrcOverlay;
// ,
((LPDIRECTDRAWSURFACE)lpOverlaySurf)->Unlock(NULL);
}
* This source code was highlighted with Source Code Highlighter .
Lock
method locks the surface for writing, and at the same time returns a pointer to the image. From there it should be picked up and unlocked as quickly as possible so as not to embarrass the video player with your presence. The IDirectDrawSurface::Lock
method returns a surface description in a DDSURFACEDESC
structure, while IDirectDrawSurface::Lock
returns a description of a surface in DDSURFACEDESC2
. Hence some leapfrog with copying data from one structure to another.desc.lpSurface
pointer, and the size of this data is calculated depending on what color model this data is stored in.if (desc.ddpfPixelFormat.dwFourCC == 0x0)
{
DataLen = desc.dwHeight * desc.lPitch * desc.ddpfPixelFormat.dwRGBBitCount >> 3;
}
if (desc.ddpfPixelFormat.dwFourCC == MAKEFOURCC( 'Y' , 'V' , '1' , '2' ))
{
DataLen = desc.dwHeight * desc.lPitch * desc.ddpfPixelFormat.dwYUVBitCount >> 3;
}
if (desc.ddpfPixelFormat.dwFourCC == MAKEFOURCC( 'Y' , 'U' , 'Y' , '2' ))
{
DataLen = desc.dwHeight * desc.lPitch * desc.ddpfPixelFormat.dwYUVBitCount >> 4;
}
if (desc.ddpfPixelFormat.dwFourCC == MAKEFOURCC( 'Y' , 'V' , 'Y' , 'U' ))
{
DataLen = desc.dwHeight * desc.lPitch * desc.ddpfPixelFormat.dwYUVBitCount >> 4;
}
if (desc.ddpfPixelFormat.dwFourCC == MAKEFOURCC( 'U' , 'Y' , 'V' , 'Y' ))
{
DataLen = desc.dwHeight * desc.lPitch * desc.ddpfPixelFormat.dwYUVBitCount >> 4;
}
* This source code was highlighted with Source Code Highlighter .
dwHeight
is the image height, lPitch
is the shift in bytes to the beginning of the next line, dwYUVBitCount
is the number of bits per image pixel.Source: https://habr.com/ru/post/111339/
All Articles