简介
有时候我们会觉得某个已经编译好了的程序的功能不是那么完美,我们想要再添加一些额外的功能,但是我们又没有源码,不方便直接进行修改重编译打包,这时候我们就可以考虑给程序添加一个新功能的按钮了...
思路
思路很简单,无非就是利用子类化技术,直接编写DLL,然后注入到程序当中去,虽然就一句话但是具体的工作还是比较多,这里我就通过给植物大战僵尸程序为例子仔细说说...
编写DLL
创建按钮
因为我们主要目的是添加一个按钮功能,使用这里主要用到的函数是CreateWindow
...
Syntax:
HWND CreateWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HANDLE hInstance,
PVOID lpParam
)
通过这个函数我们可以创建一个按钮,主要的参数是hWndParent
,这个参数表示父窗口句柄,我们可以用FindWindow
函数来获取,例如:
#define BUTTON_sir_1 3300
HWND hWndParent = FindWindow(NULL,"植物大战僵尸中文版");
CreateWindow(TEXT("BUTTON"),
TEXT("增加阳光"),
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
600,0,80,30,
hWndParent,
(HMENU)BUTTON_sir_1,
NULL,
NULL);
子类化
子类化就是用来改变或者扩展一个已存在的窗口的行为、而不用重新开发的有效途径,这是我们添加按钮,给予按钮处理事件的能力的主要方法,主要方法就是通过GetWindowLong()
获取窗口旧的消息处理函数(OldWindowProc
),然后通过SetWindowLong()
设置新的消息处理函数(NewWndProc
),进行需要进行的消息处理,其他的交给旧的消息处理函数:
LRESULT CALLBACK NewWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
OldWindowProc = GetWindowLong(hWndParent,GWL_WNDPROC);
SetWindowLong(hWndParent,GWL_WNDPROC,(LONG)NewWndProc);
新的消息处理函数中只需要写我们感兴趣的消息,比如这里我们只关心按键增加阳光的功能,其余我们没有写的消息处理通过CallWindowProc
函数交给原来的消息处理函数处理:
LRESULT CALLBACK NewWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
int wmId, wmEvent;
switch(message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case BUTTON_sir_1:
MessageBox(NULL,TEXT("3003"),TEXT("HELLO"),MB_OK);
break;
default:
return CallWindowProc((WNDPROC)OldWindowProc,hWnd,message,wParam,lParam);
}
break;
default:
return CallWindowProc((WNDPROC)OldWindowProc,hWnd,message,wParam,lParam);
}
return 0;
}
这样我们的按键就有相应消息的能力了,剩下的就是完善dll,然后编写dll注入代码了;
DLL注入
基本步骤是:
- 获取目标进程句柄
- 将要注入的dll路径写入目标进程内存
- 获取LoadLibraryW()API地址
- 在目标进程中运行远程线程
dll注入的代码确实网上确实到处都是,我这里直接贴出参考,用的是CreateRemoteThread
的方法;
效果
dll代码
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include <stdio.h>
#include <psapi.h>
#define BUTTON_sir_1 3300
#define BUTTON_sir_2 3301
#define BUTTON_sir_3 3302
//extern "C" _declspec(dllexport)
LONG OldWindowProc,Button1Proc;
HWND pro_hwnd; //程序句柄
HANDLE hpro; //进程句柄
DWORD pro_base = NULL; //程序基地址
char szBuf[1024] = { 0 };
LRESULT CALLBACK NewWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
int kill(){
pro_hwnd = FindWindow(NULL,"植物大战僵尸中文版"); //植物大战僵尸中文版
if (pro_hwnd == NULL){ //如果无法获取句柄则报错
return -1;
}
DWORD pro_id;
GetWindowThreadProcessId(pro_hwnd, &pro_id); //获取进程ID
if(pro_id == 0){
//printf("无法获取进程ID\n");
return 0;
}
//printf("进程id: %d\n",pro_id);
//打开进程对象,并获取进程句柄
hpro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pro_id);
if (hpro == 0){
printf("无法获取进程句柄");
}
printf("进程句柄id: %d\n",hpro);
// 获取每一个模块加载基址
HMODULE hModule[200] = {0};
DWORD dwRet = 0;
int num = 0;
int bRet = EnumProcessModulesEx(hpro, (HMODULE *)(hModule), sizeof(hModule),&dwRet,NULL);
if (bRet == 0){
printf("EnumProcessModules");
}
// 总模块个数
num = dwRet/sizeof(HMODULE);
pro_base = (DWORD)hModule[0];
return 0;
}
void sun_add(){
DWORD sun_addr = pro_base + 0x002A9EC0;
printf("阳光基址: 0x%p\n",sun_addr);
DWORD sun_value;
DWORD new_sun_value;
ReadProcessMemory(hpro,(PVOID)sun_addr,&sun_addr,4,0);
sun_addr = sun_addr + 0x768;
ReadProcessMemory(hpro,(PVOID)sun_addr,&sun_addr,4,0);
sun_addr = sun_addr + 0x5560;
ReadProcessMemory(hpro,(PVOID)sun_addr,&sun_value,4,0);
new_sun_value = sun_value + 2000;
WriteProcessMemory(hpro, (LPVOID)sun_addr, &new_sun_value, 4, 0); //修改阳光
}
void kill_all(){
DWORD kill_1 = pro_base + 0x0013130F; //0x0053130F
DWORD code_1 = 0x9090ff29; //0x20247c2b
WriteProcessMemory(hpro, (LPVOID)kill_1, (LPVOID)&code_1, 4, 0); //普通僵尸秒杀
DWORD kill_2 = pro_base + 0x00131044; //0x00531044
WORD code_2 = 0xC929; //0xc82b
WriteProcessMemory(hpro, (LPVOID)kill_2, (LPVOID)&code_2, 2, 0); //帽子僵尸秒杀
}
void no_time(){
DWORD no_time = pro_base + 0x00087296; //0x487296
WORD code_3 = 0x9090; //jle 004872AC
WriteProcessMemory(hpro, (LPVOID)no_time, (LPVOID)&code_3, 2, 0); //无冷却时间
}
DWORD APIENTRY Msg(LPVOID lpParameter)
{
char szBuf[1024] = { 0 };
//hwnd = FindWindow(NULL, TEXT("wintest"));
CreateWindow(TEXT("BUTTON"),
TEXT("增加阳光"),
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
600,0,80,30,
pro_hwnd,
(HMENU)BUTTON_sir_1,
NULL, //(HINSTANCE)GetWindowLongPtr((HWND)lpParameter,GWLP_HWNDPARENT)
NULL);
CreateWindow(TEXT("BUTTON"),
TEXT("僵尸秒杀"),
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
600,40,80,30,
pro_hwnd,
(HMENU)BUTTON_sir_2,
NULL,
NULL);
CreateWindow(TEXT("BUTTON"),
TEXT("无冷却"),
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
600,80,80,30,
pro_hwnd,
(HMENU)BUTTON_sir_3,
NULL,
NULL);
OldWindowProc = GetWindowLong(pro_hwnd,GWL_WNDPROC);
SetWindowLong(pro_hwnd,GWL_WNDPROC,(LONG)NewWndProc);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK NewWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
int wmId, wmEvent;
switch(message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case BUTTON_sir_1:
//MessageBox(NULL,TEXT("3003"),TEXT("HELLO"),MB_OK);
sun_add();
break;
case BUTTON_sir_2:
kill_all();
break;
case BUTTON_sir_3:
no_time();
break;
default:
return CallWindowProc((WNDPROC)OldWindowProc,hWnd,message,wParam,lParam);
}
break;
default:
return CallWindowProc((WNDPROC)OldWindowProc,hWnd,message,wParam,lParam);
}
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
kill();
CreateThread(NULL, 0, Msg, hModule, 0, NULL);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Source.def:
LIBRARY "DLL"
EXPORTS
Msg