背景
因为需要破解某款软件的防多开限制,所以就有了如题的需求。
但是改窗口类名不像改窗口标题那么简单(直接 SetWindowText),没有直接的 API 可以使用。经过几天的钻研,总结了两种修改窗口类名的方法:
- 修改 pe 文件(适合没有加壳的程序)
- hook RegisterClass(适合加壳的程序)
修改 pe 文件
以 dbgview.exe 为例,可以看到它是无壳的:
程序打开后主窗口类名为 dbgviewClass:
在 die 中直接查看 hex,搜索 dbgviewClass:
直接随便修改修改,保存,再次打开进程查看类名:
已经被改变了!
hook RegisterClass
众所周知,壳的作用无非就是以下几种作用
- 压缩
- 反动态调试
- 反静态分析
所以,如果软件加过壳,我们再用第一种方法就搜不到类名字符串了(因为真正的代码只有在程序运行时才被解密出来,用hex工具看到的都是密文)
先来看一段创建窗口的代码:
//1、设计窗口
WNDCLASS wc;
wc.cbClsExtra = 0; //类额外的内存,通常为零
wc.cbWndExtra = 0; //窗口额外的内存,通常为零
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置背景
wc.hCursor = LoadCursor(NULL, IDC_HAND); //设置光标,如果第一个参数为NULL,代表使用系统提供的默认光标
wc.hIcon = LoadIcon(NULL, IDI_WARNING);
wc.hInstance = hInstance; //当前实例句柄,WinMain函数中形参即可
wc.lpfnWndProc = WindowProc; //窗口过程函数,回调函数,名称可以随便起
wc.lpszClassName = TEXT("WINDOW"); //指定窗口类名
wc.lpszMenuName = NULL; //菜单名,没有填NULL
wc.style = 0; //0代表默认风格
//2、注册窗口类
RegisterClass(&wc);
//3、创建窗口
HWND hwnd = CreateWindow(wc.lpszClassName, TEXT("TEXT WINDOW"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT ,
NULL, NULL, hInstance, NULL);
//4、显示和更新
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
//5、通过循环取消息
MSG msg;
while(1)
{
if (GetMessage(&msg, NULL,0,0) == FALSE)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
我尝试过 Hook CreateWindowEx 或 CreateWindow,修改它的 lpClassName 参数,但是这会导致函数返回 1047 错误(找不到窗口类别)
我又尝试去在 RegisterClass 下断点,但是它被调用很多次让我很难分清哪个是我想要的
最后我在 LoadCursor ,LoadIcon 下断点,找到了合适的修改窗口类名的位置:
修改后运行程序:
已经被我成功改掉。
因为这个游戏有文件 md5 校验,所以没办法通过内存地址计算文件地址后修改文件的方法修改类名,所以只能放弃这个思路:
总结:
因为没有下 RegisterClassEx 的断点(只想到了 RegisterClass)而浪费了那么多时间。 可以用导入表 hook 实现修改类名的需求。