x64(学习笔记) - 3(x64InlineHook)

inlineHook 过程

  1. 选择hook方式
  2. 获取hook地址(如果是导入表的函数注意jmp)
  3. 计算hook掉的字节(汇编引擎 / 手动计算)
  4. 保存要被替换掉的汇编,计算被替换掉字节下一行的地址
  5. 构建hook shellcode
  6. shellCode替换掉目标地址的代码(为了不破坏原有寄存器,需要保存当前寄存器,火哥推荐的是 构建的shellcode 使用asm push所有寄存器 然后提升栈顶 调用自己的函数 恢复栈顶 然后pop)
  7. 构建调用原函数的 shell code, 执行被替换掉的汇编,然后jmp到之前存储的地址

要点

  • 因为原有call都是相对偏移,如果hook call相关的 比较麻烦
  • 不能直接hook 函数的地址 因为可能会有jmp跳转,直接调用的函数的地址 可能不是函数头是jmp
    需要使用GetModuleHandleA 然后再GetProcAddress 获取到函数地址

注意

  • 在写代码的时候,尽量少直接传递结构体(浪费性能,会多次复制结构)
  • 再使用 xx xx xx xx xx xx xx xx ff 25 f2 ff ff ff 这种构造调整的时候 需要注意 地址会被当成命令来执行

反调试

  • 回溯堆栈 看看来源 是不是自己模块的函数
  • 伪造调用 调用完挂hook / veh 在修复

代码

InlineHookEngine.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "InlineHookEngine.h"
#include "LDasm.h"

typedef HANDLE(WINAPI* OpenProcessProc)(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwProcessId
);


EXTERN_C HANDLE Hook(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwProcessId);

EXTERN_C HANDLE NewOpenProcess(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwProcessId
)
{
printf("-------------------------------------\r\n");
return 0;
}

char* oldCode;


uint32_t GetAsmLength(PVOID psrc)
{
ldasm_data ld = { 0 };
uint32_t len = ldasm(psrc, &ld, is_x64);
return len;
}

UINT GetFuncOffset(PVOID funcAddress,UINT needOffsetNum,UINT currentNum = 0)
{
PVOID newfuncAddress = (PVOID)((UINT64)funcAddress + currentNum);
currentNum += GetAsmLength(newfuncAddress);
if (currentNum >= needOffsetNum)
{
return currentNum;
}
return GetFuncOffset(funcAddress, needOffsetNum,currentNum);
}


EXTERN_C int main()
{
//1.获取hook位置
HMODULE hModule = GetModuleHandleA("kernelbase.dll");
PVOID64 funAddress = GetProcAddress(hModule, "OpenProcess");


//2.计算hook掉的字节
UINT offset = GetFuncOffset(funAddress, 6); // LDasm

//3.保存要被替换掉的汇编,计算被替换掉字节下一行的地址
oldCode = (char*)malloc(offset);
memcpy(oldCode, funAddress, offset);

ULONG64 originalFuncLastAddress = (ULONG64)funAddress + offset;

//4.构建hook shell code

//函数头部的hook 利用函数头部空白的字节来操作 需要判断函数头部空白字节是否有8个0x00 / 0x90 / 0xCC
char shellCode[] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x25,0xF2,0xff,0xff,0xff
};
*(PULONG64)&shellCode = (ULONG64)Hook;

//修改原函数
PVOID64 hookFunAddress = (PVOID64)((ULONG64)funAddress - 8);
ULONG oldProtect;
if (VirtualProtect(hookFunAddress, USN_PAGE_SIZE, PAGE_EXECUTE_READWRITE, &oldProtect))
{
memcpy(hookFunAddress, shellCode, sizeof(shellCode));
VirtualProtect(hookFunAddress, USN_PAGE_SIZE, oldProtect, &oldProtect);
}
else
{
return 0;
}

//5.构建调回去的shell code
char CallOrginalFuncShellCode[] =
{
0xFF,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
PVOID CallOrginalFunc = VirtualAlloc(NULL, USN_PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(CallOrginalFunc, oldCode, offset);
*(PULONG64)&CallOrginalFuncShellCode[6] = originalFuncLastAddress;
memcpy((PVOID)((ULONG64)CallOrginalFunc + offset), CallOrginalFuncShellCode, sizeof(CallOrginalFuncShellCode));


//6.测试调用
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 10840);
printf("句柄为 %llx\r\n", handle);

auto OrginalFunc = (OpenProcessProc)CallOrginalFunc;
handle = OrginalFunc(PROCESS_ALL_ACCESS, FALSE, 10840);
printf("句柄为 %llx\r\n", handle);
return 0;
}

hook.asm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.code
NewOpenProcess proto;
Hook proc
push rax
push rbx
push rcx
push rdx
push rbp
push rsp
push rsi
push rdi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15

sub rsp,120h
call NewOpenProcess
add rsp,120h

pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rsp
pop rbp
pop rdx
pop rcx
pop rbx
;pop rax
add rsp,8
ret

Hook endp

end
评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...