12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
游戏盒子— 各种稀有手游私服,可以下载 各种变态版 手游交流群:117375085 进入游戏
刀剑演武 现金BOSS,不氪金也能毕业! 创角就赠送至尊8 绝版GM装备送! 进入游戏
《绝世秘籍》 每日精彩活动嗨不停 充值赠送会员 积分换极品装备 进入游戏
《百战沙城》 不肝不氪也可群殴boss 装备满屏爆 超值首充 进入游戏
全民仙战 任意首充送纯白歌宴绝版绚丽时装! 元宝福利免费领 今日新开 进入游戏
查看: 303|回复: 0

InfinityHook 事件逆向

[复制链接]
发表于 2022-1-28 22:09:25 | 显示全部楼层 |阅读模式
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, 2022-10-5 13:56 , Processed in 0.109375 second(s), 22 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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