├── LICENSE ├── README.md ├── docs └── documentation.txt ├── examples └── linux │ ├── compile.sh │ └── main.cpp └── mem ├── mem.cpp └── mem.hpp /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

MOVED TO: rdbo/libmem

2 | 3 | # Memory 4 | Memory Management on Windows/Linux 5 | https://github.com/rdbo/Memory 6 | 7 | # libmem 8 | C-Compatible version of this project, which is being more updated and has more features: 9 | https://github.com/rdbo/libmem 10 | 11 | # Usage 12 | Just copy the "mem" folder to your project, then include "mem/mem.hpp" and make sure to compile "mem/mem.cpp". 13 | Check "docs/documentation.txt" for more guidance 14 | 15 | # LICENSE 16 | Read LICENSE 17 | 18 | # Overview 19 | ``` 20 | mem::ex::get_pid 21 | mem::ex::get_process 22 | mem::ex::get_process_name 23 | mem::ex::get_module_info 24 | mem::ex::is_process_running 25 | mem::ex::read 26 | mem::ex::write 27 | mem::ex::set 28 | mem::ex::scan 29 | mem::ex::protect 30 | mem::ex::allocate 31 | mem::ex::pattern_scan 32 | mem::ex::load_library 33 | 34 | mem::in::get_pid 35 | mem::in::get_process 36 | mem::in::get_process_name 37 | mem::in::get_module_info 38 | mem::in::read 39 | mem::in::write 40 | mem::in::set 41 | mem::in::scan 42 | mem::in::protect 43 | mem::in::allocate 44 | mem::in::detour 45 | mem::in::detour_length 46 | mem::in::detour_trampoline 47 | mem::in::detour_restore 48 | mem::in::pattern_scan 49 | mem::in::load_library 50 | ``` 51 | 52 | # Projects 53 | Projects made with the Memory Lib: 54 | ![Counter-Strike 1.6 External Bunnyhop Hack (Linux)](https://github.com/rdbo/cstrike-bhop-ex-linux) 55 | ![Counter-Strike 1.6 Internal Bunnyhop Hack (Linux)](https://github.com/rdbo/cstrike-bhop-in-linux) 56 | 57 | # TODO 58 | ``` 59 | Add support for allocating and protecting memory externally on Linux 60 | Add support for loading libraries externally on Linux 61 | Clean up code 62 | Add a simple documentation 63 | Add some examples 64 | ``` 65 | -------------------------------------------------------------------------------- /docs/documentation.txt: -------------------------------------------------------------------------------- 1 | Work in progress 2 | -------------------------------------------------------------------------------- /examples/linux/compile.sh: -------------------------------------------------------------------------------- 1 | clang++ -g main.cpp ../Memory/mem/mem.cpp -o main -ldl 2 | -------------------------------------------------------------------------------- /examples/linux/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../Memory/mem/mem.hpp" 2 | #define PROCESS_NAME MEM_STR("main") 3 | 4 | bool test_pid(mem::string_t process_name, mem::pid_t& pid) 5 | { 6 | mem::pid_t pid_in = mem::in::get_pid(); 7 | mem::pid_t pid_ex = mem::ex::get_pid(process_name); 8 | pid = pid_in; 9 | 10 | std::cout << "PID (in): " << pid_in << std::endl; 11 | std::cout << "PID (ex): " << pid_ex << std::endl; 12 | 13 | return pid_in != (mem::pid_t)MEM_BAD_RETURN && pid_in == pid_ex; 14 | } 15 | 16 | bool test_process_name(mem::pid_t pid, mem::string_t& process_name) 17 | { 18 | mem::string_t process_name_in = mem::in::get_process_name(); 19 | mem::string_t process_name_ex = mem::ex::get_process_name(pid); 20 | process_name = process_name_in; 21 | 22 | std::cout << "Process Name (in): " << process_name_in << std::endl; 23 | std::cout << "Process Name (ex): " << process_name_ex << std::endl; 24 | 25 | return ( 26 | process_name_in == process_name_ex && 27 | process_name_in != "" 28 | ); 29 | } 30 | 31 | bool test_process(mem::string_t process_name, mem::process_t& process) 32 | { 33 | mem::process_t process_in = mem::in::get_process(); 34 | mem::process_t process_ex = mem::ex::get_process(process_name); 35 | process = process_in; 36 | 37 | std::cout << "Process ID (in): " << process_in.pid << std::endl; 38 | std::cout << "Process ID (ex): " << process_ex.pid << std::endl; 39 | std::cout << "Process Name (in): " << process_in.name << std::endl; 40 | std::cout << "Process Name (ex): " << process_ex.name << std::endl; 41 | 42 | return ( 43 | process_in.is_valid() && 44 | process_in == process_ex 45 | ); 46 | } 47 | 48 | bool function(bool ret) 49 | { 50 | asm( 51 | "nop\n" 52 | "nop\n" 53 | "nop\n" 54 | "nop\n" 55 | "nop\n" 56 | "nop\n" 57 | "nop\n" 58 | "nop\n" 59 | "nop\n" 60 | "nop\n" 61 | "nop\n" 62 | "nop\n" 63 | "nop\n" 64 | "nop\n" 65 | "nop\n" 66 | "nop\n" 67 | "nop\n" 68 | "nop\n" 69 | ); 70 | 71 | std::cout << "the return is: " << ret << std::endl; 72 | return ret; 73 | } 74 | 75 | typedef bool(* function_t)(bool ret); 76 | function_t o_function; 77 | 78 | bool hk_function(bool ret) 79 | { 80 | std::cout << "the old ret was: " << ret << std::endl; 81 | ret = true; 82 | std::cout << "ret set to true" << std::endl; 83 | return o_function(ret); 84 | } 85 | 86 | bool test_hook() 87 | { 88 | mem::detour_int method = mem::detour_int::method0; 89 | o_function = (function_t)mem::in::detour_trampoline((mem::voidptr_t)&function, (mem::voidptr_t)&hk_function, mem::in::detour_length(method)); 90 | bool ret = function(false); 91 | return ret; 92 | } 93 | 94 | bool test_module(mem::process_t process) 95 | { 96 | mem::string_t mod_name = mem::string_t("/" + process.name + "\n"); 97 | mem::module_t mod_in = mem::in::get_module(mod_name); 98 | mem::module_t mod_ex = mem::ex::get_module(process, mod_name); 99 | 100 | std::cout << "Module Name (in): " << mod_in.name << std::endl; 101 | std::cout << "Module Name (ex): " << mod_ex.name << std::endl; 102 | std::cout << "Module Path (in): " << mod_in.path << std::endl; 103 | std::cout << "Module Path (ex): " << mod_ex.path << std::endl; 104 | std::cout << "Module Base (in): " << mod_in.base << std::endl; 105 | std::cout << "Module Base (ex): " << mod_ex.base << std::endl; 106 | std::cout << "Module Size (in): " << std::hex << mod_in.size << std::endl; 107 | std::cout << "Module Size (ex): " << std::hex << mod_ex.size << std::endl; 108 | std::cout << "Module End (in): " << mod_in.end << std::endl; 109 | std::cout << "Module End (ex): " << mod_ex.end << std::endl; 110 | std::cout << "Module Handle (in): " << mod_in.handle << std::endl; 111 | mod_ex.handle = mod_in.handle; 112 | 113 | return ( 114 | mod_in.is_valid() && 115 | mod_ex.is_valid() && 116 | mod_in == mod_ex 117 | ); 118 | } 119 | 120 | void separator() 121 | { 122 | std::cout << "-------------------" << std::endl; 123 | } 124 | 125 | int main() 126 | { 127 | mem::pid_t pid; 128 | mem::string_t process_name; 129 | mem::process_t process; 130 | 131 | std::cout << "test pid" << std::endl; 132 | bool btest_pid = test_pid(PROCESS_NAME, pid); 133 | separator(); 134 | 135 | std::cout << "test process name" << std::endl; 136 | bool btest_process_name = test_process_name(pid, process_name); 137 | separator(); 138 | 139 | std::cout << "test process" << std::endl; 140 | bool btest_process = test_process(process_name, process); 141 | separator(); 142 | 143 | std::cout << "test module" << std::endl; 144 | bool btest_module = test_module(process); 145 | separator(); 146 | 147 | std::cout << "test hook" << std::endl; 148 | bool btest_hook = test_hook(); 149 | separator(); 150 | 151 | std::cout << "<< Results >>" << std::endl; 152 | std::cout << "Test PID: " << btest_pid << std::endl; 153 | std::cout << "Test Process Name: " << btest_process_name << std::endl; 154 | std::cout << "Test Process: " << btest_process << std::endl; 155 | std::cout << "Test Module: " << btest_module << std::endl; 156 | std::cout << "Test Hook: " << btest_hook << std::endl; 157 | 158 | return 0; 159 | } -------------------------------------------------------------------------------- /mem/mem.cpp: -------------------------------------------------------------------------------- 1 | //Made by rdbo 2 | //https://github.com/rdbo/Memory 3 | 4 | #include "mem.hpp" 5 | #if defined(MEM_COMPATIBLE) 6 | 7 | const mem::byte_t MEM_JMP[] = ASM_GENERATE(_MEM_JMP); 8 | const mem::byte_t MEM_JMP_RAX[] = ASM_GENERATE(_MEM_JMP_RAX); 9 | const mem::byte_t MEM_JMP_EAX[] = ASM_GENERATE(_MEM_JMP_EAX); 10 | const mem::byte_t MEM_CALL[] = ASM_GENERATE(_MEM_CALL); 11 | const mem::byte_t MEM_CALL_EAX[] = ASM_GENERATE(_MEM_CALL_EAX); 12 | const mem::byte_t MEM_CALL_RAX[] = ASM_GENERATE(_MEM_CALL_RAX); 13 | const mem::byte_t MEM_MOVABS_RAX[] = ASM_GENERATE(_MEM_MOVABS_RAX); 14 | const mem::byte_t MEM_MOV_EAX[] = ASM_GENERATE(_MEM_MOV_EAX); 15 | const mem::byte_t MEM_PUSH[] = ASM_GENERATE(_MEM_PUSH); 16 | const mem::byte_t MEM_PUSH_RAX[] = ASM_GENERATE(_MEM_PUSH_RAX); 17 | const mem::byte_t MEM_PUSH_EAX[] = ASM_GENERATE(_MEM_PUSH_EAX); 18 | const mem::byte_t MEM_RET[] = ASM_GENERATE(_MEM_RET); 19 | const mem::byte_t MEM_BYTE[] = ASM_GENERATE(_MEM_BYTE); 20 | const mem::byte_t MEM_WORD[] = ASM_GENERATE(_MEM_WORD); 21 | const mem::byte_t MEM_DWORD[] = ASM_GENERATE(_MEM_DWORD); 22 | const mem::byte_t MEM_QWORD[] = ASM_GENERATE(_MEM_QWORD); 23 | #if defined(MEM_86) 24 | const mem::byte_t MEM_MOV_REGAX[] = ASM_GENERATE(_MEM_MOV_EAX); 25 | #elif defined(MEM_64) 26 | const mem::byte_t MEM_MOV_REGAX[] = ASM_GENERATE(_MEM_MOVABS_RAX); 27 | #endif 28 | 29 | //mem 30 | 31 | mem::string_t mem::parse_mask(string_t mask) 32 | { 33 | for (size_t i = 0; i < mask.length(); i++) 34 | mask[i] = mask.at(i) == MEM_KNOWN_BYTE || mask.at(i) == (char)toupper(MEM_KNOWN_BYTE) ? MEM_KNOWN_BYTE : MEM_UNKNOWN_BYTE; 35 | 36 | return mask; 37 | } 38 | 39 | //mem::ex 40 | 41 | mem::pid_t mem::ex::get_pid(string_t process_name) 42 | { 43 | pid_t pid = (pid_t)MEM_BAD_RETURN; 44 | # if defined(MEM_WIN) 45 | HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 46 | if (hSnap != INVALID_HANDLE_VALUE) 47 | { 48 | PROCESSENTRY32 procEntry; 49 | procEntry.dwSize = sizeof(procEntry); 50 | 51 | if (Process32First(hSnap, &procEntry)) 52 | { 53 | do 54 | { 55 | if (!lstrcmp(procEntry.szExeFile, process_name.c_str())) 56 | { 57 | pid = procEntry.th32ProcessID; 58 | break; 59 | } 60 | } while (Process32Next(hSnap, &procEntry)); 61 | 62 | } 63 | } 64 | CloseHandle(hSnap); 65 | # elif defined(MEM_LINUX) 66 | DIR* pdir = opendir("/proc"); 67 | if (!pdir) 68 | return pid; 69 | 70 | struct dirent* pdirent; 71 | while (pid < 0 && (pdirent = readdir(pdir))) 72 | { 73 | pid_t id = atoi(pdirent->d_name); 74 | if (id > 0) 75 | { 76 | std::string proc_name = get_process_name(id); 77 | if (!strcmp(proc_name.c_str(), process_name.c_str())) 78 | pid = id; 79 | } 80 | } 81 | closedir(pdir); 82 | # endif 83 | return pid; 84 | } 85 | 86 | mem::process_t mem::ex::get_process(string_t process_name) 87 | { 88 | process_t process; 89 | process.pid = get_pid(process_name); 90 | process.name = get_process_name(process.pid); 91 | # if defined(MEM_WIN) 92 | process.handle = OpenProcess(PROCESS_ALL_ACCESS, NULL, process.pid); 93 | # elif defined(MEM_LINUX) 94 | # endif 95 | return process; 96 | } 97 | 98 | mem::process_t mem::ex::get_process(pid_t pid) 99 | { 100 | process_t process; 101 | process.name = get_process_name(pid); 102 | process.pid = pid; 103 | # if defined(MEM_WIN) 104 | process.handle = OpenProcess(PROCESS_ALL_ACCESS, NULL, process.pid); 105 | # elif defined(MEM_LINUX) 106 | # endif 107 | return process; 108 | } 109 | 110 | mem::string_t mem::ex::get_process_name(pid_t pid) 111 | { 112 | mem::string_t process_name; 113 | # if defined(MEM_WIN) 114 | HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 115 | if (hSnap != INVALID_HANDLE_VALUE) 116 | { 117 | PROCESSENTRY32 procEntry; 118 | procEntry.dwSize = sizeof(procEntry); 119 | 120 | if (Process32First(hSnap, &procEntry)) 121 | { 122 | do 123 | { 124 | if (pid == procEntry.th32ProcessID) 125 | { 126 | process_name = string_t(procEntry.szExeFile); 127 | process_name = process_name.substr(process_name.rfind('\\', process_name.length()) + 1, process_name.length()); 128 | break; 129 | } 130 | } while (Process32Next(hSnap, &procEntry)); 131 | } 132 | } 133 | CloseHandle(hSnap); 134 | # elif defined(MEM_LINUX) 135 | char path_buffer[64]; 136 | snprintf(path_buffer, sizeof(path_buffer), "/proc/%i/maps", pid); 137 | std::ifstream file(path_buffer, std::ios::binary); 138 | if (!file.is_open()) return process_name; 139 | std::stringstream ss; 140 | ss << file.rdbuf(); 141 | std::size_t end = ss.str().find('\n', 0); 142 | std::size_t begin = ss.str().rfind('/', end) + 1; 143 | if (end == -1 || begin == -1 || begin == 0) return process_name; 144 | process_name = ss.str().substr(begin, end - begin); 145 | file.close(); 146 | # endif 147 | return process_name; 148 | } 149 | 150 | mem::module_t mem::ex::get_module(process_t process, string_t module_name) 151 | { 152 | module_t modinfo; 153 | if(!process.is_valid()) return modinfo; 154 | # if defined(MEM_WIN) 155 | HMODULE hMod; 156 | char_t modpath[MAX_PATH]; 157 | GetModuleHandleEx(NULL, module_name.c_str(), &hMod); 158 | MODULEINFO module_info = { 0 }; 159 | GetModuleInformation(process.handle, hMod, &module_info, sizeof(module_info)); 160 | GetModuleFileName(hMod, modpath, sizeof(modpath) / sizeof(char_t)); 161 | modinfo.base = (voidptr_t)module_info.lpBaseOfDll; 162 | modinfo.size = (size_t)module_info.SizeOfImage; 163 | modinfo.end = (voidptr_t)((uintptr_t)modinfo.base + modinfo.size); 164 | modinfo.handle = (module_handle_t)hMod; 165 | modinfo.path = modpath; 166 | 167 | # elif defined(MEM_LINUX) 168 | char path_buffer[64]; 169 | snprintf(path_buffer, sizeof(path_buffer), "/proc/%i/maps", process.pid); 170 | std::ifstream file(path_buffer, std::ios::binary); 171 | if (!file.is_open()) return modinfo; 172 | std::stringstream ss; 173 | ss << file.rdbuf(); 174 | 175 | std::size_t module_name_pos = 0; 176 | std::size_t module_name_end = 0; 177 | std::size_t next = 0; 178 | std::string module_name_str = ""; 179 | while((next = ss.str().find(module_name.c_str(), module_name_end)) != ss.str().npos && (module_name_pos = ss.str().find('/', next))) 180 | { 181 | module_name_end = ss.str().find('\n', module_name_pos); 182 | module_name_pos = ss.str().rfind('/', module_name_end) + 1; 183 | module_name_str = ss.str().substr(module_name_pos, module_name_end - module_name_pos); 184 | if(module_name_str.length() >= module_name.length()) 185 | { 186 | if(!MEM_STR_N_CMP(module_name_str.c_str(), module_name.c_str(), module_name.length())) 187 | break; 188 | } 189 | } 190 | 191 | if(module_name_pos == 0 || module_name_pos == -1 || module_name_pos == ss.str().npos || module_name_end == 0 || module_name_end == -1 || module_name_end == ss.str().npos) return modinfo; 192 | 193 | std::size_t base_address_pos = ss.str().rfind('\n', ss.str().find(mem::string_t('/' + module_name_str + '\n').c_str(), 0)) + 1; 194 | std:size_t base_address_end = ss.str().find('-', base_address_pos); 195 | if(base_address_pos == (std::size_t)-1 || base_address_end == (std::size_t)-1) return modinfo; 196 | std::string base_address_str = ss.str().substr(base_address_pos, base_address_end - base_address_pos); 197 | 198 | std::size_t end_address_pos = ss.str().rfind('\n', ss.str().rfind(mem::string_t('/' + module_name_str + '\n').c_str())); 199 | end_address_pos = ss.str().find('-', end_address_pos) + 1; 200 | std::size_t end_address_end = ss.str().find(' ', end_address_pos); 201 | if(end_address_pos == (std::size_t)-1 || end_address_end == (std::size_t)-1) return modinfo; 202 | std::string end_address_str = ss.str().substr(end_address_pos, end_address_end - end_address_pos); 203 | 204 | std::size_t module_path_pos = ss.str().find('/', end_address_end); 205 | std::size_t module_path_end = ss.str().find('\n', module_path_pos); 206 | if(module_path_pos == (std::size_t)-1 || module_path_end == (std::size_t)-1) return modinfo; 207 | std::string module_path_str = ss.str().substr(module_path_pos, module_path_end - module_path_pos); 208 | 209 | # if defined(MEM_86) 210 | mem::uintptr_t base_address = strtoul(base_address_str.c_str(), NULL, 16); 211 | mem::uintptr_t end_address = strtoul(end_address_str.c_str(), NULL, 16); 212 | # elif defined(MEM_64) 213 | mem::uintptr_t base_address = strtoull(base_address_str.c_str(), NULL, 16); 214 | mem::uintptr_t end_address = strtoull(end_address_str.c_str(), NULL, 16); 215 | # endif 216 | 217 | module_handle_t handle = (module_handle_t)MEM_BAD_RETURN; 218 | if(MEM_STR_CMP(process.name.c_str(), module_name_str.c_str())) 219 | handle = (module_handle_t)dlopen(module_path_str.c_str(), RTLD_LAZY); 220 | 221 | if( 222 | module_name_pos == (std::size_t)-1 || module_name_end == (std::size_t)-1 || 223 | base_address_pos == (std::size_t)-1 || base_address_end == (std::size_t)-1 || 224 | end_address_pos == (std::size_t)-1 || end_address_end == (std::size_t)-1 || 225 | module_path_pos == (std::size_t)-1 || module_path_end == (std::size_t)-1 226 | ) return modinfo; 227 | 228 | modinfo.name = module_name_str; 229 | modinfo.base = (mem::voidptr_t)base_address; 230 | modinfo.end = (mem::voidptr_t)end_address; 231 | modinfo.size = end_address - base_address; 232 | modinfo.path = module_path_str; 233 | modinfo.handle = handle; 234 | ss.str(""); 235 | file.close(); 236 | 237 | # endif 238 | 239 | return modinfo; 240 | } 241 | 242 | mem::bool_t mem::ex::is_process_running(process_t process) 243 | { 244 | if(!process.is_valid()) return (bool_t)false; 245 | # if defined(MEM_WIN) 246 | DWORD exit_code; 247 | GetExitCodeProcess(process.handle, &exit_code); 248 | return (bool_t)(exit_code == STILL_ACTIVE); 249 | # elif defined(MEM_LINUX) 250 | struct stat sb; 251 | char path_buffer[64]; 252 | snprintf(path_buffer, sizeof(path_buffer), "/proc/%i", process.pid); 253 | stat(path_buffer, &sb); 254 | return (bool_t)S_ISDIR(sb.st_mode); 255 | # endif 256 | return (bool_t)MEM_BAD_RETURN; 257 | } 258 | 259 | mem::int_t mem::ex::read(process_t process, voidptr_t src, voidptr_t dst, size_t size) 260 | { 261 | int_t ret = (int_t)MEM_BAD_RETURN; 262 | if(!process.is_valid()) return ret; 263 | # if defined(MEM_WIN) 264 | ret = (int_t)ReadProcessMemory(process.handle, (LPCVOID)src, (LPVOID)dst, (SIZE_T)size, NULL); 265 | # elif defined(MEM_LINUX) 266 | struct iovec iosrc; 267 | struct iovec iodst; 268 | iodst.iov_base = dst; 269 | iodst.iov_len = size; 270 | iosrc.iov_base = src; 271 | iosrc.iov_len = size; 272 | ret = process_vm_readv(process.pid, &iodst, 1, &iosrc, 1, 0); 273 | # endif 274 | return ret; 275 | } 276 | 277 | mem::int_t mem::ex::write(process_t process, voidptr_t src, voidptr_t data, size_t size) 278 | { 279 | int_t ret = (int_t)MEM_BAD_RETURN; 280 | if(!process.is_valid()) return ret; 281 | # if defined(MEM_WIN) 282 | ret = (int_t)WriteProcessMemory(process.handle, (LPVOID)src, (LPCVOID)data, (SIZE_T)size, NULL); 283 | # elif defined(MEM_LINUX) 284 | struct iovec iosrc; 285 | struct iovec iodst; 286 | iosrc.iov_base = data; 287 | iosrc.iov_len = size; 288 | iodst.iov_base = src; 289 | iodst.iov_len = size; 290 | ret = process_vm_writev(process.pid, &iosrc, 1, &iodst, 1, 0); 291 | # endif 292 | return ret; 293 | } 294 | 295 | mem::int_t mem::ex::set(process_t process, voidptr_t src, byte_t byte, size_t size) 296 | { 297 | int_t ret = MEM_BAD_RETURN; 298 | byte_t* data = new byte_t[size]; 299 | mem::in::set(data, byte, size); 300 | ret = write(process, src, data, size); 301 | delete[] data; 302 | return ret; 303 | } 304 | 305 | mem::int_t mem::ex::protect(process_t process, voidptr_t src, size_t size, prot_t protection) 306 | { 307 | int_t ret = (int_t)MEM_BAD_RETURN; 308 | # if defined(MEM_WIN) 309 | DWORD old_protect; 310 | if (process.handle == (HANDLE)NULL || src <= (voidptr_t)NULL || size == 0 || protection <= NULL) return ret; 311 | ret = (mem::int_t)VirtualProtectEx(process.handle, (LPVOID)src, (SIZE_T)size, (DWORD)protection, &old_protect); 312 | # elif defined(MEM_LINUX) 313 | # endif 314 | return ret; 315 | } 316 | 317 | mem::int_t mem::ex::protect(process_t process, voidptr_t begin, voidptr_t end, prot_t protection) 318 | { 319 | return protect(process, begin, (size_t)((uintptr_t)end - (uintptr_t)begin), protection); 320 | } 321 | 322 | mem::voidptr_t mem::ex::allocate(process_t process, size_t size, alloc_t allocation) 323 | { 324 | voidptr_t ret = (voidptr_t)MEM_BAD_RETURN; 325 | # if defined(MEM_WIN) 326 | if (process.handle == (HANDLE)NULL || size == 0 || allocation.protection == NULL || allocation.type == NULL) return ret; 327 | ret = (mem::voidptr_t)VirtualAllocEx(process.handle, NULL, size, (DWORD)allocation.type, (DWORD)allocation.protection); 328 | # elif defined(MEM_LINUX) 329 | # endif 330 | return ret; 331 | } 332 | 333 | mem::voidptr_t mem::ex::scan(process_t process, voidptr_t data, voidptr_t base, voidptr_t end, size_t size) 334 | { 335 | voidptr_t ret = (voidptr_t)MEM_BAD_RETURN; 336 | if(!process.is_valid()) return ret; 337 | for(uintptr_t i = 0; (uintptr_t)base + i < (uintptr_t)end; i += size) 338 | { 339 | voidptr_t read_bytes = malloc(size); 340 | mem::ex::read(process, (voidptr_t)((uintptr_t)base + i), read_bytes, size); 341 | if(in::compare(data, read_bytes, size)) 342 | { 343 | ret = (voidptr_t)((uintptr_t)base + i); 344 | break; 345 | } 346 | } 347 | 348 | return ret; 349 | } 350 | 351 | mem::voidptr_t mem::ex::pattern_scan(process_t process, bytearray_t pattern, string_t mask, voidptr_t base, voidptr_t end) 352 | { 353 | mask = parse_mask(mask); 354 | voidptr_t ret = (mem::voidptr_t)MEM_BAD_RETURN; 355 | uintptr_t scan_size = (uintptr_t)end - (uintptr_t)base; 356 | if(!process.is_valid()) return ret; 357 | 358 | for (uintptr_t i = 0; i < scan_size; i++) 359 | { 360 | bool found = true; 361 | int8_t pbyte; 362 | for (uintptr_t j = 0; j < pattern.length(); j++) 363 | { 364 | read(process, (voidptr_t)((uintptr_t)base + i + j), &pbyte, 1); 365 | found &= mask[j] == MEM_UNKNOWN_BYTE || pattern[j] == pbyte; 366 | } 367 | 368 | if (found) 369 | { 370 | ret = (voidptr_t)((uintptr_t)base + i); 371 | break; 372 | } 373 | } 374 | 375 | return ret; 376 | } 377 | 378 | mem::voidptr_t mem::ex::pattern_scan(process_t process, bytearray_t pattern, string_t mask, voidptr_t base, size_t size) 379 | { 380 | return pattern_scan(process, pattern, mask, base, (voidptr_t)((uintptr_t)base + size)); 381 | } 382 | 383 | mem::int_t mem::ex::load_library(process_t process, lib_t lib) 384 | { 385 | int_t ret = (int_t)MEM_BAD_RETURN; 386 | if(!lib.is_valid()) return ret; 387 | # if defined(MEM_WIN) 388 | if (lib.path.length() == 0 || process.handle == NULL) return ret; 389 | size_t buffer_size = (size_t)((lib.path.length() + 1) * sizeof(char_t)); 390 | alloc_t allocation; 391 | allocation.type = MEM_COMMIT | MEM_RESERVE; 392 | allocation.protection = PAGE_READWRITE; 393 | voidptr_t buffer_ex = allocate(process, buffer_size, allocation); 394 | if (buffer_ex == (voidptr_t)MEM_BAD_RETURN || buffer_ex == NULL) return ret; 395 | if (write(process, buffer_ex, (voidptr_t)lib.path.c_str(), buffer_size) == (int_t)MEM_BAD_RETURN) return ret; 396 | HANDLE hThread = CreateRemoteThread(process.handle, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, buffer_ex, 0, 0); 397 | if (hThread == INVALID_HANDLE_VALUE || hThread == NULL) return ret; 398 | WaitForSingleObject(hThread, -1); 399 | CloseHandle(hThread); 400 | VirtualFreeEx(process.handle, buffer_ex, 0, MEM_RELEASE); 401 | # elif defined(MEM_LINUX) 402 | # endif 403 | return ret; 404 | } 405 | 406 | //mem::in 407 | 408 | mem::pid_t mem::in::get_pid() 409 | { 410 | # if defined(MEM_WIN) 411 | return (pid_t)::GetCurrentProcessId(); 412 | # elif defined(MEM_LINUX) 413 | return (pid_t)::getpid(); 414 | # endif 415 | return (pid_t)MEM_BAD_RETURN; 416 | } 417 | 418 | mem::process_t mem::in::get_process() 419 | { 420 | process_t process; 421 | 422 | process.pid = get_pid(); 423 | process.name = get_process_name(); 424 | # if defined(MEM_WIN) 425 | process.handle = GetCurrentProcess(); 426 | # elif defined(MEM_LINUX) 427 | # endif 428 | 429 | return process; 430 | } 431 | 432 | mem::string_t mem::in::get_process_name() 433 | { 434 | mem::string_t process_name; 435 | # if defined(MEM_WIN) 436 | char_t buffer[MAX_PATH]; 437 | GetModuleFileName(NULL, buffer, sizeof(buffer)/sizeof(char_t)); 438 | process_name = buffer; 439 | process_name = process_name.substr(process_name.rfind('\\', process_name.length()) + 1, process_name.length()); 440 | # elif defined(MEM_LINUX) 441 | process_name = mem::ex::get_process_name(get_pid()); 442 | # endif 443 | return process_name; 444 | } 445 | 446 | mem::module_t mem::in::get_module(process_t process, string_t module_name) 447 | { 448 | return mem::ex::get_module(process, module_name); 449 | } 450 | 451 | mem::module_t mem::in::get_module(string_t module_name) 452 | { 453 | module_t modinfo; 454 | # if defined(MEM_WIN) 455 | MODULEINFO module_info; 456 | HMODULE hmod = GetModuleHandle(module_name.c_str()); 457 | HANDLE cur_handle = mem::in::get_process().handle; 458 | if (hmod == NULL || cur_handle == NULL) return modinfo; 459 | GetModuleInformation(cur_handle, hmod, &module_info, sizeof(module_info)); 460 | modinfo.base = (voidptr_t)module_info.lpBaseOfDll; 461 | modinfo.size = (size_t)module_info.SizeOfImage; 462 | modinfo.end = (voidptr_t)((uintptr_t)modinfo.base + modinfo.size); 463 | modinfo.handle = hmod; 464 | # elif defined(MEM_LINUX) 465 | modinfo = get_module(get_process(), module_name); 466 | # endif 467 | return modinfo; 468 | } 469 | 470 | mem::void_t mem::in::read(voidptr_t src, voidptr_t dst, size_t size) 471 | { 472 | memcpy(dst, src, size); 473 | } 474 | 475 | mem::void_t mem::in::write(voidptr_t src, voidptr_t data, size_t size) 476 | { 477 | memcpy(src, data, size); 478 | } 479 | 480 | mem::void_t mem::in::set(voidptr_t src, byte_t byte, size_t size) 481 | { 482 | memset(src, byte, size); 483 | } 484 | 485 | mem::int_t mem::in::protect(voidptr_t src, size_t size, prot_t protection) 486 | { 487 | int_t ret = (int_t)MEM_BAD_RETURN; 488 | # if defined(MEM_WIN) 489 | if (src <= (voidptr_t)0 || size <= 0 || protection <= (int_t)0) return ret; 490 | DWORD old_protect; 491 | ret = (int_t)VirtualProtect((LPVOID)src, (SIZE_T)size, (DWORD)protection, &old_protect); 492 | # elif defined(MEM_LINUX) 493 | long pagesize = sysconf(_SC_PAGE_SIZE); 494 | uintptr_t src_page = (uintptr_t)src - ((uintptr_t)src % pagesize); 495 | ret = (int_t)mprotect((voidptr_t)src_page, size, protection); 496 | # endif 497 | return ret; 498 | } 499 | 500 | mem::int_t mem::in::protect(voidptr_t begin, voidptr_t end, prot_t protection) 501 | { 502 | return protect(begin, (size_t)((uintptr_t)end - (uintptr_t)begin), protection); 503 | } 504 | 505 | mem::voidptr_t mem::in::allocate(size_t size, alloc_t allocation) 506 | { 507 | voidptr_t addr = (voidptr_t)MEM_BAD_RETURN; 508 | # if defined(MEM_WIN) 509 | addr = VirtualAlloc(NULL, (SIZE_T)size, allocation.type, (DWORD)allocation.protection); 510 | # elif defined(MEM_LINUX) 511 | addr = mmap(NULL, size, allocation.protection, allocation.type, -1, 0); 512 | # endif 513 | return addr; 514 | } 515 | 516 | mem::bool_t mem::in::compare(voidptr_t pdata1, voidptr_t pdata2, size_t size) 517 | { 518 | return (bool_t)(memcmp(pdata1, pdata2, size) == 0); 519 | } 520 | 521 | mem::voidptr_t mem::in::scan(voidptr_t data, voidptr_t base, voidptr_t end, size_t size) 522 | { 523 | voidptr_t ret = (voidptr_t)MEM_BAD_RETURN; 524 | for(uintptr_t i = 0; (uintptr_t)base + i < (uintptr_t)end; i += size) 525 | { 526 | if(compare(data, (voidptr_t)((uintptr_t)base + i), size)) 527 | { 528 | ret = (voidptr_t)((uintptr_t)base + i); 529 | break; 530 | } 531 | } 532 | 533 | return ret; 534 | } 535 | 536 | mem::size_t mem::in::detour_length(detour_int method) 537 | { 538 | switch (method) 539 | { 540 | case detour_int::method0: return CALC_ASM_LENGTH(_MEM_DETOUR_METHOD0); break; 541 | case detour_int::method1: return CALC_ASM_LENGTH(_MEM_DETOUR_METHOD1); break; 542 | case detour_int::method2: return CALC_ASM_LENGTH(_MEM_DETOUR_METHOD2); break; 543 | case detour_int::method3: return CALC_ASM_LENGTH(_MEM_DETOUR_METHOD3); break; 544 | case detour_int::method4: return CALC_ASM_LENGTH(_MEM_DETOUR_METHOD4); break; 545 | case detour_int::method5: return CALC_ASM_LENGTH(_MEM_DETOUR_METHOD5); break; 546 | } 547 | 548 | return (mem::int_t)MEM_BAD_RETURN; 549 | } 550 | 551 | mem::int_t mem::in::detour(voidptr_t src, voidptr_t dst, size_t size, detour_int method, bytearray_t* stolen_bytes) 552 | { 553 | size_t detour_size = detour_length(method); 554 | prot_t protection; 555 | # if defined(MEM_WIN) 556 | protection = PAGE_EXECUTE_READWRITE; 557 | # elif defined(MEM_LINUX) 558 | protection = PROT_EXEC | PROT_READ | PROT_WRITE; 559 | # endif 560 | if (detour_size == MEM_BAD_RETURN || size < detour_size || protect(src, size, protection) == MEM_BAD_RETURN) return (mem::int_t)MEM_BAD_RETURN; 561 | if(stolen_bytes != NULL) 562 | { 563 | *stolen_bytes = {}; 564 | for(size_t i = 0; i < size; i++) 565 | stolen_bytes->insert(i, 1, reinterpret_cast(src)[i]); 566 | } 567 | switch (method) 568 | { 569 | case detour_int::method0: 570 | { 571 | byte_t detour_buffer[] = ASM_GENERATE(_MEM_DETOUR_METHOD0); 572 | *(uintptr_t*)((uintptr_t)detour_buffer + sizeof(MEM_MOV_REGAX)) = (uintptr_t)dst; 573 | write(src, detour_buffer, sizeof(detour_buffer)); 574 | break; 575 | } 576 | 577 | case detour_int::method1: 578 | { 579 | byte_t detour_buffer[] = ASM_GENERATE(_MEM_DETOUR_METHOD1); 580 | *(dword_t*)((uintptr_t)detour_buffer + sizeof(MEM_JMP)) = (dword_t)((uintptr_t)dst - (uintptr_t)src - detour_size); 581 | write(src, detour_buffer, sizeof(detour_buffer)); 582 | break; 583 | } 584 | 585 | case detour_int::method2: 586 | { 587 | byte_t detour_buffer[] = ASM_GENERATE(_MEM_DETOUR_METHOD2); 588 | *(uintptr_t*)((uintptr_t)detour_buffer + sizeof(MEM_MOV_REGAX)) = (uintptr_t)dst; 589 | write(src, detour_buffer, sizeof(detour_buffer)); 590 | break; 591 | } 592 | 593 | case detour_int::method3: 594 | { 595 | byte_t detour_buffer[] = ASM_GENERATE(_MEM_DETOUR_METHOD3); 596 | *(dword_t*)((uintptr_t)detour_buffer + sizeof(MEM_PUSH)) = (dword_t)((uintptr_t)dst - (uintptr_t)src - detour_size); 597 | write(src, detour_buffer, sizeof(detour_buffer)); 598 | break; 599 | } 600 | 601 | case detour_int::method4: 602 | { 603 | byte_t detour_buffer[] = ASM_GENERATE(_MEM_DETOUR_METHOD4); 604 | *(uintptr_t*)((uintptr_t)detour_buffer + sizeof(MEM_MOV_REGAX)) = (uintptr_t)dst; 605 | write(src, detour_buffer, sizeof(detour_buffer)); 606 | break; 607 | } 608 | 609 | case detour_int::method5: 610 | { 611 | byte_t detour_buffer[] = ASM_GENERATE(_MEM_DETOUR_METHOD5); 612 | *(dword_t*)((uintptr_t)detour_buffer + sizeof(MEM_CALL)) = (dword_t)((uintptr_t)dst - (uintptr_t)src - detour_size); 613 | write(src, detour_buffer, sizeof(detour_buffer)); 614 | break; 615 | } 616 | 617 | default: 618 | { 619 | return (mem::int_t)MEM_BAD_RETURN; 620 | break; 621 | } 622 | } 623 | 624 | return !(MEM_BAD_RETURN); 625 | } 626 | 627 | mem::voidptr_t mem::in::detour_trampoline(voidptr_t src, voidptr_t dst, size_t size, detour_int method, bytearray_t* stolen_bytes) 628 | { 629 | size_t detour_size = detour_length(method); 630 | alloc_t allocation; 631 | prot_t protection; 632 | # if defined(MEM_WIN) 633 | protection = PAGE_EXECUTE_READWRITE; 634 | allocation.type = MEM_COMMIT | MEM_RESERVE; 635 | allocation.protection = PAGE_EXECUTE_READWRITE; 636 | # elif defined(MEM_LINUX) 637 | protection = PROT_EXEC | PROT_READ | PROT_WRITE;; 638 | allocation.protection = PROT_EXEC | PROT_READ | PROT_WRITE; 639 | allocation.type = MAP_ANON | MAP_PRIVATE; 640 | # endif 641 | 642 | if (detour_size == MEM_BAD_RETURN || size < detour_size || protect(src, size, protection) == MEM_BAD_RETURN) return (voidptr_t)MEM_BAD_RETURN; 643 | 644 | size_t gateway_size = size + detour_size; 645 | voidptr_t gateway = allocate(gateway_size, allocation); 646 | if (!gateway || gateway == (voidptr_t)MEM_BAD_RETURN) return (voidptr_t)MEM_BAD_RETURN; 647 | set(gateway, 0x0, gateway_size); 648 | write(gateway, src, size); 649 | detour((voidptr_t)((uintptr_t)gateway + size), (voidptr_t)((uintptr_t)src + size), detour_size, method); 650 | 651 | # if defined(MEM_WIN) 652 | protection = PAGE_EXECUTE_READ; 653 | # elif defined(MEM_LINUX) 654 | protection = PROT_EXEC | PROT_READ; 655 | # endif 656 | 657 | protect(gateway, gateway_size, protection); 658 | detour(src, dst, size, method, stolen_bytes); 659 | return gateway; 660 | } 661 | 662 | mem::void_t mem::in::detour_restore(voidptr_t src, bytearray_t stolen_bytes) 663 | { 664 | prot_t protection; 665 | # if defined(MEM_WIN) 666 | protection = PAGE_EXECUTE_READWRITE; 667 | # elif defined(MEM_LINUX) 668 | protection = PROT_EXEC | PROT_READ | PROT_WRITE; 669 | # endif 670 | 671 | protect(src, stolen_bytes.length(), protection); 672 | write(src, (mem::voidptr_t)stolen_bytes.data(), (mem::size_t)stolen_bytes.length()); 673 | } 674 | 675 | mem::voidptr_t mem::in::pattern_scan(bytearray_t pattern, string_t mask, voidptr_t base, voidptr_t end) 676 | { 677 | mem::voidptr_t ret = (mem::voidptr_t)MEM_BAD_RETURN; 678 | mask = parse_mask(mask); 679 | uintptr_t scan_size = (uintptr_t)end - (uintptr_t)base; 680 | 681 | for (uintptr_t i = 0; i < scan_size; i++) 682 | { 683 | bool found = true; 684 | for (uintptr_t j = 0; j < pattern.length(); j++) 685 | { 686 | found &= mask[j] == MEM_UNKNOWN_BYTE || pattern[j] == *(int8_t*)((uintptr_t)base + i + j); 687 | } 688 | 689 | if (found) 690 | { 691 | ret = (voidptr_t)((uintptr_t)base + i); 692 | break; 693 | } 694 | } 695 | 696 | return ret; 697 | } 698 | 699 | mem::voidptr_t mem::in::pattern_scan(bytearray_t pattern, string_t mask, voidptr_t base, size_t size) 700 | { 701 | return pattern_scan(pattern, mask, base, (voidptr_t)((uintptr_t)base + size)); 702 | } 703 | 704 | mem::int_t mem::in::load_library(lib_t lib, module_t* mod) 705 | { 706 | int_t ret = (int_t)MEM_BAD_RETURN; 707 | if(!lib.is_valid()) return ret; 708 | # if defined(MEM_WIN) 709 | HMODULE h_mod = LoadLibrary(lib.path.c_str()); 710 | ret = (h_mod == NULL ? MEM_BAD_RETURN : !MEM_BAD_RETURN); 711 | if(mod != NULL && ret != (mem::int_t)MEM_BAD_RETURN) 712 | { 713 | *mod = mem::in::get_module(lib.path.substr(lib.path.rfind('\\', -1), -1)); 714 | } 715 | # elif defined(MEM_LINUX) 716 | void* h_mod = dlopen(lib.path.c_str(), lib.mode); 717 | ret = (h_mod == (mem::voidptr_t)-1 ? MEM_BAD_RETURN : !MEM_BAD_RETURN); 718 | if(mod != NULL && ret != (mem::int_t)MEM_BAD_RETURN) 719 | { 720 | *mod = mem::in::get_module(lib.path.substr(lib.path.rfind('/', -1), -1)); 721 | mod->handle = h_mod; 722 | } 723 | # endif 724 | return ret; 725 | } 726 | 727 | #endif //MEM_COMPATIBLE -------------------------------------------------------------------------------- /mem/mem.hpp: -------------------------------------------------------------------------------- 1 | //Made by rdbo 2 | //https://github.com/rdbo/Memory 3 | 4 | #pragma once 5 | #ifndef MEM 6 | #define MEM 7 | 8 | //Operating System 9 | 10 | #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) && !defined(linux) 11 | #define MEM_WIN 12 | #elif defined(linux) || defined(__linux__) 13 | #define MEM_LINUX 14 | #endif 15 | 16 | //Architecture 17 | 18 | #if defined(_M_IX86) || defined(__i386__) || __WORDSIZE == 32 19 | #define MEM_86 20 | #elif defined(_M_X64) || defined(__LP64__) || defined(_LP64) || __WORDSIZE == 64 21 | #define MEM_64 22 | #endif 23 | 24 | //Charset 25 | 26 | #if defined(_UNICODE) && defined(MEM_WIN) 27 | #define MEM_UCS 28 | #else 29 | #define MEM_MBCS 30 | #endif 31 | 32 | //Functions 33 | 34 | #if defined(_MSC_VER) 35 | #define PP_NARG(...) _COUNTOF_CAT( _COUNTOF_A, ( 0, ##__VA_ARGS__, 100,\ 36 | 99, 98, 97, 96, 95, 94, 93, 92, 91, 90,\ 37 | 89, 88, 87, 86, 85, 84, 83, 82, 81, 80,\ 38 | 79, 78, 77, 76, 75, 74, 73, 72, 71, 70,\ 39 | 69, 68, 67, 66, 65, 64, 63, 62, 61, 60,\ 40 | 59, 58, 57, 56, 55, 54, 53, 52, 51, 50,\ 41 | 49, 48, 47, 46, 45, 44, 43, 42, 41, 40,\ 42 | 39, 38, 37, 36, 35, 34, 33, 32, 31, 30,\ 43 | 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,\ 44 | 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,\ 45 | 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ) ) 46 | #define _COUNTOF_CAT( a, b ) a b 47 | #define _COUNTOF_A( a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,\ 48 | a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,\ 49 | a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,\ 50 | a30, a31, a32, a33, a34, a35, a36, a37, a38, a39,\ 51 | a40, a41, a42, a43, a44, a45, a46, a47, a48, a49,\ 52 | a50, a51, a52, a53, a54, a55, a56, a57, a58, a59,\ 53 | a60, a61, a62, a63, a64, a65, a66, a67, a68, a69,\ 54 | a70, a71, a72, a73, a74, a75, a76, a77, a78, a79,\ 55 | a80, a81, a82, a83, a84, a85, a86, a87, a88, a89,\ 56 | a90, a91, a92, a93, a94, a95, a96, a97, a98, a99,\ 57 | a100, n, ... ) n 58 | #else 59 | #define PP_NARG(...) \ 60 | PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) 61 | #define PP_NARG_(...) \ 62 | PP_ARG_N(__VA_ARGS__) 63 | #define PP_ARG_N( \ 64 | _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ 65 | _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ 66 | _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ 67 | _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ 68 | _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ 69 | _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ 70 | _61,_62,_63,N,...) N 71 | #define PP_RSEQ_N() \ 72 | 63,62,61,60, \ 73 | 59,58,57,56,55,54,53,52,51,50, \ 74 | 49,48,47,46,45,44,43,42,41,40, \ 75 | 39,38,37,36,35,34,33,32,31,30, \ 76 | 29,28,27,26,25,24,23,22,21,20, \ 77 | 19,18,17,16,15,14,13,12,11,10, \ 78 | 9,8,7,6,5,4,3,2,1,0 79 | #endif 80 | 81 | #define PAD_STR __pad 82 | #define _CONCAT_STR(a, b) a##b 83 | #define CONCAT_STR(a, b) _CONCAT_STR(a, b) 84 | #define _MERGE_STR(a, b) a b 85 | #define MERGE_STR(a, b) _MERGE_STR(a, b) 86 | #define NEW_PAD(size) CONCAT_STR(PAD_STR, __COUNTER__)[size] 87 | #define CREATE_UNION_MEMBER(type, varname, offset) struct { unsigned char NEW_PAD(offset); type varname; } //Create relative offset variable from union 88 | #define _BUFFER_GENERATE(...) { __VA_ARGS__ } 89 | #define ASM_GENERATE(...) _BUFFER_GENERATE(__VA_ARGS__) 90 | #define _CALC_ARG_LENGTH(...) PP_NARG(__VA_ARGS__) 91 | #define CALC_ARG_LENGTH(...) _CALC_ARG_LENGTH(__VA_ARGS__) 92 | #define CALC_ASM_LENGTH(...) CALC_ARG_LENGTH(__VA_ARGS__) 93 | #if defined(MEM_UCS) 94 | #define MEM_STR(str) CONCAT_STR(L, str) 95 | #define MEM_STR_CMP(str1, str2) wcscmp(str1, str2) 96 | #define MEM_STR_N_CMP(str1, str2, n) wcsncmp(str1, str2, n) 97 | #elif defined(MEM_MBCS) 98 | #define MEM_STR(str) str 99 | #define MEM_STR_CMP(str1, str2) strcmp(str1, str2) 100 | #define MEM_STR_N_CMP(str1, str2, n) strncmp(str1, str2, n) 101 | #endif 102 | 103 | //Assembly 104 | 105 | #define _MEM_JMP 0xE9 106 | #define _MEM_JMP_RAX 0xFF, 0xE0 107 | #define _MEM_JMP_EAX 0xFF, 0xE0 108 | #define _MEM_CALL 0xE8 109 | #define _MEM_CALL_EAX 0xFF, 0xD0 110 | #define _MEM_CALL_RAX 0xFF, 0xD0 111 | #define _MEM_MOVABS_RAX 0x48, 0xB8 112 | #define _MEM_MOV_EAX 0xB8 113 | #define _MEM_PUSH 0x68 114 | #define _MEM_PUSH_RAX 0x50 115 | #define _MEM_PUSH_EAX 0x50 116 | #define _MEM_RET 0xC3 117 | #define _MEM_BYTE 0x0 118 | #define _MEM_WORD 0x0, 0x0 119 | #define _MEM_DWORD 0x0, 0x0, 0x0, 0x0 120 | #define _MEM_QWORD 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 121 | 122 | #if defined(MEM_86) 123 | #define _MEM_DETOUR_METHOD0 _MEM_MOV_EAX, _MEM_DWORD, _MEM_JMP_EAX 124 | #define _MEM_DETOUR_METHOD1 _MEM_JMP, _MEM_DWORD 125 | #define _MEM_DETOUR_METHOD2 _MEM_MOV_EAX, _MEM_DWORD, _MEM_PUSH_EAX, _MEM_RET 126 | #define _MEM_DETOUR_METHOD3 _MEM_PUSH, _MEM_DWORD, _MEM_RET 127 | #define _MEM_DETOUR_METHOD4 _MEM_MOV_EAX, _MEM_DWORD, _MEM_CALL_EAX 128 | #define _MEM_DETOUR_METHOD5 _MEM_CALL, _MEM_DWORD 129 | #elif defined(MEM_64) 130 | #define _MEM_DETOUR_METHOD0 _MEM_MOVABS_RAX, _MEM_QWORD, _MEM_JMP_RAX 131 | #define _MEM_DETOUR_METHOD1 _MEM_JMP, _MEM_DWORD 132 | #define _MEM_DETOUR_METHOD2 _MEM_MOVABS_RAX, _MEM_QWORD, _MEM_PUSH_RAX, _MEM_RET 133 | #define _MEM_DETOUR_METHOD3 _MEM_PUSH, _MEM_DWORD, _MEM_RET 134 | #define _MEM_DETOUR_METHOD4 _MEM_MOVABS_RAX, _MEM_QWORD, _MEM_CALL_RAX 135 | #define _MEM_DETOUR_METHOD5 _MEM_CALL, _MEM_DWORD 136 | #endif 137 | 138 | //Other 139 | #define MEM_BAD_RETURN -1 140 | #define MEM_KNOWN_BYTE MEM_STR('x') 141 | #define MEM_UNKNOWN_BYTE MEM_STR('?') 142 | 143 | //Compatibility 144 | 145 | #if (defined(MEM_WIN) || defined(MEM_LINUX)) && (defined(MEM_86) || defined(MEM_64)) 146 | #define MEM_COMPATIBLE 147 | #endif //MEM_COMPATIBLE 148 | 149 | #if defined(MEM_COMPATIBLE) 150 | 151 | //Includes 152 | #include 153 | #include 154 | #include 155 | #include 156 | #include 157 | #include 158 | #include 159 | #include 160 | #if defined(MEM_WIN) 161 | #include 162 | #include 163 | #include 164 | #elif defined(MEM_LINUX) 165 | #include 166 | #include 167 | #include 168 | #include 169 | #include 170 | #include 171 | #include 172 | #include 173 | #include 174 | #include 175 | #include 176 | #include 177 | #endif 178 | 179 | namespace mem 180 | { 181 | typedef bool bool_t; 182 | # if defined(MEM_UCS) 183 | typedef wchar_t char_t; 184 | # elif defined(MEM_MBCS) 185 | typedef char char_t; 186 | # endif 187 | typedef int int_t; 188 | typedef void void_t; 189 | 190 | typedef char int8_t; 191 | typedef short int16_t; 192 | typedef int int32_t; 193 | typedef long long int64_t; 194 | 195 | typedef unsigned char uint8_t; 196 | typedef unsigned short uint16_t; 197 | typedef unsigned int uint32_t; 198 | typedef unsigned long long uint64_t; 199 | 200 | # if defined(MEM_WIN) 201 | typedef uint32_t pid_t; 202 | typedef uint32_t prot_t; 203 | typedef HMODULE module_handle_t; 204 | typedef uint32_t alloc_type_t; 205 | # elif defined(MEM_LINUX) 206 | typedef int32_t pid_t; 207 | typedef int32_t prot_t; 208 | typedef void* module_handle_t; 209 | typedef int32_t alloc_type_t; 210 | # endif 211 | 212 | # if defined(MEM_86) 213 | typedef int32_t intptr_t; 214 | typedef uint32_t uintptr_t; 215 | # elif defined(MEM_64) 216 | typedef int64_t intptr_t; 217 | typedef uint64_t uintptr_t; 218 | # endif 219 | 220 | typedef uint8_t byte_t; 221 | typedef uint16_t word_t; 222 | typedef uint32_t dword_t; 223 | typedef uint64_t qword_t; 224 | 225 | typedef byte_t* byteptr_t; 226 | typedef std::basic_string bytearray_t; 227 | typedef void_t* voidptr_t; 228 | typedef unsigned long size_t; 229 | typedef std::basic_string string_t; 230 | 231 | typedef class _module_t 232 | { 233 | public: 234 | string_t name = MEM_STR(""); 235 | string_t path = MEM_STR(""); 236 | voidptr_t base = (voidptr_t)MEM_BAD_RETURN; 237 | uintptr_t size = (uintptr_t)MEM_BAD_RETURN; 238 | voidptr_t end = (voidptr_t)MEM_BAD_RETURN; 239 | module_handle_t handle = (module_handle_t)MEM_BAD_RETURN; 240 | 241 | public: 242 | bool_t is_valid() 243 | { 244 | return ( 245 | MEM_STR_CMP(name.c_str(), MEM_STR("")) && 246 | MEM_STR_CMP(path.c_str(), MEM_STR("")) && 247 | base != (voidptr_t)MEM_BAD_RETURN && 248 | size != (size_t)MEM_BAD_RETURN && 249 | end != (voidptr_t)MEM_BAD_RETURN 250 | ); 251 | } 252 | 253 | bool_t operator==(_module_t _mod) 254 | { 255 | return (bool_t)( 256 | !MEM_STR_CMP(this->name.c_str(), _mod.name.c_str()) && 257 | !MEM_STR_CMP(this->path.c_str(), _mod.path.c_str()) && 258 | this->base == _mod.base && 259 | this->size == _mod.size && 260 | this->end == _mod.end && 261 | this->handle == _mod.handle 262 | ); 263 | } 264 | }module_t; 265 | 266 | typedef class _process_t 267 | { 268 | public: 269 | string_t name = MEM_STR(""); 270 | pid_t pid = (pid_t)MEM_BAD_RETURN; 271 | # if defined(MEM_WIN) 272 | HANDLE handle = (HANDLE)NULL; 273 | # elif defined(MEM_LINUX) 274 | # endif 275 | 276 | public: 277 | bool_t is_valid() 278 | { 279 | return ( 280 | # if defined(MEM_WIN) 281 | handle != (HANDLE)NULL && 282 | # elif defined(MEM_LINUX) 283 | # endif 284 | 285 | MEM_STR_CMP(name.c_str(), "") && 286 | pid != MEM_BAD_RETURN 287 | ); 288 | } 289 | 290 | bool_t operator==(_process_t _process) 291 | { 292 | return (bool_t)( 293 | !MEM_STR_CMP(this->name.c_str(), _process.name.c_str()) && 294 | this->pid == _process.pid 295 | ); 296 | } 297 | }process_t; 298 | 299 | typedef class _alloc_t 300 | { 301 | public: 302 | prot_t protection = (prot_t)NULL; 303 | alloc_type_t type = (alloc_type_t)NULL; 304 | 305 | public: 306 | bool_t is_valid() 307 | { 308 | return ( 309 | protection != (prot_t)NULL && 310 | type != (alloc_type_t)NULL 311 | ); 312 | } 313 | 314 | bool_t operator==(_alloc_t _allocation) 315 | { 316 | return (bool_t)( 317 | this->protection == _allocation.protection && 318 | this->type == _allocation.type 319 | ); 320 | } 321 | }alloc_t; 322 | 323 | typedef class _lib_t 324 | { 325 | public: 326 | string_t path = ""; 327 | # if defined(MEM_WIN) 328 | # elif defined(MEM_LINUX) 329 | int_t mode = (int_t)RTLD_LAZY; 330 | # endif 331 | 332 | public: 333 | 334 | bool_t is_valid() 335 | { 336 | return (bool_t)( 337 | # if defined(MEM_WIN) 338 | # elif defined(MEM_LINUX) 339 | mode != (int_t)NULL && 340 | # endif 341 | MEM_STR_CMP(path.c_str(), MEM_STR("")) 342 | ); 343 | } 344 | 345 | bool_t operator==(_lib_t _lib) 346 | { 347 | return (bool_t)( 348 | # if defined(MEM_WIN) 349 | # elif defined(MEM_LINUX) 350 | this->mode == _lib.mode && 351 | # endif 352 | MEM_STR_CMP(this->path.c_str(), _lib.path.c_str()) 353 | ); 354 | } 355 | }lib_t; 356 | 357 | enum class detour_int 358 | { 359 | method0, 360 | method1, 361 | method2, 362 | method3, 363 | method4, 364 | method5 365 | }; 366 | 367 | string_t parse_mask(string_t mask); 368 | 369 | namespace ex 370 | { 371 | pid_t get_pid(string_t process_name); 372 | process_t get_process(string_t process_name); 373 | process_t get_process(pid_t pid); 374 | string_t get_process_name(pid_t pid); 375 | module_t get_module(process_t process, string_t module_name); 376 | bool_t is_process_running(process_t process); 377 | int_t read(process_t process, voidptr_t src, voidptr_t dst, size_t size); 378 | template 379 | type_t read(process_t process, voidptr_t src) 380 | { 381 | type_t holder; 382 | read(process, src, &holder, sizeof(holder)); 383 | return holder; 384 | } 385 | int_t write(process_t process, voidptr_t src, voidptr_t data, size_t size); 386 | template 387 | void_t write(process_t process, voidptr_t src, type_t value) 388 | { 389 | write(process, src, new type_t(value), sizeof(type_t)); 390 | } 391 | int_t set(process_t process, voidptr_t src, byte_t byte, size_t size); 392 | int_t protect(process_t process, voidptr_t src, size_t size, prot_t protection); 393 | int_t protect(process_t process, voidptr_t begin, voidptr_t end, prot_t protection); 394 | voidptr_t allocate(process_t process, size_t size, alloc_t allocation); 395 | voidptr_t scan(process_t process, voidptr_t data, voidptr_t base, voidptr_t end, size_t size); 396 | template 397 | voidptr_t scan(process_t process, type_t data, voidptr_t base, voidptr_t end) 398 | { 399 | type_t holder = data; 400 | return scan(process, &holder, base, end, sizeof(type_t)); 401 | } 402 | voidptr_t pattern_scan(process_t process, bytearray_t pattern, string_t mask, voidptr_t base, voidptr_t end); 403 | voidptr_t pattern_scan(process_t process, bytearray_t pattern, string_t mask, voidptr_t base, size_t size); 404 | int_t load_library(process_t process, lib_t lib); 405 | } 406 | 407 | namespace in 408 | { 409 | pid_t get_pid(); 410 | process_t get_process(); 411 | string_t get_process_name(); 412 | module_t get_module(process_t process, string_t module_name); 413 | module_t get_module(string_t module_name); 414 | voidptr_t pattern_scan(bytearray_t pattern, string_t mask, voidptr_t base, voidptr_t end); 415 | voidptr_t pattern_scan(bytearray_t pattern, string_t mask, voidptr_t base, size_t size); 416 | void_t read(voidptr_t src, voidptr_t dst, size_t size); 417 | template 418 | type_t read(voidptr_t src) 419 | { 420 | type_t holder; 421 | read(src, &holder, sizeof(holder)); 422 | return holder; 423 | } 424 | void_t write(voidptr_t src, voidptr_t data, size_t size); 425 | template 426 | void_t write(voidptr_t src, type_t value) 427 | { 428 | write(src, new type_t(value), sizeof(type_t)); 429 | } 430 | void_t set(voidptr_t src, byte_t byte, size_t size); 431 | int_t protect(voidptr_t src, size_t size, prot_t protection); 432 | int_t protect(voidptr_t begin, voidptr_t end, prot_t protection); 433 | voidptr_t allocate(size_t size, alloc_t allocation); 434 | bool_t compare(voidptr_t pdata1, voidptr_t pdata2, size_t size); 435 | voidptr_t scan(voidptr_t data, voidptr_t base, voidptr_t end, size_t size); 436 | template 437 | voidptr_t scan(type_t data, voidptr_t base, voidptr_t end) 438 | { 439 | type_t holder = data; 440 | return scan(&holder, base, end, sizeof(type_t)); 441 | } 442 | size_t detour_length(detour_int method); 443 | int_t detour(voidptr_t src, voidptr_t dst, size_t size, detour_int method = detour_int::method0, bytearray_t* stolen_bytes = NULL); 444 | voidptr_t detour_trampoline(voidptr_t src, voidptr_t dst, size_t size, detour_int method = detour_int::method0, bytearray_t* stolen_bytes = NULL); 445 | void_t detour_restore(voidptr_t src, bytearray_t stolen_bytes); 446 | int_t load_library(lib_t lib, module_t* mod = NULL); 447 | } 448 | } 449 | 450 | #endif //MEM_COMPATIBLE 451 | #endif //MEM --------------------------------------------------------------------------------