C语言获取任意Windows程序模块基地址

我已无力接住你,再也不能抗风雨

函数

这里主要用到的函数是EnumProcessModulesEx:

BOOL EnumProcessModulesEx(
  HANDLE  hProcess,
  HMODULE *lphModule,
  DWORD   cb,
  LPDWORD lpcbNeeded,
  DWORD   dwFilterFlag
);

hProcess表示处理的句柄;
lphModule表示接收模块句柄列表的数组;
cb表示lphModule数组的大小,以字节为单位;
lpcbNeeded表示在lphModule数组中存储所有模块句柄所需的字节数;
dwFilterFlag表示过滤条件,下列值之一:

含义
LIST_MODULES_32BIT
0x01
列出32位模块
LLIST_MODULES_64BIT
0x02
列出64位模块
LIST_MODULES_ALL
0x03
列出所有模块
LIST_MODULES_DEFAULT
0x00
使用默认行为

所以我们在用这个函数时需要先利用函数FindWindow()找到程序的窗口句柄,然后利用函数GetWindowThreadProcessId()找到程序的进程ID,最后调用函数OpenProcess()找到程序进程的打开句柄,最后可以调用EnumProcessModulesEx()函数获取模块的基地址;

实例

这里直接以获取植物大战僵尸的基地址来演示:

#include
#include
#include
int main(){
	HWND hWnd = FindWindow(NULL,"植物大战僵尸中文版");
	if (hWnd == NULL){	//如果无法获取句柄则报错
		printf("无法获取窗口句柄,请检查进程是否存在!\n");
		system("pause");
		return -1;
	}

	DWORD pro_id;
	GetWindowThreadProcessId(hWnd, &pro_id);	//获取进程ID  
	if(pro_id == 0){
		printf("无法获取进程ID\n");
		system("pause");
		return 0;
	}
	printf("进程id: %d\n",pro_id);
	//打开进程对象,并获取进程句柄
	HANDLE hpro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pro_id);
	if (hpro == 0){
		printf("无法获取进程句柄");
	}
	printf("进程句柄id: %d\n",hpro);

	// 获取每一个模块加载基址
	DWORD pro_base = NULL;
	HMODULE hModule[100] = {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);
	printf("总模块个数: %d\n",num);
	// 打印每一个模块加载基址
	char lpBaseName[100];
	for(int i = 0;i<num;i++){
		GetModuleBaseNameA(hpro,hModule[i],lpBaseName,sizeof(lpBaseName));
		printf("%-2d %-25s基址: 0x%p\n",i,lpBaseName,hModule[i]);
	}

    pro_base = (DWORD)hModule[0];
	printf("程序基址: 0x%p\n",pro_base);
	
	DWORD sun_addr = pro_base + 0x002A9EC0;
	printf("阳光基址: 0x%p\n",sun_addr);
	DWORD sun_value;
	DWORD new_sun_value = 2000;
	DWORD kill_1 = pro_base + 0x0013130F; //0x0053130F
	DWORD code_1 = 0x9090ff29; //0x20247c2b
	DWORD kill_2 = pro_base + 0x00131044; //0x00531044
	WORD code_2 = 0xC929;	//0xc82b
	// 0x0048728C
	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);
	printf("阳光地址: %p\n当前阳光值: %d\n",sun_addr,sun_value);
	printf("修改的阳光值: 2000\n");
	//scanf("%d",&new_sun_value);
	WriteProcessMemory(hpro, (LPVOID)sun_addr, &new_sun_value, 4, 0); //修改阳光
	WriteProcessMemory(hpro, (LPVOID)kill_1, (LPVOID)&code_1, 4, 0); //普通僵尸秒杀
	WriteProcessMemory(hpro, (LPVOID)kill_2, (LPVOID)&code_2, 2, 0); //帽子僵尸秒杀
	system("pause");
	return 0;
}

可以通过CE进行查看对比:
C语言获取任意Windows程序模块基地址_第1张图片

你可能感兴趣的:(Windows)