首页
社区
课程
招聘
[原创]分享下wow PE section保护技术
发表于: 2021-6-11 23:06 18689

[原创]分享下wow PE section保护技术

2021-6-11 23:06
18689

游戏的关键lua函数加了检测,主要是检测返回地址,而且不是检测返回地址是模块PE范围内就行,返回地址必须是游戏真实调用lua函数的返回地址,而且检测字节码...
例子:

还是看代码:

告诉大家,wow 从调试到注入到调用lua,不需要任何r0技术,不要再用高射炮打蚊子了......
这是2020年1.13.6.36714 作为例子写的,理解了原理套用现在的版本就没问题

WOW 使用了PE节保护技术,重新映射PE内存,致使PE节不可修改,这个技术比较有意思,可以参考    [self-remapping](https://github.com/changeofpace/Self-Remapping-Code)
WOW 使用了PE节保护技术,重新映射PE内存,致使PE节不可修改,这个技术比较有意思,可以参考    [self-remapping](https://github.com/changeofpace/Self-Remapping-Code)
只喜欢用lua凑合看吧,都是调用windowsapi领会意思就行 
注意先SuspendProcess,重新映射后ResumeProcess
只喜欢用lua凑合看吧,都是调用windowsapi领会意思就行 
注意先SuspendProcess,重新映射后ResumeProcess
local STATUS_SUCCESS = 0
local ViewShare = 1
local ViewUnmap = 2
local SEC_NO_CHANGE = 0x00400000;
local SEC_COMMIT = 0x08000000
local MEM_RELEASE = 0x00008000
local NULL = ffi.cast("void *", 0)
 
function _RemapViewOfSection(ProcessHandle, BaseAddress, RegionSize, NewProtection, CopyBuffer)
 
    local numberOfBytesRead = ffi.new("SIZE_T[1]")
    if ffi.C.ReadProcessMemory(ProcessHandle, ffi.cast("void *", BaseAddress), ffi.cast("void *", CopyBuffer), RegionSize, numberOfBytesRead) == 0 then
        return false;
    end
 
 
 
    local hSection = ffi.new("HANDLE[1]");
    local sectionMaxSize = ffi.new("LARGE_INTEGER[1]")
    sectionMaxSize[0].QuadPart = RegionSize;
 
    local status = win.ntdll.NtCreateSection(hSection, win.SECTION_ALL_ACCESS, NULL, sectionMaxSize, win.PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL);
    if (status ~= STATUS_SUCCESS) then
        return false;
    end
 
    --// Unmap the current view.
    status = win.ntdll.NtUnmapViewOfSection(ProcessHandle, ffi.cast("void *", BaseAddress));
    if status ~= STATUS_SUCCESS then
        return false;
    end
 
 
    local viewBase = ffi.new("uintptr_t[1]", BaseAddress)
    local sectionOffset = ffi.new("LARGE_INTEGER[1]")
    local viewSize = ffi.new("SIZE_T[1]");
    status = win.ntdll.NtMapViewOfSection(
            hSection[0],
            ProcessHandle,
            ffi.cast("void **", viewBase),
            0,
            RegionSize,
            sectionOffset,
            viewSize,
            ViewUnmap,
            0,
            NewProtection);
    if status ~= STATUS_SUCCESS then
        return false;
    end
 
    local numberOfBytesWritten = ffi.new("SIZE_T[1]")
    if ffi.C.WriteProcessMemory(ProcessHandle, ffi.cast("void *", viewBase[0]), ffi.cast("void *", CopyBuffer), viewSize[0], numberOfBytesWritten) == 0 then
        return false;
    end
    return true;
end
 
function RemapViewOfSection(ProcessHandle, BaseAddress, RegionSize, NewProtection)
    local copybuf = ffi.C.VirtualAlloc(ffi.cast("void *", 0), RegionSize, bit.bor(win.MEM_COMMIT, win.MEM_RESERVE), win.PAGE_EXECUTE_READWRITE)
    if not copybuf then
        return false
    end
    local result = _RemapViewOfSection(ProcessHandle, BaseAddress, RegionSize, NewProtection, copybuf);
    ffi.C.VirtualFree(copybuf, 0, MEM_RELEASE);
    return result;
end
 
 
local PROCESS_ALL_ACCESS = 0x1fffff
local BaseAddress = 0x0000000140000000
local RegionSize = 0x0000000002330000
local NewProtection = 0x40
 
local 进程名 = "wowclassic.exe"
local tbl = enum.EnumSystemProcessorInformation()
for _, process in pairs(tbl) do
   local processname = process.Name:lower()
   if processname == 进程名 then
       local hProcess = ffi.C.OpenProcess(PROCESS_ALL_ACCESS, 0, process.Pid);
       if hProcess then
           win.ntdll.NtSuspendProcess(hProcess)
           print(RemapViewOfSection(hProcess, BaseAddress, RegionSize, NewProtection))
           win.ntdll.NtResumeProcess(hProcess)
           ffi.C.CloseHandle(hProcess)
           break
       end
   end
end
local STATUS_SUCCESS = 0
local ViewShare = 1
local ViewUnmap = 2
local SEC_NO_CHANGE = 0x00400000;
local SEC_COMMIT = 0x08000000
local MEM_RELEASE = 0x00008000
local NULL = ffi.cast("void *", 0)
 
function _RemapViewOfSection(ProcessHandle, BaseAddress, RegionSize, NewProtection, CopyBuffer)
 
    local numberOfBytesRead = ffi.new("SIZE_T[1]")
    if ffi.C.ReadProcessMemory(ProcessHandle, ffi.cast("void *", BaseAddress), ffi.cast("void *", CopyBuffer), RegionSize, numberOfBytesRead) == 0 then
        return false;
    end
 
 
 
    local hSection = ffi.new("HANDLE[1]");
    local sectionMaxSize = ffi.new("LARGE_INTEGER[1]")
    sectionMaxSize[0].QuadPart = RegionSize;
 
    local status = win.ntdll.NtCreateSection(hSection, win.SECTION_ALL_ACCESS, NULL, sectionMaxSize, win.PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL);
    if (status ~= STATUS_SUCCESS) then
        return false;
    end
 
    --// Unmap the current view.
    status = win.ntdll.NtUnmapViewOfSection(ProcessHandle, ffi.cast("void *", BaseAddress));
    if status ~= STATUS_SUCCESS then
        return false;
    end
 
 
    local viewBase = ffi.new("uintptr_t[1]", BaseAddress)
    local sectionOffset = ffi.new("LARGE_INTEGER[1]")
    local viewSize = ffi.new("SIZE_T[1]");
    status = win.ntdll.NtMapViewOfSection(
            hSection[0],
            ProcessHandle,
            ffi.cast("void **", viewBase),
            0,
            RegionSize,
            sectionOffset,
            viewSize,
            ViewUnmap,
            0,
            NewProtection);
    if status ~= STATUS_SUCCESS then
        return false;
    end
 
    local numberOfBytesWritten = ffi.new("SIZE_T[1]")
    if ffi.C.WriteProcessMemory(ProcessHandle, ffi.cast("void *", viewBase[0]), ffi.cast("void *", CopyBuffer), viewSize[0], numberOfBytesWritten) == 0 then
        return false;
    end
    return true;
end
 
function RemapViewOfSection(ProcessHandle, BaseAddress, RegionSize, NewProtection)
    local copybuf = ffi.C.VirtualAlloc(ffi.cast("void *", 0), RegionSize, bit.bor(win.MEM_COMMIT, win.MEM_RESERVE), win.PAGE_EXECUTE_READWRITE)
    if not copybuf then
        return false
    end
    local result = _RemapViewOfSection(ProcessHandle, BaseAddress, RegionSize, NewProtection, copybuf);
    ffi.C.VirtualFree(copybuf, 0, MEM_RELEASE);
    return result;
end
 
 
local PROCESS_ALL_ACCESS = 0x1fffff
local BaseAddress = 0x0000000140000000
local RegionSize = 0x0000000002330000
local NewProtection = 0x40
 
local 进程名 = "wowclassic.exe"
local tbl = enum.EnumSystemProcessorInformation()
for _, process in pairs(tbl) do
   local processname = process.Name:lower()
   if processname == 进程名 then
       local hProcess = ffi.C.OpenProcess(PROCESS_ALL_ACCESS, 0, process.Pid);
       if hProcess then
           win.ntdll.NtSuspendProcess(hProcess)

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 9
支持
分享
最新回复 (11)
雪    币: 65
活跃值: (482)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
2
都是干货. Mark 一下。
2021-6-15 16:11
0
雪    币: 5354
活跃值: (3582)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
我还买了个 传说中得VT反反调试工具
2021-6-18 16:47
0
雪    币: 5354
活跃值: (3582)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
2021-6-18 16:48
0
雪    币: 63
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
感谢大佬雪中送炭。无奈技术不行,目前是通过R0勉强过了反调试,但是卡在不能下int3断点这里,应该就是您说的代码段被重映射保护了
2021-6-20 21:08
0
雪    币: 123
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
int3的问题我解决了一部分。  WOW用的rdtsc指令判断CPU时间戳间隔,用VT接管即可,生成一个专门的时间队列,每次WOW调用就加1000,不调用就不加。 但WOW每秒都在自己触发INT 3,我现在虽然断了下来暂停多久都能恢复运行,但只要调试器不忽略INT3 断点,由于INT3触发太频繁根本没法单步。我卡在了附加调试器之后进入游戏,登陆界面好好的,一进入游戏就会崩溃 ,有人知道原因吗...
2021-6-22 01:53
0
雪    币: 123
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
还有 你们有没有遇到线程检查,我看外国佬是HOOK的DxGi->PreSent,从PreSent去call lua,有人功能做到这一步了吗
2021-6-22 01:57
0
雪    币: 63
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8

继续踩坑

最后于 2021-6-24 16:30 被fullxu编辑 ,原因:
2021-6-23 08:58
0
雪    币: 63
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
大佬你好,我直接用调试器启动游戏可以下断调试,但1~2分钟后就会触发异常崩掉,即使你什么都不做
如果是附加,只要触发断点就立刻异常,把异常抛给被调试程序也没用。
从r3~vt都试过了,我很菜只会用现成的插件,需要自己处理的部分完全不知道怎么操作
2021-6-25 07:56
0
雪    币: 40
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
我按照大佬的代码去掉了代码页的保护,  去掉页面保护之前,游戏CRC正常执行,但是去掉保护之后,个别CRC 不再执行了,请问这是什么原因
2021-7-1 22:14
0
雪    币: 11
活跃值: (199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
Mark 一下
2021-8-14 11:04
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
很老的手段了,section给写就好了
2021-8-14 13:00
0
游客
登录 | 注册 方可回帖
返回
//