c++hook内联汇编模板
1 #include "Windows.h" 2 #include "tlhelp32.h" 3 #include "String.h" 4 #include "Shlwapi.h" 5 #include "iostream" 6 #include "map" 7 using namespace std; 8 9 HANDLE hProcess; 10 LPVOID lp_address; 11 LPVOID lp_ret_value_address; 12 DWORD lp_ret_jmp, calladd; 13 DWORD lp_to_jmp; 14 15 template <typename T> 16 T Read(LPVOID Address) 17 { 18 T Data; 19 ReadProcessMemory(hProcess, (LPVOID)Address, &Data, sizeof(T), nullptr); 20 return Data; 21 } 22 23 uintptr_t FindPattern(uintptr_t start, uintptr_t length, const unsigned char* pattern, const char* mask) 24 { 25 size_t pos = 0; 26 auto maskLength = strlen(mask) - 1; 27 28 auto startAdress = start; 29 for (auto it = startAdress; it < startAdress + length; ++it) 30 { 31 if (Read<unsigned char>(LPVOID(it)) == pattern[pos] || mask[pos] == '?') 32 { 33 if (mask[pos + 1] == '\0') 34 return it - maskLength; 35 36 pos++; 37 } 38 else pos = 0; 39 } 40 return 0; 41 } 42 43 //读内存4字节整数型 44 DWORD _ReadMemeryInt(HANDLE hGameHandle, DWORD _address) 45 { 46 DWORD buffer; 47 ReadProcessMemory(hGameHandle, LPCVOID(_address), &buffer, sizeof(buffer), NULL); 48 return buffer; 49 } 50 51 //读内存小数型 52 FLOAT _ReadMemeryFloat(HANDLE hGameHandle, DWORD _address) 53 { 54 FLOAT buffer; 55 ReadProcessMemory(hGameHandle, LPCVOID(_address), &buffer, sizeof(buffer), NULL); 56 return buffer; 57 } 58 59 //读内存文本型 60 char* _ReadMemeryString(HANDLE hGameHandle, DWORD _address) 61 { 62 char read[256]; 63 char* pa; 64 65 pa = read; 66 67 ReadProcessMemory(hGameHandle, LPCVOID(_address), read, sizeof(read), NULL); 68 69 for (pa; *pa != '\0'; pa++) 70 { 71 return pa; 72 } 73 74 } 75 76 //写内存整数型 77 BOOL WriteMemeryInt(HANDLE hGameHandle, DWORD _address, DWORD Data) 78 { 79 return WriteProcessMemory(hGameHandle, LPVOID(_address), &Data, sizeof(Data), NULL); 80 } 81 82 //写内存小数型 83 BOOL WriteMemeryFloat(HANDLE hGameHandle, DWORD _address, FLOAT Data) 84 { 85 return WriteProcessMemory(hGameHandle, LPVOID(_address), &Data, sizeof(Data), NULL); 86 } 87 88 //写内存字节数组 89 BOOL WriteMemeryBytes(HANDLE hGameHandle, DWORD _address, BYTE Data[], SIZE_T Bytes) 90 { 91 return WriteProcessMemory(hGameHandle, LPVOID(_address), Data, Bytes, NULL); 92 } 93 94 95 96 //特征码寻址 97 uintptr_t FindPattern(HMODULE hModule, const unsigned char* pattern, const char* mask) 98 { 99 IMAGE_DOS_HEADER DOSHeader = Read<IMAGE_DOS_HEADER>(hModule); 100 IMAGE_NT_HEADERS NTHeaders = Read<IMAGE_NT_HEADERS>(LPVOID(uintptr_t(hModule) + DOSHeader.e_lfanew)); 101 102 return FindPattern( 103 reinterpret_cast<uintptr_t>(hModule) + NTHeaders.OptionalHeader.BaseOfCode, 104 reinterpret_cast<uintptr_t>(hModule) + NTHeaders.OptionalHeader.SizeOfCode, pattern, mask); 105 } 106 107 HMODULE GetProcessModuleHandleByName(DWORD pid, LPCSTR ModuleName) 108 { 109 MODULEENTRY32 ModuleInfo; 110 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); 111 if (!hSnapshot) 112 { 113 return 0; 114 } 115 ZeroMemory(&ModuleInfo, sizeof(MODULEENTRY32)); 116 ModuleInfo.dwSize = sizeof(MODULEENTRY32); 117 if (!Module32First(hSnapshot, &ModuleInfo)) 118 { 119 return 0; 120 } 121 do 122 { 123 if (!lstrcmpi(ModuleInfo.szModule, ModuleName)) 124 { 125 CloseHandle(hSnapshot); 126 return ModuleInfo.hModule; 127 } 128 } while (Module32Next(hSnapshot, &ModuleInfo)); 129 CloseHandle(hSnapshot); 130 return 0; 131 } 132 133 DWORD GetProcessIDByName(const char* pName) 134 { 135 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 136 if (INVALID_HANDLE_VALUE == hSnapshot) { 137 return NULL; 138 } 139 PROCESSENTRY32 pe = { sizeof(pe) }; 140 for (BOOL ret = Process32First(hSnapshot, &pe); ret; ret = Process32Next(hSnapshot, &pe)) { 141 if (strcmp(pe.szExeFile, pName) == 0) { 142 CloseHandle(hSnapshot); 143 return pe.th32ProcessID; 144 } 145 //printf("%-6d %s\n", pe.th32ProcessID, pe.szExeFile); 146 } 147 CloseHandle(hSnapshot); 148 return 0; 149 } 150 151 152 //内联汇编被写入 153 inline __declspec(naked) void ret_hook() 154 { 155 __asm 156 { 157 Pushfd 158 Pushad 159 add esi, 0xC 160 push esi 161 mov dword ptr[esi], edx 162 mov eax ,0xCF7000 163 mov [eax], esi 164 sub esi, 0xC 165 pop esi 166 popad 167 popfd 168 mov dword ptr[esi + 0xC], edx 169 } 170 } 171 172 173 int main() 174 { 175 SetConsoleTitleA("过考试"); 176 177 DWORD OldProtect = NULL; 178 int Pid = GetProcessIDByName("qwq.exe"); 179 hProcess = INVALID_HANDLE_VALUE; 180 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);//游戏进程句柄 181 182 cout << "进程ID:" << Pid << endl << "进程句柄:" << hProcess << endl; 183 184 HMODULE hbcryptPrimitives = GetProcessModuleHandleByName(Pid, "qwq.exe"); 185 lp_ret_jmp = (DWORD)hbcryptPrimitives + 0x74c93; 186 lp_to_jmp = (DWORD)hbcryptPrimitives + 0x74c8b; 187 calladd = (DWORD)hbcryptPrimitives + 0x742a0; 188 189 lp_address = VirtualAllocEx(hProcess, NULL, 128, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 190 cout << lp_address << endl; 191 192 SIZE_T num_byte; 193 SIZE_T *p = &num_byte; 194 195 WriteProcessMemory(hProcess, lp_address, ret_hook, 50, p); 196 197 198 BYTE call_e8 = { 0xe8 }; 199 WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_address + 0x18), (LPVOID)&call_e8, 1, NULL); 200 int rec_call = (int)calladd - ((DWORD)lp_address + 0x18) - 5; 201 WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_address + 0x19), (LPVOID)&rec_call, 4, NULL); 202 203 BYTE jmp_e9 = { 0xe9 }; 204 WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_address+0x19+4), (LPVOID)&jmp_e9, 1, NULL); 205 int jmp_ret = (int)lp_ret_jmp - ((DWORD)lp_address + 0x19 + 4) - 5; 206 WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_address + 0x19 + 5), (LPVOID)&jmp_ret, 4, NULL); 207 208 WriteProcessMemory(hProcess, (LPVOID)(DWORD)lp_to_jmp, (LPVOID)&jmp_e9, 1, NULL); 209 int jmp_to = (int)lp_address - (DWORD)lp_to_jmp -5; 210 WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_to_jmp + 1), (LPVOID)&jmp_to, 4, NULL); 211 212 213 BYTE nop_90 = { 0x90 }; 214 WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_to_jmp +5), (LPVOID)&nop_90, 1, NULL); 215 WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_to_jmp + 6), (LPVOID)&nop_90, 1, NULL); 216 WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_to_jmp + 7), (LPVOID)&nop_90, 1, NULL); 217 218 DWORD tmpadd_mon = _ReadMemeryInt(hProcess, 0xCF7000); 219 double add_data_mon = _ReadMemeryFloat(hProcess, tmpadd_mon); 220 //cout << "对象地址:" << hex << tmpadd_mon << " " << "对象坐标:" << add_data_mon << "\r"; 221 222 std::map<DWORD, DWORD> mymap; 223 224 225 int t = 100000; 226 while (t--) 227 { 228 DWORD tmpadd = _ReadMemeryInt(hProcess, 0xCF7000); 229 double add_data = _ReadMemeryFloat(hProcess, tmpadd); 230 std::map<DWORD, DWORD>::iterator it; 231 it = mymap.find(tmpadd); 232 if(it==mymap.end()) 233 { 234 cout << "怪物地址:" << hex << tmpadd << endl; 235 } 236 mymap[tmpadd] = tmpadd; 237 } 238 cout << "GO" << endl; 239 while (1) 240 { 241 DWORD tmpadd = _ReadMemeryInt(hProcess, 0xCF7000); 242 float add_data = _ReadMemeryFloat(hProcess, tmpadd); 243 std::map<DWORD, DWORD>::iterator qwq; 244 qwq = mymap.find(tmpadd); 245 //cout << hex << tmpadd << endl; 246 if (qwq == mymap.end()) 247 { 248 cout << "人物地址:" << hex << tmpadd << " " << "人物坐标:" << add_data <<" "<< "\r"; 249 } 250 } 251 252 //while (1) 253 //{ 254 // for (std::map<char, int>::iterator it = mymap.begin(); it != mymap.end(); it++) 255 // { 256 // double add_data = _ReadMemeryFloat(hProcess, (DWORD)(it->second)); 257 // cout << "对象地址:" << hex << (DWORD)(it->second) << " " << "对象坐标:" << add_data << endl; 258 // } 259 // system("cls"); 260 //} 261 262 263 264 ////cout << "分配的写入hook的地址:" << lp_address << hex << endl; 265 266 ////bcryptPrimitives.dll+24AFF - CC - int 3 267 268 //HMODULE hbcryptPrimitives = GetProcessModuleHandleByName(Pid, "qwq.exe"); 269 270 271 ////这边自己搞检测地址 272 //lp_ret_jmp = (DWORD)hbcryptPrimitives + 0x74C93; 273 //lp_to_jmp = (DWORD)hbcryptPrimitives + 0x74C8B; 274 //calladd = (DWORD)hbcryptPrimitives + 0x742A0; 275 ////cout << "跳回的地址计算:" << lp_ret_jmp << endl; 276 277 278 ///*写ret hook*/ 279 //if (WriteProcessMemory(hProcess, lp_address, ret_hook, 50, NULL) != 0) { 280 // cout << "写入成功!" << endl; 281 // cout << lp_address << endl; 282 283 284 // BYTE jmp_e9 = { 0xe9 }; 285 // WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_address + 0x7), (LPVOID)&jmp_e9, 1, NULL); 286 // int jmp_ret = (int)lp_ret_jmp - ((DWORD)lp_address + 0x7) - 5; 287 // WriteProcessMemory(hProcess, (LPVOID)((DWORD)lp_address + 0x8), (LPVOID)&jmp_ret, 4, NULL); 288 289 290 // //to hook 291 292 // BYTE jmp_to_e9 = { 0xe9 }; 293 // WriteProcessMemory(hProcess, (LPVOID)lp_to_jmp, (LPVOID)&jmp_to_e9, 1, NULL); 294 // int jmp_to_hook = (int)lp_address; 295 // WriteProcessMemory(hProcess, (LPVOID)(lp_to_jmp + 0x1), (LPVOID)&jmp_to_hook, 4, NULL); 296 297 298 299 //} 300 ///*ret jmp*/ 301 302 // 303 304 getchar(); 305 return 0; 306 }
实际操作时对写内存函数有疑问,jmp的机器码和跳转的地址不一致。从https://blog.csdn.net/chenchong_219/article/details/17973935转载过来这篇文章。
总结就是E9跳转的是相对地址,不是绝对地址,并且该相对地址不包含当前指令的长度。
要跳转的地址=偏移+5+当前E9指令的内存地址。
也就是说,当偏移为0时(E9 00000000),就会跳转到该E9指令的下一个位置。
比如 010073B4 - E9 00000000
那么他就会跳到 010073B9 这个地址
要跳转的地址=偏移+5+当前E9指令的内存地址。
也就是说,当偏移为0时(E9 00000000),就会跳转到该E9指令的下一个位置。
比如 010073B4 - E9 00000000
那么他就会跳到 010073B9 这个地址
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
od随便打开一个记事本,汇编几条jmp指令,可以看到如下
地址 HEX 反汇编
010073B4 - E9 7B9E8787 JMP 88881234
010073B9 - E9 769E8787 JMP 88881234
010073BE - E9 719E8787 JMP 88881234
010073C3 - E9 6C9E8787 JMP 88881234
010073C8 - E9 679E8787 JMP 88881234
010073CD - E9 629E8787 JMP 88881234
010073D2 - E9 5D9E8787 JMP 88881234
010073D7 - E9 589E8787 JMP 88881234
010073DC - E9 539E8787 JMP 88881234
010073E1 - E9 4E9E8787 JMP 88881234
010073E6 - E9 499E8787 JMP 88881234
可以看到同样的汇编指令,在不同的地址上的机器码不一样。
有啥关系呢?看第一条:88881234-010073b4=87879e80
这个值跟E9后面的那个值差了5(E9后面那个值要反过来看,因为X86是大端模式)
同样这个规律也使用与后面几条。
为什么呢?
下面摘录一个网上的
直接的jmp分3种
Short Jump(短跳转)机器码 EB rel8
只能跳转到256字节的范围内
Near Jump(近跳转)机器码 E9 rel16/32
可跳至同一个段的范围内的地址
Far Jump(远跳转)机器码EA ptr 16:16/32
可跳至任意地址,使用48位/32位全指针
要注意的是,短跳转和近跳转指令中包含的操作数都是相对于(E)IP的偏移,而远跳转指令中包含的是目标的绝对地址,所以短/近跳转会出现跳至同一目标的指令机器码不同,不仅会不同,而且应该不同。而远跳转中包含的是绝对地址,因此转移到同一地址的指令机器码相同
下面的指令是这样计算偏移的.
004A2FCE ^ E9 072BFEFF jmp 00485ADA
========
485ADA-4A2FCE= FFFE2B0C 这里只是指向当前指令的IP处,实际计算跳转地址要去
掉当前指令的长度,当前的跳转指令需要5个字节,FFFE2B0C-5=FFFE2B07
我们一般就用E9了,所以计算公式就是 要跳转的地址-指令所在的位置-5=机器码
当然 如果我们要在内存中写的话,肯定是写机器码的。也就是也E9 机器码。
结合上面的博文,可以在被HOOK的地址出写入JMP指令跳回到原来的地方,
被HOOK的地址-原来地址-5 = 机器码(这个就是要写入到 被HOOK地址的地方)
为什么不直接修改SSDT表,因为很多程序都会循环去看又没有被改回来,又会被修改回去。

浙公网安备 33010602011771号