·汉化新世纪 ·汉化新世纪论坛 ·百家争鸣 ·论坛集萃 ·汉化问答 ·软件介绍
文章首页 >> 汉化教学 >> 特殊汉化 >> 汉化中的几个问题    Creative Commons License,创作共用协议(中文版)  署名 非商业性使用 禁止演绎

汉化中的几个问题

作者: 梁利峰 来源:点睛工作室 时间:2003-08-02 点击:8164


汉化中的几个问题


声明

个人可以自由转载本文,不过应保持原文的完整性,并通知我;商业转载先请和我联系。

本文没有任何明确或不明确地提示说本文完全正确,阅读和使用本文的内容是您自己的选择,本人不负任何责任。

如果您发现本文有错漏的地方,请您给我指出;如果有什么不理解的,请您给我提出。

意见、建议和提出的问题最好写在我的主页 http://llf.126.com 的留言版上。

怎样判断 VB 编写的程序

在伟乾和 YY 写的关于 VB 汉化探讨的文章里曾介绍过怎样判断 VB 编写的程序,其中使用的是软件 FileInfo 。

FileInfo 可以用来判断程序的很多信息,包括使用什么方法压缩、加密,基地址,各段及其偏移量等,当然也可以用来判断程序是用哪一种编译器编译的,确实不错。

最近用了 YY 汉化的 Chime Tray Play ,打眼一看我就觉得是用 VB 编写的,但是窗体的字体都很小,我就比较奇怪,按说我已经写了四篇文章说这个问题,而且阿涛也写了一篇文章,修改 VB 程序的字体应该不成问题,为什么没有修改呢?所以我就使用 FileInfo 查看了一下原程序,发现 FileInfo 报告说这是一个 Windows GUI 程序,并没有说是 VB 程序,那么它究竟是不是 VB 程序呢?

Chime Tray Play 的原程序只有一个文件“TrayPlay.exe”,用 FileInfo 可以知道这个程序使用 NeoLite 2 压缩,所以使用 ProcDump 进行解压缩,使用 FileInfo 检测解压缩后的程序就会发现被报告成 Windows GUI 程序。不过还是可以使用其它的方法检测一下的。

运行 eXeScope ,打开解压缩后的“TrayPlay.exe”,打开“Import”,这里是程序的函数导入表,如果是 VB5 编写的程序,其中会包含 MSVBVM50.DLL ,如果是 VB6 编写的程序,其中会包含 MSVBVM60.DLL ,而且因为是 VB 专用的运行库,其调用格式并未公布,所以基本可以肯定,只要使用了 MSVBVM50.DLL 的程序一定是 VB5 编写的,而使用了 MSVBVM60.DLL 的程序一定是 VB6 编写的。而且大部分的 VB 程序只导入这一个动态链接库,其它的 API 调用使用“Declare”来定义,并不使用导入表,包括 Vopt99 也是这样。(我的程序一般会多出一两个库,这是使用类型库的结果,不过不会很多)而“TrayPlay.exe”正好有且只有一个 MSVBVM60.DLL 的导入,基本可以肯定是 VB6 编写的。(VB4 使用 VBRUN40.DLL ,VB3 使用 VBRUN30.DLL ,不过这些程序中让人有兴趣汉化的就非常少了)

另一种方法。运行一个 VB 编写的程序,等它的主界面出来以后,使用 Spy++(VC 中附带的软件)的查找窗口模式,拖动其中的靶子图标到目标程序的界面上,注意其中的“Class”项的值,如果是 ThunderRT5xxxx ,就说明是用 VB5 编写的程序,如果是 ThunderRT6xxxx ,就说明是 VB6 编写的程序,其中最后的 xxxx 表示不同的控件,比如 VB5 编写的程序中的 ListBox 的“Class”项就是 ThunderRT5ListBox ,而 VB6 编写的程序中的 TextBox 的“Class”项就是 ThunderRT6TextBox 。作为“TrayPlay.exe”有一些不太方便使用这种方法,因为如果选择其它的程序的话,其主窗体会自动隐藏,使之不容易检测,不过可以先选择“关联”按钮,出现消息框,这时就可以切换到其它的程序而它并不消失,也就可以检测,结果也同样发现是 VB6 编写的。(使用我编写的“刺客”程序也可以进行这种检测,虽然比起 Spy++ 来说功能不强大,但是对于这种任务来说反而方便不少。在“刺客”中,“类名”就是“Class”)

还有一种方法。在阿涛的关于 VB 汉化的文章里说过,只要在 VB5/6 的程序中查找“VB5!”就可以找到需要复制那22个字节的位置,因为其中只会有一个“VB5!”。如果连 VB 编写的程序中也只有一个“VB5!”的话,那么其它程序有“VB5!”的可能性就几乎为 0 了,不是吗? :)

需要注意的是,这并不是说 FileInfo 的检测不准确,这里的问题其实是 ProcDump 引起的,想必它在解压缩的时候改变了文件的某些结构,从而使 FileInfo 出现了不能正确检测的后果,所以,如果有专用的解压缩程序的话,尽量不要使用 ProcDump 这种通用解压缩程序。(现在很多程序使用 ASPack 2.1 压缩,ProcDump 解压此种文件并不好,甚至使用了汉化新世纪提供的新的 INI 文件也同样不是很好,而 UnAspack 1.091 已经可以解压缩这种文件,应该尽量使用 UnAspack 1.091 来解压缩 ASPack 2.1 压缩的文件。)

修改 VB 程序的字号

关于 VB 程序的字号我已经有文章说过了,不过还是觉得阿涛的最后对于无字体块的程序的修改法更好,所以也学他的方法修改了“TrayPlay.exe”,结果程序不能运行了,真是奇怪。

阿涛的原文说复制 22 个字节,而其中的图显示的却是 44 个字节,不过这是小问题,问题在于,究竟复制的这些多字节有什么用处呢?

我不知道它有什么用处,所以进一步测试,发现根本不需要复制这些字节,而只需要加入“vb5chs.dll”这个字符串就可以了。

在“TrayPlay.exe”文件中查找“VB5!”,找到后,再向后的第三个字节是“*”,十六进制是“2A”,后面是一大串“00”,只要把从这个“*”开始的地方修改“vb5chs.dll”,程序就可以正常显示“宋体,9”了。

对于 VB6 编写的程序,一般的可以改成“vb6chs.dll”,不过,即使改成“vb5chs.dll”也没有问题,同样能让程序正常显示“宋体,9”,因为不管是 vb5chs.dll 还是 vb6chs.dll 都不是代码所在的地方,它们只是提供一些资源罢了,即使没有这些资源,程序也一样能照常运行。

版权符号的问题

这不是 VB 的问题,而是所有英文软件的问题,不过这里也使用一个 VB 程序作例子。

打开 Vopt99 ,选择菜单“帮助->关于 Vopt99”,可以看到第一行信息是“Copyright ? Golden Bow System”,很奇怪的其中有一个“?”,难道作者对于版权的信息本身有疑问么?当然不是,其实这里是的“?”是版权符号 © ,因为使用的是大于 7F 的 ASCII (具体说就是 A9),其编码和 GBK 有冲突,而 Windows 的转换函数在转换过程中如果发现非法的字符就会把它转换成“?”,所以这个版权符号就成了“?”。因为 GBK 的编码中没有版权符号,所以很不方便,很多程序使用“(C)”来代替,是一个不错的选择,汉化时也应该如此,而不是把“?”留在那里或者干脆真的转成“?”。类似的情况可能还有注册商标符号 ® (AE) 也同样需要注意。

对于大多数的 C 程序来说,因为是 ASCII ,所以如果一个字符串如“Copyright © Golden Bow System”的话,因为 © 是非法字符,所以很多查找 ASCII 的程序会查找不到这个字符串,而我的字串替换器也不例外,查到的字符串将是“ Golden Bow System”。

对于 VB 程序来说,可能是 ASCII ,也可能是 UniCode ,具体取决于作者是使用在 IDE 里设置属性的方法(ASCII),还是使用在程序中赋值的方法(UniCode)。在这里,Vopt99 使用的是 UniCode ,而且分成两部分,“Copyright © ”和“Golden Bow System”,这是因为“Golden Bow System”是从资源的版本信息中取得的。因为“Copyright © ”中的非法字符在最后,所以使用我的字串替换器不管使用查找 VB 字串还是查找 UniCode 都不能查找到这个字串,只有使用查找 VB 字串的“非限制查找”模式才能找到。(“非限制查找”模式会有很多非法字符,而很多对照项会有很多的“?”也正是因为这个原因,并非原来就是“?”。)

对于 ASCII 来说,因为我的字串替换器不提供“非限制查找”模式,所以不能正常查找到,只能使用手工查找修改的方法。

当然,很多 C 程序的版权信息在资源里,所以使用普通的资源修改器(比如 eXeScope、ResHacker 等)就可以找到并修改,而不需要这么麻烦。但是修改是需要的,千万不要让大家以为所用的软件的版权都是有疑问的。

可能在 NT/2000 下使用 UniCode 模式的版权符号可以正常显示,不过这需要确实是全都是使用的 UniCode 的函数,VB 在 NT/2000 下好像用的是先把 UniCode 转换成 ASCII ,然后再由 Windows 转换成 UniCode 的方法,所以仍然不能正常显示。不过我没有在 NT/2000 上验证过。

文件过滤

在送给打开文件对话框的参数里有一个文件过滤参数,形式如:

	Text Files(*.txt)|*.txt

如果翻译成中文的话,因为一般比原字串短,会多出几个字节,我建议还是把末尾添加“00”为好,不过总有种种原因使得我们需要添加空格,在末尾添加空格比较普遍:(其中“※”表示空格)

	文本文件(*.txt)|*.txt※※

另外,也有在“*.txt”之前添加空格的:

	文本文件(*.txt)|※※*.txt

不过,我觉得还是把空格添加到“|”之前的好:

	文本文件(*.txt)※※|*.txt

因为“|”之前的项目是用来显示的,对程序的运行不造成任何影响,而“|”之后的是作为过滤选项用来分析的,如果多出空格可能会造成出错。具体是否出错还在于分析程序是否会有消除前后空格的行为,但是如果写成上面这种形式,不论程序是否消除空格,程序都将正常运行。

下面是另一个复杂一点的例子:

	Program Files(*.exe;*.dll;*.ocx)|*.exe;*.dll;*.ocx|All Files(*.*)|*.*

	                                 

	程序文件(*.exe;*.dll;*.ocx)|*.exe;*.dll;*.ocx|全部文件(*.*)※※※※※※|*.*

	                                 

	程序文件(*.exe;*.dll;*.ocx)※※|*.exe;*.dll;*.ocx|全部文件(*.*)※※※※|*.*

 

C 程序字号的问题

关于 C 程序字号的问题我也说过了,不过还有一个问题,就是总有一些程序修改过后中文和英文显示的不平行,本来这个问题应该加在上一篇 C 程序字号的里面,不过这一次还是加在这里好了。

关于这个问题,最主要的问题在于没有修改语系,也就是 CharSet 项,只要在原来的压入语系的地方改成压入语系就可以了。还以 Opera 为例,按照上一篇的修改方法修改后,会出现中英文不平行的问题,而我们知道,第六个被压入的参数就是语系,所以修改这里就可以了:

	偏移量        字节代码                汇编代码
	015F:00441101 FF7544                  push [ebp+44]
	015F:00441104 50                      push eax
	015F:00441105 0FB6453C                movzx eax, byte ptr [ebp+3C]
	015F:00441109 50                      push eax
	015F:0044110A 0FB64538                movzx eax, byte ptr [ebp+38]
	015F:0044110E 50                      push eax
	015F:0044110F 0FB64534                movzx eax, byte ptr [ebp+34]
	015F:00441113 50                      push eax
	015F:00441114 0FB64530                movzx eax, byte ptr [ebp+30]
	015F:00441118 50                      push eax
	015F:00441119 0FB6452C                movzx eax, byte ptr [ebp+2C]
	015F:0044111D 50                      push eax
	015F:0044111E 0FB64528                movzx eax, byte ptr [ebp+28]
	015F:00441122 50                      push eax
	015F:00441123 0FB64524                movzx eax, byte ptr [ebp+24]
	015F:00441127 50                      push eax
	015F:00441128 FF7520                  push [ebp+20]
	015F:0044112B FF751C                  push [ebp+1C]
	015F:0044112E FF7518                  push [ebp+18]
	015F:00441131 FF7514                  push [ebp+14]
	015F:00441134 FF7510                  push [ebp+10]
	015F:00441137 FF15F8005300            Call GDI32!CreateFontA
	015F:0044113D 8BF0                    mov esi, eax

如上表,红色的语句就是压入语系的语句,而且可以看到,它上面的 movzx 指令是把内存中的数据转入 eax 寄存器,而后这一句 push 再把 eax 的值压入堆栈,因为我们铁定要压入 86 ,所以可以修改成 push 86,不过这需要两个字节,原来的 push eax 只有一个字节 50 ,这样我们就需要把上面一句也修改了,这两句就是上表中用绿色表示的部分,因为正好够一个四字节的 push 语句,所以修改如下:

	偏移量        字节代码                汇编代码
	015F:00441101 FF7544                  push [ebp+44]
	015F:00441104 50                      push eax
	015F:00441105 0FB6453C                movzx eax, byte ptr [ebp+3C]
	015F:00441109 50                      push eax
	015F:0044110A 0FB64538                movzx eax, byte ptr [ebp+38]
	015F:0044110E 50                      push eax
	015F:0044110F 0FB64534                movzx eax, byte ptr [ebp+34]
	015F:00441113 50                      push eax
	015F:00441114 6886000000              push 00000086
	015F:00441119 0FB6452C                movzx eax, byte ptr [ebp+2C]
	015F:0044111D 50                      push eax
	015F:0044111E 0FB64528                movzx eax, byte ptr [ebp+28]
	015F:00441122 50                      push eax
	015F:00441123 0FB64524                movzx eax, byte ptr [ebp+24]
	015F:00441127 50                      push eax
	015F:00441128 FF7520                  push [ebp+20]
	015F:0044112B FF751C                  push [ebp+1C]
	015F:0044112E FF7518                  push [ebp+18]
	015F:00441131 FF7514                  push [ebp+14]
	015F:00441134 FF7510                  push [ebp+10]
	015F:00441137 FF15F8005300            Call GDI32!CreateFontA
	015F:0044113D 8BF0                    mov esi, eax

经过这样的修改,中英文就可以平行的显示了。

但是,如果其它的地方也有需要修改的,岂不是很麻烦?我们总是需要确定压入堆栈的数据,可以不理会这些问题么?可以,还是上面的例子,可以全盘修改成这样:

	偏移量        字节代码                汇编代码
	015F:00441101 6A00                    push 00
	015F:00441103 6A00                    push 00
	015F:00441105 6A00                    push 00
	015F:00441107 6A00                    push 00
	015F:00441109 6A00                    push 00
	015F:0044110B 6A86                    push 86
	015F:0044110D 6A00                    push 00
	015F:0044110F 6A00                    push 00
	015F:0044110D 6A00                    push 00
	015F:0044110F 6890010000              push 00000190
	015F:00441113 6A00                    push 00
	015F:00441115 6A00                    push 00
	015F:00441117 6A00                    push 00
	015F:00441119 6AF4                    push -0C
	  ·
	  ·
	  ·
	015F:00441137 FF15F8005300            Call GDI32!CreateFontA
	015F:0044113D 8BF0                    mov esi, eax

中间有一些省略号,这是因为这样修改后的代码比上面的方式短的多,这样就需要在中间添加 NOP(90)指令,在这个例子中,一共需要添加 23 个 90 。

(才发现,这里的代码开始地址都是奇数,这样的代码运行速很慢,而只需要把地址改变成偶数就可以极大的加快速度,一般的编译器都会做这样的优化,不知道 Opera 使用的是什么编译器,这么龌龊!)

在本小节中,我把压入语系的语句写成了 push 86 ,也就是字节代码的 6A86 ,现在发现这样写是错误的,因为 86 大于 7F ,而所有大于 7F 的单字节数字被认为负数,所以这一句应该改成 push 00000086 ,也就是字节代码的 6886000000 ,特此更正。

Delphi 字体设置中的一个小问题(7.25 补充)

修改 Delphi 软件的字体是一个比较简单的问题,因为有很多软件都可以反编译 Delphi 程序的窗体,只要修改关于 Font 部分的代码就可以做到修改字体了。一般修改成如下的样子:

  Font.Charset = GB2312_CHARSET
  Font.Color = clWindowText
  Font.Height = -12
  Font.Name = '宋体'
  Font.Style = []

不过真的这样修改就可以了吗?并非如此。我见到过一些字体设置,明明是 GB2312 的 -12 的“宋体”,显示却不正常,为什么呢?经我的观察,应该是窗体代码其中的一项“TextHeight”的不同才造成这种情况:

  PixelsPerInch = 96
  TextHeight = 12

正常的中文软件中,“TextHeight”如上等于“12”,而一般的英文软件,“TextHeight”却等于“13”,所以,修改“TextHeight”为“12”,然后再修改 Font 相关的项才是我们想要的结果。

点睛工作室·梁利锋 结稿于 2000.6.22(7.16 更正)

汉化新世纪 责任编辑: 乾 .:|:. 标签(Tag): 字体 VB

·上一篇: C 程序字号的修改 ·下一篇: 基地址引深

· 版权申明: 本文引自《点睛工作室》,如有版权疑问请及时联系本站,以便本站处理。

· 转载申明: 本文引自《点睛工作室》[ 作者: 梁利峰],如需转载请直接联系原始作者,并请注明原始出处。

相关文章                                                                                发表评论 打印此文 关闭窗口

| 设为首页 | 加入收藏 | 联系我们 | 友情链接
Creative Commons License,创作共用协议(中文版)  署名 非商业性使用 禁止演绎
本站内容,除转载或版权特别申明的内容外,皆遵守 创造共用协议中文版之“署名-非商业性使用-禁止演绎 2.5 中国大陆”条款
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.5 China License.
本网站内容源自汉化新世纪论坛的摘录和汉化新世纪成员的原创文章。
凡汉化新世纪论坛的文字皆默认为汉化新世纪与原作者共同拥有并授权发布。
如对本站发布文章有所异议请来信告知,我们将及时删除。
凡商业摘录本站文字请先与我们联系,本站将保留非授权商业发布的追究权利。
凡非商业摘录本站文字请明显注明出处和原作者,并不得改动,凡改动必先征求原作者同意。
苏ICP备05002283号