在Putty中使用SecureCRT vt100的字体

在Putty中使用SecureCRT vt100字体

  • 前言
  • 两种字体的比较
  • 准备工作
  • 修改Putty源码
  • 结束语

前言

Putty和SecureCRT都是IT人员常用的ssh客户端软件,区别在于:Putty是开源免费的,而SecureCRT则是非常完善的商业级软件,是收费的。Putty非常小巧,只有一个putty.exe就可以运行,但是它的默认字体是Courier New 10号字体。这种字体是Windows系统缺省都带的,不过这种字体并不好看。SecureCRT有一种字体叫vt100,这种字体非常适合SSH命令行,是我最爱的命令行字体,但是vt100是SecureCRT自带的字体,Windows中并没有安装。而且SecureCRT运行后你才能在别的软件的字体选择对话框中看到这种字体。当SecureCRT关闭后,这种字体就消失了。

这个问题困扰了我很多年。我一直想让Putty缺省字体是vt100,13号字体。但是你使用这种字体必须先安装而且运行SecureCRT,这非常不爽。最近我解决了这个问题。 我把vt100字体文件从SecureCRT软件中抠出来,嵌入到了putty.exe中,并设置为缺省字体。这样你只要一个putty.exe,在任何一台Windows机器上都可以使用vt100字体了。

本文章就是介绍我是如何一步步克服这个问题的,希望对大家有帮助。

两种字体的比较

首先,我们看一下两种字体的比较。第一幅图是putty的缺省字体Courier New 10号字体,第二幅图是vt100 13号字体。
在Putty中使用SecureCRT vt100的字体_第1张图片在Putty中使用SecureCRT vt100的字体_第2张图片
如果你也觉得第二幅图的字体更好看,也想使用vt100字体,就继续往下看,否则打住。

准备工作

首先,你要下载安装一个SecureCRT试用版软件。然后在它的目录下寻找vt100.fon文件。还有两个vt100的字体文件,分别是加粗加斜,我不喜欢。我只喜欢这个vt100.fon

在我的机器上,vt100.fon文件是在如下目录:

C:\Program Files\VanDyke Software\SecureCRT>dir vt100*
 Volume in drive C has no label.
 Volume Serial Number is E093-1844

 Directory of C:\Program Files\VanDyke Software\SecureCRT

11/07/2018  10:50 AM            45,056 VT100.FON
11/07/2018  10:50 AM            62,976 VT100DB.FON
11/07/2018  10:50 AM            62,976 VT100DT.FON
11/07/2018  10:50 AM            62,976 VT100W.FON
               4 File(s)        233,984 bytes
               0 Dir(s)  125,151,936,512 bytes free

如果修改后的软件包含两个文件,一个是putty.exe,一个是VT100.FON,就存在第二个文件丢失的问题。所以我们需要把这个字体文件嵌入到putty.exe中,保持最终的结果只有一个putty.exe。因为VT100.FON已经在putty.exe中,你把putty.exe拷贝到任何一台Windows机器上,不需要这台机器事先安装好vt100字体,你就可以使用vt100字体了。事实上,你看到了,这个字体是SecureCRT自带的。如果你不安装SecureCRT,你的Windows系统几乎不会有这种字体。

第二步:下载和编译putty源码

putty源码的官方下载地址是:https://the.earth.li/~sgtatham/putty/latest/putty-src.zip

把这个zip文件下载到本地磁盘,并解压缩到一个目录。我假设你解压缩到了D:\Code\putty目录下。

第三步:你要安装Visual C++。我选择的是Visual C++ 2017社区版,它是免费的。微软真有良心,点赞一下!因为这是成熟软件,所以安装过程不用啰嗦。你遇到问题,在网上自行研究。

第四步:编译putty源码。
在开始菜单中选择"Developer Command Prompt for VS 2017",如下图所示:
在Putty中使用SecureCRT vt100的字体_第3张图片
这个会进入命令行窗口,不过Visual C++的各种环境变量都已经设置好了,你直接可以在命令行下使用C++编译器了。 在这个命令行窗口中执行如下命令:

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community>d:

D:\>cd code\putty

D:\Code\putty>cd windows

D:\Code\putty\windows>nmake -f Makefile.vc

等了一会,你就会看到编译好了。你执行 dir *.exe,就会看到已经编译好的putty.exe和其它可执行文件。

通过以上过程,我们已经学习了如何编译来自官方的putty源码。 我们并没有做任何修改。下面就是拿起手术刀开始对putty源码动刀子的干货过程了。

修改Putty源码

我们的思路是把VT100.FON文件嵌入到最终的putty.exe中。这个可以通过把这个文件嵌入到Windows资源文件来完成。过程如下:

  1. 用文本编辑器打开win_res.h,你会看到它就是简单地定义了一些宏。随便找一个地方,照猫画虎,加入一行:
    #define IDR_FONT_VT100 121
  2. 然后用文本编辑器打开win_res.rc2文件,找到一行:IDI_CFGICON ICON “puttycfg.ico”,在它下面加入一行:
    IDR_FONT_VT100 RCDATA "VT100.FON"
  3. 你把VT100.FON文件要拷贝到D:\Code\putty\windows目录下。这样上一步的命令才能找到这个文件。否则编译资源文件的时候会报错。

完成以上三步后,你再执行nmake -f Makefile.vc,最终生成的putty.exe文件中已经包含了VT100.FON的数据。因为这个VT100.FON文件才45056个字节,所以putty.exe增加的尺寸不大,才区区40K左右。

修改完毕资源文件,接下来的思路就是在putty.exe启动阶段加一些代码,读取这个字体数据,加载字体到系统中。然后在putty.exe的结束部分,卸载这个vt100字体。过程如下:

  1. 用任何一个文本编辑器打开D:\Code\putty\windows\window.c源程序文件。这个是putty的入口文件。搜索WinMain函数。稍微懂点Windows编程的人都知道WinMain函数是任何一个Windows程序的执行起点。 在WinMain函数上部,加一个全局变量和两个函数。
HANDLE g_fontVT100 = NULL;

static HANDLE install_VT100(HINSTANCE inst)
{
   HANDLE          h;
   HGLOBAL			res_handle = NULL;
   HRSRC			res;
   unsigned char  *res_data;
   DWORD			res_size, font_cnt = 0;

   res = FindResource(inst, MAKEINTRESOURCE(IDR_FONT_VT100), RT_RCDATA);

   h = NULL;
   if (res) {
   	res_handle = LoadResource(NULL, res);
   	if (res_handle) {
   		res_data = (unsigned char*)LockResource(res_handle);
   		res_size = SizeofResource(NULL, res);
   		h = AddFontMemResourceEx(res_data, res_size, 0, &font_cnt);
   	}
   }
   
   return h;
}

static void deinstall_VT100(HANDLE h)
{
   if(h) {
   	RemoveFontMemResourceEx(h);
   }
}

int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
{
   MSG msg;
   ......

大家看到了,这段代码很简单。install_VT100函数是安装vt100字体。它先读取前面嵌入的vt100字体数据(此时这些数据已经在内存中了),然后使用一个函数AddFontMemResourceEx把vt100字体安装到系统中。这个函数大家自行搜索和研究,非常简单。这里不再啰嗦。 deinstall_VT100函数是卸载字体的函数。

  1. 有了这两个函数,接下来的任务就是在WinMain的开始部分找一个合适的位置,加入加载字体函数install_VT100和卸载字体函数deinstall_VT100。 我加的位置如下:
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
{
    MSG msg;
    HRESULT hr;
    int guess_width, guess_height;

    dll_hijacking_protection();

    hinst = inst;
    hwnd = NULL;
    flags = FLAG_VERBOSE | FLAG_INTERACTIVE;

    sk_init();

    init_common_controls();
	
	g_fontVT100 = install_VT100(inst);  /* 这一行是我加的。上边的是老代码,供你定位位置*/

在WinMain函数的最后,当然是卸载vt100字体了:

    finished:
	deinstall_VT100(g_fontVT100);  /* 我就加了这一行。*/
    cleanup_exit(msg.wParam);	       /* this doesn't return... */

    return msg.wParam;		       /* ... but optimiser doesn't know */
}

/*
 * Clean up and exit.
 */
void cleanup_exit(int code)
{
    /*
     * Clean up.
     */
    deinit_fonts();
    sfree(logpal);
    if (pal)
	DeleteObject(pal);
    sk_cleanup();

以上代码仅仅是在putty启动的时候加载VT100字体,在putty关闭的之前卸载VT100字体。你加载的字体并不会显示在putty的字体设置对话框中。这一点微软的文档上说的很清楚:

This function allows an application to get a font that is embedded in a document or a webpage. A font that is added by AddFontMemResourceEx is always private to the process that made the call and is not enumerable.

既然vt100字体已经被putty.exe进程加载了,可以供它私用。下一步我们要找到设置putty缺省字体的地方,设置putty的字体为vt100。
3. 用文本编辑器打开D:\Code\putty\windows\windefs.c文件,找到platform_default_fontspec函数。这个函数就是设置putty缺省字体的函数。它的代码如下:

FontSpec *platform_default_fontspec(const char *name)
{
    if (!strcmp(name, "Font"))
        return fontspec_new("Courier New", 0, 10, ANSI_CHARSET);
    else
        return fontspec_new("", 0, 0, 0);
}

大家可以很清楚地看到,它设置Courier New 10号字体为缺省字体。下面我们就改动一下:

FontSpec *platform_default_fontspec(const char *name)
{
    if (!strcmp(name, "Font"))
        return fontspec_new("vt100", 0, 13, ANSI_CHARSET);
    else
        return fontspec_new("", 0, 0, 0);
}

大功告成! 你再到D:\Code\putty\windows目录下执行nmake -f Makefile.vc,生成的putty.exe就是我们想要的缺省字体是vt100的putty了。你可以nmake编译之前先删除老的putty.exe,确保编译后的putty.exe是最新的。希望这是多此一举。

当然这里的代码逻辑应该可以更加完善一些,改成下面的似乎更好:

extern HANDLE g_fontVT100;

FontSpec *platform_default_fontspec(const char *name)
{
    if (!strcmp(name, "Font"))	{
       if(NULL== g_fontVT100) { /* vt100字体没有安装成功,依然用原来的字体 */
			return fontspec_new("Courier New", 0, 10, ANSI_CHARSET);
		} else {  /* vt100字体安装成功,用vt100字体 */
			return fontspec_new("vt100", 0, 13, ANSI_CHARSET);
		}
    else
        return fontspec_new("", 0, 0, 0);
}

但是我编译的时候,在链接阶段,它抱怨找不到g_fontVT100这个全局变量。我懒得研究如何克服这个问题了。如果你解决了,发信到[email protected] 或者[email protected] 告诉我一下方法。我会非常感谢的。

结束语

Putty是非常敏感的安全软件,它已经有了20年的历史,久经考验。请不要随便下载非官方的putty.exe。因为可能有人植入了后门,在你登录系统的时候,把密码发到某一个邮箱。 我们的方法是编译官方的源码,整个修改过程非常简单,应该没有任何后门,也不会对整个putty软件造成重大安全问题。所以这种修改hacking putty的方法全部过程都是在阳光底下,经得住考验的。编译后的putty你可以分享给自己的朋友。

如果你有什么想法和建议,可以发信给我:[email protected]

你可能感兴趣的:(Win32,C/C++编程)