findwindow获取托盘区图标程序的句柄_C/C++编程笔记:替换windows应用图标

好多年前的一些恶作剧程序就是将windows上其他的程序图标全部换成一个;

或者将一个用户常用的一个应用(比如QQ)图标替换到一个其他程序上,然后将该应用替换伪装成这个常用的应用。

当用户点击的时候,运行的可能是意想不到的程序。

抛开恶作剧的想法,我们单从技术角度去看这个问题,如何去实现呢?

0c5e12deaea80800a9bef42619fdd2ce.png

都是资源

程序图标都是资源图片,在打包的时候,由打包程序拷贝到exe的程序文件里面去了。

因为exe文件是有对应的格式的,不同的数据存储在对应位置,而且格式比较复杂。

有兴趣的小伙伴可以百度搜索相关的exe文件格式介绍,并且还有一个PEView的文件查看器。

抛开繁杂的exe文件格式,我们如何去进行操作呢?

WIN32 API

微软提供了繁多的API,供我们来使用。

其中 LoadLibraryEx 函数可以加载dll或者exe,返回模块句柄;

再通过 EnumResourceNames 函数枚举出对应的资源(比如图标),通过传入的回调函数进行操作;

在回调函数中通过 UpdateResource 函数操作资源,这样就可以实现对exe文件中资源的更换。

需要注意的是在替换之前,需要将需要替换的exe文件里面的资源删除;再将另一个exe文件的资源(比如图标)更新到该exe里面,这样我们就实现了程序图标的替换,以假乱真。

具体实现

代码很短,且有详细的注释,请看:

删除图标回调函数BOOL CALLBACK DelIcons(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) {    HANDLE hUpdate = (HANDLE)lParam;    void* pData = 0;  // 数据为空,即为删除    int nSizeOfIconRes = 0;    UpdateResource(hUpdate,lpszType,lpszName,MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),pData,nSizeOfIconRes);    return TRUE;}替换图标回调函数BOOL CALLBACK UpdateIcons(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) {    HANDLE hUpdate = (HANDLE)lParam;    HRSRC hRes = FindResource(hModule,lpszName,lpszType); // 查找数据源    HGLOBAL hResLoaded = LoadResource(hModule, hRes); // 加载数据源    void* pData = LockResource(hResLoaded);  // 加锁    int nSizeOfIconRes = SizeofResource(hModule,hRes);  // 获取资源大小    UpdateResource(hUpdate,lpszType,lpszName,MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),pData,nSizeOfIconRes);    UnlockResource(hResLoaded); // 解锁    FreeResource(hResLoaded); // 释放资源    return TRUE;}// brief changeIcon 改变程序图标( eg: changeIcon("xxx.exe", "QQ.exe");///        将 QQ.exe 的企鹅图标 换到  xxx.exe;)/// param dstApp  要改图标的程序名称/// param srcApp  图标来源图标///void changeIcon(const char*dstApp, const char*srcApp) {    HANDLE hUpdate = BeginUpdateResourceA(dstApp, false);    // 加载目的文件,并删除图标    HMODULE hdst = LoadLibraryExA(dstApp, 0, LOAD_LIBRARY_AS_DATAFILE);    EnumResourceNames(hdst,RT_ICON,DelIcons,(long)hUpdate);    EnumResourceNames(hdst,RT_GROUP_ICON,DelIcons,(long)hUpdate);    FreeLibrary(hdst);    // 加载源文件,并更新图标    HMODULE hsrc = LoadLibraryExA(srcApp, 0, LOAD_LIBRARY_AS_DATAFILE);    EnumResourceNames(hsrc,RT_ICON,UpdateIcons,(long)hUpdate);    EnumResourceNames(hsrc,RT_GROUP_ICON,UpdateIcons,(long)hUpdate);    FreeLibrary(hsrc);    EndUpdateResource(hUpdate,FALSE);}

使用的时候,只需要简单的传入两个对应的exe路径即可:

int main(int argc, char* argv[]){    changeIcon("X:/xxx/xxx.exe", "X:/xxx/QQ.exe");    return 0;}

总结

希望大家看后能够对exe文件有所理解,其实它也只是一个有着对应格式的二进制文件而已,只是windows赋予它可执行权限而已。

此文仅作为技术讨论,请勿乱用,否则后果自负,与本人无关!

如果觉得我写的还不错的话,求赞,求关注哦!(^▽^)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果使用`FindWindow`函数无法获取到开始菜单的句柄,可能是因为该窗口是由Windows Shell进程创建的,而不是由当前进程创建的。在这种情况下,可以使用`EnumWindows`函数枚举所有顶级窗口,然后通过窗口类名或窗口标题来查找开始菜单的句柄。 以下是一个示例代码,演示如何使用`EnumWindows`函数获取开始菜单的句柄: ```cpp #include <windows.h> #include <tchar.h> // 回调函数,用于枚举窗口 BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { TCHAR szClassName[256]; TCHAR szWindowText[256]; GetClassName(hwnd, szClassName, 256); GetWindowText(hwnd, szWindowText, 256); // 如果窗口类名和标题符合条件,则认为找到了开始菜单 if (_tcscmp(szClassName, _T("Windows.UI.Core.CoreWindow")) == 0 && _tcscmp(szWindowText, _T("Start")) == 0) { *(HWND*)lParam = hwnd; return FALSE; } return TRUE; } int main() { // 枚举所有顶级窗口,查找开始菜单句柄 HWND hStartMenuWnd = NULL; EnumWindows(EnumWindowsProc, (LPARAM)&hStartMenuWnd); if (hStartMenuWnd) { // 找到了开始菜单句柄 // TODO: 在这里使用开始菜单句柄进行操作 } else { // 没有找到开始菜单句柄 } // 等待用户按下任意键,结束程序 system("pause"); return 0; } ``` 在上面的代码中,我们使用`EnumWindows`函数枚举所有顶级窗口,并在回调函数中查找符合条件的窗口。如果找到了开始菜单的句柄,则在回调函数中将其保存到`lParam`参数中,然后返回`FALSE`,以终止窗口枚举。最后,我们在主函数中判断是否找到了开始菜单句柄,如果找到了则可以使用该句柄进行操作。 注意:上述代码中使用的窗口类名和窗口标题可能在不同的Windows版本中有所不同,需要根据具体情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值