CE Lua 内存扫描与结果管理

CE Lua 内存扫描与结果管理

通过 CE Lua 的 MemScan 与 FoundList 可以组织一次扫描和结果读取。本篇帮助读者理解扫描对象的顺序、索引以及释放责任。

扫描对象的职责

createMemScan() 新建扫描对象;首次扫描需要扫描选项、数据类型、范围、内存保护筛选和对齐等参数。官方文档列出 firstScan 的完整参数,也支持先设置属性再调用 firstScan()。不要直接照搬不认识的参数:扫描范围过大耗时,保护筛选或对齐设置不合适也会漏掉结果。

第一次与下一次

例如用 soExactValue 和 vtDword 查找四字节整数,值通过字符串传入。首次扫描完成后,让 Tutorial 改变数值,再以 nextScan 使用新值缩小结果。soChanged、soUnchanged 等模式比较上一次结果;重新开始使用 newScan,旧结果不应继续当作当前候选。

等待结果并释放

扫描在后台进行,调用 waitTillDone() 后再用 createFoundList(scan) 创建结果列表并调用 initialize()。Count 是数量,Address[0] 是第一项;只在数量大于零时访问。读取完先调用 deinitialize(),然后销毁自己创建的 FoundList 与 MemScan。异常处理也需要执行同样的清理,不能等到 CE 关闭。

验证方法

先在界面中对 Tutorial 手动完成一次精确扫描,记录类型、值和内存筛选。再按官方 celua 文档构建参数,先打印结果数量和少量地址,不在遍历时改写数据。重复扫描时每次等待结束并重新初始化结果视图;若无结果,核对值是否已变化、类型、地址范围及对齐方式。CE 7.7 还增加了其他结果访问方式;这里使用兼容传统 API 的 FoundList。

在已知范围内扫描整数

先附加自己的练习程序,以十六进制填写本次运行中已知可读范围的起始和结束地址,并将 target 改为其中一个已知的四字节整数。这个例子仅打印前五个候选;不要把示例中的范围当作自己的地址。范围较大时扫描可能耗时。

local startAddress = tonumber("10000000", 16) -- 替换
local stopAddress  = tonumber("1000FFFF", 16) -- 替换
local target = "100"                           -- 替换
local scan, found
local initialized = false
local ok, err = pcall(function()
  assert(startAddress and stopAddress and startAddress <= stopAddress)
  scan = createMemScan()
  scan.firstScan(soExactValue, vtDword, rtRounded, target, "",
    startAddress, stopAddress, "+W", fsmNotAligned, "",
    false, false, false, false)
  scan.waitTillDone()
  found = createFoundList(scan)
  found.initialize()
  initialized = true
  print("结果数量: " .. found.Count)
  for i = 0, math.min(found.Count, 5) - 1 do
    print(found.Address[i], found.Value[i])
  end
end)
if found then
  if initialized then found.deinitialize() end
  found.destroy()
end
if scan then scan.destroy() end
if not ok then print("扫描失败: " .. tostring(err)) end

+W 仅包含可写区域,范围或筛选错误可能导致零结果。实际使用前先确认范围和目标进程;要继续下一次扫描,应在释放对象之前执行 nextScan 并再次等待完成。

进一步验证

结果数量只说明符合当前条件的地址数量,并不保证结果就是目标字段。有多个结果时,可改变练习程序的数值后继续扫描,再将少量候选加入地址表观察。注意在每次筛选之前记录输入值和变化事件;一旦改变其他条件,应考虑是否需要重新开始。扫描对象和结果列表独立创建时,谁创建谁负责在正常结束与错误分支均完成清理。

参考资料