相信有些朋友遇到过类似的问题,某个程序在一种语言环境下工作正常但换一种系统语言后却出现种种问题,这时候如果一定要运行该程序,对于普通用户来说有下面这几个选择:


    * 修改系统语言并重启,但这样可能会影响到其他程序的运行
    * 在虚拟机内其他语言系统下运行
    * 如果系统是XP或2003 server还可以使用微软的applocale选择相应的语言然后运行



这些方式都各有优缺点,而对于程序员来说或许还有一种方式就是自己动手丰衣足食

先解释一下LPK.DLL的工作原理。通常应用程序启动的时都会加载多个%windows%\system32\目录下的动态链接库,而在如果不是动态调用LoadLibrary并使用完整路径的情况下,被调用的库文件都是系统按照如下顺序搜索的:

1. DLL安全搜索模式(XP SP2及更新的系统并且HKEY_LOCALE_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode的值不是0, XP或2000 SP4并且HKEY_LOCALE_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode的值是1)


    * 应用程序被加载的目录
    * 系统目录(GetSystemDirectory函数返回的目录)
    * 16位的系统目录(GetWindowsDirectory函数返回的目录\system)
    * Windows目录(GetWindowsDirectory函数返回的目录)
    * 当前目录
    * 所有PATH环境变量中的目录


2. 传统模式(XP SP2及更新的系统并且HKEY_LOCALE_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode的值是0,XP或2000 SP4并且HKEY_LOCALE_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode的值不是1,以及所有更早版本的Windows 2000)


    * 应用程序被加载的目录
    * 当前目录
    * 系统目录(GetSystemDirectory函数返回的目录)
    * 16位的系统目录(GetWindowsDirectory函数返回的目录\system)
    * Windows目录(GetWindowsDirectory函数返回的目录)
    * 所有PATH环境变量中的目录



因此我们可以通过在应用程序被加载的目录下放一个同名的系统动态库(除了一些内核库例如kernel32.dll、ntdll.dll等等以外)来获取控制权,这就是LPK.DLL的启动原理,虽然部分病毒及恶意代码可能会使用到同样的技术,但我们也一样可以合理的使用这个特性来解决一些问题。

现在我们回到开始的问题,如果某个程序在一种语言环境下工作正常但换一种系统语言后却出现问题,这通常是因为调用字符串处理函数的时候使用到了CP_ACP导致的,因为使用不同的codepage转换字符串时输出的结果可能是不一样。这时候如果有源代码能修改当然最好,但如果只有可执行文件,所以我们要写程序解决此类问题的话一般有两个问题,第一是如何获取控制权,这一点可以通过如下途径获得


    * 写个Loader(类似于Applocale的方式)
    * 写个类似LPK.dll这样必须用到的动态库, 请参考yonsm的AheadLib



第二个问题是如何模拟其他语言环境,这一点我们可能会需要跟踪或反编译有问题的这个程序去了解一下都需要做些什么修改,但不妨先试一下最常见的两个函数MultiByteToWideChar和WideCharToMultiByte,这两个函数即便没有被直接调用也很可能被其他系统函数调用到。这里我们要做的其实很简单,首先hook住该进程内的这两个函数并检查对这两个函数的调用,当发现第一个参数codepage的值为CP_ACP时,则修改为能正常工作的codepage然后调用原始函数并返回

但必须注意,不同版本的系统上可能会有所差异导致hook失败,这一点需要具体问题具体分析,但总的来说用这个思路能解决大多数此类问题

附件是针对VB Decompiler Pro 5.0写的LPK源代码

上传的附件 vbdp5lpk_src.rar