打开软件,发现系统字体十分难看。
ctrl+n查找可疑API
运行程序 打开属性窗口 断点没有断下来。看来断点不对。
继续查看可以API
CreateWindowExA
下断,运行程序查看属性,直接断在断点处。
运行程序 直到弹出属性窗口 发现4处断点中 使用到了两处
00408F27 |> /8B75 E4 /mov esi,[local.7]
00408F2A |. |6A 00 |push 0x0
00408F2C |. |2B75 DC |sub esi,[local.9]
00408F2F |. |83C6 05 |add esi,0x5
00408F32 |. |0FAF75 FC |imul esi,[local.1]
00408F36 |. |E8 D398FFFF |call myuninst.0040280E
00408F3B |. |50 |push eax ; |hInst = 0000000B
00408F3C |. |8B45 C0 |mov eax,[local.16] ; |kernel32.7736F6D2
00408F3F |. |6A 00 |push 0x0 ; |hMenu = NULL
00408F41 |. |03C6 |add eax,esi ; |
00408F43 |. |FF75 08 |push [arg.1] ; |hParent = 0012F648
00408F46 |. |FF75 D0 |push [local.12] ; |Height = 0x0
00408F49 |. |57 |push edi ; |Width = 5A (90.)
00408F4A |. |50 |push eax ; |Y = B (11.)
00408F4B |. |FF75 BC |push [local.17] ; |X = 776E3B2C (2003712812.)
00408F4E |. |FF75 EC |push [local.5] ; |Style = WS_OVERLAPPED|WS_MAXIMIZEBOX|WS_VSCROLL|WS_HSCROLL|WS_SYSMENU|WS_THICKFRAME|1A90
00408F51 |. |68 80DE4000 |push myuninst.0040DE80 ; |WindowName = ""
00408F56 |. |68 DCD94000 |push myuninst.0040D9DC ; |Class = "STATIC"
00408F5B |. |FF75 D4 |push [local.11] ; |ExtStyle = 0
00408F5E |. |FF15 98B24000 |call dword ptr ds:[<&USER32.CreateWindo>; \CreateWindowExA
00408F64 |. |6A 00 |push 0x0
00408F66 |. |8945 F4 |mov [local.3],eax
00408F69 |. |E8 A098FFFF |call myuninst.0040280E
00408F6E |. |50 |push eax ; |hInst = 0000000B
00408F6F |. |8B45 DC |mov eax,[local.9] ; |
00408F72 |. |6A 00 |push 0x0 ; |hMenu = NULL
00408F74 |. |03F0 |add esi,eax ; |
00408F76 |. |FF75 08 |push [arg.1] ; |hParent = 0012F648
00408F79 |. |FF75 CC |push [local.13] ; |Height = 40D1F8 (4248056.)
00408F7C |. |53 |push ebx ; |Width = 1EB (491.)
00408F7D |. |56 |push esi ; |Y = 169 (361.)
00408F7E |. |FF75 D8 |push [local.10] ; |X = 0x0
00408F81 |. |FF75 E8 |push [local.6] ; |Style = WS_OVERLAPPED|WS_VSCROLL|WS_HSCROLL
00408F84 |. |68 80DE4000 |push myuninst.0040DE80 ; |WindowName = ""
00408F89 |. |68 D4D94000 |push myuninst.0040D9D4 ; |Class = "EDIT"
00408F8E |. |FF75 B8 |push [local.18] ; |ExtStyle = WS_EX_NOPARENTNOTIFY|WS_EX_TOPMOST|WS_EX_ACCEPTFILES|WS_EX_TRANSPARENT|WS_EX_MDICHILD|WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE|WS_EX_CLIENTEDGE|WS_EX_CONTEXTHELP|WS_EX_RIGHT|WS_EX_RTLREADING|WS_EX_LEFTSCROLLBAR|WS_EX_CONTROLPARENT|WS_EX_STATICEDGE
00408F91 |. |FF15 98B24000 |call dword ptr ds:[<&USER32.CreateWindo>; \CreateWindowExA
00408F97 |. |8945 F0 |mov [local.4],eax
00408F9A |. |8B45 F8 |mov eax,[local.2]
00408F9D |. |FF30 |push dword ptr ds:[eax] ; /<%s>
00408F9F |. |8D85 B0FEFFFF |lea eax,[local.84] ; |
00408FA5 |. |68 D0D94000 |push myuninst.0040D9D0 ; |format = "%s:"
00408FAA |. |50 |push eax ; |s = 0000000B
00408FAB |. |FF15 90B14000 |call dword ptr ds:[<&MSVCRT.sprintf>] ; \sprintf
00408FB1 |. |8B35 84B24000 |mov esi,dword ptr ds:[<&USER32.SetWindo>; user32.SetWindowTextA
00408FB7 |. |83C4 0C |add esp,0xC
00408FBA |. |8D85 B0FEFFFF |lea eax,[local.84]
00408FC0 |. |50 |push eax ; /Text = 0000000B ???
00408FC1 |. |FF75 F4 |push [local.3] ; |hWnd = 00000066 (class='Shell_TrayWnd')
00408FC4 |. |FFD6 |call esi ; \SetWindowTextA
00408FC6 |. |8D85 ACFAFFFF |lea eax,[local.341]
00408FCC |. |50 |push eax
00408FCD |. |FF75 FC |push [local.1]
00408FD0 |. |FF35 00EF4000 |push dword ptr ds:[0x40EF00]
00408FD6 |. |E8 1884FFFF |call myuninst.004013F3
00408FDB |. |83C4 0C |add esp,0xC
00408FDE |. |50 |push eax
00408FDF |. |FF75 F0 |push [local.4]
00408FE2 |. |FFD6 |call esi
00408FE4 |. |FF45 FC |inc [local.1]
00408FE7 |. |8345 F8 14 |add [local.2],0x14
00408FEB |. |837D FC 0F |cmp [local.1],0xF
00408FEF |.^\0F8C 32FFFFFF \jl myuninst.00408F27
00408FF5 |. 5F pop edi
00408FF6 |. 5E pop esi
00408FF7 |. 5B pop ebx
00408FF8 |. C9 leave
00408FF9 \. C3 retn
所以,这里程序的思路就很明确了,我们看到的窗口控件都是又 CreateWindowExA创建的。随后使用SetWindowText来设置显示的内容,根本没有考虑到字体的 问题。
所以我们可以在窗口创建之后,设置内容之前,调用 SendMessageA 函数发送 WM_SETFONT 消息来设置控件字体。
我们看API列表 CreateFontIndirectA 这个字体创建函数已经有了,再看看 SendMessageA也已经有了。这样我们就可以直接用了。
CreateFontIndirectA 在 GDI32.dll 里面,ThunkRVA 值是 0000B044,这样我们就知道在程序中调用它的时候就是 CALL DWORD PTR [0040B044]。同样,SendMessageA 的ThunkRVA 值是 0000B23C,调用时应该是这样:CALL DWORD PTR [0040B23C]
然后我们来了解这两个API函数的用法
CreateFontIndirectA:
HFONT CreateFontIndirect(
CONST LOGFONT *lplf // pointer to logical font structure
);
CreateFontIndirect的返回值就是字体的句柄。
我们传递一个logical font structure指针就可以得到一个字体的句柄。
SendMessageA:
LRESULT SendMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to send
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
hWnd 就是我们的窗口句柄。 Msg就是我们要传递的消息,选WM_SETFONT,这个值是 30H。第三个参数是字体的句柄,第四个参数我们用不到。
接下来我们看一下LOGFONT的结构。
typedef struct tagLOGFONT { //
LONG lfHeight;
LONG lfWidth;
LONG lfEscapement;
LONG lfOrientation;
LONG lfWeight;
BYTE lfItalic;
BYTE lfUnderline;
BYTE lfStrikeOut;
BYTE lfCharSet;
BYTE lfOutPrecision;
BYTE lfClipPrecision;
BYTE lfQuality;
BYTE lfPitchAndFamily;
TCHAR lfFaceName[LF_FACESIZE];
} LOGFONT;
这样我们的标准9号宋体的 LOGFONT 值应该是32字节,16进制就像这样:F4FFFFFF000000000000000000000000900100000000008600000000CBCECCE5
用winhex将该内容写入到pe文件中的空白区
用PEID探测空白区
我们就写到.text节区的 0x009815处,注意是覆盖写入,不要改变大小
然后我们用OD重新载入程序,修改我们上面两处的代码,并在下面的空白区加入两处新增的代码。
分别在CreateWindow后添加跳转,跳转到我们要执行的代码处,代码执行后再跳转回来。
以下是我们添加的代码、
我们执行CreateWindow后创建了句柄存储在eax中,所以我们把该值拷贝到0x40c56e处然后创建字体句柄,并调用SendMessage 从而改变显示的字体。
两处代码原理相同。
右键保存到可执行文件即可。
因为我们在写补丁代码的过程中,将数据写入到了rdata区,所以要改变rdata节的属性为可写入,
通过PE Loarder来编辑标志位为可写入,保存、
打开Cracked文件,
改变成功.