#include "stdafx.h"
#include <windows.h>
#include <assert.h>
#pragma comment(lib,"user32.lib")

typedef int (*detour_MessageBoxA)(HWND hWnd,LPCSTR,LPCSTR,UINT);
detour_MessageBoxA msg;
char origInstr[8] = {0};
char newInstr[8] = {"\xe9\x00\x00\x00\x00"};

int _tmain(int argc, _TCHAR* argv[])
{
DWORD tmp;
DWORD curr;
char str[] = {""};
char* funcName = NULL;
HMODULE hMod = LoadLibrary("user32.dll");
char* dllBase = (char*)hMod;
IMAGE_DOS_HEADER *pDosHeader = (IMAGE_DOS_HEADER*)dllBase;
IMAGE_OPTIONAL_HEADER *pOptHeader = (IMAGE_OPTIONAL_HEADER*)((BYTE*)dllBase + pDosHeader->e_lfanew + 24);
IMAGE_EXPORT_DIRECTORY *pExport = (IMAGE_EXPORT_DIRECTORY*)((BYTE*)dllBase + pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
char* dllname = dllBase+pExport->Name;
//函数名数组RVA,其数组元素为函数名的RVA
DWORD* funcNameRvaTab = (DWORD*)(dllBase+pExport->AddressOfNames);
//函数在dllBase+pExport->AddressOfFunctions数组中的索引值
WORD* funcOrdinalTab = (WORD*)(dllBase+pExport->AddressOfNameOrdinals);
DWORD* exportFuncAddrTab = (DWORD*)(dllBase+pExport->AddressOfFunctions);
DWORD NumberOfNames = pExport->NumberOfNames;
DWORD idx;
DWORD oldProct;
for(idx=0;idx<NumberOfNames;idx++)
{
funcName = (char*)(dllBase+funcNameRvaTab[idx]);
if(strcmp((const char*)funcName,"MessageBoxA")==0)
{
DWORD idxInFuncAddrArry = funcOrdinalTab[idx];
//获得函数在dll中的入口地址
//exportFuncAddrTab[idxInFuncAddrArry]中存放的RVA了
msg = (detour_MessageBoxA)(dllBase + exportFuncAddrTab[idxInFuncAddrArry]);
#if 0
//能成功调用msgBox,但过不了checkEsp 设置调用约定_cdecl->stdcall
(msg)(NULL,"","",MB_OK);
#endif
assert(VirtualProtect(msg,8,PAGE_EXECUTE_READWRITE,&oldProct)!=0);
//save
ReadProcessMemory(GetCurrentProcess(),msg,origInstr,8,&tmp);
__asm
{
mov eax,Lab1;
mov curr,eax;
}
//把函数入口处的指令替换为相对跳转指令,跳转的目标为Lab1
//diff的计算可以搜索网上jmp跳转计算
DWORD diff = (DWORD)curr-(DWORD)msg-5;
memcpy(newInstr+1,(char*)&diff,sizeof(DWORD));

WriteProcessMemory(GetCurrentProcess(),msg,newInstr,5,&tmp);
(msg)(NULL,"","",MB_OK);
}
}

while(1)
{
Sleep(1);
}

//这段代码本应该写成函数形式 但因为要用裸函数(否则函数开始就push ebp了)
//所以直接改成代码片了
Lab1:
static int cnt=0;

cnt++;
WriteProcessMemory(GetCurrentProcess(),msg,origInstr,8,&tmp);
__asm
{
mov eax,Lab2;
mov curr,eax;
}
assert(VirtualProtect((DWORD*)curr,8,PAGE_EXECUTE_READWRITE,&oldProct)!=0);
//计算从Lab2跳回msg入口的相对偏移
DWORD diff = (DWORD)msg-(DWORD)curr-5;
__asm
{
mov ebx,diff;
mov eax,Lab2;
inc eax;
mov [eax],ebx;
}
Lab2:
__asm
{
_emit 0xe9;
_emit 0x00;
_emit 0x00;
_emit 0x00;
_emit 0x00;
}

return 0;
}