HOOK技术学习笔记-其二

0x00 前言

​ 来学习一下内联汇编的hook

0x01 一个借鉴并改编来的HOOK小模板

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
//======================================================================================

void MakeMemoryWritable(unsigned long ulAddress, unsigned long ulSize,DWORD *OldProtect)
{
MEMORY_BASIC_INFORMATION* mbi = new MEMORY_BASIC_INFORMATION;
VirtualQuery((void*)ulAddress, mbi, ulSize);
*OldProtect = mbi->Protect;
if (mbi->Protect != PAGE_EXECUTE_READWRITE)
{
unsigned long * ulProtect = new unsigned long;
VirtualProtect((void*)ulAddress, ulSize, PAGE_EXECUTE_READWRITE, ulProtect);
delete ulProtect;
}
delete mbi;
}
//======================================================================================

void RestoreMemoryProtect(unsigned long ulAddress, unsigned long ulSize, DWORD OldProtect)
{
if (OldProtect != PAGE_EXECUTE_READWRITE) {
unsigned long* temp = new unsigned long;
VirtualProtect((void*)ulAddress, ulSize, OldProtect, temp);
delete temp;
}
}

//======================================================================================

/*
由于采用InterlockedExchange64方式,固定会占8字节
从HOOK的起始位置往后数8字节,不足的进行对齐,ulNops即需要对齐多少字节
这里并没有将多出来的碎片字节nop掉,而是直接返回到存在碎片字节的指令的下一条指令
*/
BOOL Hook(unsigned long ulAddress, void* Function, BYTE** pSavedArray, unsigned long ulNops)
{
__try{
DWORD OldProtect = 0;
MakeMemoryWritable(ulAddress, 8+ ulNops, &OldProtect);
*pSavedArray = (BYTE*)malloc(8+ ulNops);
if (*pSavedArray == NULL) {
return FALSE;
}
memcpy(*pSavedArray, (void*)ulAddress, 8+ ulNops);
BYTE bReplace[8] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
bReplace[0] = 0xE9;
*(DWORD*)(&(bReplace[1])) = JumpCall(ulAddress, Function);
LONG64 llReplace;
memcpy(&llReplace, bReplace, 8);
InterlockedExchange64((LONG64 volatile*)ulAddress, llReplace);
RestoreMemoryProtect(ulAddress, 8+ ulNops, OldProtect);
return TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; }
}
//======================================================================================
1
2
3
4
5
6
7
8
//小示例
void Start() {
Hook(hookAddr, targetFunc, &pSavedArray,0);
}
void End() {
memcpy((void*)hookAddr, pSavedArray, _msize(pSavedArray));
//_msize可以取到malloc时的长度,但是这对函数的使用提出了更严格的要求,由于单位是BYTE,所以没有必要去除以sizeof(BYTE)
}

0x02 编写中遇到的几个问题

LNK2005 某个变量已经在***.obj中定义

这个问题的原因有多种

而我是因为头文件的重复包含,具体来讲就是,某个头文件有被多个.h或者.cpp文件包含。

因为在一个大的工程中,需要增加一个全局变量,一开始我是加在了某一个头文件中,然后报重复定义的错误,很显然,由于这个头文件被多个源文件include,虽然在编译阶段可能能通过,但是在链接的时候就会出现重复定义的错误。

解决方法

首先要做的

尽量不把其他.cpp文件需要用到的变量定义在.h文件中!

直接在其他.cpp文件中定义变量

方案一

使用ifndef-define-endif的结构

1
2
3
4
5
6
//InlineHook.h
#include "pch.h"
#ifndef INLINEHOOK_H_FILE
#define INLINEHOOK_H_FILE
//在这里面写内容
#endif

方案二

使用#prama once结构

1
2
3
#pragma once
#include "pch.h"
//在这写内容

C2065 未声明的标识符

很尴尬的一个错误,是头文件顺序错了

1
2
3
4
5
6
7
//错误的顺序
#include"InlineHook.h"
#include"pch.h"

//正确的顺序
#include"pch.h"
#include"InlineHook.h"

naked只能应用到非成员函数的定义

这种汇编的函数在头文件中的话,需要声明且实现,不可以在头文件(.h)声明而在源文件(.c或者.cpp)中实现

而且为了避免再次出现LNK2005的报错,最好加上static关键字

1
2
3
4
5
6
7
8
9
10
//示例, InlineHook.h
static __declspec(naked) void test()
{
__asm {
xor ecx, ecx
mov dword ptr[ebp - 0x7c], ecx
push 0x48C6E2
ret
}
}

0x03 参考

能不能在头文件中定义全局变量

为什么不将全局变量的声明放在头文件中

C++中为什么不能将全局变量定义在头文件中?

ifndef与pragma once的对比

-------------至此本文结束感谢您的阅读-------------
如果觉得这篇文章对您有用,请随意打赏。 (๑•⌄•๑) 您的支持将鼓励我继续创作!