RGSS301(金庸5) 内存数据分析
我游戏已经翻版了,修改器应该不会在更新,抛砖引玉,希望大能们能写出更完善的修改器用rgss3写的 引用dll为rgss301.dll的游戏程序,应该都遵循下面几个特点:
数据基本都是4字节存放的,除了浮点,二进制数据等
1.[["RGSS301.dll"+0025A2AC]+10]存放所有类型变量的映射表。
读取方式:+4==名称的存放地址,+8==映射值, +0x10下一个地址,为0是最后一个,+0x14上一个地址,为0是第一个
在rmxp编辑器的脚本中定义的类型,变量,都在这里,字符串都不重复,有唯一的映射值
2.["RGSS301.dll"+002AC044]存放所有的对象数据(映射表中以$开头的类型),+4是列表的数量,+0xc是列表
遍历列表中的每个4字节地址,+0==+4==映射值,+8存放数据的基址,+c下一个数据,一直+c直到为0时结束此4字节的循环。
3.通过以上2步,就能得到所有你想要的数据基址。 比如$game_variables为游戏中的变量 $game_switches为游戏中的开关
[[[基址]]+4]到数据类型
01?1:对象数据 ?为0时,+8长度,+c是值,+0x10是类型结构,以映射值存放,具体读法和第一步差不多, 不为0时代表长度。+8开始是值(金庸5一般+8就是要读取的值的地址)
类型结构数据读取:
+8,双数时/2为长度,+0是映射值,+10是下一个数据
单数时+4 +8值要一样,长度=(值-1)/2。+c是值的地址+0映射值,+4为0,+8映射值 +c为1 以此类推
存储的值是数组时,不用读取类型结构,+c +10值为6
0401:double
05?1?0:字符串 问号的地方为长度,参考以下代码
uint firstbit = (len & 0x000f0000) >> 4*4;
uint secondbit= (len & 0x0000f000) >> 3*4;
if(secondbit%4!=0)
{
return -1;
}
return firstbit * 4 + secondbit / 4;
-1时+8长度,+c值的地址
非-1是+8是值的起点
07?1:数组
+8==+c=长度
+0x10为值存放地址,进去就是数组列表
0c?1:二进制
其他的类型对照存档文件分析下就知道了,不一一例举
值存放形式: 0==false, 2==true,4==nil 其他的单数值减一除2, 其他的双数值为地址
举例:
["RGSS301.dll"+0025A2AC]=02252ff0
=022530d0
=CB 57 85 7B 60 98 0F 02(名称) 6D 01 00 00(映射值) 00 00 00 00 10 31 25 02(下一个地址) 00 00 00 00(上一个地址,0是第一个地址)
60 98 0F 02(名称)= 05 08 D0 00 00 00 00 00 00 00 00 00 00 00 00 00 (空值)
10 31 25 02(下一个地址)=D1 28 C2 39 4C 98 0F 02 6F 01 00 00 00 00 00 00 50 31 25 02 D0 30 25 02
4C 98 0F 02(名称)=05 C8 D1 00 00 00 00 00 3C 49 46 55 4E 43 3E(<IFUNC>) 00
...
...
递归得到$game_player 映射值22315
通过第二步,递归得到映射值为22315的地址为91bb198 2B 57 00 00(映射值) 2B 57 00 00 00 6F FE 08(基址)
==090eb7c8
=14086b14
=01 01 00 00(类型)18 E7 19 14 31 00 00 00(长度) D8 42 F4 09(值存放的地址) 30 74 63 11(结构)
先读结构数据:
0@damage_pop
1@damage
2@critical
3@is_battle
4@duration_battle
5@id
6@x
7@y
8@real_x
9@real_y
10@tile_id
11@get_rect
12@character_name
....
25@move_speed
.....
.....
48@encounter_count
可以看到,2暴击,6 7是坐标信息,25是移动速度,12角色名字等等
再读值:00 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 47 00 00 00 43 00 00 00 01 23 00 00
每4字节就是对应的值,
@damage_pop=false
@damage=0
@critical=0
...
...
@x=35
@y=33
...
...
@move_speed=80 68 08 14 是地址,读进去=04 01(数据类型) 00 00 84 6F 0F 02 CD CC CC CC CC CC 12 40(双精度类型值 4.70)
其他的数据都是这个读法,在我那个修改器下面有个测试用程序,可以得到我认为有用的一些基址
运行结果:
得到$game_map
得到$game_player
得到$game_variables
得到$game_actors
得到$game_switches
得到$game_skills
得到$game_party
得到映射7/7
$game_variables 22443
$game_switches23051
$game_actors 23003
$game_skills 23411
$game_map 22299
$game_player 22315
$game_party 23555
//类型与映射值
$game_switches:91c0ff8,offset:3,
$game_player:91bb198,offset:4,
$game_actors:91c09b8,offset:22,
$game_skills:91c50b8,offset:28,
$game_party:91c5e98,offset:38,
$game_map:91964a8,offset:55,
$game_variables:91bbbd8,offset:65,
//类型,基址,"RGSS301.dll"+002AC044的一系列4字节偏移,读进4字节的+c的偏移
4。穿墙
我穿墙很暴力,可能会影响其他数据。
原理是分析了下Tilesets.rxdata,其中"@passages"的二进制数据,0是可以通过,15是不能通过,下面代码就是下内存访问断点找到的。
RGSS301.dll+14874 - movsx ecx,word ptr
RGSS301.dll+14878 - push ecx当ecx==0F时不允许通过,ecx==0时允许通过,其他的我没管,直接注入当等于0F时改成0
RGSS301.dll+14879 - call RGSS301.dll+14AE0
5.增加物品的call
直接改内存你能改数量,但是不能增加物品,以下call可以
10027AC4 - 8B 50 04 - mov edx,
10027AC7 - 8B 00 - mov eax,
10027AC9 - 52 - push edx //数量
10027ACA - 50 - push eax//物品ID
10027ACB - 56 - push esi//物品基址
10027ACC - FF D7 - call edi//edi==10096BA0
5.增加技能
直接修改内存可以改变技能,但不能增加技能,以下是call
10027AA4 - 56 - push esi//基址
10027AA5 - 50 - push eax//==技能ID注意这里是个地址,地址中存放ID
10027AA6 - 52 - push edx// 1
10027AA7 - FF D7 - call edi //1008D2C0
10027AA9 - 83 C4 0C - add esp,0C
10027AAC - 5B - pop ebx
10027AAD - 5F - pop edi
10027AAE - C3 - ret
6.地图事件代码
放在$game_map中的@events, 具体结构自己看看就清楚了,很简单,
这里只分析@code,至于@parameters 基本看到就能懂,很多参数我也没分析,对于攻略来说没帮助
太多,直接贴代码
switch (codeNumber)
{
case 0:
return calcIndent(indent) + "!";
case 101:
return calcIndent(indent) + "对话抬头:" + parameters;
case 401:
if (ep.EventCommand.Last().Replace("\t", "").StartsWith("内容"))
{
string s401 = ep.EventCommand.Last() + parameters;
ep.EventCommand.RemoveAt(ep.EventCommand.Count - 1);
return s401;
}
else
{
return calcIndent(indent) + "内容:" + parameters;
}
case 102:
return calcIndent(indent) + "选择:" + parameters;
case 103: //数值输入的处理
return calcIndent(indent) + "接受输入:变量 [" + parameters + wb.Variables)] + "]," + parameters + "位";
case 402:
return calcIndent(indent) + "选项:" + parameters + "的场景";
case 104:
return calcIndent(indent) + "更改选择:显示位置(0上1中2下):" + parameters + " 窗口显示 0显1布显 " + parameters;
case 105:
return calcIndent(indent) + "输入信息存储到:变量[" + parameters + wb.Variables)] + "]";
case 106:
return calcIndent(indent) + "等待" + parameters + "帧";
case 108:
return calcIndent(indent) + "注释:" + parameters;
case 408:
string s408 = ep.EventCommand.Last() + parameters;
ep.EventCommand.RemoveAt(ep.EventCommand.Count - 1);
return s408;
case 111://if语句
return calcIndent(indent) + code111(parameters);
case 112: //循环
return calcIndent(indent) + "循环";
case 113: //循环
return calcIndent(indent) + "中断循环";
case 115:
return calcIndent(indent) + "中断事件处理";
case 116:
return calcIndent(indent) + "暂时消除事件";
case 117:
return calcIndent(indent) + "公共事件:[" + parameters + wb.CommentEvent)] + "]";
case 118:
return calcIndent(indent) + "标签:" + parameters;
case 119:
return calcIndent(indent) + "跳转到标签:" + parameters;
case 121://开关赋值
return calcIndent(indent) + code121(parameters);
case 122: //变量赋值
return calcIndent(indent) + code122(parameters);
case 123: //独立开关
return calcIndent(indent) + "独立开关" + parameters + ":" + (parameters == "0" ? "on" : "off");
case 124://计时器
return calcIndent(indent) + code124(parameters);
case 125: //金钱赋值
return calcIndent(indent) + code125(parameters);
case 126: //物品
return calcIndent(indent) + code126(parameters);
case 127: //武器
return calcIndent(indent) + code127(parameters);
case 128: //防具
return calcIndent(indent) + code128(parameters);
case 129: //替换队员
string s129 = "替换队员:";
s129 += parameters == "1" ? "主角" : "[" + parameters + wb.Actors)] + "]";
s129 += parameters == "0" ? "加入" : "离开";
s129 += parameters == "0" ? "" : "初始化";
return calcIndent(indent) + s129;
case 131:
return calcIndent(indent) + "更改战斗外观";
case 132:
return calcIndent(indent) + "更改战斗BGM";
case 133:
return calcIndent(indent) + "更改战斗结束 ME ";
case 134:
return calcIndent(indent) + "更改禁止存档 ";
case 135:
return calcIndent(indent) + "更改禁止菜单 ";
case 136:
return calcIndent(indent) + " 更改禁止遇敌 ";
case 201: //场景移动
return calcIndent(indent) + code201(parameters);
case 202: //设置事件位置
return calcIndent(indent) + "人物移动";
case 203: //画面卷动
return calcIndent(indent) + "画面卷动";
case 204://更改地图设置
return calcIndent(indent) + "更改地图设置";
case 205:// 更改雾的色调
return calcIndent(indent) + "更改雾的色调";
case 206: //更改雾的不透明度
return calcIndent(indent) + "更改雾的不透明度";
case 207: //更改透明状态
return calcIndent(indent) + "显示动画";
case 208: //显示动画
return calcIndent(indent) + "显示动画";
case 209: //事件移动
return calcIndent(indent) + "事件移动";
case 210: //事件移动
return calcIndent(indent) + "等待移动结束";
case 231:
return calcIndent(indent) + "显示图片";
case 232:
return calcIndent(indent) + "移动图片";
case 233:
return calcIndent(indent) + "旋转图片";
case 234: //更改图片色调
return calcIndent(indent) + "更改图片色调";
case 235:
return calcIndent(indent) + "图片消失";
case 221://准备渐变
return calcIndent(indent) + "准备渐变";
case 222: //执行渐变
return calcIndent(indent) + "执行渐变";
case 223: //更改画面色调
return calcIndent(indent) + "更改画面色调";
case 224://画面闪烁
return calcIndent(indent) + "画面闪烁";
case 225://画面振动
return calcIndent(indent) + "画面振动";
case 236: //设置天候
return calcIndent(indent) + "设置天候";
case 241://更改色调
return calcIndent(indent) + "更改色调";
case 242: //bgm淡出
return calcIndent(indent) + "bgm淡出";
case 245: //演奏bgs
return calcIndent(indent) + "演奏bgs";
case 246: //bgs淡出
return calcIndent(indent) + "bgs淡出";
case 247: //记忆bgm/bgs
return calcIndent(indent) + "记忆bgm";
case 248://还原bgm/bgs
return calcIndent(indent) + "还原bgm";
case 249://演奏me
return calcIndent(indent) + "演奏me";
case 250://演奏se
return calcIndent(indent) + "演奏se";
case 251://停止se
return "停止se";
case 301:
//战斗
return "战斗";
case 302:
return calcIndent(indent) + "开商店";
case 303:
return calcIndent(indent) + "输入更改角色[" + parameters + wb.Actors)] + "]的名字(最多" + parameters + "个字)";
case 311://增减血量
case 312: //增加sp
case 315://增加exp
return calcIndent(indent) + code311(parameters, codeNumber);
case 313:
string s313 = "更改状态 ";
if (parameters == "0") s313 += "全部同伴";
else if (parameters == "1") s313 += "主角";
else s313 += "角色[" + parameters + wb.Actors)] + "]";
s313 += parameters == "0" ? "附加" : "解除";
s313 += "[" + parameters + wb.States)] + "]";
return calcIndent(indent) + s313;
case 314:
string s = "完全恢复 ";
if (parameters == "0") s += "全部同伴";
else if (parameters == "1") s += "主角";
else s += "角色[" + parameters + wb.Actors)] + "]";
return calcIndent(indent) + s;
case 316: //等级增减
return calcIndent(indent) + code316(parameters);
case 317: //改变4维
return calcIndent(indent) + code317(parameters);
case 318: //特技
return calcIndent(indent) + code318(parameters);
case 319: //改变装备
return calcIndent(indent) + code319(parameters);
case 320:
if (ep.EventCommand.Count > 0 && ep.EventCommand.Last().Replace("\t", "").StartsWith("更改名字"))
{
string s320 = ep.EventCommand.Last() + parameters;
ep.EventCommand.RemoveAt(ep.EventCommand.Count - 1);
return s320;
}
else
{
return calcIndent(indent) + "更改名字:" + parameters;
}
case 321: //更改角色职业;
return calcIndent(indent) + "更改角色职业";
case 322:
return calcIndent(indent) + "更换角色图片" + "[" + parameters + wb.Actors)] + "]";
case 337:
return calcIndent(indent) + "显示动画";
case 338:
return calcIndent(indent) + "伤害处理";
case 339:
return calcIndent(indent) + "强制行动 ";
case 340:
return calcIndent(indent) + "战斗中断 ";
case 351:
return calcIndent(indent) + "呼叫菜单画面";
case 352:
return calcIndent(indent) + "呼叫存档画面";
case 353:
return calcIndent(indent) + "游戏结束";
case 354:
return calcIndent(indent) + "返回标题画面";
case 355:
return calcIndent(indent) + "脚本:" + parameters;
case 655:
string s655 = ep.EventCommand.Last() + parameters;
ep.EventCommand.RemoveAt(ep.EventCommand.Count - 1);
return s655;
case 403:
return calcIndent(indent) + "选择取消的场景";
case 404:
return calcIndent(indent) + "分歧结束";
case 411:
return calcIndent(indent) + "除此以外场合";
case 412:
return calcIndent(indent) + "分歧结束";
case 413:
return calcIndent(indent) + "回到循环";
case 509: //设置移动下一行
return calcIndent(indent) + "设置方位事件";
case 605: //商店后续
return calcIndent(indent) + "商店";
default:
return "";
}
:sleepy:我是谁我在那儿 我是谁?我在哪?发生了什么?
页:
[1]