
디바이스 정보에서 "빌드 번호" 항목을 연속해서 7회에서 9회 정도를 연속으로 누르면 "개발자 모드가 실행 되었습니다" 라는 문구가 나오면서 활성화 된다. 상위로 가서 개발자 옵션이 활성화 되었는지 확인해 보자.

int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException
{
....
if (Security.verifyPurchase(mSignatureBase64, purchaseData, signature)) {
logDebug("Sku is owned: " + sku);
Purchase purchase = new Purchase(itemType, purchaseData, signature);
// Record ownership and token
inv.addPurchase(purchase);
}
else {
logWarn("Purchase signature verification **FAILED**. Not adding item.");
logDebug(" Purchase data: " + purchaseData);
logDebug(" Signature: " + signature);
verificationFailed = true;
}
....
public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
...
Purchase purchase = null;
try {
purchase = new Purchase(mPurchasingItemType, purchaseData, dataSignature);
String sku = purchase.getSku();
// Verify signature
// bisuit_jump
/*
if (!Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) {
logError("Purchase signature verification FAILED for sku " + sku);
result = new IabResult(IABHELPER_VERIFICATION_FAILED, "Signature verification failed for sku " + sku);
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, purchase);
return true;
}
*/
logDebug("Purchase signature successfully verified.");
...
/* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
* (that you got from the Google Play developer console). This is not your
* developer public key, it's the *app-specific* public key.
*
* Instead of just storing the entire literal string here embedded in the
* program, construct the key at runtime from pieces or
* use bit manipulation (for example, XOR with some other string) to hide
* the actual key. The key itself is not secret information, but we don't
* want to make it easy for an attacker to replace the public key with one
* of their own and then fake messages from the server.
*/
String base64EncodedPublicKey = "CONSTRUCT_YOUR_KEY_AND_PLACE_IT_HERE";
String piece1 = "SDFGJKGB4UIH234WE/FRT23RS#trashdata#DF/3DFUISDFVWE";
String piece2 = "SDFGJKGB4UIHUI#trashdata#SDFVWE";
String piece3 = "BDY#trashdata#ASGBDNAWGRET24IYE23das4saGBENWKD";
String piece4 = "#trashdata#432423SDF23R/+SDDS";
mHelper = new IabHelper(this, piece1.substring(...) + piece2.substring(...) + piece3.substring(...) + piece4.substring(...));
이런식으로만 해 두어도 난이도가 올라간다. 크래커입장에서는 이 키를 자기자신의 키로 변경하고자 시도할텐데, 일반 문자열로 들어가 있으면 식은죽 먹기일테지.
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
if(purchase != null){
// provision the in-app purchase to the user
verifyBilling(purchase.getSignature(), purchase.getOriginalJson());
} else {
LogToServer("onConsumeFinished:purchase=null");
}
} else {
LogToServer("onConsumeFinished:consume=failed");
}
}
int InappBillingVerify(const char* data, const char* signature, const char* pub_key_id) { std::shared_ptr<EVP_MD_CTX> mdctx = std::shared_ptr<EVP_MD_CTX>(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); const EVP_MD* md = EVP_get_digestbyname("SHA1"); EVP_VerifyInit_ex(mdctx.get(), md, NULL); EVP_VerifyUpdate(mdctx.get(), (void*)data, strlen(data)); std::shared_ptr<BIO> b64 = std::shared_ptr<BIO>(BIO_new(BIO_f_base64()), BIO_free); BIO_set_flags(b64.get(),BIO_FLAGS_BASE64_NO_NL); std::shared_ptr<BIO> bPubKey = std::shared_ptr<BIO>(BIO_new(BIO_s_mem()), BIO_free); BIO_puts(bPubKey.get(),pub_key_id); BIO_push(b64.get(), bPubKey.get()); std::shared_ptr<EVP_PKEY> pubkey = std::shared_ptr<EVP_PKEY>(d2i_PUBKEY_bio(b64.get(), NULL), EVP_PKEY_free); std::string decoded_signature = Base64Decode(std::string(signature)); return EVP_VerifyFinal(mdctx.get(), (unsigned char*)decoded_signature.c_str(), decoded_signature.length(), pubkey.get()); }
String s = "소곤소곤abcd"; System.out.println(s.length()); // 8
String s = "소곤소곤abcd"; byte[] buf = s.getBytes(); // using DefaultCharset System.out.println(buf.length); // 16이 경우는, 메모리상에 위치할 실제 바이트수를 알아낼 수 있다. 잠깐! 한글은 2바이트니깐 결과값이 12일텐데 16이라고??? 12도 맞고 16도 맞다. 내 시스템의 eclipse는 UTF-8로 세팅되어 있고, 여기서 한글 한글자는 3바이트를 차지한다. 즉, 결과값은 이 코드가 동작하는 시스템의 기본 인코딩이 뭐냐에 달려있다.
String s = "소곤소곤abcd"; System.out.println(s.getBytes("UTF-8").length);하지만 그냥은 런타임에러가 난다. 엔코딩실패를 대비해서 try catch로 감싸주어야 한다. 함수로 만들어 보았다.
public int getRealSize(String text) { int size = -1; try { size = text.getBytes("UTF-8").length; } catch (UnsupportedEncodingException e1){ } return size; }이종시스템간 데이터교환 (특히 클라이언트-서버방식의 게임)에서는 항상 주의해야 한다.