RPGMaker防破解

一、资源
RPGMaker为了保护原创作者的游戏,提供了加密工具,可以对游戏内资源进行加密处理,这样就算有不怀好意者获得了资源包,也需要花一定时间才能进行破解。
png->rpgmvp
ogg->rpgmvo
m4a->rpgmvm
以下是rpg_core.js对于加密资源的读取操作:

Bitmap.load = function(url) { //资源加载
    var bitmap = new Bitmap();
    bitmap._image = new Image();
    bitmap._url = url;
    bitmap._isLoading = true;
    if(!Decrypter.checkImgIgnore(url) && Decrypter.hasEncryptedImages) { //如果资源进行了加密
        Decrypter.decryptImg(url, bitmap); //资源解密
    } else {
        bitmap._image.src = url;
        bitmap._image.onload = Bitmap.prototype._onLoad.bind(bitmap);
        bitmap._image.onerror = Bitmap.prototype._onError.bind(bitmap);
    }
    return bitmap;
};
Decrypter.decryptImg = function(url, bitmap) { //解密方法
    url = this.extToEncryptExt(url);
    var requestFile = new XMLHttpRequest();
    requestFile.open("GET", url);
    requestFile.responseType = "arraybuffer";
    requestFile.send();
    requestFile.onload = function () {
        if(this.status < Decrypter._xhrOk) {
            var arrayBuffer = Decrypter.decryptArrayBuffer(requestFile.response); //对数据流进行解密
            bitmap._image.src = Decrypter.createBlobUrl(arrayBuffer); //解密后的资源,形成新的资源对象
            bitmap._image.onload = Bitmap.prototype._onLoad.bind(bitmap);
            bitmap._image.onerror = Bitmap.prototype._onError.bind(bitmap);
        }
    };
};
Decrypter.decryptArrayBuffer = function(arrayBuffer) { //解密算法
    if (!arrayBuffer) return null;
    var header = new Uint8Array(arrayBuffer, 0, this._headerlength);
    var i;
    var ref = this.SIGNATURE + this.VER + this.REMAIN;
    var refBytes = new Uint8Array(16);
    for (i = 0; i < this._headerlength; i++) {
        refBytes[i] = parseInt("0x" + ref.substr(i * 2, 2), 16);
    }
    for (i = 0; i < this._headerlength; i++) {
        if (header[i] !== refBytes[i]) {
            throw new Error("Header is wrong");
        }
    }
    arrayBuffer = this.cutArrayHeader(arrayBuffer, Decrypter._headerlength);
    var view = new DataView(arrayBuffer);
    this.readEncryptionkey();
    if (arrayBuffer) {
        var byteArray = new Uint8Array(arrayBuffer);
        for (i = 0; i < this._headerlength; i++) {
            byteArray[i] = byteArray[i] ^ parseInt(Decrypter._encryptionKey[i], 16); //使用秘钥进行解密
            view.setUint8(i, byteArray[i]);
        }
    }
    return arrayBuffer; //返回解密后的数据量,供后续使用
};

可以看出,由于游戏的单机化,_encryptionKey会直接存储至客户端,相当于将秘钥直接提供给了对方。当对方拿到_encryptionKey并利用解密算法,很快加密资源就会被破解。

现在我们知道了_encryptionKey的重要性,就可以对_encryptionKey进行进一步的处理,让那些想破解游戏的人耗费更多的精力,增加破解成本。

Decrypter.readEncryptionkey = function(){ //读取_encryptionKey
    this._encryptionKey = $dataSystem.encryptionKey.split(/(.{2})/).filter(Boolean);
};

以上是正常情况下获取_encryptionKey的方法,实质就是System.json中encryptionKey的读取拆分进数组,供解密使用。
我们可以直接将System.json中encryptionKey删除,使其隐藏。
那么我们怎么才能在资源加载的时候进行资源解密呢?
你可以将你的encryptionKey任意拆分并隐藏在任意的代码迷宫中,等使用的时候通过各种方法提取出来使用,这样你的encryptionKey就不会那么明显的直接暴露,当然这样的做法也只是增加破解成本,安了心要破解也是挡不住的。
以下是部分防解密代码:

......
arrayBuffer = this.cutArrayHeader(arrayBuffer, Decrypter._headerlength);
    var view = new DataView(arrayBuffer);
    if (arrayBuffer) {
        this.f_drillUP(view,arrayBuffer);
        this.f_DRilluP(view,arrayBuffer);
        this.f_dRiLlUp(view,arrayBuffer);
        this.f_DrILLUp(view,arrayBuffer);
        this.f_drILLup(view,arrayBuffer);
        this.f_dRIlLuP(view,arrayBuffer);
    }
.......
Decrypter.code_map_drillup = ['3d','58','a4','70','38','5c','81','6c','ad','0c','8c','ad','cd','93','67','68','08','3d','86','23','7b','38','93','67','02','7f','6e','60','41','ee','bb','88','0a','e1','ac','9a','0d','78','38','19','2b','ad','f4','f4','61','bc','7f','1c','dc','75','69','49','93','d7','20','84','e3','e4','e1','c0','52','97','f4','41','62','70','1c','26','c3','09','d3','3e','18','7b','41','84','42','01','47','c3','2c','eb','b0','b5','03','3d','38','93','d4','9f','23','81','da','7c','2b','1b','03','20','6c','41'];
Decrypter.map_code_DrILLup = [32,37,80,24,71,1,87,89,74,84,67,69,9,44,5,61,21,78,2,31,33,27,34,4,70,81,6,58,18,45,54,35];
Decrypter.map_code_DrIlLuP = [66,90,36,44,37,87,75,48,56,68,61,13,84,82,55,98,50,14,46,95,83,60,17,0,27,94,24,38,30,34,45,99];
Decrypter.map_code_dRILlup = [20,40,76,89,5,87,56,94,6,82,31,37,11,50,96,98,55,88,22,81,65,74,19,66,24,90,33,48,57,71,70,83];
Decrypter.map_code_dRiLlup = [0,93,45,79,20,27,77,72,88,71,96,80,8,94,16,15,26,3,61,60,40,41,81,31,2,73,42,34,76,39,86,65];
Decrypter.map_code_drILLup = [36,9,40,79,62,82,57,67,61,94,90,12,98,52,75,28,60,44,4,32,48,64,93,30,51,35,72,88,89,14,3,38];
Decrypter.map_code_DRillup = [61,46,87,31,13,41,33,12,45,71,29,15,79,83,44,39,30,64,97,56,21,25,6,93,3,23,78,85,98,38,59,68];
......
Decrypter.n_dRILLup = function(drILlUP, drIlLuP){ return parseInt(this.code_map_drillup[this.map_code_dRILLUp[drILlUP+9]], 16); }
Decrypter.n_dRillUp = function(drIlLUp, dRilLuP){ return parseInt(this.code_map_drillup[this.map_code_dRILluP[drIlLUp+10]], 16); }
Decrypter.n_drIllUP = function(DRIlLUp, DriLlup){ return parseInt(this.code_map_drillup[this.map_code_drillUP[DRIlLUp+9]], 16); }
Decrypter.n_dRilluP = function(dRillUp, driLluP){ return parseInt(this.code_map_drillup[this.map_code_driLLUp[dRillUp+10]], 16); }
Decrypter.n_driLLUp = function(DRiLLup, DrillUp){ return parseInt(this.code_map_drillup[this.map_code_DRiLluP[DRiLLup+2]], 16); }
Decrypter.n_DrIlLup = function(DrILLuP, DriLluP){ return parseInt(this.code_map_drillup[this.map_code_drILLUP[DrILLuP+11]], 16); }
Decrypter.n_DRIlLuP = function(DRilLup, dRiLLUp){ return parseInt(this.code_map_drillup[this.map_code_DRillup[DRilLup+0]], 16); }
Decrypter.n_DRIlluP = function(DRIllUP, dRilLup){ return parseInt(this.code_map_drillup[this.map_code_DrilLup[DRIllUP+11]], 16); }
Decrypter.n_DrILLup = function(DrIlLUP, drILluP){ return parseInt(this.code_map_drillup[this.map_code_dRILlUp[DrIlLUP+1]], 16); }
......

二、插件
辛苦写的自用插件(开源插件大神勿喷),是否也不想让他人破解,或者插件内有部分与服务端的交互过程,那就更不想让别人破解了。
市面上已经有很多对JS文件进行混淆加密的方法,最近接触了一个号称“最牛加密”的方法,据说绝对绝对无法100%破解,亲试了一波,破解起来确实有难度,相当耗费精力,确实牛。

//源码
var a={},b={}; 
(function(w, d) { 
 w.info = "这是一个一系列js操作。"; 
 d.adinfo = "站长接高级 “JS加密” 和 “JS解密” ,保卫你的 js。"; 
 d.warning = "如果您的JS里嵌套了PHP,JSP标签,等等其他非JavaScript的代码,请提取出来再加密。这个工具不能加密php、jsp等模版内容"; 
})(a, b);
//混淆加密后 
;var encode_version = 'sojson.v5', bvale = '',  _0x137b=['5YqG6ZiF54mO5pyf5Y2S77++bBTkvbvlrajmnrXlvq/nq6s=','w6U8w4BYbw==','AsOLw6FwEg==','SCjDvsO0w7U=','54mX5py+5Y+R77+BwrQN5L+w5ayq5p2R5b2956qW77676L+S6K6q5pWx5oyg5oq65Lu/55mf5bWl5L20','RnfCsm4i','5Ymw6Zi+54mv5p2k5YyF776fQhnkvqHlr5/mnI/lv5znq78=','w5TCnk9+','w4HDgcK9aEc=','56ug6ZeT5oyP6aue57u7wonigJ1+ReWKj+WspeKDs2nlkp7DouKAjMO8w4nopI/lrLPig70Q776k5L6p5Y6f5L2T55ilWcOUP+ODvw==','5aad5p6O5oKO55mJwpQt6YSm5be85aSZ5LuCUcO/Wu+9kRRyw7vmoJTnrqXvvoznraHnrJnlhLPkurPpn4YyA8OqN8OiwpvDmsOEAcO655ir5LqD56KI772w6K+t5o2l5Y2r5YSV5p6q5YSb5YqF5a+o44KC6Lyt5LiQ5beU5Yav5LiN6IOr5YmJ5a2Nw5M0w4XjgKbDlUJu56y+5qiH54q05YeG5a+E','JTRDLcKUw7pGD8Of','w5svwoLDqMO1wprDri4s','WnLCqw=='];(function(_0x59cc19,_0xa33bc6){var _0x373186=function(_0x22fb36){while(--_0x22fb36){_0x59cc19['push'](_0x59cc19['shift']());}};_0x373186(++_0xa33bc6);}(_0x137b,0x157));var _0x8d27=function(_0x25ef43,_0x21b8e7){_0x25ef43=_0x25ef43-0x0;var _0x8bcc7b=_0x137b[_0x25ef43];if(_0x8d27['initialized']===undefined){(function(){var _0x2a5348=typeof window!=='undefined'?window:typeof process==='object'&&typeof require==='function'&&typeof global==='object'?global:this;var _0x3ccd8f='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';_0x2a5348['atob']||(_0x2a5348['atob']=function(_0x3e8e4b){var _0x3ff844=String(_0x3e8e4b)['replace'](/=+$/,'');for(var _0x28af07=0x0,_0x27609d,_0x5b63d7,_0x31e66f=0x0,_0x4ec419='';_0x5b63d7=_0x3ff844['charAt'](_0x31e66f++);~_0x5b63d7&&(_0x27609d=_0x28af07%0x4?_0x27609d*0x40+_0x5b63d7:_0x5b63d7,_0x28af07++%0x4)?_0x4ec419+=String['fromCharCode'](0xff&_0x27609d>>(-0x2*_0x28af07&0x6)):0x0){_0x5b63d7=_0x3ccd8f['indexOf'](_0x5b63d7);}return _0x4ec419;});}());var _0x266b43=function(_0x4446b9,_0x3fd172){var _0x286dc7=[],_0x3b68a7=0x0,_0x5bd2f9,_0x2be62e='',_0x4653b5='';_0x4446b9=atob(_0x4446b9);for(var _0x4d07e4=0x0,_0x190db4=_0x4446b9['length'];_0x4d07e4<_0x190db4;_0x4d07e4++){_0x4653b5+='%'+('00'+_0x4446b9['charCodeAt'](_0x4d07e4)['toString'](0x10))['slice'](-0x2);}_0x4446b9=decodeURIComponent(_0x4653b5);for(var _0x3eebc8=0x0;_0x3eebc8<0x100;_0x3eebc8++){_0x286dc7[_0x3eebc8]=_0x3eebc8;}for(_0x3eebc8=0x0;_0x3eebc8<0x100;_0x3eebc8++){_0x3b68a7=(_0x3b68a7+_0x286dc7[_0x3eebc8]+_0x3fd172['charCodeAt'](_0x3eebc8%_0x3fd172['length']))%0x100;_0x5bd2f9=_0x286dc7[_0x3eebc8];_0x286dc7[_0x3eebc8]=_0x286dc7[_0x3b68a7];_0x286dc7[_0x3b68a7]=_0x5bd2f9;}_0x3eebc8=0x0;_0x3b68a7=0x0;for(var _0x10f6e0=0x0;_0x10f6e0<_0x4446b9['length'];_0x10f6e0++){_0x3eebc8=(_0x3eebc8+0x1)%0x100;_0x3b68a7=(_0x3b68a7+_0x286dc7[_0x3eebc8])%0x100;_0x5bd2f9=_0x286dc7[_0x3eebc8];_0x286dc7[_0x3eebc8]=_0x286dc7[_0x3b68a7];_0x286dc7[_0x3b68a7]=_0x5bd2f9;_0x2be62e+=String['fromCharCode'](_0x4446b9['charCodeAt'](_0x10f6e0)^_0x286dc7[(_0x286dc7[_0x3eebc8]+_0x286dc7[_0x3b68a7])%0x100]);}return _0x2be62e;};_0x8d27['rc4']=_0x266b43;_0x8d27['data']={};_0x8d27['initialized']=!![];}var _0x3eb94f=_0x8d27['data'][_0x25ef43];if(_0x3eb94f===undefined){if(_0x8d27['once']===undefined){_0x8d27['once']=!![];}_0x8bcc7b=_0x8d27['rc4'](_0x8bcc7b,_0x21b8e7);_0x8d27['data'][_0x25ef43]=_0x8bcc7b;}else{_0x8bcc7b=_0x3eb94f;}return _0x8bcc7b;};var a={},b={};(function(_0x1dd944,_0x1f3eb4){var _0x4be34d={'BRtje':'这是一个一系列js操作。'};_0x1dd944[_0x8d27('0x0','07(1')]=_0x4be34d[_0x8d27('0x1','Q!^g')];_0x1f3eb4['adinfo']=_0x8d27('0x2','U9@6');_0x1f3eb4['warning']=_0x8d27('0x3','Jl1#');}(a,b));;(function(_0x40d200,_0x3bd66e,_0x436c33){var _0x39d952={'khnMW':_0x8d27('0x4','giYA'),'grwTF':function _0x5744af(_0x4e153c,_0x3ecf15){return _0x4e153c===_0x3ecf15;},'WcNOU':_0x8d27('0x5','[%ul'),'DOoHM':function _0xd9761c(_0x300650,_0x4c62d2){return _0x300650!==_0x4c62d2;},'dgdcl':_0x8d27('0x6','os)m'),'eDNQj':_0x8d27('0x7','1)yn')};_0x436c33='al';try{_0x436c33+='ert';_0x3bd66e=encode_version;if(!(typeof _0x3bd66e!==_0x39d952[_0x8d27('0x8','vc#s')]&&_0x39d952[_0x8d27('0x9','MSHW')](_0x3bd66e,_0x39d952['WcNOU']))){if(_0x39d952[_0x8d27('0xa','Y9iI')](_0x39d952['dgdcl'],'kkj')){_0x40d200[_0x436c33]('删除'+_0x8d27('0xb','Jl1#'));}else{_0x40d200[_0x436c33](_0x39d952[_0x8d27('0xc','os)m')]);}}}catch(_0x11f794){_0x40d200[_0x436c33](_0x8d27('0xd','giYA'));}}(window));;encode_version = 'sojson.v5';

三、游戏数据检测
这个方法对破解玩家不是很友好。有两个思路:
1、本地检测,针对一些关键数据,在游戏加载过程中,进行数据(玩家游戏时长与各项成长数值关系,物品、装备等持有量)的校验,如果超出阈值,则提示玩家,强制结束游戏。当然这需要充分考虑游戏的各项数值极限,避免伤害到正常玩家,毕竟玩家体验第一。
2、远端检测,这需要与后端服务进行交互,实际已经不是那么单纯的单机游戏,每个玩家在后端都有唯一的账号,创造者可以定期分析玩家数据,进行非法玩家的探测,及时发现非法玩家,并剔除(封禁)账号。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352