我通过调试dx程序得到LPDIRECTDRAWSURFACE的 blt方法的地址,然后写代码hook该地址,在头部跳转到我自己的Blt1函数,在这个函数内部判断blt的this指针,如果是主表面的话,就在后台表面输出文字,最后把参数压栈并恢复破坏的指令后跳转到blt+5的地址,现在问题是再程序第一次进入我的Blt1函数时候是正常的,文字也显示出来了,但是在第二次进入的时候,就崩溃了,调试发现第二次进入时候LPDIRECTDRAWSURFACE的方法地址都为0,下面是代码:
#include "stdafx.h"
#include <ddraw.h>
//#include "myDirectDraw.h"
//myDirectDraw *lpMyDD;DWORD dwAddrBase = 0;
DWORD dwOriAddrFn = 0;
//blt 地址 0x736D581B
DWORD blt_addr=0x736D581B;
DWORD realblt=0;
BYTE OriginalBytes[5]={0};
BYTE JmpAddress[5]={0xE9,0,0,0,0}; //跳转到HOOK函数的地址
BYTE jmp_orig_code[7] = { 0xEA, 0, 0, 0, 0, 0x08, 0x00 }; //跳到原函数+5地方
DWORD oldpro=0;//
HRESULT Blt1(void * pp,LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,
DWORD dwFlags,LPDDBLTFX lpDDBltFx) ;
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if(ul_reason_for_call == DLL_PROCESS_ATTACH)
{
MessageBox(NULL,"ok","ok",MB_OK); VirtualProtect((void*)blt_addr,5,PAGE_EXECUTE_READWRITE,&oldpro);
memcpy(OriginalBytes,(void*)blt_addr,5);
realblt=blt_addr+5;
*(BYTE*)blt_addr=0xe9;//0xe9在汇编中是跳转指令操作码
*(DWORD*)((BYTE*)blt_addr+1)=(DWORD)Blt1-(DWORD)blt_addr-5;//目标地址-原地址-5
}
return TRUE;
}HRESULT __declspec(naked) OriginalBlt(void * pp,LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,
LPRECT lpSrcRect, DWORD dwFlags,LPDDBLTFX lpDDBltFx)
{
_asm
{
push 0x318 // 恢复破坏的指令
mov eax,blt_addr
add eax,5
jmp eax //跳转到hook地址后5字节
}
}HRESULT Blt1(void * pp,LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,
DWORD dwFlags,LPDDBLTFX lpDDBltFx)
{
LPDIRECTDRAWSURFACE lpdds = (LPDIRECTDRAWSURFACE)pp;
//lpdds-> AddRef();
HRESULT hr;
MessageBox(NULL,"bit","ok",MB_OK);
DDSURFACEDESC ddsd;
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd); //问题再这里,第一次进入函数时候完全正常,第
lpdds-> GetSurfaceDesc(&ddsd); //二次进入时后lpdds不可用了,所有的方法地址都为0; bool b = (bool)(ddsd.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
if(!b)
{
//hr = lpdds-> Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx);
hr = OriginalBlt(lpdds,lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx); }else
{
// HDC hdc;
// lpDDSrcSurface-> GetDC(&hdc);
// SetBkColor(hdc,0);
// SetTextColor(hdc,RGB(255,0,0));
// char *str="Hook_DirectDraw 写屏";
// TextOut(hdc,100,100,str ,strlen(str));
// lpDDSrcSurface-> ReleaseDC(hdc);
// hr = lpdds-> Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx);
hr = OriginalBlt(lpdds,lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx);
}
_asm sub esp,0x18; //平衡堆栈
return hr;
} 这是什么原因呢?
#include "stdafx.h"
#include <ddraw.h>
//#include "myDirectDraw.h"
//myDirectDraw *lpMyDD;DWORD dwAddrBase = 0;
DWORD dwOriAddrFn = 0;
//blt 地址 0x736D581B
DWORD blt_addr=0x736D581B;
DWORD realblt=0;
BYTE OriginalBytes[5]={0};
BYTE JmpAddress[5]={0xE9,0,0,0,0}; //跳转到HOOK函数的地址
BYTE jmp_orig_code[7] = { 0xEA, 0, 0, 0, 0, 0x08, 0x00 }; //跳到原函数+5地方
DWORD oldpro=0;//
HRESULT Blt1(void * pp,LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,
DWORD dwFlags,LPDDBLTFX lpDDBltFx) ;
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if(ul_reason_for_call == DLL_PROCESS_ATTACH)
{
MessageBox(NULL,"ok","ok",MB_OK); VirtualProtect((void*)blt_addr,5,PAGE_EXECUTE_READWRITE,&oldpro);
memcpy(OriginalBytes,(void*)blt_addr,5);
realblt=blt_addr+5;
*(BYTE*)blt_addr=0xe9;//0xe9在汇编中是跳转指令操作码
*(DWORD*)((BYTE*)blt_addr+1)=(DWORD)Blt1-(DWORD)blt_addr-5;//目标地址-原地址-5
}
return TRUE;
}HRESULT __declspec(naked) OriginalBlt(void * pp,LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,
LPRECT lpSrcRect, DWORD dwFlags,LPDDBLTFX lpDDBltFx)
{
_asm
{
push 0x318 // 恢复破坏的指令
mov eax,blt_addr
add eax,5
jmp eax //跳转到hook地址后5字节
}
}HRESULT Blt1(void * pp,LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,
DWORD dwFlags,LPDDBLTFX lpDDBltFx)
{
LPDIRECTDRAWSURFACE lpdds = (LPDIRECTDRAWSURFACE)pp;
//lpdds-> AddRef();
HRESULT hr;
MessageBox(NULL,"bit","ok",MB_OK);
DDSURFACEDESC ddsd;
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd); //问题再这里,第一次进入函数时候完全正常,第
lpdds-> GetSurfaceDesc(&ddsd); //二次进入时后lpdds不可用了,所有的方法地址都为0; bool b = (bool)(ddsd.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
if(!b)
{
//hr = lpdds-> Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx);
hr = OriginalBlt(lpdds,lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx); }else
{
// HDC hdc;
// lpDDSrcSurface-> GetDC(&hdc);
// SetBkColor(hdc,0);
// SetTextColor(hdc,RGB(255,0,0));
// char *str="Hook_DirectDraw 写屏";
// TextOut(hdc,100,100,str ,strlen(str));
// lpDDSrcSurface-> ReleaseDC(hdc);
// hr = lpdds-> Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx);
hr = OriginalBlt(lpdds,lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx);
}
_asm sub esp,0x18; //平衡堆栈
return hr;
} 这是什么原因呢?
你能保证你jmp修改掉的5个字节正好是完整的指令吗?
还有就是函数是__stdcall 吗?那个恢复堆栈0x18如何得来?