修改函数头5个字节Hook,不明白解决办法

修改函数头5个字节Hook,不明白
把函数头5个字节修改为jmp XXXX,其中XXXX的值是这样计算出来的
DWORD dwNew = (DWORD)MyHookAPI - (DWORD)m_AddrAPI - 5;
不明白上面是根据什么原理计算出来的,请了解的朋友帮解释下,谢谢!


C/C++ code

// hook5bytes_.cpp : 定义 DLL 应用程序的入口点。
//

#include "stdafx.h"

#include <Windows.h>
#include <stdio.h>


#define HookModName  "user32.dll"
#define HookApiName  "MessageBoxW"



//修改API入口为jmp eax是程序能跳转到自己的函数
BYTE g_btNew5Bytes[5] = { 0xE9, 0x0, 0x0,0x0, 0x0};

//保存原API入口的5个字节
BYTE g_dwOld5Bytes[5] = { 0x0, 0x0, 0x0, 0x0, 0x0};


//API地址
void * m_AddrAPI;

//定义自己的API,参数表和原函数一致,MyHookAPI中调用的也一样
int WINAPI MyHookAPI(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);


BOOL APIENTRY DllMain( HANDLE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{
    if(ul_reason_for_call==DLL_PROCESS_ATTACH)        
    {
        
        //找到API地址
        HMODULE hModule = LoadLibrary(HookModName);
        m_AddrAPI = (void *)GetProcAddress( hModule,HookApiName);            

        /*修改5字节*/
        
        //保存原始字节
        ReadProcessMemory(INVALID_HANDLE_VALUE,m_AddrAPI, ( void * )g_dwOld5Bytes, sizeof( DWORD )+1, NULL );                                        
               
        DWORD dwNew = (DWORD)MyHookAPI - (DWORD)m_AddrAPI - 5;
        memcpy(&g_btNew5Bytes[1], &dwNew, 4);
                        
        WriteProcessMemory( INVALID_HANDLE_VALUE,m_AddrAPI,( void * )g_btNew5Bytes, sizeof( DWORD )+1, NULL ); 
        

    }

    return TRUE;
}
int _stdcall MyHookAPI(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{
            
    WriteProcessMemory( INVALID_HANDLE_VALUE,m_AddrAPI,( void * )g_dwOld5Bytes, sizeof( DWORD )+1, NULL );    
    ::MessageBoxW(hWnd,lpText,L"HOOK",uType);    
    WriteProcessMemory( INVALID_HANDLE_VALUE,m_AddrAPI,( void * )g_btNew5Bytes, sizeof( DWORD )+1, NULL );        
    return 0;
}





------解决方案--------------------
长跳转jmp XXXX指令占5字节
偏移 = 目标地址 - JMP的下一条指令地址
即是:偏移 = 目标地址 - ( JMP的地址 + 5 )
展开:偏移 = 目标地址 - JMP的地址 - 5

具体语法查CPU指令手册或相关汇编资料
------解决方案--------------------
探讨
(另外:最好能推荐一些这方面学习的资料,谢谢!)

------解决方案--------------------
汇编啊,都是高手. 学习之..
------解决方案--------------------
你就直接写jmp就OK了,编译器知道这是什么跳转,是远跳还是近跳。什么东西的存在都是有道理的,比如这个jmp far 和jmp near,如果你看一下对应的机器指令就清楚了,你想一个字节能跳多远?4个字节能跳多远?
------解决方案--------------------
e9是近跳,就是段内跳
e9后面的4字节的意义是,跳的目标地址减去jmp下一个指令的地址
这是为了看起来像最初cpu执行指令的过程,先取指令,增加pc,执行指令