老汉的一位朋友,不知从什么犄角旮旯淘到了一款 hx2790 的 PDA,大喜若望,喜不自胜,常常在其上启动纸牌程序而整夜不寐。无奈该机万般好处,唯有一点不爽,就是该机原始为美利坚合众国的户口,上边整篇整篇蝌蚪一般的洋文,弄得何首乌煞是爱不得恨不得。于是在某云南菜馆摆下酒席一桌,恳请老汉帮助则个,把上面的英文系统给他换成中文的。
老汉的优点之一就是有困难要上,没有困难创造困难也要上。不管它三七二十一,接过来再说,大不了弄得它再也启动不了。
回家之后,开始摆弄。虽然头一次鼓捣这玩意儿,不过好歹还懂得要想改成中文的系统,首先要找到中文版的 ROM。擒贼擒王嘛,先去 HP 的官方网站打打秋风!这一去不要紧,hx2700 系列(当然包括 hx2790)的中文版升级包赫然在目,而且可以随便下载。赶忙用快车拽回来一个。解开压缩包一看,里面有个挺大个头的家伙,名字叫 iPAQ_hx2700_WM5_CHS.nbf。依稀记得 nbf 类型的文件就是 ROM 映像,到网上搜搜看也证实了这一点。看来开头不错,这个包里只有这么一个 nbf 文件,而且大小又有近 50MB,老汉可以断定这是一个完整的系统。暗暗叫喜,呵呵,得来全不费功夫么。那知道,这才是噩梦开始的地方……
按照 HP 网站的说明,并且又在实践中根据软件界面的提示作了若干次的修正,终于,HP 的刷机程序启动了。其实主要有两点:1、PDA 一定要接到外部交流电源上,2、要和计算机的 USB 连接起来。看到刷机程序的启动界面时,不由得一阵欣喜,心想何首乌这个笨伯,这么简单的事情,竟然还需要我老人家出马。点了两下“下一步”就傻眼了,提示“语言不正确”,不能继续。靠,鸟 HP,老子看什么语言和你有狗屁的相干!
Google 在困难的时候经常是会来帮助我的,这一次我也这样认为,所以义无反顾地命令它给我寻找有用的信息。在一个现在已经想不起来的站点上,我第一次知道了刷机还有另外一种模式,叫“Boot Loader”模式,那位高人说:要同时按住 PDA 的按钮二和按钮三以及重置键三十秒以上,PDA 重新启动后,按下按钮一,即可进入“Boot Loader”模式。晕倒,我老人家怎么知道哪个是按钮一二三……
根据这个隐约的线索,功夫不负有心人,最终还是把按钮搞明白了。其实就是按住“联系人”和“邮件”键的同时,用笔点一下“重置”,等到机器重新启动后,按一下“日历”键即可,所谓的三十秒完全是不必要的,当然,如果谁不嫌累,老汉也不反对他这么做。这时屏幕的左下方会有状态文字,提示你要么是需要接通交流电源,要么是应该接通 USB 连接,按照提示把该干的干好。这里之所以这么罗嗦地讲清楚怎么进入“Boot Loader”模式,是因为后面要用到它。
可叹的是,人世间不如意之事十有八九,这次得到的错误提示依旧。在 Google 上疯狂搜索,只见提问的多,回答得少。
返过头来又去研究刷机程序本身,娘西匹,主程序一点几个兆,顿时把我要反汇编的激情打了个粉粉碎,有个名叫 RUUClientDriver.dll 的动态库很可疑,刚用 IDA 分析完毕,一看表已经深夜了,明天还要上班呢……
何首乌于两日后虚情假意地和我寒暄,两句客套话之后就露出了狼尾巴:那个事情办得怎么样啊,党和人民很关心啊。靠,你当是像吃一碗米线那么简单啊!
迷迷糊糊地想起原来某人曾经和我说过另一个同学是在 HP 工作,得病乱投医,把电话号码要了过来。一问才发现跨国公司和咱们这小打小闹惯了的根本不是一回事儿,人家在中国的小公司、大部门无数,我的这个同学负责大容量存储方面的事情,和手持设备约等于是风马牛。唉。
顺便在公司的内部论坛里贴了求助帖,顺便把我认识的和 PDA 这种先进设备靠谱的同事打听了个遍,再问他认不认识兜售 PDA 的供货商,看看那些人能不能帮忙……
除了一个朋友说可以问问他的另一个经销硬件的朋友之外,基本陷入了僵局。
老汉说:天要下雨,娘要嫁人,由它去吧!
事情在两个来礼拜之后的昨天,好像出现了转机。我的朋友让我今天带上那个机器,中午的时候去拜访一下他的那位经销硬件的哥们儿。在我的眼里,这几乎就是最后一根稻草了,恨不得把何首乌请我的那顿饭从胃里热热乎乎地掏还给他。
见了面之后,朋友的朋友挺热情。不过问了我几个问题,就把我问住了,比如说你有没有解码过啊,比如说我们刷机就是往 ROM 映像里要挂字库啊什么的,弄得我晕晕糊糊,更糟糕的是好长时间没碰这个破玩意儿,竟然连型号也忘了,把顺便带来的手册说明书翻了个遍也没找到哪儿标注有型号。急切中倒是正好发现了何首乌留在一张广告彩页上的墨宝,有四个数字 2790,心想,大概齐就是它了。听了挂字库的方法之后,我心里敲起了鼓,虽然不知道是怎么回事,可总觉得恐怕也还是对英文的 ROM 映像作一些手脚,使它能支持中文,正好也避过了语言检查,和我想要的直接把已经好好地在那儿的中文 ROM 映像刷进去不大一样。
不过这件事又激起了我的斗志。好歹也是个程序员啊,好歹也是被何首乌崇拜了无数次的搞技术的人才啊,明明知道这是 HP 的那班工程师人为设置的障碍,难道就真的一点办法也没有?
吃了两盘老婆做的炒饼、喝了一碗老婆熬的小米粥之后,老汉又继续 Google 了。
这次搜出来点不一样的东西。首先是我的猜测得到了进一步的证实,HP 的刷机程序确实是故意人为地增加了语言比对,也有人已经使用其他方法绕过了这个比对。他所采取的方法是,把 iPAQPCSDK.dll 中的若干个比较语言的地方的代码进行了更改,而且对要刷到机器里的中文 ROM 映像也作了改动,把 ROM 映像中表示中文的地方改成了英文。我按照他的办法查看了一下,结果由于他更改的机型根本不是 2790,所以在他指出的偏移处也理所当然地找不到他所说的值。而且,这种方法也要更改 ROM 映像,非我本意。
不过等等,既然 HP 的程序要进行比对,总要从设备中获取原来的信息吧?我们把它从设备里取回来的语言信息(目前的情况当然取回来的是英文了)改掉,改成我们要刷的中文,岂不也能达到使比较能够成功的效果?既然别人是破解 iPAQPCSDK.dll 这个文件的,不由得老汉也仔细看了一下它,嗯,有个名叫 iPAQGetInfo 的导出函数非常像是要作所需要的操作。
把刷机程序 hpRUU.exe 运行了起来,在 iPAQGetInfo 处设置了断点,一跑,乖乖,要断好几次呐!老老实实地运行到返回指令处,在执行回调用者,依次把调用此函数的地址记录了下来。在所有的调用地址处下断点再跑一遍,检查了一下输入参数。这回有点眉目了,这个函数接收两个 UNICODE 字符串参数,其中一个是一个函数名一样的东西,再用 IDA 反汇编的结果一比照,呵呵,原来它是要通过 RAPI 远程调用目标机上的函数。而第四次调用的函数名叫“iPAQGetLanguageID”,如果要是不对它产生一些兴趣,那我简直无法原谅自己。按照道理来讲,既然是需要远程机器返回信息,必然需要提供返回信息所需的缓冲区,可是很显然并没有多余的参数传递入内,我只好输入参数假定为也是输出缓冲来观察,于是——“我找到了!”函数执行完毕后,缓冲区内的前几个字节的内容变成了 UNICODE 形式的“ENG”。不好意思,我毫不手软地把它改成了“CHS”,继续运行,MY GOD,那个惹人生厌的“语言不正确”对话框终于没有再出现,代之以机器型号、新旧版本号、语言等等信息的摘要,最重要的是,下面的一个按钮的文字为“更新”!还有比这个更激动人心的事情么?
我跳下床来,跑到老婆的身边大喊:我终于可以给老何刷机了!
至尊宝说:可惜快乐永远是短暂的。这个谶言就恰好降落到了老汉的头上,在我手舞足蹈五分钟之后,在用终于不再颤抖的手指在“更新”按钮上点击之后,快乐就结束了。该死的程序提示说“错误 514,检测设备失败:检测到另外一台设备已经连接到 USB 上,请在确保连接正确之后重新运行本程序。”我天真地又尝试了两遍,然后,分别重新启动电脑、重新启动 PDA、重新同时启动电脑和 PDA 之后各尝试了一遍,每次都得到同样的错误。还有比这个更令人沮丧的事情么?
可是,我是老汉,我是无坚不摧的老汉啊。我又回想起那个“Boot Loader”模式来,要不试试?试试就试试!
这回简直就是快绝望了,连 iPAQPCSDK.dll 中下的断点都失效了!且慢,我在绝望中猛然捕捉到了一丝曙光,那个名叫 RUUClientDriver.dll 的动态库到底是做什么的?为什么里面会有一个 Client_OS_Lang 的导出函数呢?不妨对这个函数下个断点玩玩!
老汉的天才被证明了!很显然 RUUClientDriver.dll 和 iPAQPCSDK.dll 是分别工作在“Boot Loader”模式和正常模式下的执行同种工作的动态库。Client_OS_Lang 这个函数执行的方式与 iPAQPCSDK.dll 中的 iPAQGetInfo 如出一辙,执行结束后,我清楚地在缓冲里看到了“ENG”,只不过这次是 ANSI 版本的。再一次地,我把它改成了“CHS”。
“更新”按钮又出现了,我不再犹豫,反正是最后的希望了,点它!
感谢上帝,进度条出现了!
大概在五分钟之后,我成功地把 PDA 引导至了中文 Windows Mobile 5 系统中。
如果黄某人在我身边的话,他应该这样喊:“搞定了!搞定了!!搞定了!!!伟大的……、……、……在这一刻灵魂附体!!!……”他喊他的吧,我要睡觉了。
最后一次引用 —— 周华健说:“现在时间是:凌晨……”,老汉补充结尾:零点三十六分。