一个改程序小记
原文首发 CC98 白洪欢老师答疑版( http://10.71.45.99/dispbbs.asp?boardID=323&ID=1979518 )
今天的改程序小记
昨晚逛 WZ 水区,居然有个人问怎么改程序。是这么一个东西:

文件名叫“补丁.exe”……(那改了后是不是该叫“补丁过的补丁.exe”之类的了?)
按菜单上这个“设置”,会出来这么个框。
那个人说要让那个框出来时编辑框里面就有文字,直接改资源没用。
于是为了抓住锻炼的机会我就开搞啦!
首先是找显示这个对话框的 API。
我原先以为对话框的 CreateDialog 也是调用 CreateWindow 的,可是截不住。
抓到两个 CreateWindow 动作,一个是主窗口。还有一个很奇怪的,类名是 "CicMarshalWndClass",
是点击托盘图标弹出菜单的时候发生的。当时以为是这个对话框,可是这个把我搞得却没头绪了。
于是不知怎么的我就觉得应该不是它。
于是我想,可能 CreateDialog 跟 CreateWindow 是不一样的。可是,CreateDialogA、CreateDialogExA,
都说没有这个函数……郁闷。后来查到了,是这么些:
CreateDialogParamA(W)
CreateDialogIndirectParamA(W)
DialogBoxParamA(W)
DialogBoxIndirectParamA(W)
一个一个试过去,原来是 DialogBoxParamA。然后就到了这里:

MSDN 里对 DialogBoxParamA 函数的说明如下:
Syntax
INT_PTR DialogBoxParam(
HINSTANCE hInstance,
LPCTSTR lpTemplateName,
HWND hWndParent,
DLGPROC lpDialogFunc,
LPARAM dwInitParam
);
Parameters
...
Return Value
If the function succeeds, the return value is the value of the nResult parameter specified
in the call to the EndDialog function used to terminate the dialog box.
If the function fails because the hWndParent parameter is invalid, the return value is zero.
The function returns zero in this case for compatibility with previous versions of Microsoft Windows.
If the function fails for any other reason, the return value is –1. To get extended error information, call GetLastError.
跟进去逛了几圈,发现 DialogBoxParamA 里面是调用 ShowWindow 的。
那就没法抢在 ShowWindow 之前去设置文本了。接下来的想法是,那就在 DialogBoxParamA 之后,
紧接着马上去设置编辑框文本。这里地方比较紧凑,又产生了暑假用过的一个想法:
Call 到自己添加的函数;
在自己的函数里面 Call DialogBoxParamA;
然后设置那个编辑框的文本;
返回;
这是昨晚想的事情,当时快 12 点了要熄灯,作罢。接下来是今天考试归来后的。
我开始添加函数了。不是要 SetDlgItemText 吗?那就要 GetDlgItem,于是就需要对话框的句柄。
可是从上面的引文可以看到,DialogBoxParamA 并不返回对话框句柄。
我考虑把它改成 CreateDialogParamA,那就可以得到句柄了。
CreateDialogParamA 函数说明:
Syntax
HWND CreateDialogParam(
HINSTANCE hInstance,
LPCTSTR lpTemplateName,
HWND hWndParent,
DLGPROC lpDialogFunc,
LPARAM dwInitParam
);
Parameters
...
Return Value
If the function succeeds, the return value is the window handle to the dialog box.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
好的,就这么干。为 CreateDialogParamA 准备参数。第一个 dwInitParam 大概可以 NULL 的。
然后是回调函数。到原来 Call DialogBoxParamA 的地方找,函数地址是 401019。
这时突然又有个思路了,既然找到了回调函数,那就到里面给他来个 case WM_INITDIALOG,
就可以在那里设置文本了呀。
401019 处:

这里好像是个函数总目录,呵呵。4020E0 那里才是真正的回调函数体的开始。
发现有个
00402148 52 push edx
00402149 68 EA030000 push 3EA
0040214E |. 8B45 08 mov eax, dword ptr [ebp+8]
00402151 |. 50 push eax
00402152 |. FF15 D0C44200 call dword ptr [<&USER32.SetDl>]
3EA 是 1002,可是资源里面找不到:

那个编辑框的 ID 是 1003。试着把 3EA 改成 3EB,可是没用。
发现紧接着的地方有个:
0040216C |. 68 EB030000 push 3EB
00402171 |. 8B4D 08 mov ecx, dword ptr [ebp+8]
00402174 |. 51 push ecx
00402175 |. FF15 D4C44200 call dword ptr [<&USER32.GetDlgItem>]
0040217B |. 3BFC cmp edi, esp
0040217D |. E8 FE0F0000 call 00403180
00402182 50 push eax
00402183 FF15 D8C44200 call dword ptr [<&USER32.SendMessageA>]
00402189 |. 3BF4 cmp esi, esp
0040218B |. E8 F00F0000 call 00403180
试着把这里的 SendMessage 跳过去(jmp 到 402189),却出来一个错误的框框。再接下去的部分是别的东西了,那个错误框框……只能是 0040218B |. E8 F00F0000 call 00403180 这里面有名堂了。可是前面没有 je 之类的判断跳转,cmp 又不影响流程,难道它每次都显示错误不成?所以比较好奇,进去看了一下,原来是:
00403180 /$ /75 01 jnz short 00403183
00403182 |. |C3 retn
00403183 |> /55 push ebp
00403184 |. 8BEC mov ebp, esp
00403186 |. 83EC 00 sub esp, 0
00403189 |. 50 push eax
0040318A |. 52 push edx
原来如此,呵呵。现在我知道了,后面所有的
cmp esi, esp
call 00403180
都是在检查函数调用结果。如果出问题就跳出一个错误框。
刚才试改了上面两处都不行,我考虑实现自己原先的思路了,嗯,找 switch (message) 的 case。
函数前面有这么两个 cmp:
004020FE |. 8B45 0C mov eax, dword ptr [ebp+C]
00402101 |. 8945 8C mov dword ptr [ebp-74], eax
00402104 |. 817D 8C 10010>cmp dword ptr [ebp-74], 110
0040210B |. 74 12 je short 0040211F
0040210D |. 817D 8C 11010>cmp dword ptr [ebp-74], 111
00402114 |. 0F84 C0000000 je 004021DA
0040211A |. E9 0E020000 jmp 0040232D
比较,跳转,比较,跳转,跟 switch case 有点像。那么 dword ptr [ebp-74] 就是消息值了。第二个 je 后的 jmp 跳到了:
0040232D |> /33C0 xor eax, eax
0040232F |> 5F pop edi
00402330 |. 5E pop esi
00402331 |. 5B pop ebx
00402332 |. 81C4 B4000000 add esp, 0B4
00402338 |. 3BEC cmp ebp, esp
0040233A |. E8 410E0000 call 00403180
0040233F |. 8BE5 mov esp, ebp
00402341 |. 5D pop ebp
00402342 /. C2 1000 retn 10
这里已经是函数末尾了。那么我就 jmp 到其他空白地方,在那里比较消息值是不是 WM_INITDIALOG,是的话设置文本,jmp 回来,应该就好了。我查 WM_INITDIALOG 的值,MSDN索引里填进去没有……对,打开一个 Win32 工程看:

110?前面好像打眼过……回去找。
00402104 |. 817D 8C 10010>cmp dword ptr [ebp-74], 110
0040210B |. 74 12 je short 0040211F
0040210D |. 817D 8C 11010>cmp dword ptr [ebp-74], 111
00402114 |. 0F84 C0000000 je 004021DA
0040211A |. E9 0E020000 jmp 0040232D
0040211F |> 8BF4 mov esi, esp
40211F 之后却就是原来我试改过的地方。晕死了。只好接着刚才的两个地方看下来,看看把代码插在哪里好。却发现:
004021B6 8D45 CC lea eax, dword ptr [ebp-34]
004021B9 50 push eax
004021BA 68 EB030000 push 3EB
004021BF |. 8B4D 08 mov ecx, dword ptr [ebp+8]
004021C2 |. 51 push ecx
004021C3 |. FF15 D0C44200 call dword ptr [<&USER32.SetDlgItemTextA>]
004021C9 |. 3BF4 cmp esi, esp
004021CB |. E8 B00F0000 call 00403180
004021D0 |. B8 01000000 mov eax, 1
它自己在对编辑框设置文本。[ebp-34] 那里是个 0。终于搞明白了,资源里改编辑框的文本还是有用的,只是程序自己把它清除了。
然后是,把这一段跳过(当然是跳到 call 00403180 的后面,不然又会一个错误框),再在资源里改,哈哈,成功了!

文件修改:
004021B6 8D 45 CC => EB 18 90
发现还是缺乏好多常识,折腾了这么久,比较没技术含量。不过快感还是有滴~~~
2008-01-23
今天的改程序小记
昨晚逛 WZ 水区,居然有个人问怎么改程序。是这么一个东西:

文件名叫“补丁.exe”……(那改了后是不是该叫“补丁过的补丁.exe”之类的了?)
按菜单上这个“设置”,会出来这么个框。
那个人说要让那个框出来时编辑框里面就有文字,直接改资源没用。
于是为了抓住锻炼的机会我就开搞啦!
首先是找显示这个对话框的 API。
我原先以为对话框的 CreateDialog 也是调用 CreateWindow 的,可是截不住。
抓到两个 CreateWindow 动作,一个是主窗口。还有一个很奇怪的,类名是 "CicMarshalWndClass",
是点击托盘图标弹出菜单的时候发生的。当时以为是这个对话框,可是这个把我搞得却没头绪了。
于是不知怎么的我就觉得应该不是它。
于是我想,可能 CreateDialog 跟 CreateWindow 是不一样的。可是,CreateDialogA、CreateDialogExA,
都说没有这个函数……郁闷。后来查到了,是这么些:
CreateDialogParamA(W)
CreateDialogIndirectParamA(W)
DialogBoxParamA(W)
DialogBoxIndirectParamA(W)
一个一个试过去,原来是 DialogBoxParamA。然后就到了这里:

MSDN 里对 DialogBoxParamA 函数的说明如下:
Syntax
INT_PTR DialogBoxParam(
HINSTANCE hInstance,
LPCTSTR lpTemplateName,
HWND hWndParent,
DLGPROC lpDialogFunc,
LPARAM dwInitParam
);
Parameters
...
Return Value
If the function succeeds, the return value is the value of the nResult parameter specified
in the call to the EndDialog function used to terminate the dialog box.
If the function fails because the hWndParent parameter is invalid, the return value is zero.
The function returns zero in this case for compatibility with previous versions of Microsoft Windows.
If the function fails for any other reason, the return value is –1. To get extended error information, call GetLastError.
跟进去逛了几圈,发现 DialogBoxParamA 里面是调用 ShowWindow 的。
那就没法抢在 ShowWindow 之前去设置文本了。接下来的想法是,那就在 DialogBoxParamA 之后,
紧接着马上去设置编辑框文本。这里地方比较紧凑,又产生了暑假用过的一个想法:
Call 到自己添加的函数;
在自己的函数里面 Call DialogBoxParamA;
然后设置那个编辑框的文本;
返回;
这是昨晚想的事情,当时快 12 点了要熄灯,作罢。接下来是今天考试归来后的。
我开始添加函数了。不是要 SetDlgItemText 吗?那就要 GetDlgItem,于是就需要对话框的句柄。
可是从上面的引文可以看到,DialogBoxParamA 并不返回对话框句柄。
我考虑把它改成 CreateDialogParamA,那就可以得到句柄了。
CreateDialogParamA 函数说明:
Syntax
HWND CreateDialogParam(
HINSTANCE hInstance,
LPCTSTR lpTemplateName,
HWND hWndParent,
DLGPROC lpDialogFunc,
LPARAM dwInitParam
);
Parameters
...
Return Value
If the function succeeds, the return value is the window handle to the dialog box.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
好的,就这么干。为 CreateDialogParamA 准备参数。第一个 dwInitParam 大概可以 NULL 的。
然后是回调函数。到原来 Call DialogBoxParamA 的地方找,函数地址是 401019。
这时突然又有个思路了,既然找到了回调函数,那就到里面给他来个 case WM_INITDIALOG,
就可以在那里设置文本了呀。
401019 处:

这里好像是个函数总目录,呵呵。4020E0 那里才是真正的回调函数体的开始。
发现有个
00402148 52 push edx
00402149 68 EA030000 push 3EA
0040214E |. 8B45 08 mov eax, dword ptr [ebp+8]
00402151 |. 50 push eax
00402152 |. FF15 D0C44200 call dword ptr [<&USER32.SetDl>]
3EA 是 1002,可是资源里面找不到:

那个编辑框的 ID 是 1003。试着把 3EA 改成 3EB,可是没用。
发现紧接着的地方有个:
0040216C |. 68 EB030000 push 3EB
00402171 |. 8B4D 08 mov ecx, dword ptr [ebp+8]
00402174 |. 51 push ecx
00402175 |. FF15 D4C44200 call dword ptr [<&USER32.GetDlgItem>]
0040217B |. 3BFC cmp edi, esp
0040217D |. E8 FE0F0000 call 00403180
00402182 50 push eax
00402183 FF15 D8C44200 call dword ptr [<&USER32.SendMessageA>]
00402189 |. 3BF4 cmp esi, esp
0040218B |. E8 F00F0000 call 00403180
试着把这里的 SendMessage 跳过去(jmp 到 402189),却出来一个错误的框框。再接下去的部分是别的东西了,那个错误框框……只能是 0040218B |. E8 F00F0000 call 00403180 这里面有名堂了。可是前面没有 je 之类的判断跳转,cmp 又不影响流程,难道它每次都显示错误不成?所以比较好奇,进去看了一下,原来是:
00403180 /$ /75 01 jnz short 00403183
00403182 |. |C3 retn
00403183 |> /55 push ebp
00403184 |. 8BEC mov ebp, esp
00403186 |. 83EC 00 sub esp, 0
00403189 |. 50 push eax
0040318A |. 52 push edx
原来如此,呵呵。现在我知道了,后面所有的
cmp esi, esp
call 00403180
都是在检查函数调用结果。如果出问题就跳出一个错误框。
刚才试改了上面两处都不行,我考虑实现自己原先的思路了,嗯,找 switch (message) 的 case。
函数前面有这么两个 cmp:
004020FE |. 8B45 0C mov eax, dword ptr [ebp+C]
00402101 |. 8945 8C mov dword ptr [ebp-74], eax
00402104 |. 817D 8C 10010>cmp dword ptr [ebp-74], 110
0040210B |. 74 12 je short 0040211F
0040210D |. 817D 8C 11010>cmp dword ptr [ebp-74], 111
00402114 |. 0F84 C0000000 je 004021DA
0040211A |. E9 0E020000 jmp 0040232D
比较,跳转,比较,跳转,跟 switch case 有点像。那么 dword ptr [ebp-74] 就是消息值了。第二个 je 后的 jmp 跳到了:
0040232D |> /33C0 xor eax, eax
0040232F |> 5F pop edi
00402330 |. 5E pop esi
00402331 |. 5B pop ebx
00402332 |. 81C4 B4000000 add esp, 0B4
00402338 |. 3BEC cmp ebp, esp
0040233A |. E8 410E0000 call 00403180
0040233F |. 8BE5 mov esp, ebp
00402341 |. 5D pop ebp
00402342 /. C2 1000 retn 10
这里已经是函数末尾了。那么我就 jmp 到其他空白地方,在那里比较消息值是不是 WM_INITDIALOG,是的话设置文本,jmp 回来,应该就好了。我查 WM_INITDIALOG 的值,MSDN索引里填进去没有……对,打开一个 Win32 工程看:

110?前面好像打眼过……回去找。
00402104 |. 817D 8C 10010>cmp dword ptr [ebp-74], 110
0040210B |. 74 12 je short 0040211F
0040210D |. 817D 8C 11010>cmp dword ptr [ebp-74], 111
00402114 |. 0F84 C0000000 je 004021DA
0040211A |. E9 0E020000 jmp 0040232D
0040211F |> 8BF4 mov esi, esp
40211F 之后却就是原来我试改过的地方。晕死了。只好接着刚才的两个地方看下来,看看把代码插在哪里好。却发现:
004021B6 8D45 CC lea eax, dword ptr [ebp-34]
004021B9 50 push eax
004021BA 68 EB030000 push 3EB
004021BF |. 8B4D 08 mov ecx, dword ptr [ebp+8]
004021C2 |. 51 push ecx
004021C3 |. FF15 D0C44200 call dword ptr [<&USER32.SetDlgItemTextA>]
004021C9 |. 3BF4 cmp esi, esp
004021CB |. E8 B00F0000 call 00403180
004021D0 |. B8 01000000 mov eax, 1
它自己在对编辑框设置文本。[ebp-34] 那里是个 0。终于搞明白了,资源里改编辑框的文本还是有用的,只是程序自己把它清除了。
然后是,把这一段跳过(当然是跳到 call 00403180 的后面,不然又会一个错误框),再在资源里改,哈哈,成功了!

文件修改:
004021B6 8D 45 CC => EB 18 90
发现还是缺乏好多常识,折腾了这么久,比较没技术含量。不过快感还是有滴~~~
2008-01-23
(原发表于 CSDN:https://blog.csdn.net/cnStreamlet/article/details/2066836)
分类:
ASM & Crack
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY