给程序加一个按钮

简介

有时候我们会觉得某个已经编译好了的程序的功能不是那么完美,我们想要再添加一些额外的功能,但是我们又没有源码,不方便直接进行修改重编译打包,这时候我们就可以考虑给程序添加一个新功能的按钮了…

思路

思路很简单,无非就是利用子类化技术,直接编写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注入

基本步骤是:

  1. 获取目标进程句柄
  2. 将要注入的dll路径写入目标进程内存
  3. 获取LoadLibraryW()API地址
  4. 在目标进程中运行远程线程

dll注入的代码确实网上确实到处都是,我这里直接贴出参考,用的是CreateRemoteThread的方法;

效果

在这里插入图片描述2

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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值