·汉化新世纪 ·汉化新世纪论坛 ·百家争鸣 ·论坛集萃 ·汉化问答 ·软件介绍
文章首页 >> 汉化教学 >> 编程知识 >> 一款软件的乱码处理 - 看二位高手的不同解决方案    Creative Commons License,创作共用协议(中文版)  署名 非商业性使用 禁止演绎

一款软件的乱码处理 - 看二位高手的不同解决方案

作者: wanfu 来源:http://bbs.hanzify.org/index.php?showtopic=49834 时间:2009-05-10 点击:13214

问题文件

wanfu的问题:

我汉化了一款VC软件,该软件有标准资源和Uncode和ASCII非标字符,我已修改了所有标准资源中的字体和语系为简体中文,但是修改主程序中的ASCII非标字符为简体中文时,结果在“验证”的列表框中显示乱码。我试图改为UFT-8和Uncode也没有成功。试图用OllyDBG修改,只找到与字体设置相关的CreateFontW模块,字符设置 CharSet = DEFAULT_CHARSET 应该不用改。

哪位高手可以帮助我?
文件在此:  LOOMConfig.rar ( 314.42k ) 下载次数: 20

问题所在

cao_cong的答复:

你这个是程序的转码问题。比如你汉化的验证列表框中的第一个“添加“<%s>”标记将改变文档“%s”的格式和/或结构。”,ASCII码是
CCEDBCD3A1B03C25733EA1B1B1EABCC7BDABB8C4B1E4CEC4B5B5A1B02573A1B1B5C4B8F1CABDBACD2FBBF2BDE1B9B9A1A3,
程序转换成MultiByte,成为CC00ED00BC00D300A100B0003C00250073003E00A100B100B100EA00BC00C700BD00AB00B800C400B100E400CE00C400B50
0B500A100B00025007300A100B100B500C400B800F100CA00BD00BA00CD002F00BB00F200BD00E100B900B900A100A300,
而最后显示的应该是UNICODE,对应你的翻译最后应该显示的是UNICODE编码FB6DA0521C203C00250073003E001D200768B08B065C3965D853876563681C20250073001D2084763C680F5F8C542F001662D
37E84670230,可程序没干这事,给你转换成MultiByte它就完事了。所以你英文显示正常,变成中文宽字符时肯定不正常了。
貌似除了在程序中写转换字符的补丁代码外没啥更好的方法。贴个效果图:
弄起来应该也比较麻烦。我有空的话就帮你搞一下,也对你那个老盖的工具比较感兴趣,想瞅瞅

 

附加缩略图
附加图片

解决方案

restools的解决方案(1)

汇编不在行,所以打洞放代码的功夫就留待高人来实现了,我的方法很简单,作了个DLL,里面有个函数,然后让软件的处理变成调用我的DLL来处理。我还是喜欢这种方式,因为我不需要在软件中寻找合适位置放置合适代码,而且这需要很强的ASM代码整合能力,一不小心,可能引起异常(这里花的时间绝对不会少)。

虽然这不是完美的实现方法,但是对于汉化这样的工程,如果不是为了技术探讨,大可不必做到非常完美,只需要实现效果即可。

DLL做出来了,用来参考,可把里面反汇编的代码稍作修改应该可以在原程序上放置实现更完美的效果。

附加文件
 LM.rar ( 73.28k ) 下载次数: 25

cao_cong的评价(解释了原理和用法):

restools 兄这个方法好!比直接在程序中写补丁代码简单多了,学习!我看了你改的主程序,应该是用LordPE添加了你DLL中的导出函数,把一个调用SendMessageW的地方改成调用你的函数。严重学习!



cao_cong
的解决方案

再来一个打过补丁的。本来想用LordPE直接添加程序中没有的函数WideCharToMultiByte和SendMessageA的,看了一下程序中有LoadLibraryA和GetProcAddress这两个函数,想想还是用这两个函数来获取WideCharToMultiByte和SendMessageA函数地址吧。因为调用的都是系统函数,我就不考虑用FreeLibrary来释放了。原本想直接抄restools兄的DLL文件中的代码来补丁的,不过堆栈平衡实在不大好处理,反而耗了我很多时间。最后干脆直接写了。我在程序的最后添加了一个大小为400H的区段用来写代码,主要是在程序中找不到够写代码的空间了。
贴上用于OllyDBG的写补丁代码插件NonaWrite的代码,我在里面都加了注释,应该容易理解。在程序中添加一个区段后就可以用OD载入,再用NonaWrite插件把这些代码直接写到程序中保存就行了:

变量:
;temp1:用来存放用GetProcAddress获取的WideCharToMultiByte函数地址。
;偏移:00039639,VA:0043B039

;temp2:用来存放用GetProcAddress获取的SendMessageA函数地址。
;偏移:0003963E,VA:0043B03E

;temp3:用来保存调用SendMessageW时的句柄。
;偏移:00039643,VA:0043B043

;temp4:用来保存要转换的字串地址。
;偏移:00039648,VA:0043B048

;temp5:分配200字节用来作为转换字串的缓冲区
;偏移:00039660,VA:0043B060
;结束偏移:00039860,VA:0043B260

;常量:
;const1:用来存放字串KERNEL32.dll。
;偏移:39600,RVA:00032C70,VA:0043B000

;const2:用来存放字串WideCharToMultiByte。
;偏移:3960D,VA:0043B00D

;const3:用来存放字串USER32.dll。
;偏移:39621,VA:0043B021

;const4:用来存放字串SendMessageA。
;偏移:3962C,VA:0043B02C

;其他:
;LoadLibraryA:
;VA:40105C

;GetProcAddress:
;VA:401060

;原程序中还要在418508处改一下:
;0x418508:
;call 43B270                              ;改成这个

;补丁代码:开始地址为0043B270
;获取WideCharToMultiByte和SendMessageA函数:
0x43B270:
pushad
mov eax,[esp+24]                      ;temp3,保存前面修改SendMessageW时的句柄
mov dword ptr [0043B043],eax
mov eax,[esp+30]                      ;temp4,保存要转换的字串地址
mov dword ptr [0043B048],eax
cmp dword ptr [0043B039],0      ;判断是否已获取了要用的函数
jnz 43B2ab                                ;out1
push 0043B000                         ;const1
call dword ptr[40105C]               ;调用LoadLibraryA
push 0043B00D                         ;const2
push eax
call dword ptr[401060]               ;调用GetProcAddress
mov dword ptr [0043B039],eax   ;保存WideCharToMultiByte函数地址到temp1
;out1
cmp dword ptr [0043B03E],0
jnz 43B2d1                               ;out2
push 0043B021                         ;const3
call dword ptr[40105C]               ;调用LoadLibraryA
push 0043B02C                         ;const4
push eax
call dword ptr[401060]               ;调用GetProcAddress
mov dword ptr [0043B03E],eax   ;保存SendMessageA函数地址到temp2
;out2,开始转换
push    0                                  ; lpUsedDefaultChar
push    0                                  ; lpDefaultChar
push    200                               ; cchMultiByte
push    0043B060                      ; temp5,lpMultiByteStr
push    -1                                 ; cchWideChar
push    dword ptr [0043B048]     ; temp4,lpWideCharStr
push    0                                  ; dwFlags
push    4E4                               ; CodePage
call    dword ptr[0043B039]         ;调用WideCharToMultiByte
mov    eax,0043B060
push    eax                               ; lParam
push    0                                  ; wParam
push    180                               ; Message = LB_ADDSTRING
push    dword ptr [0043B043]     ; hWnd
call    dword ptr[0043B03E]        ;调用SendMessageA
popad
ret 10

 附件是修改过的主程序:
 LOOMConfig.rar ( 72.46k ) 下载次数: 4
 

 restools的解决方案(2)

既然cc兄作了相当完美的解决方案出来,那我就借用一下,再把它处理的完善已点,以下的修改

;变量:
;首先,文件没有扩展任何实际大小,所有代码,常量都在文件的空隙中存放,至于变量,大部分使用的是虚的空间。这样做是因为文件实际上是没有足够实际空间的。
;先把文件的text段虚拟大小用尽也就是2F00,这不影响原来的程序结构的,据测试,好像改不改都可以用,不过还是按规矩修改了
;再把文件的data段虚拟大小用尽也就是3000,这不影响原来的程序结构的,据测试,好像改不改都可以用,不过还是按规矩修改了
;开放text的写入功能,使变量可以写入

;temp1:用来存放用GetProcAddress获取的WideCharToMultiByte函数地址。 ---把text段虚拟空间扩展到2F000,变量运行时放到虚的位置,就是文件中并不存在的位置
;VA:42FE28

;temp2:用来存放用GetProcAddress获取的SendMessageA函数地址。---同上
;VA:42FE2E

;temp3:用来保存调用SendMessageW时的句柄。---同上
;VA:42FE34

;temp4:用来保存要转换的字串地址。---同上
;VA:42FE3A

;temp5:分配190字节用来作为转换字串的缓冲区 ---放到 Data 段空闲位置,大部分是虚的,文件没有实位置
;VA:432E60 --使用靠在后面扩展的虚拟空间,因为这个段大多数会有数据写入,前面已经分配的虚拟空间不太安全
;0x190 就是 400 个字节,对于这个程序,我想应该足够了

;常量:
;const1:用来存放字串KERNEL32.dll。---------------------------原程序已有该字串,借用,省去空间
;VA:42F602

;const2:用来存放字串WideCharToMultiByte。---放到 text 段空闲位置 ,文件实位置
;VA:42FDE0

;const3:用来存放字串USER32.dll。---------------------------原程序已有该字串,借用,省去空间
;VA:42F6D4

;const4:用来存放字串SendMessageA。---放到 text 段空闲位置 ,文件实位置
;VA:42FDF4

;其他:
;LoadLibraryA:
;VA:40105C

;GetProcAddress:
;VA:401060

;原程序中还要在418508处改一下:
;0x418508:
;call 42FD3E                            ;改成这个

;补丁代码:开始地址为0042FD3E
;获取WideCharToMultiByte和SendMessageA函数:
0x42FD3E:
pushad
mov eax,[esp+24]                    ;temp3,保存前面修改SendMessageW时的句柄, ListBox 句柄
mov dword ptr [42FE34],eax
mov eax,[esp+30]                    ;temp4,保存要转换的字串地址, 错误字符串的地址,准备用来修复
mov dword ptr [42FE3A],eax
cmp dword ptr [42FE28],0            ;temp1,WideCharToMultiByte判断是否已获取了要用的函数,如果有跳转,不再获取
jnz 42FD7C                          ;out1
push 42F602                         ;const1
call dword ptr[40105C]              ;调用LoadLibraryA
push 42FDE0                         ;const2
push eax
call dword ptr[401060]              ;调用GetProcAddress
mov dword ptr [42FE28],eax          ;保存WideCharToMultiByte函数地址到 temp1
;out1
cmp dword ptr [42FE2E],0            ;temp2,判断是否已获取了要用的函数,如果有跳转,不再获取
jnz 43FDA2                          ;out2
push 42F6D4                         ;const3,字串USER32.dll
call dword ptr[40105C]              ;调用LoadLibraryA
push 42FDF4                         ;const4,字串SendMessageA
push eax
call dword ptr[401060]              ;调用GetProcAddress
mov dword ptr [42FE2E],eax          ;保存SendMessageA函数地址到temp2
;out2,开始转换
push    0                        ; lpUsedDefaultChar
push    0                        ; lpDefaultChar
push    190                         ; cchMultiByte
push    432E60                      ; temp5,lpMultiByteStr
push    -1                          ; cchWideChar
push    dword ptr [42FE3A]          ; temp4,lpWideCharStr
push    0                        ; dwFlags
push    4E4                         ; CodePage
call    dword ptr[42FE28]        ; temp1,调用WideCharToMultiByte
mov    eax,432E60                ; 输出正确的 ANSI 字符串
push    eax                         ; lParam
push    0                        ; wParam
push    180                         ; Message = LB_ADDSTRING
push    dword ptr [42FE34]          ; temp3,hWnd
call    dword ptr [42FE2E]          ; 调用SendMessageA
popad
ret 10

文件没增加一个字节,资源段仍然处在最后位置,可以用资源编辑工具继续编辑而无需担心。

附加文件
 LOOMConfig.rar ( 72.43k ) 下载次数: 5

 

汉化新世纪 责任编辑: wanfu .:|:. 标签(Tag): 乱码 WideCharToMultiByte

·上一篇: Radialix.2.06.1.1267 脱壳演示 ·下一篇: MultiByteToWideChar 一例乱码的解决

· 版权申明: 本文引自《http://bbs.hanzify.org/index.php?showtopic=49834》,如有版权疑问请及时联系本站,以便本站处理。

· 转载申明: 本文引自《http://bbs.hanzify.org/index.php?showtopic=49834》[ 作者: wanfu],如需转载请直接联系原始作者,并请注明原始出处。

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

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