四通利方(RichWin)
中文之星(CStar)是大家廣為熟知的漢化Windows產品
陷阱
技術即動態修改Windows代碼
一直是其對外宣稱的過人技術
本文從Windows的模塊調用機制與重定位概念著手
介紹了
陷阱
技術的實現
並給出了采用
陷阱
技術動態修改Windows代碼的示例源程序
一發現了什麼? 筆者多年來一直從事Windows下的軟件開發工作
經歷了Windows
直至Windows
NT的成長過程
也遍歷了長青窗口
長城窗口
DBWin
CStar
RichWin等多個Windows漢化產品
從現在看來
影響最大也最為成功的
當推四通利方的RichWin;此外
中文之星CStar與RichWin師出一門
其核心技術自然也差不多
其對外宣傳采用獨特的
陷阱
技術即動態修改Windows代碼
一直是筆者感興趣的地方
EXEHDR是Microsoft Visual C++開發工具中很有用的一個程序
它可以檢查NE(New
Exe cutable)格式文件
用它來分析RichWin的WSENGINE
DLL或CStar的CHINESE
DLL
就會發現與眾不同的兩點(以CStar
為例):
C:\CSTAR>exehdr chinese
dll /v
type offset target BASE
a seg
offset
PTR
e imp GDI
GETCHARABCWIDTHS PTR
b imp GDI
ENUMFONTFAMILIES PTR
imp DISPLAY
( EXTTEXTOUT ) PTR
imp KEYBOARD
( TOASCII ) PTR
ba imp KEYBOARD
( ANSITOOEM ) PTR
c
imp KEYBOARD
( OEMTOANSI ) PTR
d
imp KEYBOARD
( ANSITOOEMBUFF ) PTR
f
imp USER
( LSTRCMP ) PTR
e
imp KEYBOARD
( OEMTOANSIBUFF ) PTR
imp USER
( ANSIUPPER ) PTR
imp USER
( ANSILOWER ) PTR
aa imp GDI
( CREATEFONT ) PTR
e imp USER
( ISCHARALPHA ) PTR
b
imp GDI
( CREATEFONTINDIRECT ) PTR
d imp USER
( ISCHARALPHANUMERIC ) PTR
c imp USER
( GETSYSTEMMETRICS ) PTR
imp USER
( ISCHARUPPER ) PTR
f imp USER
( ISCHARLOWER ) PTR
imp USER
( ANSIUPPERBUFF ) PTR
imp USER
( ANSILOWERBUFF ) PTR
c
imp GDI
( DELETEOBJECT ) PTR
c imp GDI
( ENUMFONTS ) PTR
ab imp KERNEL
ISDBCSLEADBYTE PTR
d
imp GDI
( GETOBJECT ) PTR
d imp KERNEL
( OPENFILE ) PTR
imp GDI
( GETTEXTEXTENT ) PTR
e
imp GDI
( GETTEXTFACE ) PTR
f imp GDI
( GETCHARWIDTH ) PTR
imp GDI
( EXTTEXTOUT ) PTR
imp USER
( LSTRCMPI ) PTR
f
imp USER
( ANSINEXT ) PTR
imp USER
( ANSIPREV ) PTR
imp USER
( GETMESSAGE ) PTR
imp USER
( PEEKMESSAGE )
relocations
(括號內為筆者加上的對應Windows API函數
)
第一
在數據段中
發現了重定位信息
第二
這些重定位信息提示的函數
全都與文字顯示輸出和鍵盤
字符串有關
也就是說漢化Windows
必須修改這些函數
在這非常特殊的地方
隱藏著什麼呢?毋庸置疑
這與眾不同的兩點
對打開
陷阱
技術之門而言
不是金鑰匙
也是敲門磚
二Windows的模塊調用機制與重定位概念 為了深入探究
陷阱
技術
我們先來介紹Windows的模塊調用機制
Windows的運行分實模式
標准模式和增強模式三種
雖然這幾種模式各不相同
但其核心模塊的調用關系卻是完全一致的
見圖一
主要的三個模塊
有如下的關系:
·KERNEL是Windows系統內核
它不依賴其它模塊
·GDI是Windows圖形設備接口模塊
它依賴於KERNEL模塊
·USER是Windows用戶接口服務模塊
它依賴於KERNEL
GDI模塊及設備驅動程序等所有模塊
這三個模塊
實際上就是Windows的三個動態鏈接庫
KERNEL有三種系統存在形式:Kern el
exe(實模式)
Krnl
exe(標准模式)
Krnl
exe(
增強模式);GDI模塊是Gdi
ex e;USER模塊是User
exe
雖然文件名都以EXE為擴展名
但它們實際都是動態鏈接庫
同時
幾乎所有的API函數都隱藏在這三個模塊中
用EXEHDR對這三個模塊分析
就可列出一大堆大家所熟悉的Windows API函數
以GDI模塊為例
運行結果如下:
C:\WINDOWS\SYSTEM>exehdr gdi
exe Exports: rd seg offset name
e EXTTEXTOUT exported
shared data
e
CREATEFONT exported
shared data
至此
讀者已能從Windows紛繁復雜的系統中理出一些頭續來
下面
再引入一個重要概念——重定位
一個Windows執行程序對調用API函數或對其它動態庫的調用
在程序裝入內存前
都是一些不能定位的動態鏈接;當程序調入內存時
這些遠調用都需要重新定位
重新定位的依據就是重定位表
在Windows執行程序(包括動態庫)的每個段後面
通常都跟有這樣一個重定位表
重定位包含調用函數所在模塊
函數序列號以及定位在模塊中的位置
例如
用EXEHDR /v 分析CHINESE
DLL得到:
type offset target
PTR
imp GDI
就表明
在本段的
H偏移處
調用了GDI的第
號函數
如果在
H處是
:FFFF
表示本段內僅此一處調用了GDI
函數;否則
表明了本段內還有一處調用此函數
調用的位置就是
H處所指向的內容
實際上重定位表只含有引用位置的鏈表的鏈頭
那麼
GDI
是一個什麼函數呢?用EXEHDR對GDI
EXE作一分析
就可得出
在GDI的出口(Export)函數中
第
號是ExtTextOut
這樣
我們在EXEHDR這一簡單而非常有用的工具幫助下
已經在Windows的浩瀚海洋中暢游了一會
下面讓我們繼續深入下去
三動態漢化Windows原理 我們知道
傳統的漢化Windows的方法
是要直接修改Windows的顯示
輸入
打印等模塊代碼
或用DDK直接開發
中文設備
驅動模塊
這樣不僅工作量大
而且
系統的完備性很難保證
性能上也有很多限制(早期的長青窗口就是如此)
所以只有從內核上修改Windows核心代碼才是最徹底的辦法
從Windows的模塊調用機制
我們可以看到
Windows實際上是由包括在KERNEL
GDI
US ER等幾個模塊中的眾多函數支撐的
那麼
修改其中涉及語言文字處理的函數
使之能適應中文需要
不就能達到漢化目的了嗎?
因而
我們可以得出這樣的結論:在自己的模塊中重新編寫涉及文字顯示
輸入的多個函數
然後
將Windows中對這些函數的引用
改向到自己的這些模塊中來
修改哪些函數才能完成漢化
這需要深入分析Windows的內部結構
但CHINESE
DLL已明確無誤地告訴了我們
在其數據段的重定位表中列出的引用函數
正是CStar修改了的Windows函數!為了驗證這一思路
我們利用RichWin作一核實
用EXEHDR分析GDI
EXE
得出ExtTextOut函數在GDI的第一代碼段
H偏移處(不同版本的Windows其所在代碼段和偏移可能不一樣)
然後
用HelpWalk(也是Microsoft Visual C+ +開發工具中的一個)檢查GDI的Code
段
H處前
個字節是 B
FF
經過運行Ri chWin
for Internet後
再查看同樣的地方
已改為 EA
F
D
其實反匯編就知道
這
個字節就是 Jmp
D
F:
而句柄為
x
D
F的模塊
用HelpWalk能觀察正是RichWin 的WSENGINE
DLL的第一代碼段( 模塊名為TEXTMAN)
而偏移
H處 B
B
D
B E C
E
正是一個函數起始的地方
這實際上就是RichWin所重改寫的ExtTextOut函數
退出Ri chWin後
再用HelpWalk觀察GDI的Code
代碼段
一切又恢復正常!這與前面的分析結論完全吻合!那麼
下一個關鍵點就是如何動態修改Windows的函數代碼
也就是漢化Windows的核心——
陷阱
技術
四陷阱技術 討論
陷阱
技術
還要回到前面的兩個發現
發現之二
已能解釋為修改的Windows函數
而發現之一卻仍是一個迷
數據段存放的是變量及常量等內容
如果這裡面包含有重定位信息
那麼
必定要在變量說明中將函數指針賦給一個FARPROC類型的變量
於是
在變量說明中寫下:
FARPROC FarProcFunc=ExtTextOut;
果然
在自己程序的數據段中也有了重定位信息
這樣
當程序調入內存時
變量FarPro cFunc已是函數ExtTextOut的地址了
要直接修改代碼段的內容
還遇到一個難題
就是代碼段是不可改寫的
這時
需要用到一個未公開的Windows函數AllocCStoDSAlias
取得與代碼段有相同基址的可寫數據段別名
其函數聲明為:
WORD FAR PASCAL AllocCStoDSAlias(WORD code_sel);
參數是代碼段的句柄
返回值是可寫數據段別名句柄
Windows中函數地址是
位
高字節是其模塊的內存句柄
低字節是函數在模塊內的偏移
將得到的可寫數據段別名句柄鎖定
再將函數偏移處的
個字節保留下來
然後將其改為轉向替代函數(用 EA Jmp):
*(lpStr+wOffset) =
xEA;
四通利方(RichWin)
中文之星(CStar)是大家廣為熟知的漢化Windows產品
陷阱
技術即動態修改Windows代碼
一直是其對外宣稱的過人技術
本文從Windows的模塊調用機制與重定位概念著手
介紹了
陷阱
技術的實現
並給出了采用
陷阱
技術動態修改Windows代碼的示例源程序
//源程序 relocate
c#include <WINDOW
From:http://tw.wingwit.com/Article/os/youhua/201311/10862.html