12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
三国霸业 战车-珍宝-觉醒-攻城掠地SF-全新玩法 免费玩新区 攻城掠地私服 进入游戏
手游私服盒子 各类免费游戏 0.1折送海量资源 各类手游私服 进入游戏
皇家MU2 《奇迹 2:传奇》韩国网禅公司《奇迹》正统续作。 3D锁视角Mmrpg 暗黑3+传奇+流放之路+奇迹 进入游戏
查看: 284|回复: 0

InfinityHook 事件逆向

[复制链接]

51

主题

51

帖子

112

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
112
发表于 2021-5-7 23:01:59 | 显示全部楼层 |阅读模式
0x0 媒介

看本文之前发起先看一下《剖析InfinityHook原理 掀起一场更激烈的攻与防恶战》这篇文章。
相识一下InfinityHook的基本原理。
0xI InfinityHook寻找指针方式剖析

我们先来看看原作者是怎样寻找的,在源码的IfhpInternalGetCpuClock函数内
    PVOID* StackMax = (PVOID*)__readgsqword(OFFSET_KPCR_RSP_BASE);    PVOID* StackFrame = (PVOID*)_AddressOfReturnAddress();StackFrame为栈顶,StackMax为栈底,
获取两个值是为了确定范围,要在这两个值范围之间寻找在堆栈中那个要更换的指针。
for (PVOID* StackCurrent = StackMax;        StackCurrent > StackFrame;        --StackCurrent)    {        //         // This is intentionally being read as 4-byte magic on an 8        // byte aligned boundary.        //        PULONG AsUlong = (PULONG)StackCurrent;        if (*AsUlong != INFINITYHOOK_MAGIC_1)        {            continue;        }        //         // If the first magic is set, check for the second magic.        //        --StackCurrent;        PUSHORT AsShort = (PUSHORT)StackCurrent;        if (*AsShort != INFINITYHOOK_MAGIC_2)        {            continue;        }将StackMax栈底给StackCurrent再给AsUlong,用AsUlong所在里的值与INFINITYHOOK_MAGIC_1相比较,
不相等就回到for循环减一,相等就减1继续与INFINITYHOOK_MAGIC_2比较,不相等就回到for减一循环,
直到找到两个值,也就是说,从栈底往上一个个的比对值是否为INFINITYHOOK_MAGIC,直到找到两个值才继续。这两个值分别为 0x501802 和0xF33,这里记下两个值后面有提及。
for (;StackCurrent < StackMax;++StackCurrent)        {            PULONGLONG AsUlonglong = (PULONGLONG)StackCurrent;            if (!(PAGE_ALIGN(*AsUlonglong) >= SystemCallEntryPage &&                PAGE_ALIGN(*AsUlonglong) < (PVOID)((uintptr_t)SystemCallEntryPage + (PAGE_SIZE * 2))))            {                continue;            }            void** SystemCallFunction = &StackCurrent[9];                       if (IfhpCallback)            {                IfhpCallback(SystemCallIndex, SystemCallFunction);            }            break;        }找到两个值的位置后,再从这个位置向下,寻找体系调用,找到后,以这个体系调用的位置为基准,
往后找9个,每个8字节,也就是偏移72的位置的值,这样这个函数指针就找到了。
0x2逆向HOOK体系调用事件

是不是看的一脸懵逼,没错我也是,为什么是那两个特定值,那两个值是怎么来的。
那篇文章没写 ,源码的表明也没说,那换个其他事件这个寻找方式还能用吗?
不能,我试过了。
这里就要理一理思路了,这两个值既然在堆栈中,那么不是当前函数搞进去的,就是前一个函数,
或者前前的函数.........., 那么这个函数就应该在调用栈上,那我们就下个断点,在windbg中看一下调用栈。

从调用栈分析, ntdll!NtCreateEvent+0xa进入体系调用,然后在nt!KiSystemServiceExit+0x26a进入etw的记录函数,那么关键就应该是PerfInfoLogSysCallEntry函数,通过函数头部的二进制,在ida里搜刮
.text:0000000140162A40                 mov     r11, rsp.text:0000000140162A43                 sub     rsp, 48h.text:0000000140162A47                 lea     rax, [r11+8].text:0000000140162A4B                 mov     [r11+8], rcx.text:0000000140162A4F                 lea     rcx, [r11-18h].text:0000000140162A53                 mov     [r11-18h], rax.text:0000000140162A57                 and     [rsp+48h+var_C], 0.text:0000000140162A5C                 mov     r9d, 0F33h.text:0000000140162A62                 mov     edx, 1.text:0000000140162A67                 mov     r8d, 40000040h.text:0000000140162A6D                 mov     [rsp+48h+var_20], 501802h.text:0000000140162A75                 and     qword ptr [r11-28h], 0.text:0000000140162A7A                 mov     [rsp+48h+var_10], 8.text:0000000140162A82                 call    EtwpTraceKernelEvent.text:0000000140162A87                 add     rsp, 48h.text:0000000140162A8B                 retnPerfInfoLogSysCallEntry很短,看完就能发现两个熟悉的数字,
在0000000140162A5C 的 mov     r9d, 0F33h
与0000000140162A6D mov     [rsp+48h+var_20], 501802h
0F33与501802h不刚好是在堆栈里搜刮的两个数,
这里又要理一理思路了,还记得前面说的吗,找到这两个值后,向下寻找体系调用,
我们都知道,堆栈是先push的在底下,后push的在上面,先下寻找意味着寻找之前的调用函数,
看调用栈之前的函数那就是KiSystemServiceExit。
void** SystemCallFunction = &StackCurrent[9];            DbgBreakPoint();写个断点,断下后查看StackCurrent,这个基准体系调用的值
kd> dq 0xfffff880`03b82b88fffff880`03b82b88  fffff800`03ee0205 fffff960`00134164fffff880`03b82b98  00000000`00000000 00000000`0000002afffff880`03b82ba8  fffff960`00133fd6 00000000`00000003fffff880`03b82bb8  00000000`00000000 00000000`0192efb0fffff880`03b82bc8  00000000`00000005 fffff960`00134164fffff880`03b82bd8  fffff800`03edff93 fffffa80`31d69660fffff880`03b82be8  fffffa80`31d63910 00000000`00000000fffff880`03b82bf8  fffffa80`31d63910 00000000`00000000StackCurrent为0xfffff880`03b82b88,dq查看存的是 fffff800 03ee0205
kd> u fffff800`03ee0205nt!KiSystemServiceExit+0x26a:fffff800`03ee0205 488b4c2420      mov     rcx,qword ptr [rsp+20h]fffff800`03ee020a 488b542428      mov     rdx,qword ptr [rsp+28h]fffff800`03ee020f 4c8b442430      mov     r8,qword ptr [rsp+30h]fffff800`03ee0214 4c8b4c2438      mov     r9,qword ptr [rsp+38h]fffff800`03ee0219 4c8b542440      mov     r10,qword ptr [rsp+40h]fffff800`03ee021e 4883c450        add     rsp,50hfffff800`03ee0222 41ffd2          call    r10fffff800`03ee0225 488945b0        mov     qword ptr [rbp-50h],raxu看下汇编,恰好是KiSystemServiceExit,正如前面猜想的寻找KiSystemServiceExit
kd> dq 0xfffff880`03b82b88fffff880`03b82b88  fffff800`03ee0205 fffff960`00134164fffff880`03b82b98  00000000`00000000 00000000`0000002afffff880`03b82ba8  fffff960`00133fd6 00000000`00000003fffff880`03b82bb8  00000000`00000000 00000000`0192efb0fffff880`03b82bc8  00000000`00000005 fffff960`00134164fffff880`03b82bd8  fffff800`03edff93 fffffa80`31d69660fffff880`03b82be8  fffffa80`31d63910 00000000`00000000fffff880`03b82bf8  fffffa80`31d63910 00000000`00000000以这个基准偏移9个(不是9个字节,偏移一个指8字节,也就是偏移72的地方)的地方,为所在ffff880`03b82bd0,这所在里的值为fffff960 00134164,也就是要更换的函数指针。
kd> u fffff960`00134164win32k!NtUserCallNoParam:fffff960`00134164 48895c2408      mov     qword ptr [rsp+8],rbxfffff960`00134169 57              push    rdifffff960`0013416a 4883ec20        sub     rsp,20hfffff960`0013416e 8bf9            mov     edi,ecxfffff960`00134170 488b0da1a72000  mov     rcx,qword ptr [win32k!gpresUser (fffff960`0033e918)]fffff960`00134177 ff15f3d21c00    call    qword ptr [win32k!_imp_ExEnterPriorityRegionAndAcquireResourceExclusive (fffff960`00301470)]fffff960`0013417d c605249e200001  mov     byte ptr [win32k!gbValidateHandleForIL (fffff960`0033dfa8)],1fffff960`00134184 48890565c32000  mov     qword ptr [win32k!gptiCurrent (fffff960`003404f0)],raxu看一下是什么函数,为win32k!NtUserCallNoParam:,这个所在为UserCallNoParam的开头
MyDriver2!IfhpInternalGetCpuClock+0x15e [c:\users\hasee\documents\visual studio 2013\projects\mydriver1\mydriver1\infinityhook.cpp home.php?mod=space&uid=402414 622]nt!EtwpReserveTraceBuffer+0xe2nt!EtwpLogKernelEvent+0x24dnt!EtwpTraceKernelEvent+0xa6nt!PerfInfoLogSysCallEntry+0x47nt!KiSystemServiceExit+0x26auser32!NtUserCallNoParam+0xa调用栈的发起者为user32!NtUserCallNoParam+0xa,
我们都知道调用一个函数,都是push 参数1,push参数 2,push 参数3,然后call ,,
这时候堆栈里上面是返回所在,往下是参数,他以返回所在为基准向下加偏移寻找要更换的函数指针,
那会不会他寻找的就是参数,
                  : Args to Child        : Call Sitefffff880`03b82b40 : fffff960`00134164  : nt!PerfInfoLogSysCallEntry+0x47windbg查看调用栈显示参数,
为了雅观省略了后面的参数,参数为fffff960`00134164,这个不恰好和寻找的那个一样
kd> dq fffff880`03b82b40 fffff880`03b82b40  fffffa80`31d69660 fffff880`03b82c60fffff880`03b82b50  00000000`0192f250 00000000`00000001fffff880`03b82b60  00000000`00000000 fffff800`00501802fffff880`03b82b70  fffff880`03b82b90 00000000`00000008fffff880`03b82b80  fffff880`03b82b88 fffff800`03ee0205fffff880`03b82b90  fffff960`00134164 00000000`00000000查看这个函数的堆栈,在fffff880 03b82b88是我们寻找的基准体系调用的位置
kd> dq 0xfffff880`03b82b88fffff880`03b82b88  fffff800`03ee0205 fffff960`00134164fffff880`03b82b98  00000000`00000000 00000000`0000002afffff880`03b82ba8  fffff960`00133fd6 00000000`00000003fffff880`03b82bb8  00000000`00000000 00000000`0192efb0fffff880`03b82bc8  00000000`00000005 fffff960`00134164fffff880`03b82bd8  fffff800`03edff93 fffffa80`31d69660fffff880`03b82be8  fffffa80`31d63910 00000000`00000000fffff880`03b82bf8  fffffa80`31d63910 00000000`00000000回过头来再以这个基准体系调用的位置,要更换的函数指针值为fffff960`00134164,
一处为偏移1的(偏移1不是指偏移一个字节,是8个字节)fffff880`03b82b90,
宁一处为偏移9的fffff880`03b82bd0,原作者更换的是偏移9处的函数指针。
总结一下:
作者通过寻找EtwPerfInfoLogSysCallEntry放入堆栈的特定值来寻找,
EtwPerfInfoLogSysCallEntry函数的堆栈位置,
再向下寻找体系调用找到
KiSystemServiceExit函数返回所在在堆栈中位置,
再通过以KiSystemServiceExit为基准,更换偏移9处的参数指针,达到hook的目的。
0x3 逆向其他事件

1 特定值的寻找

EVENT_TRACE_FLAG_PROCESS0x00000001Property->EnableFlags = 0x00000001;通过官网查询PROCESS事件的falg为1,修改这个值就行了,
nt!EtwpReserveTraceBuffer+0xe2nt!EtwpLogKernelEvent+0x122nt!EtwpTraceKernelEvent+0xa6nt! ?? ::NNGAKEGL::`string'+0x219f0nt!PspExitProcess+0x4ent!PspExitThread+0x4e9nt!NtTerminateProcess+0x138nt!KiSystemServiceCopyEnd+0x13ntdll!NtTerminateProcess+0xa函数虽然变了,但在调用栈的大概位置没变,查看nt! ?? ::NNGAKEGL::`string'+0x21a03
fffff800`0412de2b 8b5504          mov     edx,dword ptr [rbp+4]fffff800`0412de2e 488d8d90000000  lea     rcx,[rbp+90h]fffff800`0412de35 450fb7cd        movzx   r9d,r13wfffff800`0412de39 41b801000000    mov     r8d,1fffff800`0412de3f c744242803195000 mov     dword ptr [rsp+28h],501903hfffff800`0412de47 488364242000    and     qword ptr [rsp+20h],0fffff800`0412de4d e8bedae8ff      call    nt!EtwpTraceKernelEvent (fffff800`03fbb910)fffff800`0412de52 488d4d20        lea     rcx,[rbp+20h]可以在fffff800`0412de3f瞥见501903h,宁一个特定值不好从代码看,
我们在 mov     dword ptr [rsp+28h],501903h在这段体系代码下个断点
断下后记下rsp+28的值,等断在我们的代码后再dq查看内存偏移1处的后三位,颠末多次测试,
第二个值为8d0 。
2寻找所在猜想

nt!EtwpReserveTraceBuffer+0xe2nt!EtwpLogKernelEvent+0x122nt!EtwpTraceKernelEvent+0xa6nt! ?? ::NNGAKEGL::`string'+0x219f0nt!PspExitProcess+0x4ent!PspExitThread+0x4e9nt!NtTerminateProcess+0x138nt!KiSystemServiceCopyEnd+0x13ntdll!NtTerminateProcess+0xa从调用栈看,函数指针应该是PspExitProcess的所在,但我找了半天,u查看没找到PspExitProcess函数。
nt!PspExitProcess:fffff800`04191288 48895c2408      mov     qword ptr [rsp+8],rbxfffff800`0419128d 48896c2410      mov     qword ptr [rsp+10h],rbpfffff800`04191292 4889742418      mov     qword ptr [rsp+18h],rsifffff800`04191297 57              push    rdifffff800`04191298 4154            push    r12fffff800`0419129a 4155            push    r13fffff800`0419129c 4156            push    r14fffff800`0419129e 4157            push    r15fffff800`041912a0 4883ec30        sub     rsp,30hfffff800`041912a4 488bda          mov     rbx,rdxfffff800`041912a7 448af9          mov     r15b,clfffff800`041912aa f0838a4004000004 lock or dword ptr [rdx+440h],4fffff800`041912b2 65488b3c2588010000 mov   rdi,qword ptr gs:[188h]fffff800`041912bb 4533ed          xor     r13d,r13dfffff800`041912be 41be01000000    mov     r14d,1fffff800`041912c4 413acd          cmp     cl,r13bfffff800`041912c7 747c            je      nt!PspExitProcess+0xbd (fffff800`04191345)fffff800`041912c9 ba02030000      mov     edx,302hfffff800`041912ce 488bcb          mov     rcx,rbxfffff800`041912d1 e842d6feff      call    nt!EtwTraceProcess (fffff800`0417e918)fffff800`041912d6 66ff8fc4010000  dec     word ptr [rdi+1C4h]看了一下PspExitProcess,在fffff800`041912d1 call    nt!EtwTraceProcess,这里距离PspExitProcess开头非常近,基本上保存了参数,颠末应该一个判断,就进入了etw。
而体系调用的事件,进入etw是在函数快竣事的位置,返回就继续返回就竣事了。
据此猜想,process事件的要更换的函数指针应该是PspExitProcess里call进etw时保存函数返回所在,
而不是想体系调用一样PspExitProcess的一个新开始所在指针。
如果是新的会有重入题目,而且既然在头部进入etw记录,
返回就继续实行就行了,没须要那么做,当然这不是百分之百的确定,要把PspExitProcess逆一遍,看看返回后是否真的在继续实行PspExitProcess,或者颠末一个判断直接跳到末尾然后返回(当然在ida里看跳转图,不能一次到末尾),如果是返回继续实行,那么更换函数返回所在,本身构造一个fakePspExitProcess函数,应该也是可行的。
0x4竣事

以上均为个人的逆向分析,如果有错误或是不同观点,欢迎指出。

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-11-24 19:38 , Processed in 0.062500 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表