如前所述,
Windows95
不是一個(gè)“純”
32
位操作系統(tǒng),其內(nèi)核模塊中的
USER
和
GDI
均是用
16
位代碼實(shí)現(xiàn)的。
USER32.DLL
和
GDI32.DLL
只是
16
位的
USER.EXE
和
GDI.EXE
的
32
位調(diào)用接口。因此,如果屏幕截獲程序用
32
位代碼實(shí)現(xiàn),則只能截獲
32
位應(yīng)用程序?qū)?/span>
USER32.DLL
和
GDI32.DLL
的調(diào)用,無(wú)法截獲
16
位應(yīng)用程序?qū)?/span>
USER.EXE
和
GDI.EXE
的調(diào)用,所以如果想截獲所有應(yīng)用程序(包括
Windows95
的桌面程序
Explorer
)中有關(guān)屏幕輸出的系統(tǒng)調(diào)用,則應(yīng)該用
16
位代碼實(shí)現(xiàn)屏幕截獲功能。這就是
LTW32
為什么不是“純”
32
位應(yīng)用程序的原因。
LTW32
主要截獲兩個(gè)系統(tǒng)調(diào)用
TextOut()
和
ExtTextOut()
,方法很簡(jiǎn)單,把這兩個(gè)函數(shù)的頭五個(gè)字節(jié)修改為一個(gè)
JMP FAR
指令,使得對(duì)這兩個(gè)函數(shù)的調(diào)用均轉(zhuǎn)向屏幕截獲程序。這就涉及到一個(gè)關(guān)鍵問(wèn)題:動(dòng)態(tài)修改
Windows
的代碼。
在傳統(tǒng)的
DOS
程序中,動(dòng)態(tài)修改程序代碼無(wú)任何困難,但在
Windows
中則不然,因?yàn)樵?/span>
Windows
中,代碼可被同一程序的多個(gè)實(shí)例(進(jìn)程)共享,所以系統(tǒng)不允許應(yīng)用程序動(dòng)態(tài)的修改代碼。在
16
位側(cè),內(nèi)存的可讀、寫屬性是與段選擇符聯(lián)系在一起的。段選擇符基本上可分為兩類:數(shù)據(jù)段選擇符和代碼段選擇符。前者可讀、可寫、不可執(zhí)行;后者可讀、可執(zhí)行、不可寫。
Windows
提供了這兩類段選擇符相轉(zhuǎn)換的系統(tǒng)調(diào)用。未公開(kāi)的
16
位系統(tǒng)調(diào)用
AllocCStoDSAlias()
為給定的代碼段選擇符分配一個(gè)具有相同線性基址和尺寸的數(shù)據(jù)段別名(
DS Alias
)。通過(guò)
DS
別名可以對(duì)給定的代碼段進(jìn)行修改。
AllocCStoDSAlias()
的使用方法如下:
WORD (FAR PASCAL *AllocCStoDSAlias)(WORD);
AllocCStoDSAlias = GetProcAddress(
GetModuleHandle(“KERNEL”), ”ALLOCCSTODSALIAS”);
調(diào)用參數(shù)為給定的代碼選擇符,調(diào)用成功時(shí)返回一個(gè)線性基址和尺寸均與原代碼選擇符相同的
DS
別名。當(dāng)不再使用此
DS
別名時(shí),要用系統(tǒng)調(diào)用
FreeSelector()
把
DS
別名釋放掉。
使用上述技術(shù),就可實(shí)現(xiàn)動(dòng)態(tài)修改
Windows
代碼,從而改變
GDI
的系統(tǒng)調(diào)用
TextOut()
和
ExtTextOut()
的執(zhí)行動(dòng)作,實(shí)時(shí)地截獲屏幕輸出,為實(shí)現(xiàn)鼠標(biāo)隨動(dòng)翻譯提供可能。
把上述的
32
位到
16
位的形式替換、
32
位代碼與
16
位代碼的數(shù)據(jù)交換、動(dòng)態(tài)修改
Windows
內(nèi)核等技術(shù)綜合應(yīng)用在一起,配合單詞查找算法和詞組分析算法就可以實(shí)現(xiàn)鼠標(biāo)隨動(dòng)翻譯功能。