1 /*
2 
3 Copyright(c) 2010. Victor M. Alvarez [plusvic@gmail.com] &
4                    Stefan Buehlmann [stefan.buehlmann@joebox.org].
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 */
17 
18 
19 
20 #ifdef WIN32
21 
22 #include <windows.h>
23 #include "mem.h"
24 #include "proc.h"
25 
get_process_memory(int pid,MEMORY_BLOCK ** first_block)26 int get_process_memory(int pid, MEMORY_BLOCK** first_block)
27 {
28     PVOID address;
29     SIZE_T read;
30 
31     unsigned char* data;
32 
33     SYSTEM_INFO si;
34     MEMORY_BASIC_INFORMATION mbi;
35 
36     MEMORY_BLOCK* new_block;
37     MEMORY_BLOCK* current_block = NULL;
38 
39     TOKEN_PRIVILEGES tokenPriv;
40     LUID luidDebug;
41     HANDLE hProcess;
42     HANDLE hToken;
43 
44     if( OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) &&
45         LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidDebug))
46     {
47             tokenPriv.PrivilegeCount = 1;
48             tokenPriv.Privileges[0].Luid = luidDebug;
49             tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
50 
51             AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(tokenPriv), NULL, NULL);
52     }
53 
54     hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
55 
56     *first_block = NULL;
57 
58     if (hProcess == NULL)
59     {
60         return ERROR_COULD_NOT_ATTACH_TO_PROCESS;
61     }
62 
63     GetSystemInfo(&si);
64 
65     address = si.lpMinimumApplicationAddress;
66 
67     while (address < si.lpMaximumApplicationAddress)
68     {
69          if (VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi)) != 0)
70          {
71              if (mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS)
72              {
73                  data = (unsigned char*) yr_malloc(mbi.RegionSize);
74 
75                  if (data == NULL)
76                      return ERROR_INSUFICIENT_MEMORY;
77 
78                  if (ReadProcessMemory(hProcess, address, data, mbi.RegionSize, &read))
79                  {
80                      new_block = (MEMORY_BLOCK*) yr_malloc(sizeof(MEMORY_BLOCK));
81 
82                      if (new_block == NULL)
83                      {
84                          yr_free(data);
85                          return ERROR_INSUFICIENT_MEMORY;
86                      }
87 
88                      if (*first_block == NULL)
89                          *first_block = new_block;
90 
91                      new_block->base = (size_t) mbi.BaseAddress;
92                      new_block->size = mbi.RegionSize;
93                      new_block->data = data;
94                      new_block->next = NULL;
95 
96                      if (current_block != NULL)
97                          current_block->next = new_block;
98 
99                      current_block = new_block;
100                  }
101                  else
102                  {
103                      yr_free(data);
104                  }
105              }
106 
107              address = (PVOID)((DWORD) mbi.BaseAddress + mbi.RegionSize);
108          }
109      }
110 
111      return ERROR_SUCCESS;
112 }
113 
114 #else
115 
116 #include <fcntl.h>
117 #include <unistd.h>
118 #include <sys/types.h>
119 #include <sys/ptrace.h>
120 #include <sys/wait.h>
121 
122 #include "mem.h"
123 #include "proc.h"
124 
125 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__MACH__)
126 #define PTRACE_ATTACH PT_ATTACH
127 #define PTRACE_DETACH PT_DETACH
128 #endif
129 
130 #if defined(__MACH__)
131 
132 #include <mach/mach.h>
133 #include <mach/mach_vm.h>
134 #include <mach/vm_region.h>
135 #include <mach/vm_statistics.h>
136 
get_process_memory(pid_t pid,MEMORY_BLOCK ** first_block)137 int get_process_memory(pid_t pid, MEMORY_BLOCK** first_block)
138 {
139     task_t task;
140     kern_return_t kr;
141 
142     vm_size_t size = 0;
143     vm_address_t address = 0;
144     vm_region_basic_info_data_64_t info;
145     mach_msg_type_number_t info_count;
146     mach_port_t object;
147 
148     unsigned char* data;
149 
150     MEMORY_BLOCK* new_block;
151     MEMORY_BLOCK* current_block = NULL;
152 
153     *first_block = NULL;
154 
155     if ((kr = task_for_pid(mach_task_self(), pid, &task)) != KERN_SUCCESS)
156     {
157         return ERROR_COULD_NOT_ATTACH_TO_PROCESS;
158     }
159 
160     do {
161 
162          info_count = VM_REGION_BASIC_INFO_COUNT_64;
163 
164          kr = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t) &info, &info_count, &object);
165 
166          if (kr == KERN_SUCCESS)
167          {
168              data = (unsigned char*) yr_malloc(size);
169 
170              if (data == NULL)
171                  return ERROR_INSUFICIENT_MEMORY;
172 
173              if (vm_read_overwrite(task, address, size, (vm_address_t) data, &size) == KERN_SUCCESS)
174              {
175                  new_block = (MEMORY_BLOCK*) yr_malloc(sizeof(MEMORY_BLOCK));
176 
177                  if (new_block == NULL)
178                  {
179                      yr_free(data);
180                      return ERROR_INSUFICIENT_MEMORY;
181                  }
182 
183                  if (*first_block == NULL)
184                      *first_block = new_block;
185 
186                  new_block->base = address;
187                  new_block->size = size;
188                  new_block->data = data;
189                  new_block->next = NULL;
190 
191                  if (current_block != NULL)
192                      current_block->next = new_block;
193 
194                  current_block = new_block;
195              }
196 
197              address += size;
198          }
199 
200 
201      } while (kr != KERN_INVALID_ADDRESS);
202 
203      if (task != MACH_PORT_NULL)
204      {
205           mach_port_deallocate(mach_task_self(), task);
206      }
207 
208      return ERROR_SUCCESS;
209 }
210 
211 #else
212 
213 #include <errno.h>
214 
get_process_memory(pid_t pid,MEMORY_BLOCK ** first_block)215 int get_process_memory(pid_t pid, MEMORY_BLOCK** first_block)
216 {
217     char buffer[256];
218     unsigned char* data;
219     size_t begin, end, length;
220 
221     MEMORY_BLOCK* new_block;
222     MEMORY_BLOCK* current_block = NULL;
223 
224     *first_block = NULL;
225 
226     sprintf(buffer, "/proc/%u/maps", pid);
227 
228     FILE* maps = fopen(buffer, "r");
229 
230     if (maps == NULL)
231     {
232         return ERROR_COULD_NOT_ATTACH_TO_PROCESS;
233     }
234 
235     sprintf(buffer, "/proc/%u/mem", pid);
236 
237     int mem = open(buffer, O_RDONLY);
238 
239     if (mem == -1)
240     {
241         fclose(maps);
242         return ERROR_COULD_NOT_ATTACH_TO_PROCESS;
243     }
244 
245     if (ptrace(PTRACE_ATTACH, pid, NULL, 0) == -1)
246     {
247         return ERROR_COULD_NOT_ATTACH_TO_PROCESS;
248     }
249 
250     wait(NULL);
251 
252     while (fgets(buffer, sizeof(buffer), maps) != NULL)
253     {
254         sscanf(buffer, "%lx-%lx", &begin, &end);
255 
256         length = end - begin;
257 
258         data = yr_malloc(length);
259 
260         if (data == NULL)
261             return ERROR_INSUFICIENT_MEMORY;
262 
263         if (pread(mem, data, length, begin) != -1)
264         {
265             new_block = (MEMORY_BLOCK*) yr_malloc(sizeof(MEMORY_BLOCK));
266 
267             if (new_block == NULL)
268             {
269                 yr_free(data);
270                 return ERROR_INSUFICIENT_MEMORY;
271             }
272 
273             if (*first_block == NULL)
274                 *first_block = new_block;
275 
276             new_block->base = begin;
277             new_block->size = length;
278             new_block->data = data;
279             new_block->next = NULL;
280 
281             if (current_block != NULL)
282                 current_block->next = new_block;
283 
284             current_block = new_block;
285         }
286     }
287 
288     ptrace(PTRACE_DETACH, pid, NULL, 0);
289 
290     close(mem);
291     fclose(maps);
292 
293     return ERROR_SUCCESS;
294 }
295 
296 #endif
297 #endif
298 
299