CCUserDefault 以明文 XML 儲存遊戲資料(金幣、等級、道具),玩家可直接修改 UserDefault.xml 作弊。引入摘要演算法(Hash)可偵測資料竄改:寫入時計算資料+密鑰的摘要並存檔;讀取時重新計算比對,不一致即判定作弊。
常見摘要演算法有 MD5、SHA-1、SHA-256。SHA-1 安全性足夠應對單機遊戲,且有極輕量的實現(tamale.net 提供 sha1.h/cpp 兩檔案,無第三方依賴)。
下載 sha1.h、sha1.cpp 加入專案,並確保編譯選項支援 C++11。
// AppDelegate.cpp
#include <tchar.h>
bool AppDelegate::applicationDidFinishLaunching() {
_tsetlocale(LC_ALL, _T(""));
::AllocConsole();
::freopen("conout$", "w", stdout);
// ... 原有初始化程式碼
}
#define SAVE_KEY "goldlion" // 硬編碼密鑰,實際專案建議加密或動態生成
#define SAVE_TAG "player_gold"
void SaveWithHash(int gold) {
CCUserDefault* save = CCUserDefault::sharedUserDefault();
char buf[32];
sprintf(buf, "%d", gold);
save->setStringForKey(SAVE_TAG, buf);
// 計算 SHA-1(data + key)
SHA1* sha1 = new SHA1();
sha1->addBytes(buf, strlen(buf));
sha1->addBytes(SAVE_KEY, strlen(SAVE_KEY));
unsigned char* digest = sha1->getDigest(); // 20 bytes
// 存儲十六進位摘要
char hexDigest[41];
for (int i = 0; i < 20; ++i) sprintf(hexDigest + i*2, "%02x", digest[i]);
save->setStringForKey(std::string(SAVE_TAG) + "_hash", hexDigest);
delete sha1;
free(digest);
save->flush();
}
bool LoadWithHash(int& outGold) {
CCUserDefault* save = CCUserDefault::sharedUserDefault();
std::string data = save->getStringForKey(SAVE_TAG);
std::string storedHash = save->getStringForKey(std::string(SAVE_TAG) + "_hash");
SHA1* sha1 = new SHA1();
sha1->addBytes(data.c_str(), data.length());
sha1->addBytes(SAVE_KEY, strlen(SAVE_KEY));
unsigned char* digest = sha1->getDigest();
char calcHash[41];
for (int i = 0; i < 20; ++i) sprintf(calcHash + i*2, "%02x", digest[i]);
delete sha1;
free(digest);
if (storedHash != calcHash) {
CCLOG("存檔校驗失敗:資料已被竄改!");
return false;
}
outGold = atoi(data.c_str());
return true;
}
UserDefault.xml 中的 player_gold 值 → 讀取時校驗失敗,偵測到作弊。

SetIntegerForKeyWithHash、GetIntegerForKeyWithHash 等模板函數,支援 int、float、bool 等型別。ENABLE_SAVE_VERIFY 控制校驗開關,測試階段關閉方便修改存檔,發布時開啟。SHA-1 摘要加密鑰的方式,以極低成本實現了存檔防篡改。雖非絕對安全(客戶端程式碼可被逆向),但足以阻擋 99% 普通玩家的修改器作弊,是單機遊戲存檔保護的性價比之選。