好友
阅读权限 10
听众
最后登录 1970-1-1
1、小地图的战争迷雾 一般对于MOBA游戏透视来说,用GG修改器就足以很简单的实现了:开局敌人全部在小地图上看不到,那直接搜0就行了,然后对着对面一个特定的英雄,简称H。当H小头像出现在小地图上的时候搜1,没有的时候搜0。这样很快就能找到H在内存中的数据,将那个值改成1冻结掉就可以实现H的小地图透视了。如果说想实现对面全部英雄透视的话。那就在H的那个“1”值的内存中往上找特征码,然后搜索特征码+偏移,找到的一起改成1就行了。这样的结果一般是对面塔、小兵、水晶、英雄一起暴露在小地图的视野里面。
实现的GG修改器脚本可以参考以下代码
[Lua] 纯文本查看 复制代码
-----------------------------------------------------------------------------------------
function split(szFullString, szSeparator)
local nFindStartIndex = 1
local nSplitIndex = 1
local nSplitArray = {}
while true do
local nFindLastIndex = string.find
(szFullString, szSeparator, nFindStartIndex)
if not nFindLastIndex then
nSplitArray[nSplitIndex] =
string.sub(szFullString, nFindStartIndex, string.len
(szFullString))
break end
nSplitArray[nSplitIndex] = string.sub
(szFullString, nFindStartIndex, nFindLastIndex - 1)
nFindStartIndex = nFindLastIndex + string.len
(szSeparator)
nSplitIndex = nSplitIndex + 1 end return
nSplitArray end
function xgxc(szpy, qmxg)
for x = 1, #(qmxg) do
xgpy = szpy + qmxg[x]["offset"]
xglx = qmxg[x]["type"]
xgsz = qmxg[x]["value"]
xgdj = qmxg[x]["freeze"]
if xgdj == nil or xgdj == "" then
gg.setValues({[1]
= {address = xgpy, flags = xglx, value = xgsz}})
else
gg.addListItems({[1]
= {address = xgpy, flags = xglx,
freeze = xgdj, value = xgsz}}) end
xgsl = xgsl + 1 xgjg = true end end
function xqmnb(qmnb)
gg.clearResults()
gg.setRanges(qmnb[1]["memory"])
gg.searchNumber(qmnb[3]["value"], qmnb[3]["type"])
if gg.getResultCount() == 0 then
gg.toast(qmnb[2]["name"] .. "开启失败")
else
gg.refineNumber(qmnb[3]["value"], qmnb[3]["type"])
gg.refineNumber(qmnb[3]["value"], qmnb[3]["type"])
gg.refineNumber(qmnb[3]["value"], qmnb[3]["type"])
if gg.getResultCount() == 0 then
gg.toast(qmnb[2]["name"] .. "开启失败")
else
sl = gg.getResults(999999)
sz = gg.getResultCount()
xgsl = 0 if sz > 999999 then
sz = 999999 end for i = 1, sz do
pdsz = true for v = 4, #(qmnb) do if
pdsz == true then
pysz = {} pysz[1]
= {} pysz[1].address
= sl[i].address + qmnb[v]["offset"] pysz[1].flags
= qmnb[v]["type"]
szpy = gg.getValues(pysz)
pdpd = qmnb[v]["lv"] .. ";" .. szpy[1].value szpd
= split(pdpd, ";") tzszpd
= szpd[1] pyszpd = szpd[2]
if tzszpd == pyszpd then
pdjg = true pdsz = true else
pdjg = false pdsz = false end end end if
pdjg == true then szpy
= sl[i].address xgxc(szpy, qmxg) end end
if xgjg == true then
gg.toast(qmnb[2]["name"] .. "开启成功,共修改" .. xgsl .. "条数据")
else
gg.toast(qmnb[2]["name"] .. "开启失败")
end
end
end
end
-------配置↑↑↑勿修改-------
-------支持冻结------
-----------------------------------------------------------------------------------------
function Main()
SN = gg.choice({
"扩大视野开启",
"扩大视野关闭",
"小视野开启",
"小视野关闭",
"锁头像透视开启",
"锁头像透视关闭",
"高视角(小型)",
"高视角(小型关闭)",
"高视角(中型)",
"高视角(中型关闭)",
"高视角(大型)",
"高视角(大型关闭)",
"高视角(巨型)",
"高视角(巨型关闭)",
"退出脚本"
}, nil, "")
if SN == 1 then a() end
if SN == 2 then b() end
if SN == 3 then c() end
if SN == 4 then d() end
if SN == 5 then e() end
if SN == 6 then f() end
if SN == 7 then g() end
if SN == 8 then h() end
if SN == 9 then i() end
if SN == 10 then j() end
if SN == 11 then k() end
if SN == 12 then l() end
if SN == 13 then m() end
if SN == 14 then n() end
if SN == 15 then os.exit() end XGCK = -1 end
function a()
qmnb = {
{["memory"] = gg.REGION_C_ALLOC},
{["name"] ="视野扩大开启"},
{["value"] =, ["type"] = 4},
{["lv"] = , ["offset"] = -4, ["type"] = 4},
{["lv"] = , ["offset"] = 4, ["type"] = 4},
{["lv"] = , ["offset"] = -8, ["type"] = 4},
}
qmxg = {
{["value"] =1, ["offset"] = 20, ["type"] = 4},
}
xqmnb(qmnb)
end
function b()
qmnb = {
{["memory"] = gg.REGION_C_ALLOC},
{["name"] ="视野扩大关闭"},
{["value"] =, ["type"] = 4},
{["lv"] = , ["offset"] = -4, ["type"] = 4},
{["lv"] = , ["offset"] = 4, ["type"] = 4},
{["lv"] = , ["offset"] = -8, ["type"] = 4},
}
qmxg = {
{["value"] =, ["offset"] = 20, ["type"] = 4},
}
xqmnb(qmnb)
end
function c()
qmnb = {
{["memory"] = gg.REGION_C_ALLOC},
{["name"] ="小视野开启"},
{["value"] =, ["type"] = 4},
{["lv"] = , ["offset"] = -4, ["type"] = 4},
{["lv"] = , ["offset"] = -12, ["type"] = 4},
{["lv"] = , ["offset"] = -24, ["type"] = 4},
}
qmxg = {
{["value"] =1, ["offset"] = 12, ["type"] = 4},
}
xqmnb(qmnb)
end
function d()
qmnb = {
{["memory"] = gg.REGION_C_ALLOC},
{["name"] ="小视野关闭"},
{["value"] =, ["type"] = 4},
{["lv"] = , ["offset"] = -4, ["type"] = 4},
{["lv"] = , ["offset"] = -12, ["type"] = 4},
{["lv"] = , ["offset"] = -24, ["type"] = 4},
}
qmxg = {
{["value"] =0, ["offset"] = 12, ["type"] = 4},
}
xqmnb(qmnb)
end
function e()
qmnb = {
{["memory"] = gg.REGION_C_ALLOC},
{["name"] ="锁头像透视开启"},
{["value"] =, ["type"] = 4},
{["lv"] = , ["offset"] = -12, ["type"] = 4},
{["lv"] = , ["offset"] = -24, ["type"] = 4},
{["lv"] = , ["offset"] = -32, ["type"] = 4},
}
qmxg = {
{["value"] =1, ["offset"] = -64, ["type"] = 4,["freeze"] = true},
}
xqmnb(qmnb)
end
function f()
qmnb = {
{["memory"] = gg.REGION_C_ALLOC},
{["name"] ="锁头像透视关闭"},
{["value"] =, ["type"] = 4},
{["lv"] = , ["offset"] = -12, ["type"] = 4},
{["lv"] = , ["offset"] = -24, ["type"] = 4},
{["lv"] = , ["offset"] = -32, ["type"] = 4},
}
qmxg = {
{["value"] =1, ["offset"] = -64, ["type"] = 4,["freeze"] = false},
}
xqmnb(qmnb)
end
function g()
gg.clearResults()
gg.setRanges(37)
gg.searchNumber("", gg.TYPE_FLOAT, false, gg.SIGN_EQUAL, 0, -1)
gg.getResults(100)
gg.editAll("", gg.TYPE_FLOAT)
gg.toast("小型高视角开启成功")
gg.clearResults()
end
function h()
gg.clearResults()
gg.setRanges(37)
gg.searchNumber("", gg.TYPE_FLOAT, false, gg.SIGN_EQUAL, 0, -1)
gg.getResults(100)
gg.editAll("", gg.TYPE_FLOAT)
gg.toast("小型高视角关闭成功")
gg.clearResults()
end
function i()
gg.clearResults()
gg.setRanges(37)
gg.searchNumber("", gg.TYPE_FLOAT, false, gg.SIGN_EQUAL, 0, -1)
gg.getResults(100)
gg.editAll("", gg.TYPE_FLOAT)
gg.toast("中型高视角开启成功")
gg.clearResults()
end
function j()
gg.clearResults()
gg.setRanges(37)
gg.searchNumber("", gg.TYPE_FLOAT, false, gg.SIGN_EQUAL, 0, -1)
gg.getResults(100)
gg.editAll("", gg.TYPE_FLOAT)
gg.toast("中型高视角关闭成功")
gg.clearResults()
end
function k()
gg.clearResults()
gg.setRanges(37)
gg.searchNumber("", gg.TYPE_FLOAT, false, gg.SIGN_EQUAL, 0, -1)
gg.getResults(100)
gg.editAll("", gg.TYPE_FLOAT)
gg.toast("大型高视角开启成功")
gg.clearResults()
end
function l()
gg.clearResults()
gg.setRanges(37)
gg.searchNumber("", gg.TYPE_FLOAT, false, gg.SIGN_EQUAL, 0, -1)
gg.getResults(100)
gg.editAll("", gg.TYPE_FLOAT)
gg.toast("大型高视角关闭成功")
gg.clearResults()
end
function m()
gg.clearResults()
gg.setRanges(37)
gg.searchNumber("", gg.TYPE_FLOAT, false, gg.SIGN_EQUAL, 0, -1)
gg.getResults(100)
gg.editAll("", gg.TYPE_FLOAT)
gg.toast("巨型高视角开启成功")
gg.clearResults()
end
function n()
gg.clearResults()
gg.setRanges(37)
gg.searchNumber("", gg.TYPE_FLOAT, false, gg.SIGN_EQUAL, 0, -1)
gg.getResults(100)
gg.editAll("", gg.TYPE_FLOAT)
gg.toast("巨型高视角关闭成功")
gg.clearResults()
end
while true do
if gg.isVisible(true) then
XGCK = 1
gg.setVisible(false)
end
gg.clearResults()
if XGCK == 1 then
Main()
end
end
如果说不喜欢用GG修改器,而且喜欢frIDA 的话。可以参考以下:
cocos2dx中,MOBA的地图、战争迷雾、英雄的头像在小地图上不在一个layer里面,关于迷雾的实现,有一大段乱七八糟的东西,具体实现关心的话可以搜索cocos2dx 战争迷雾。这里我们不关心战争迷雾的实现方式。
在我分析的那个游戏里面,关于英雄在小地图上实现头像显示的流程如下:首先它会将一个房间里面的英雄分成两个阵营:0和1;然后在0和1阵营里面分别给五个英雄做标号,通俗来说就是2个数组。在游戏加载时,系统会做一些初始化的东西,关于战争迷雾的R半径初始化和是否隔墙显示战争魔物这些,最重要的是它会让1阵营的英雄的小头像不在0阵营英雄的小地图上。
然后关于在游戏中小头像在地图上的显示(也就是战争迷雾的显示与遮盖)实际上是在一个帧同步的进程里面。而且它的计算是放在本地进行的。为什么它会放到本地主要是因为手机网速不稳定,性能差异大,而且moba游戏对延时要求高。
而且一般cocos2dx游戏的主要游戏逻辑是放在这个游戏安装包里最大的那个so里面进行的,为什么是最大的?
主要是一般cocos2dx游戏都内嵌了lua引擎,所以最大的so最有可能含有lua引擎。
如何查找战争迷雾的显示与遮盖:
对于一般的cocos2dx游戏来说,你需要查找什么函数你就在cocos2dx官方文档上找这种函数的实现名字,找到它的名字直接在so里面搜就行了。
比如说战争迷雾,先搜索process,找找游戏逻辑主进程。
最笨的办法就是全部hook,看那个函数会不停地被调用。定位到bloodMoveString2::process(ulong long)这个函数
查找这个函数出现warfog的名字,然后跳过去看
这个很像,isWarfogVisble。F5反编译
bool函数,而且看代码也很像。应该是了。然后frida hook一下,成功。
[JavaScript] 纯文本查看 复制代码
function hook_WarforgOpen(){// var warfogoepn=Module.findExportByName("libcos.so","_ZN4CMap14isWarfogVisbleEff");
//console.log("the addr of this func is :",warfogoepn);
Interceptor.attach(flagaddr,{
onEnter:function(args){
//console.log("enter this merhod successful",args[1]);
},onLeave:function(retval){
//console.log(retval);
retval.replace(1);
// console.log("the retval changged is :",retval);
// retval.replace(201); //修改flag 同样可以生效
}
});
}
2、lua脚本dump
cocos2dx游戏lua脚本dump时机点就在loadbuffer这个函数里面。一般找到这个函数就是了luaex_loadbuffer(lua_State *,char const*,uint,char const*) 或者相似的。
找到直接frida就能dump下来。我分析的这个游戏没有加密所有dump下来的全是明文,如果加密的话,可以顺着这个函数往上找,应该可以找到解密函数。
[Asm] 纯文本查看 复制代码
function hook_LuaBufferload(){
var loadbuffer=Module.findExportByName("libcos.so","_ZN2tq16luaex_loadbufferEP9lua_StatePKcjS3_");
console.log("the addr of this func is :",loadbuffer);
Interceptor.attach(loadbuffer,{
onEnter:function(args){
console.log(ptr(args[3]).readCString());
//参数3是lua放置的位置和名字
var tmp =ptr(args[3]).readCString();
var tmp1=tmp.split("/");
var siz=tmp1.length;
//console.log(tmp1[siz-1]);
//console.log("大小是:",args[2].toInt32());
write_lua(tmp1[siz-1],ptr(args[1]).readCString());
},onLeave:function(retval){
}
});
}
function write_lua(name , content){
//frida 的api来写文件
var file = new File("/sdcard/lua/"+name, "w");
file.write(content);
file.flush();
file.close();
}
dump下来的lua脚本存放在sdcard/lua文件夹下面。直接adb pull拉出来就好了
免费评分
查看全部评分