FantasyDR 发表于 2006-7-18 01:10:23

[广告]想保护自己的游戏么?[2007.9.2更新]

假如您早就对RMXP的破解有所耳闻……
假如您希望加密可以真正保护您的知识产权……
假如您不愿让浸透血汗的作品沦为他人解剖的样本……

那么,您还是放弃RMXP吧!!

啊呀呀,说错广告词了。应该是:
脚本漏洞修补程序为您服务=.=

所谓漏洞修补程序,一贯作风,就不详细解释原理,只说修补的部分。
修补了脚本事件执行时,没有过滤危险脚本的漏洞。

题外话:
看日期就知道,老早写的……之所以放,是因为先是《Aveyond》,然后是《契约之绊》
大家都被华丽的拆了,老实说拆的还真辛苦,动用了这么多工具,算是综合实力的体现伐?
我继续猜下,某些作品是不是怕拆了然后放出来会被拍死,所以没有放呢?
早就说过,既然都把商业游戏拆成那样了,就不能放过那点RMXP游戏么?
哈哈,还真是一个都不放过,这叫什么来着?

对了,一个都不能少!

拆的这么过瘾,怕也没空干别的了,最多做做demo,都是不值一拆的东西。
因为自己的东西没有加密的意义了,所以也剥夺别人的么?=.=
恶呵呵,那么偶不厚道的说下啊,有些人天天叫唤拆啊拆啊拆别人的,那么自己也别加密了。
等你有一天又想加密的时候,别忘记,你已经丧失了加密的权利。
衷心希望别出现这一天哦~~

这个脚本没有经过严格的测试,但是基本保证可以防御三流拆卸工,不妨试试看。
经3E的提醒,继续更新……
经柳之一提醒,发现依旧有漏洞,再次可耻更新。不过……请别对这个脚本太认真,关键是下面的存档更新脚本。
经さくら提醒,的确还有好多情况没有考虑进去,于是7.18下午更新了一次……
转载请注明本贴URL并保持脚本的完整性
#==============================================================================
# ☆★☆ Eval Checker ☆★☆
#------------------------------------------------------------------------------
# - FantasyDR
#------------------------------------------------------------------------------
# MSN: FantasyDR_SJL@hotmail.com
#------------------------------------------------------------------------------
# - 2007.9.2
# - 改正了一些错误的判断条件……可能会导致误判。
# - 2007.9.1
# 添加了新的过滤词汇,感谢柳之一的提醒。
# 这个脚本功能有限,心理效用大于实际效用。
# 我就聊胜于无的继续更新下吧~
# - 2006.7.18
# 更新了脚本过滤不严格的漏洞。-.-|||
# 感谢さくら的提醒。大家一起来完善吧~
# - 2006.3.6
# 第一版
#------------------------------------------------------------------------------
# 运行脚本事件之前检测是否含有恶意代码
#==============================================================================

#==============================================================================
# ■ Eval Checker
#------------------------------------------------------------------------------
# 语法检测的类,使用HASH表来存检查结果
#==============================================================================
class Eval_Checker
attr_accessor :alarm # 出现错误是否报告
#--------------------------------------------------------------------------
# ● 初始化对像
#--------------------------------------------------------------------------
def initialize
    @code_hash = {}
    @alarm = true
end
#--------------------------------------------------------------------------
# ● 检测代码
#--------------------------------------------------------------------------
def test(code)
    if !code.is_a?(String)
      return true
    elsif @code_hash != nil
      result = @code_hash
    else
      result = true
      # 禁止alias重命名
      if code[/[\W]*alias[\W]/] != nil
      result = false
      # 禁止require加载文件
      elsif code[/[\W]*require[\s]*[^\w\[]/] != nil
      result = false
      # 禁止打印
      elsif code[/[\W]*[\s]*[^\w\[]/] != nil
      result = false
      # 禁止打印
      elsif code[/[\W]*print[\W]/] != nil
      result = false
      # 禁止Marshal模块
      elsif code[/[\W]*Marshal[\s]*[^\w\[]/] != nil
      result = false
      # 禁止save_data方法
      elsif code[/[\W]*save_data[\s]*[^\w\[]/] != nil
      result = false
      # 禁止load_data方法
      elsif code[/[\W]*load_data[\s]*[^\w\[]/] != nil
      result = false
      # 禁止load方法
      elsif code[/[\W]*load[\s]*[^\w\[]/] != nil
      result = false
      # 禁止调用API
      elsif code[/[\W]*Win32API[\s]*[^\w\[]/] != nil
      result = false
      # 禁止调用文件方法
      elsif code[/[\W]*File[\s]*[^\w\[]/] != nil
      result = false
      # 禁止使用eval
      elsif code[/[\W]*eval[\W]/] != nil
      result = false
      end
      @code_hash = result
    end
    if !result and @alarm
      print("=====非法脚本=====\n",code)
    end
    return result
end
end

# 实例化一个全局Checker
$FDR_EC = Eval_Checker.new

#==============================================================================
# ■ Game_Character
#==============================================================================

class Game_Character
alias :fdr_EC_Game_Character_move_type_custom :move_type_custom
#--------------------------------------------------------------------------
# ● 移动类型 : 自定义
#--------------------------------------------------------------------------
def move_type_custom
    i = @move_route_index
    while i < @move_route.list.size
      command = @move_route.list
      # 脚本
      if command.code == 45 and !$FDR_EC.test(command.parameters)
      @move_route_index += 1
      return
      end
      i += 1
    end
    return fdr_EC_Game_Character_move_type_custom
end
end

#==============================================================================
# ■ Interpreter
#==============================================================================

class Interpreter
alias :fdr_EC_Interpreter_command_111 :command_111
alias :fdr_EC_Interpreter_command_355 :command_355
#--------------------------------------------------------------------------
# ● 条件分支
#--------------------------------------------------------------------------
def command_111
    # 脚本
    if @parameters == 12 and !$FDR_EC.test(@parameters)
      return command_skip
    end
    return fdr_EC_Interpreter_command_111
end

#--------------------------------------------------------------------------
# ● 脚本
#--------------------------------------------------------------------------
def command_355
    i = @index
    while i < @list.size
      return true unless $FDR_EC.test(@list.parameters)
      break unless @list.code == 655 or @list.code == 355
      i += 1
    end
    return fdr_EC_Interpreter_command_355
end
end

二楼是存档自定义的脚本……包含存档校验。

FantasyDR 发表于 2006-7-18 01:11:55

做成通用版本了……有兴趣的可以实验一下,保险起见可以和顶楼的脚本一起使用。
仅仅做存档自定义,根本无法避免恶意存档修改。所以再次重申自己的观点,许多日方的RM游戏自定义存档不是因为防范漏洞,不过是游戏内容需要而已。因为那边没有人这样拆……我们则不同,还是加上存档的校验比较保险。

脚本功能为:生成自定义的压缩存档,存档包含合法性校验,校验同密钥相关。
在main之前加入即可,防止存档恶意修改,不合法存档不予读取。
注意,请在使用前先把密钥更改为自己的值,不要使用默认的1234567
转载请注明本贴URL并保持脚本的完整性

#==============================================================================
# ☆★☆ Custom Save☆★☆
#------------------------------------------------------------------------------
# - FantasyDR
#------------------------------------------------------------------------------
# MSN: FantasyDR_SJL@hotmail.com
#------------------------------------------------------------------------------
# - 2006.7.18
#------------------------------------------------------------------------------
# 自定义存档数据排列顺序并校验存档
#==============================================================================

#==============================================================================
# ■ Scene_File
#------------------------------------------------------------------------------
#  存档画面及读档画面的超级类。
#==============================================================================

class Scene_File
#--------------------------------------------------------------------------
# ● 存档密钥,请定义成自己的密钥
#    密钥不同的存档将无法被读取
#--------------------------------------------------------------------------
SAVE_KEY = 1234567
#--------------------------------------------------------------------------
# ● 存档号码最大值
#    默认0~3共4个存档,如果需要大于4个存档,需要改动窗口类。
#    这里不提供大于4个存档的窗口排布,如果有需要请自己定义。
#--------------------------------------------------------------------------
SAVE_MAX = 3
#--------------------------------------------------------------------------
# ● 初始化对像
#   help_text : 帮助窗口显示的字符串
#--------------------------------------------------------------------------
def initialize(help_text,type = "档案",save_max = SAVE_MAX)
    @help_text = help_text
    @save_max = save_max
    @type = type
end
#--------------------------------------------------------------------------
# ● 主处理
#--------------------------------------------------------------------------
def main
   
    # 生成存档选择
    save_list = []
    for i in 1..@save_max+1
      save_list.push(@type+i.to_s)
    end   
    # 生成帮助窗口
    @help_window = Window_Help.new
    @help_window.set_text(@help_text)
    # 生成存档文件查
    @savefile_windows = []
    for i in 0..@save_max
      @savefile_windows.push(Window_SaveFile.new(i, make_filename(i)))
    end
    # 选择最后操作的文件
    @file_index = $game_temp.last_file_index
    @savefile_windows[@file_index].selected = true
    # 执行过渡
    Graphics.transition
    # 主循环
    loop do
      # 刷新游戏画面
      Graphics.update
      # 刷新输入信息
      Input.update
      # 刷新画面
      update
      # 如果画面被切换的话就中断循环
      if $scene != self
      break
      end
    end
    # 准备过渡
    Graphics.freeze
    # 释放窗口
    @help_window.dispose
    for i in @savefile_windows
      i.dispose
    end
end
#--------------------------------------------------------------------------
# ● 刷新画面
#--------------------------------------------------------------------------
def update
    # 刷新窗口
    @help_window.update
    for i in @savefile_windows
      i.update
    end
    # 按下 C 键的情况下
    if Input.trigger?(Input::C)
      # 调用过程 on_decision (定义继承目标)
      on_decision(make_filename(@file_index))
      $game_temp.last_file_index = @file_index
      return
    end
    # 按下 B 键的情况下
    if Input.trigger?(Input::B)
      # 调用过程 on_cancel (定义继承目标)
      on_cancel
      return
    end
    # 按下方向键下的情况下
    if Input.repeat?(Input::DOWN)
      # 方向键下的按下状态不是重复的情况下、
      # 并且光标的位置在 3 以前的情况下
      if Input.trigger?(Input::DOWN) or @file_index < 3
      # 演奏光标 SE
      $game_system.se_play($data_system.cursor_se)
      # 光标向下移动
      @savefile_windows[@file_index].selected = false
      @file_index = (@file_index + 1) % 4
      @savefile_windows[@file_index].selected = true
      return
      end
    end
    # 按下方向键上的情况下
    if Input.repeat?(Input::UP)
      # 方向键上的按下状态不是重复的情况下、
      # 并且光标的位置在 0 以后的情况下
      if Input.trigger?(Input::UP) or @file_index > 0
      # 演奏光标 SE
      $game_system.se_play($data_system.cursor_se)
      # 光标向上移动
      @savefile_windows[@file_index].selected = false
      @file_index = (@file_index + 3) % 4
      @savefile_windows[@file_index].selected = true
      return
      end
    end
end
#--------------------------------------------------------------------------
# ● 生成文件名
#   file_index : 文件名的索引 (0~3)
#--------------------------------------------------------------------------
def make_filename(file_index)
    return "Save#{file_index + 1}.rxdata"
end
end

#==============================================================================
# ■ Scene_Load
#------------------------------------------------------------------------------
#  处理读档画面的类。
#==============================================================================

class Scene_Load < Scene_File
#--------------------------------------------------------------------------
# ● 初始化对像
#--------------------------------------------------------------------------
def initialize(save_max = SAVE_MAX)
    # 再生成临时对像
    $game_temp = Game_Temp.new
    # 选择存档时间最新的文件
    $game_temp.last_file_index = 0
    latest_time = Time.at(0)
    for i in 0..save_max
      filename = make_filename(i)
      if FileTest.exist?(filename)
      begin
          file = Zlib::GzipReader.open(filename)
      rescue
          next
      end
      if file.mtime > latest_time
          latest_time = file.mtime
          $game_temp.last_file_index = i
      end
      file.close
      end
    end
    super("要载入哪个文件?","读取",save_max)
end
#--------------------------------------------------------------------------
# ● 确定时的处理
#--------------------------------------------------------------------------
def on_decision(filename)
    # 文件不存在的情况下
    unless FileTest.exist?(filename)
      # 演奏冻结 SE
      $game_system.se_play($data_system.buzzer_se)
      return
    end
    # 演奏读档 SE
    $game_system.se_play($data_system.load_se)
    # 写入存档数据
    begin
      file = Zlib::GzipReader.open(filename)
      read_save_data(file)
    rescue
      # 演奏冻结 SE
      $game_system.se_play($data_system.buzzer_se)
      return
    end
    file.close
    # 还原 BGM、BGS
    $game_system.bgm_play($game_system.playing_bgm)
    $game_system.bgs_play($game_system.playing_bgs)
    # 刷新地图 (执行并行事件)
    $game_map.update
    # 切换到地图画面
    $scene = Scene_Map.new
end
#--------------------------------------------------------------------------
# ● 取消时的处理
#--------------------------------------------------------------------------
def on_cancel
    # 演奏取消 SE
    $game_system.se_play($data_system.cancel_se)
    # 切换到标题画面
    $scene = Scene_Title.new
end
#--------------------------------------------------------------------------
# ● 读取存档数据
#   file : 读取用文件对像 (已经打开)
#--------------------------------------------------------------------------
def read_save_data(file)
    # 读取描绘存档文件用的角色数据
    characters = Marshal.load(file)
    # 读取测量游戏时间用画面计数
    Graphics.frame_count = Marshal.load(file)
    # 读取校验
    crcs = Marshal.load(file)
    # 读取文档字串
    strings = Marshal.load(file)
    # 校验检测
    key = SAVE_KEY
    strings.each_index do |i|
      key = Zlib.crc32(strings,key)
      unless crcs == key
      file.close
      raise "file check error"
      return
      end
    end
    # 读取各种游戏对像
    $game_system = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_variables = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_self_switches = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_switches = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_troop = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_map = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_player = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_screen = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_actors = Marshal.load(Zlib::Inflate.inflate(strings))
    $game_party = Marshal.load(Zlib::Inflate.inflate(strings))
   
    # 魔法编号与保存时有差异的情况下
    # (加入编辑器的编辑过的数据)
    if $game_system.magic_number != $data_system.magic_number
      # 重新装载地图
      $game_map.setup($game_map.map_id)
      $game_player.center($game_player.x, $game_player.y)
    end
    # 刷新同伴成员
    $game_party.refresh
end
end


#==============================================================================
# 自定义存档菜单
#==============================================================================

#==============================================================================
# ■ Scene_Save
#------------------------------------------------------------------------------
#  处理存档画面的类。
#==============================================================================

class Scene_Save < Scene_File
#--------------------------------------------------------------------------
# ● 初始化对像
#--------------------------------------------------------------------------
def initialize(save_max = SAVE_MAX)
    super("要保存到这个文件吗?","存入",save_max)
end
#--------------------------------------------------------------------------
# ● 确定时的处理
#--------------------------------------------------------------------------
def on_decision(filename)
    # 演奏存档 SE
    $game_system.se_play($data_system.save_se)
    # 写入存档数据
    file = Zlib::GzipWriter.open(filename,9)
    write_save_data(file)
    file.close
    # 如果被事件调用
    if $game_temp.save_calling
      # 清除存档调用标志
      $game_temp.save_calling = false
      # 切换到地图画面
      $scene = Scene_Map.new
      return
    end
    # 切换到菜单画面
    $scene = Scene_Menu.new(5)
end
#--------------------------------------------------------------------------
# ● 取消时的处理
#--------------------------------------------------------------------------
def on_cancel
    # 演奏取消 SE
    $game_system.se_play($data_system.cancel_se)
    # 如果被事件调用
    if $game_temp.save_calling
      # 清除存档调用标志
      $game_temp.save_calling = false
      # 切换到地图画面
      $scene = Scene_Map.new
      return
    end
    # 切换到菜单画面
    $scene = Scene_Menu.new(5)
end
#--------------------------------------------------------------------------
# ● 写入存档数据
#   file : 写入用文件对像 (已经打开)
#--------------------------------------------------------------------------
def write_save_data(file)   
    # 生成描绘存档文件用的角色图形
    characters = []
    for i in 0...$game_party.actors.size
      actor = $game_party.actors
      characters.push()
    end
   
    strings = []
   
    # 写入描绘存档文件用的角色数据
    Marshal.dump(characters,file)
    # 写入测量游戏时间用画面计数
    Marshal.dump(Graphics.frame_count,file)
    # 增加 1 次存档次数
    $game_system.save_count += 1
    # 保存魔法编号
    # (将编辑器保存的值以随机值替换)
    $game_system.magic_number = $data_system.magic_number
   
    # 写入各种游戏对像
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_system)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_variables)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_self_switches)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_switches)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_troop)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_map)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_player)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_screen)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_actors)))
    strings.push(Zlib::Deflate.deflate(Marshal.dump($game_party)))
   
    # 计算校验值
    crcs = []
    key = SAVE_KEY
    strings.each do |i|
      key = Zlib.crc32(i,key)
      crcs.push(key)
    end
    Marshal.dump(crcs,file)
    Marshal.dump(strings,file)
end
end

#==============================================================================
# ■ Window_SaveFile
#------------------------------------------------------------------------------
#  显示存档以及读档画面、保存文件的窗口。
#==============================================================================

class Window_SaveFile < Window_Base
#--------------------------------------------------------------------------
# ● 初始化对像
#   file_index : 存档文件的索引 (0~n)
#   filename   : 文件名
#--------------------------------------------------------------------------
def initialize(file_index, filename,viewport=nil)
    super(0, 64 + file_index % 4 * 104, 640, 104)
    self.contents = Bitmap.new(width - 32, height - 32)
   
    @file_index = file_index
    @filename = "Save#{@file_index + 1}.rxdata"
    @time_stamp = Time.at(0)
    @file_exist = FileTest.exist?(@filename)
   
    if @file_exist
      begin
      file = Zlib::GzipReader.open(filename)
      @time_stamp = file.mtime
      @characters = Marshal.load(file)
      @frame_count = Marshal.load(file)
      @total_sec = @frame_count / Graphics.frame_rate
      file.close
      rescue
      @file_exist = false
      end
    end
   
    self.refresh
    @selected = false
end
end

FantasyDR 发表于 2006-7-18 08:45:00

另,贴一个奇妙的PM

加密保护方法,申请转载

临时帐号,不用回复了,如果不允许转载请在我论坛PM我。
此外你也放心,幻森这里的游戏我是不会动的。怎么说,至少也得有值得我动的地方吧。至少幻森目前游戏区情况——你自己看好啦。


1、还好我并不在意脚本的转载,否则得去注册帐号知会人家:“嗯呐,同意转载”。唉,不说就是“是”!寒……算了,不研究这种事情,我赶快补充个说明,随便转了=.=

2、PM本不该放出来,不过我一直不厚道丫:)
之所以放出来是提醒一下广大RM游戏爱好者,您的游戏被解剖其实是一种无上的荣誉,这是您的游戏价值的体现。您的游戏支离破碎的尸体,其实是RM拆卸集团给您的最高褒奖。一定要心安理得的接受这个残酷而浪漫的现实~~爱你就要吃掉你,螳螂的爱情观啊^_^就好像游戏被盗版也是无上的光荣,那是因为你的游戏已经被盗版商肯定,已经有资格成为用来给他骗钱的东西了!就好像被QJ也是无上的光荣,那说明您的个人魅力已经达到了一定档次,否则为啥QJ你不QJ别人呢~?

3、我真的很想知道,拆卸工们以后会不会出加密游戏呢?拭目以待~~=.=

さくら 发表于 2006-7-18 08:52:21

谢谢~
下边这两种语句是不是也可以执行呢?
Marshal . dump
save_data\\t ""

盗帅冬瓜 发表于 2006-7-18 09:00:08

引用第2楼FantasyDR于2006-07-18 08:45发表的“”:
另,贴一个奇妙的PM


1、还好我并不在意脚本的转载,否则得去注册帐号知会人家:“嗯呐,同意转载”。唉,不说就是“是”!寒……算了,不研究这种事情,我赶快补充个说明,随便转了=.=

.......

[屏蔽]

我的游戏是不加密的,用不到这么高科技的东西,不过还是顶一个。

FantasyDR 发表于 2006-7-18 09:12:10

引用第3楼さくら于2006-07-18 08:52发表的“”:
谢谢~
下边这两种语句是不是也可以执行呢?
Marshal . dump
save_datat ""

这两种语句已经算在不可执行的部分了。
如果你的游戏需要执行这两种语句……那么着重放在存档校验部分吧。

さくら 发表于 2006-7-18 09:25:21

看成Marshal\\.了 >_<
后边的.不要比较好吧
save_data\\t和save_data\\n好像没有考虑哦

CountD 发表于 2006-7-18 09:42:03

厚道物,顶一个。
我还是响应第一个广告词好了……

美兽 发表于 2006-7-18 10:01:58

没说的,不支持扒衣裳。

盗帅冬瓜 发表于 2006-7-18 10:19:48

加精了,嘎嘎。。。
页: [1] 2 3
查看完整版本: [广告]想保护自己的游戏么?[2007.9.2更新]