1+ #include < string>
2+ // 跨平台兼容个灯
3+ #include < iostream>
4+ #define _WIN_PLATFORM_
5+
6+ #if defined(_WIN_PLATFORM_)
7+ #include < Windows.h>
8+ #elif defined(_LINUX_PLATFORM_)
9+ #include < cstring>
10+ #include < unistd.h>
11+ #include < sys/mman.h>
12+ #endif
13+
14+ void *GetCallAddress (uint8_t *ptr)
15+ {
16+ // 读取操作码
17+ if (ptr[0 ] != 0xE8 )
18+ {
19+ printf (" Not a call instruction!\n " );
20+ return 0 ;
21+ }
22+
23+ // 读取相对偏移量
24+ int32_t relativeOffset = *reinterpret_cast <int32_t *>(ptr + 1 );
25+
26+ // 计算函数地址
27+ uint8_t *callAddress = ptr + 5 ; // call 指令占 5 个字节
28+ void *functionAddress = callAddress + relativeOffset;
29+
30+ return reinterpret_cast <void *>(functionAddress);
31+ }
32+
33+ void *SearchAndFillJump (uint64_t baseAddress, void *targetAddress)
34+ {
35+ uint8_t jumpInstruction[] = {
36+ 0x49 , 0xBB ,
37+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
38+ 0x41 , 0xFF , 0xE3 };
39+
40+ memcpy (jumpInstruction + 2 , &targetAddress, 8 );
41+
42+ // Iterate through memory regions
43+ uint64_t searchStart = baseAddress - 0x7fffffff ;
44+ uint64_t searchEnd = baseAddress + 0x7fffffff ;
45+
46+ #if defined(_WIN_PLATFORM_)
47+ while (searchStart < searchEnd - sizeof (jumpInstruction))
48+ {
49+ MEMORY_BASIC_INFORMATION mbi;
50+ if (VirtualQuery (reinterpret_cast <void *>(searchStart), &mbi, sizeof (mbi)) == 0 )
51+ break ;
52+ if (mbi.State == MEM_COMMIT)
53+ {
54+ for (char *addr = static_cast <char *>(mbi.BaseAddress ); addr < static_cast <char *>(mbi.BaseAddress ) + mbi.RegionSize - 1024 * 5 ; ++addr)
55+ {
56+
57+ bool isFree = true ;
58+ for (int i = 0 ; i < 1024 * 5 ; ++i)
59+ {
60+ if (addr[i] != 0 )
61+ {
62+ isFree = false ;
63+ break ;
64+ }
65+ }
66+ if (isFree)
67+ {
68+ DWORD oldProtect;
69+ addr += 0x200 ;
70+ // printf("addr: %p\n", addr);
71+
72+ if (!VirtualProtect (addr, sizeof (jumpInstruction), PAGE_EXECUTE_READWRITE, &oldProtect))
73+ break ;
74+ memcpy (addr, jumpInstruction, sizeof (jumpInstruction));
75+ if (!VirtualProtect (addr, sizeof (jumpInstruction), PAGE_EXECUTE_READ, &oldProtect))
76+ break ;
77+
78+ return addr;
79+ }
80+ }
81+ }
82+ searchStart += mbi.RegionSize ;
83+ }
84+ #elif defined(_LINUX_PLATFORM_)
85+ // 保证地址对齐
86+ searchStart &= 0xfffffffffffff000 ;
87+ searchStart += 0x1000 ;
88+ searchEnd &= 0xfffffffffffff000 ;
89+
90+ auto pmap = hak::get_maps ();
91+ do
92+ {
93+ auto fpmap = pmap;
94+ pmap = fpmap->next ();
95+ if (std::min (pmap->start (), searchEnd) - std::max (fpmap->end (), searchStart) > 0x2000 ) // 搜索一片 0x2000 大小的空区域
96+ {
97+ void *addr = mmap (reinterpret_cast <void *>(std::max (fpmap->end (), searchStart)), 0x2000 , PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1 , 0 );
98+ // printf("addr: %p\n", addr);
99+ if (addr == MAP_FAILED)
100+ {
101+ printf (" mmap failed\n " );
102+ continue ;
103+ }
104+ if (reinterpret_cast <uint64_t >(addr) > searchEnd - sizeof (jumpInstruction))
105+ {
106+ munmap (addr, 0x2000 );
107+ printf (" addr > searchEnd\n " );
108+ continue ;
109+ }
110+ memcpy (addr, jumpInstruction, sizeof (jumpInstruction));
111+ if (mprotect (addr, 0x2000 , PROT_READ | PROT_EXEC) == -1 ) // 设置内存 r-w
112+ {
113+ munmap (addr, 0x2000 );
114+ printf (" mprotect failed\n " );
115+ continue ;
116+ }
117+ return addr;
118+ }
119+ } while (pmap->next () != nullptr );
120+
121+ #endif
122+ return nullptr ;
123+ }
124+
125+ bool Hook (uint8_t *callAddr, void *lpFunction)
126+ {
127+ uint64_t startAddr = reinterpret_cast <uint64_t >(callAddr) + 5 ;
128+ int64_t distance = reinterpret_cast <uint64_t >(lpFunction) - startAddr;
129+ #if defined(_WIN_PLATFORM_)
130+ // printf("Hooking %p to %p, distance: %lld\n", callAddr, lpFunction, distance);
131+
132+ DWORD oldProtect;
133+ DWORD reProtect;
134+ if (!VirtualProtect (callAddr, 10 , PAGE_EXECUTE_READWRITE, &oldProtect))
135+ {
136+ printf (" VirtualProtect failed\n " );
137+ return false ;
138+ }
139+ if (distance < INT32_MIN || distance > INT32_MAX)
140+ {
141+ void *new_ret = SearchAndFillJump (startAddr, lpFunction);
142+ if (new_ret == nullptr )
143+ {
144+ printf (" Can't find a place to jump\n " );
145+ return false ;
146+ }
147+ distance = reinterpret_cast <uint64_t >(new_ret) - startAddr;
148+ // printf("new_ret: %p, new_distance: %lld\n", new_ret, distance);
149+ }
150+ // 直接进行小跳转
151+ memcpy (callAddr + 1 , reinterpret_cast <int32_t *>(&distance), 4 ); // 修改 call 地址
152+ if (!VirtualProtect (callAddr, 10 , oldProtect, &reProtect)) // 恢复原来的内存保护属性
153+ {
154+ std::cout << GetLastError ()<<" /" <<callAddr<<" /" <<oldProtect<<" /" <<reProtect;
155+ printf (" VirtualProtect failed\n " );
156+ return false ;
157+ }
158+ return true ;
159+ #elif defined(_LINUX_PLATFORM_)
160+ // printf("Hooking %p to %p, distance: %ld\n", callAddr, lpFunction, distance);
161+
162+ auto get_page_addr = [](void *addr) -> void *
163+ {
164+ return (void *)((uintptr_t )addr & ~(getpagesize () - 1 ));
165+ };
166+
167+ if (mprotect (get_page_addr (callAddr), 2 * getpagesize (), PROT_READ | PROT_WRITE | PROT_EXEC) == -1 ) // 设置内存可写 两倍 pagesize 防止处于页边界
168+ {
169+ printf (" mprotect failed\n " );
170+ return false ;
171+ }
172+ if (distance < INT32_MIN || distance > INT32_MAX)
173+ {
174+ void *new_ret = SearchAndFillJump (startAddr, lpFunction);
175+ if (new_ret == nullptr )
176+ {
177+ printf (" Can't find a place to jump\n " );
178+ return false ;
179+ }
180+ distance = reinterpret_cast <uint64_t >(new_ret) - startAddr;
181+ // printf("new_ret: %p, new_distance: %ld\n", new_ret, distance);
182+ }
183+
184+ memcpy (callAddr + 1 , reinterpret_cast <int32_t *>(&distance), 4 ); // 修改 call 地址
185+ if (mprotect (get_page_addr (callAddr), 2 * getpagesize (), PROT_READ | PROT_EXEC) == -1 ) // 还原内存保护属性
186+ {
187+ printf (" mprotect failed\n " );
188+ return false ;
189+ }
190+ return true ;
191+ #endif
192+ }
0 commit comments