├── 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 |
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 | 
55 | 
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