這次來分析SiglusEngine的第二種與第三種檢查地區的方式。
在這之前可以先看一下之前的一些結果:
SiglusEngine地區限制破解
SiglusEngine地區檢查分析(一)
第二個檢查函式在這個地方:
0045DD10 /> E8 8BFCFFFF CALL 0045D9A0 ;檢查
0045DD15 |. 84C0 TEST AL,AL
0045DD17 \. E9 EA000000 JMP 0045DE06
0045DD1C 90 NOP
按F7跟進去,乍看之下沒什麼線索,不過有一個地方讓我比較在意:
0045D9E5 |. 50 PUSH EAX ; /Arg1 = 1
0045D9E6 |. B9 782D7C00 MOV ECX,OFFSET 007C2D78 ; |UNICODE "0411"
0045D9EB |. C64424 50 01 MOV BYTE PTR SS:[ESP+50],1 ; |
0045D9F0 |. E8 4BA0FBFF CALL 00417A40 ; \SiglusEngine.00417A40
在這之前可以先看一下之前的一些結果:
SiglusEngine地區限制破解
SiglusEngine地區檢查分析(一)
第二個檢查函式在這個地方:
0045DD10 /> E8 8BFCFFFF CALL 0045D9A0 ;檢查
0045DD15 |. 84C0 TEST AL,AL
0045DD17 \. E9 EA000000 JMP 0045DE06
0045DD1C 90 NOP
按F7跟進去,乍看之下沒什麼線索,不過有一個地方讓我比較在意:
0045D9E5 |. 50 PUSH EAX ; /Arg1 = 1
0045D9E6 |. B9 782D7C00 MOV ECX,OFFSET 007C2D78 ; |UNICODE "0411"
0045D9EB |. C64424 50 01 MOV BYTE PTR SS:[ESP+50],1 ; |
0045D9F0 |. E8 4BA0FBFF CALL 00417A40 ; \SiglusEngine.00417A40
"0411"很眼熟不是嗎? 這正是是日文的Language ID,顯然這裡是從某處得到系統語言
的Language ID的字串形式,然後再拿那個字串跟 "0411"比較。
於是我接著跟蹤了附近的幾個函式,很快就找到我要的東西了:
0045D936 |. 68 00040000 PUSH 400 ; /Count = 1024.
0045D93B |. 8D4C24 10 LEA ECX,[ESP+10] ; |
0045D93F |. 51 PUSH ECX ; |pData => OFFSET LOCAL.512
0045D940 |. 6A 01 PUSH 1 ; |LCType = 1
0045D942 |. 68 00080000 PUSH 800 ; |Locale = LOCALE_SYSTEM_DEFAULT
0045D947 |. FF15 24D27700 CALL DWORD PTR DS:[<&KERNEL32.GetLocaleInfoW>] ; GetLocaleInfoW
GetLocaleInfo是依照LCType參數來決定取得的資料,在 WinNls.h中有這麼一個定義:
#define LOCALE_ILANGUAGE 0x00000001 // language id, LOCALE_SNAME preferred
引此可以知道這個GetLocaleInfo目的就是為了取得系統語言的Language ID的字串形式。
以下為C語言的地區檢查函式,使用了上方的演算法:
BOOL isSystemLanguageJapanese() {
char buffer[50];
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, buffer, 50);
return (strcmp(buffer, "0411") == 0)? TRUE: FALSE;
}
第三種檢查方式其實跟蹤的方法也是一樣,這裡就直接把關鍵的地方列出來好了:
0045DA99 |. 51 PUSH ECX
0045DA9A |. FF15 20D27700 CALL DWORD PTR DS:[<&KERNEL32.GetTimeZoneInformation>]
BOOL isSystemLanguageJapanese() {
char buffer[50];
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, buffer, 50);
return (strcmp(buffer, "0411") == 0)? TRUE: FALSE;
}
第三種檢查方式其實跟蹤的方法也是一樣,這裡就直接把關鍵的地方列出來好了:
0045DA99 |. 51 PUSH ECX
0045DA9A |. FF15 20D27700 CALL DWORD PTR DS:[<&KERNEL32.GetTimeZoneInformation>]
GetTimeZoneInformation會取得一個 TIME_ZONE_INFORMATION 結構,其定義如下:
typedef struct _TIME_ZONE_INFORMATION {
LONG Bias;
WCHAR StandardName[32];
SYSTEMTIME StandardDate;
LONG StandardBias;
WCHAR DaylightName[32];
SYSTEMTIME DaylightDate;
LONG DaylightBias;
} TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION;
typedef struct _TIME_ZONE_INFORMATION {
LONG Bias;
WCHAR StandardName[32];
SYSTEMTIME StandardDate;
LONG StandardBias;
WCHAR DaylightName[32];
SYSTEMTIME DaylightDate;
LONG DaylightBias;
} TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION;
日光節約時間可以不去管它,其他可以用來判斷時區的就是 Bias以及StandardName兩個成員了。不過跟蹤程式碼可以發現,SiglusEngine只使用了StandardName作為判斷的依據,
判斷方法很簡單,就是比較 StandardName的前五個字元是否為 "TOKYO",相關程式碼如下:
0045DB90 |> \6A 05 PUSH 5 ; /Arg1 = 5
0045DB92 |. 33C9 XOR ECX,ECX ; |
0045DB94 |. 8D7424 14 LEA ESI,[ESP+14] ; |
0045DB98 |. 8D5424 30 LEA EDX,[ESP+30] ; |
0045DB9C |. E8 CF650000 CALL 00464170 ; \SiglusEngine.00464170
0045DBA1 |. 50 PUSH EAX ; /Arg1
0045DBA2 |. B9 8C2D7C00 MOV ECX,OFFSET 007C2D8C ; |UNICODE "TOKYO"
0045DBA7 |. C64424 58 02 MOV BYTE PTR SS:[ESP+58],2 ; |
0045DBAC |. E8 8F9EFBFF CALL 00417A40 ; \SiglusEngine.00417A40
C語言的實作也很簡單:
BOOL isJapanTimeZone() {
TIME_ZONE_INFORMATION tzi;
GetTimeZoneInformation(&tzi);
return (memcmp(tzi.StandardName, L"TOKYO", sizeof(wchar_t)*wcslen(L"TOKYO")) == 0)? TRUE: FALSE;
}
C語言的實作也很簡單:
BOOL isJapanTimeZone() {
TIME_ZONE_INFORMATION tzi;
GetTimeZoneInformation(&tzi);
return (memcmp(tzi.StandardName, L"TOKYO", sizeof(wchar_t)*wcslen(L"TOKYO")) == 0)? TRUE: FALSE;
}
至此SiglusEngine的地區檢查分析完畢,其中的C代碼都是經過編譯以及實際測試的,使用時
記得包含 windows.h 即可。
留言
張貼留言