我通过调试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; 
} 这是什么原因呢?

解决方案 »

  1.   

    楼主啊。
    你能保证你jmp修改掉的5个字节正好是完整的指令吗?
    还有就是函数是__stdcall 吗?那个恢复堆栈0x18如何得来?
      

  2.   

    hook前这些都搞清楚了才hook的,而且出错是在第二次进入这个hook里才出错的,如果像你说的那样,在第一次结束第二次开始之前就会错了
      

  3.   

    结贴了,最后发现是声明blt1时候没有stdcall的原因