之前為了破解SiglusEngine的地區限制,我有做了一些分析:
SiglusEngine地區限制破解
這一次我的目的是還原第一個關鍵跳轉那個地方的檢查算法。
首先回顧一下第一個關鍵跳轉:
0045DC5A |. E8 81F9FFFF CALL 0045D5E0 ;檢查
0045DC5F |. 84C0 TEST AL,AL
0045DC61 E9 AA000000 JMP 0045DD10 ;第一個關鍵跳轉
0045DC66 90 NOP
SiglusEngine地區限制破解
這一次我的目的是還原第一個關鍵跳轉那個地方的檢查算法。
首先回顧一下第一個關鍵跳轉:
0045DC5A |. E8 81F9FFFF CALL 0045D5E0 ;檢查
0045DC5F |. 84C0 TEST AL,AL
0045DC61 E9 AA000000 JMP 0045DD10 ;第一個關鍵跳轉
0045DC66 90 NOP
在 CALL 0045D5E0 這裡按 F7 跟進:
0045D5E0 /$ 6A FF PUSH -1 ;函式開頭
0045D5E2 |. 68 D1087600 PUSH 007608D1
0045D5E7 |. 64:A1 0000000 MOV EAX,DWORD PTR FS:[0]
0045D5ED |. 50 PUSH EAX
0045D5EE |. 81EC 7C020000 SUB ESP,27C
0045D5F4 |. A1 90348000 MOV EAX,DWORD PTR DS:[803490]
0045D5F9 |. 33C4 XOR EAX,ESP
0045D5E2 |. 68 D1087600 PUSH 007608D1
0045D5E7 |. 64:A1 0000000 MOV EAX,DWORD PTR FS:[0]
0045D5ED |. 50 PUSH EAX
0045D5EE |. 81EC 7C020000 SUB ESP,27C
0045D5F4 |. A1 90348000 MOV EAX,DWORD PTR DS:[803490]
0045D5F9 |. 33C4 XOR EAX,ESP
這個函式有點長,我就不全部列出來了。
觀察一下這個函式,可以發現它呼叫了幾個API:
GetFileVersionInfoSize
GetFileVersionInfo
VerQueryValue
查了一下MSDN,這些API可以用來取得某個exe或dll的版本訊息,而其中就包括了
那個exe或dll所支援的語言。
我們進一步跟蹤程式,可以發現SiglusEngine是把kernel32.dll的版本資訊拿來檢查,
若kernel32.dll支援不支援日文就判定為非日本地區。由於kernel32.dll有可能支援數種語言,
引此需要一個迴圈來檢查,以下為原始程式碼:
0045D7F4 |> /66:813A 1104 /CMP WORD PTR DS:[EDX], 411 ;迴圈開頭,0x411為日文的Language ID
0045D7F9 |. |74 10 | JE SHORT 0045D80B ;跳到最下方的MOV
0045D7FB |. |83C2 04 | ADD EDX,4
0045D7FE |. |83C0 01 | ADD EAX,1
0045D801 |. |3BC1 | CMP EAX,ECX
0045D803 |. |895424 18 | MOV DWORD PTR SS:[ESP+18],EDX
0045D807 |.^\7C EB \ JL SHORT 0045D7F4 ;返回迴圈開頭
0045D809 |. EB 05 JMP SHORT 0045D810 ;跳過下面的MOV
0045D80B |> C64424 16 01 MOV BYTE PTR SS:[ESP+16],1
觀察一下這個函式,可以發現它呼叫了幾個API:
GetFileVersionInfoSize
GetFileVersionInfo
VerQueryValue
查了一下MSDN,這些API可以用來取得某個exe或dll的版本訊息,而其中就包括了
那個exe或dll所支援的語言。
我們進一步跟蹤程式,可以發現SiglusEngine是把kernel32.dll的版本資訊拿來檢查,
若kernel32.dll支援不支援日文就判定為非日本地區。由於kernel32.dll有可能支援數種語言,
引此需要一個迴圈來檢查,以下為原始程式碼:
0045D7F4 |> /66:813A 1104 /CMP WORD PTR DS:[EDX], 411 ;迴圈開頭,0x411為日文的Language ID
0045D7F9 |. |74 10 | JE SHORT 0045D80B ;跳到最下方的MOV
0045D7FB |. |83C2 04 | ADD EDX,4
0045D7FE |. |83C0 01 | ADD EAX,1
0045D801 |. |3BC1 | CMP EAX,ECX
0045D803 |. |895424 18 | MOV DWORD PTR SS:[ESP+18],EDX
0045D807 |.^\7C EB \ JL SHORT 0045D7F4 ;返回迴圈開頭
0045D809 |. EB 05 JMP SHORT 0045D810 ;跳過下面的MOV
0045D80B |> C64424 16 01 MOV BYTE PTR SS:[ESP+16],1
0045D810 |> \3BFB CMP EDI, EBX
以下為C語言的地區檢查函式,使用了上面發現的方法:
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
BOOL isSystemSupportsJapanese() {
HMODULE hVersion = LoadLibrary("version.dll");
FARPROC GetFileVersionInfo = GetProcAddress(hVersion, "GetFileVersionInfoA");
FARPROC GetFileVersionInfoSize = GetProcAddress(hVersion, "GetFileVersionInfoSizeA");
FARPROC VerQueryValue = GetProcAddress(hVersion, "VerQueryValueA");
char* szFileName = "kernel32.dll";
DWORD dwLength = GetFileVersionInfoSize(szFileName, NULL);
PBYTE pBlock = HeapAlloc(GetProcessHeap(), 0, dwLength);
GetFileVersionInfo(szFileName, 0, dwLength, pBlock);
// Read the list of languages and code pages.
UINT cbTranslate;
VerQueryValue(pBlock,
"\\VarFileInfo\\Translation",
(LPVOID*)&lpTranslate,
&cbTranslate);
int i;
BOOL isSupport = FALSE;
TCHAR SubBlock[100];
for( i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ ) {
if(lpTranslate[i].wLanguage ==
MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN)) {
isSupport = TRUE;
break;
}
}
HeapFree(GetProcessHeap(), 0, pBlock);
return isSupport;
}
其中 MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN)
巨集展開之後就是常數0x411。
下一篇就來實現第二種地區檢查吧。
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
BOOL isSystemSupportsJapanese() {
HMODULE hVersion = LoadLibrary("version.dll");
FARPROC GetFileVersionInfo = GetProcAddress(hVersion, "GetFileVersionInfoA");
FARPROC GetFileVersionInfoSize = GetProcAddress(hVersion, "GetFileVersionInfoSizeA");
FARPROC VerQueryValue = GetProcAddress(hVersion, "VerQueryValueA");
char* szFileName = "kernel32.dll";
DWORD dwLength = GetFileVersionInfoSize(szFileName, NULL);
PBYTE pBlock = HeapAlloc(GetProcessHeap(), 0, dwLength);
GetFileVersionInfo(szFileName, 0, dwLength, pBlock);
// Read the list of languages and code pages.
UINT cbTranslate;
VerQueryValue(pBlock,
"\\VarFileInfo\\Translation",
(LPVOID*)&lpTranslate,
&cbTranslate);
int i;
BOOL isSupport = FALSE;
TCHAR SubBlock[100];
for( i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ ) {
if(lpTranslate[i].wLanguage ==
MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN)) {
isSupport = TRUE;
break;
}
}
HeapFree(GetProcessHeap(), 0, pBlock);
return isSupport;
}
其中 MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN)
巨集展開之後就是常數0x411。
下一篇就來實現第二種地區檢查吧。
留言
張貼留言