搜索汇编模式¶
第一个脚本定位组成出站数据包并将其发送到游戏服务器的函数。它的工作原理是在游戏的汇编代码中搜索包含特定代码序列的函数。
① BASEADDRESS = getAddress("Game.exe")
② function LocatePacketCreation(packetType)
③ for address = BASEADDRESS, (BASEADDRESS +
0x2ffffff) do
local push = readBytes(address, 1, false)
local type = readInteger(address + 1)
④ if (push == 0x68 and type == packetType and
call == 0xE8) then
return address
end
end
return 0
end
FUNCTIONHEADER = { 0xCC, 0x55, 0x8B, 0xEC, 0x6A }
⑤ function LocateFunctionHead(checkAddress)
if (checkAddress == 0) then return 0 end
⑥ for address = checkAddress, (checkAddress -
0x1fff), -1 do
local match = true
local checkheader = readBytes(address,
#FUNCTIONHEADER, true)
⑦ for i, v in ipairs(FUNCTIONHEADER) do
if (v ~= checkheader[i]) then
match = false
break
end
end
⑧ if (match) then return address + 1 end
end
return 0
end
⑨ local funcAddress = LocateFunctionHead(LocatePac
ketCreation(0x64))
if (funcAddress ~= 0) then
print(string.format("0x%x",funcAddress))
else
print("Not found!")
end
脚本首先获取 Cheat Engine 附加到的模块的基地址①。获得基地址后,定义 LocatePacketCreation() 函数②。这个函数遍历游戏中前 0x2FFFFFF 字节的内存③,搜索代表以下 x86 汇编代码的序列:
函数检查 type 是否等于 packetType,但不关心函数偏移量是什么④。一旦找到这个序列,函数就返回。
接下来定义 LocateFunctionHead() 函数⑤。该函数从给定地址回溯最多 0x1FFF 字节⑥,并在每个地址检查类似这样的汇编代码桩⑦:
这段代码桩会出现在每个函数的开头,因为它是设置函数栈帧的函数序言(prologue)的一部分。一旦找到这段代码,函数就返回代码桩地址加 1⑧(第一个字节 0xCC 是填充)。
为了把各步骤串起来,用我要找的 packetType(随意取 0x64)调用 LocatePacketCreation(),并把得到的地址传给 LocateFunctionHead() 函数⑨。这实际上定位了第一个把 packetType 压入函数调用的函数,并把它的地址存储在 funcAddress 中。这段代码桩展示了结果:
INT3 ; LocateFunctionHead 回溯到这里
PUSH EBP ; 并返回这个地址
MOV EBP, ESP
PUSH [-1]
--snip--
PUSH [0x64] ; LocatePacketCreation 返回这个地址
CALL [something]
这个 35 行的脚本可以在不到一分钟内自动定位 15 个不同的函数。