关闭

另类HOOK 以KiFastSystemCall为例

标签: c++hook
1523人阅读 评论(1) 收藏 举报
分类:
标题的另类并非什么高新技术, 说白了仍是满大街的inline hook, 只不过它为解决可patch空间不足提供了一种有限的解决方案, 本文以32位windows系统的KiFastSystemCall为例.

简言之, KiFastSystemCall是ring3程序进入内核的入口, hook KiFastSystemCall一次即可拦截大部分系统调用, 有时候甚至可以避免被检测到,但是inline较繁琐, 除了需要维护堆栈平衡, 还可能遇到可patch空间不足的问题, IDA结果如下:
.text:7C92E510 ; =============== S U B R O U T I N E =======================================
.text:7C92E510
.text:7C92E510
.text:7C92E510                 public KiFastSystemCall
.text:7C92E510 KiFastSystemCall proc near              ; DATA XREF: .text:off_7C923428o
.text:7C92E510                 mov     edx, esp
.text:7C92E512                 sysenter
.text:7C92E512 KiFastSystemCall endp ; sp-analysis failed
.text:7C92E512
.text:7C92E514 ; Exported entry  42. KiFastSystemCallRet
.text:7C92E514
.text:7C92E514 ; =============== S U B R O U T I N E =======================================
.text:7C92E514
.text:7C92E514
.text:7C92E514                 public KiFastSystemCallRet
.text:7C92E514 KiFastSystemCallRet proc near           ; DATA XREF: .text:off_7C923428o
.text:7C92E514                 retn
.text:7C92E514 KiFastSystemCallRet endp
.text:7C92E514
.text:7C92E514 ; ---------------------------------------------------------------------------
容易看出, 上面包括了两个子过程, KiFastSystemCall和KiFastSystemCallRet, 并且存在重叠部分.
这么长的分析结果其实只有三句汇编代码:
.text:7C92E510       8B D4       mov     edx, esp
.text:7C92E512       0F 34       sysenter
.text:7C92E514       C3          retn
刚刚5个字节, 恰好放下0xE9 jmp, 但是不要忘了, 上述指令存在重叠部分, 直接改写显然是不行的(对于部分打了补丁的系统, 会存在nop空隙, 不存在本文所述问题).
解决方案同样有多种多样, 上述给ntdll.dll打nop的算一种, 但是明显不容易实践, 使用短跳再长跳的也算一种(需要在附近找到可当跳板的地方), 而本文提供的则是另一种方法, 试想有没有可能实现4个字节的0xE9 jmp? (0xFF25 jmp亦可, 甚至更简单)
答案当然是有, 我们只要保证0xC3这个字节不被改变就行, 也就是找到一个合适的地址pTarget满足pTarget-(0x7C92E510+5)=0xC3??????, 这个怎么找?一种简单的方法如下:
				// little-endian, unsafe
				static unsigned long incs[] = {
					0xc3000000,0xc3001000,0xc3002000,0xc3003000,0xc3004000,0xc3005000,0xc3006000,0xc3007000,0xc3008000,0xc3009000,0xc300a000,0xc300b000,0xc300c000,0xc300d000,0xc300e000,0xc300f000,
					0xc3010000,0xc3011000,0xc3012000,0xc3013000,0xc3014000,0xc3015000,0xc3016000,0xc3017000,0xc3018000,0xc3019000,0xc301a000,0xc301b000,0xc301c000,0xc301d000,0xc301e000,0xc301f000,
					0xc3020000,0xc3021000,0xc3022000,0xc3023000,0xc3024000,0xc3025000,0xc3026000,0xc3027000,0xc3028000,0xc3029000,0xc302a000,0xc302b000,0xc302c000,0xc302d000,0xc302e000,0xc302f000,
					0xc3030000,0xc3031000,0xc3032000,0xc3033000,0xc3034000,0xc3035000,0xc3036000,0xc3037000,0xc3038000,0xc3039000,0xc303a000,0xc303b000,0xc303c000,0xc303d000,0xc303e000,0xc303f000,
					0xc3050000,0xc3051000,0xc3052000,0xc3053000,0xc3054000,0xc3055000,0xc3056000,0xc3057000,0xc3058000,0xc3059000,0xc305a000,0xc305b000,0xc305c000,0xc305d000,0xc305e000,0xc305f000,
					0xc3060000,0xc3061000,0xc3062000,0xc3063000,0xc3064000,0xc3065000,0xc3066000,0xc3067000,0xc3068000,0xc3069000,0xc306a000,0xc306b000,0xc306c000,0xc306d000,0xc306e000,0xc306f000,
					0xc3070000,0xc3071000,0xc3072000,0xc3073000,0xc3074000,0xc3075000,0xc3076000,0xc3077000,0xc3078000,0xc3079000,0xc307a000,0xc307b000,0xc307c000,0xc307d000,0xc307e000,0xc307f000,
					0xc3080000,0xc3081000,0xc3082000,0xc3083000,0xc3084000,0xc3085000,0xc3086000,0xc3087000,0xc3088000,0xc3089000,0xc308a000,0xc308b000,0xc308c000,0xc308d000,0xc308e000,0xc308f000,
					0xc3090000,0xc3091000,0xc3092000,0xc3093000,0xc3094000,0xc3095000,0xc3096000,0xc3097000,0xc3098000,0xc3099000,0xc309a000,0xc309b000,0xc309c000,0xc309d000,0xc309e000,0xc309f000,
					0xc3100000
				};
遍历上面这个表并尝试申请该块内存(0x1000内存页对齐):
				for each (auto inc in incs)
				{
					auto basic = dest + inc;
					auto ret   = VirtualAlloc(basic, sizeof(JMP_REL), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
					if (ret > 0 && (LPBYTE(ret) + 0x1000 - basic) >= 5) {
						// 找到目标地址, 放置shellcode即可
						break;
					} //if
				}

总言之, 这个方法略暴力, 但是有时候确实可以解决许多问题.

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    联系作者
    通过QQ与我联系(全天候7*24小时基本不在线)
    最新评论
    免责声明
    如果转载的文章侵犯了您的版权,请务必告知,我将立刻删除;
    博客所有文章允许转载,原创类不要求注明出处,随意就好;
    如果是转载的文章,建议直接转载原始来源,因为原作者极可能有更新