#include<windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
/*
Windows 的窗口总是基于窗口类来创建的,窗口类同时确定了处理窗口消息的窗口过程(回调函数)。
回调函数需要到函数最后面几行找
*/
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hprevInstance,PSTR szCmdLine,int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(COLOR_CAPTIONTEXT); //背景色
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("这个程序无法执行"),szAppName,MB_OK);
return 0;
}
hwnd =CreateWindow(szAppName,
TEXT("AAAAAAAAAA"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,iCmdShow); //显示窗口
UpdateWindow(hwnd); //更新窗口
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
/*
WINUSERAPI int WINAPI MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
*/
/* 根据原型我们 自己定义一个函数*/
/* PS 不要修改返回值和参数类型或参数个数 否则栈不平衡 */
int _MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
/* 在这里我们可以做很多事 */
/* 比如直接返回 等于啥也没调用 */
/* 还可以在之前保存入口的5字节现在在这里修改回去 然后调用就可以 实现数据监控 */
return 0;
}
<FONT color=red>//内存对齐
#pragma pack(1)
struct _
{
BYTE type; //直接填233 也就是JMP
int *p; //地址 需要计算
};</FONT>
void _Created(HWND hWnd)
{
_ __={0};
__.type = 233; //233 = JMP
// USER32.DLL 为什么是这个DL 因为我们要拦截的函数在里面
char szUsee32[] = "User32.DLL";
//为什么是char 因为 GetProcAddress 函数第二个参数是char*
char szFunName[] = "MessageBoxA"; //拦截 ansi版的
//加载这个DLL返回事例句柄 也可以用 GetModuleHandle
HMODULE hModule = LoadLibraryA(szUsee32);
//得到 MessageBoxA 函数在内存的地址
<FONT color=red>void *p = GetProcAddress(hModule,szFunName); //</FONT>
// 关键 计算 最终地址 = 我们函数地址 - 目标地址 - 5
int* address =(int*)((int)_MessageBoxA - (int)p - 5);
// 把计算后的地址放上去
__.p = address;
//得到最终地址后还要做一件事
//我们要做的就是把 MessageBoxA 函数入口的 5 个字节改为 jmp address 这个address就是我们经过计算后的地址
//但是默认DLL加载到的那段地址空间不能写数据
//所以我们要修改他的内存属性
//需要用 VirtualProtectEx VirtualProtect VirtualProtectEx 是 VirtualProtect 扩展版 推荐用VirtualProtectEx
//http://baike.baidu.com/link?url=nH6bZ9peV5SPveHjtRNzG-bIsm7pNQJJTlomZjerGvYqr1aCY4FhGBtmWo_GRkHBwzThbB-kWAUov6BfvUSFz_
HANDLE hProcess = (HANDLE)-1; //-1代表我们自身进程句柄
DWORD lNewPro = PAGE_EXECUTE_READWRITE,lOldPro=0 ;//属性为可读可写
//如果成功,返回非零。失败返回零。
<FONT color=red>int ret = VirtualProtectEx(hProcess,(LPVOID)p,5,lNewPro,&lOldPro</FONT>);
if(!ret) MessageBoxA(NULL,"擦,属性修改失败",NULL,NULL);
/* 实际写入了多少字节 */
DWORD _Byte = 0;
//第一个参数是进程句柄
//第二个参数是写的地址
//第三个参数是要写的数据缓冲区
//第四个参数是要写多少字节
//第五个参数是函数实际写入多少字节了
// 一次性写入去
<FONT color=red>ret = WriteProcessMemory(hProcess,(LPVOID)p,(LPCVOID)&__,5,&_Byte);</FONT>
//然后调用 实际是到我们的函数了
MessageBoxA(NULL,NULL,NULL,NULL);
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE: //当接到窗口创建完的消息
_Created(hwnd);
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}