1 #include "windows_maps.h"
2 #include "../windows/windows_debug.h"
3 
4 typedef struct {
5 	RDebugMap *map;
6 	IMAGE_SECTION_HEADER *sect_hdr;
7 	int sect_count;
8 } RWinModInfo;
9 
get_map_type(MEMORY_BASIC_INFORMATION * mbi)10 static char *get_map_type(MEMORY_BASIC_INFORMATION *mbi) {
11 	char *type;
12 	switch (mbi->Type) {
13 	case MEM_IMAGE:
14 		type = "IMAGE";
15 		break;
16 	case MEM_MAPPED:
17 		type = "MAPPED";
18 		break;
19 	case MEM_PRIVATE:
20 		type = "PRIVATE";
21 		break;
22 	default:
23 		type = "UNKNOWN";
24 	}
25 	return type;
26 }
27 
add_map(RList * list,const char * name,ut64 addr,ut64 len,MEMORY_BASIC_INFORMATION * mbi)28 static RDebugMap *add_map(RList *list, const char *name, ut64 addr, ut64 len, MEMORY_BASIC_INFORMATION *mbi) {
29 	int perm;
30 	char *map_type = get_map_type (mbi);
31 
32 	switch (mbi->Protect) {
33 	case PAGE_EXECUTE:
34 		perm = R_PERM_X;
35 		break;
36 	case PAGE_EXECUTE_READ:
37 		perm = R_PERM_RX;
38 		break;
39 	case PAGE_EXECUTE_READWRITE:
40 		perm = R_PERM_RWX;
41 		break;
42 	case PAGE_READONLY:
43 		perm = R_PERM_R;
44 		break;
45 	case PAGE_READWRITE:
46 		perm = R_PERM_RW;
47 		break;
48 	case PAGE_WRITECOPY:
49 		perm = R_PERM_W;
50 		break;
51 	case PAGE_EXECUTE_WRITECOPY:
52 		perm = R_PERM_X;
53 		break;
54 	default:
55 		perm = 0;
56 	}
57 	char *map_name = r_str_newf ("%-8s %s", map_type, name);
58 	if (!map_name) {
59 		return NULL;
60 	}
61 	RDebugMap *mr = r_debug_map_new (map_name, addr, addr + len, perm, mbi->Type == MEM_PRIVATE);
62 	free (map_name);
63 	if (mr) {
64 		r_list_append (list, mr);
65 	}
66 	return mr;
67 }
68 
add_map_reg(RList * list,const char * name,MEMORY_BASIC_INFORMATION * mbi)69 static inline RDebugMap *add_map_reg(RList *list, const char *name, MEMORY_BASIC_INFORMATION *mbi) {
70 	return add_map (list, name, (ut64)(size_t)mbi->BaseAddress, (ut64)mbi->RegionSize, mbi);
71 }
72 
r_w32_dbg_modules(RDebug * dbg)73 R_API RList *r_w32_dbg_modules(RDebug *dbg) {
74 	if (dbg->pid == -1) {
75 		return NULL;
76 	}
77 	MODULEENTRY32 me;
78 	RList *list = r_list_newf ((RListFree)r_debug_map_free);
79 	DWORD flags = TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32;
80 	HANDLE h_mod_snap = w32_CreateToolhelp32Snapshot (flags, dbg->pid);
81 
82 	if (h_mod_snap == INVALID_HANDLE_VALUE) {
83 		// Suppress if process is still initializing
84 		if (GetLastError () != ERROR_PARTIAL_COPY || r_list_length (dbg->threads) > 1) {
85 			r_sys_perror ("r_w32_dbg_modules/CreateToolhelp32Snapshot");
86 		}
87 		goto err_w32_dbg_modules;
88 	}
89 	me.dwSize = sizeof (MODULEENTRY32);
90 	if (!Module32First (h_mod_snap, &me)) {
91 		r_sys_perror ("r_w32_dbg_modules/Module32First");
92 		goto err_w32_dbg_modules;
93 	}
94 	do {
95 		ut64 baddr = (ut64)(size_t)me.modBaseAddr;
96 		char *mod_name = r_sys_conv_win_to_utf8 (me.szModule);
97 		RDebugMap *dbgmap = r_debug_map_new (mod_name, baddr, baddr + me.modBaseSize, 0, 0);
98 		free (mod_name);
99 		if (dbgmap) {
100 			dbgmap->file = r_sys_conv_win_to_utf8 (me.szExePath);
101 			if (dbgmap->file) {
102 				r_list_append (list, dbgmap);
103 			}
104 		}
105 	} while (Module32Next (h_mod_snap, &me));
106 err_w32_dbg_modules:
107 	if (h_mod_snap && h_mod_snap != INVALID_HANDLE_VALUE) {
108 		CloseHandle (h_mod_snap);
109 	}
110 	return list;
111 }
112 
is_pe_hdr(unsigned char * pe_hdr)113 static bool is_pe_hdr(unsigned char *pe_hdr) {
114 	IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER *)pe_hdr;
115 	IMAGE_NT_HEADERS *nt_headers;
116 
117 	if (dos_header->e_magic == IMAGE_DOS_SIGNATURE) {
118 		nt_headers = (IMAGE_NT_HEADERS *)((char *)dos_header
119 				+ dos_header->e_lfanew);
120 		// TODO: Check boundaries first, before the dereference
121 		if (nt_headers->Signature == IMAGE_NT_SIGNATURE)
122 			return true;
123 	}
124 	return false;
125 }
126 
set_mod_inf(HANDLE h_proc,RDebugMap * map,RWinModInfo * mod)127 static int set_mod_inf(HANDLE h_proc, RDebugMap *map, RWinModInfo *mod) {
128 	IMAGE_DOS_HEADER *dos_hdr;
129 	IMAGE_NT_HEADERS *nt_hdrs;
130 	IMAGE_NT_HEADERS32 *nt_hdrs32;
131 	IMAGE_SECTION_HEADER *sect_hdr;
132 	ut8 pe_hdr[0x1000];
133 	SIZE_T len;
134 	int mod_inf_fill;
135 
136 	len = 0;
137 	sect_hdr = NULL;
138 	mod_inf_fill = -1;
139 	ReadProcessMemory (h_proc, (LPCVOID)(size_t)map->addr, (LPVOID)pe_hdr, sizeof (pe_hdr), &len);
140 	if (len == (SIZE_T)sizeof (pe_hdr) && is_pe_hdr (pe_hdr)) {
141 		dos_hdr = (IMAGE_DOS_HEADER *)pe_hdr;
142 		nt_hdrs = (IMAGE_NT_HEADERS *)((char *)dos_hdr + dos_hdr->e_lfanew);
143 		if (nt_hdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { // check for x32 pefile
144 			nt_hdrs32 = (IMAGE_NT_HEADERS32 *)((char *)dos_hdr + dos_hdr->e_lfanew);
145 			mod->sect_count = nt_hdrs32->FileHeader.NumberOfSections;
146 			sect_hdr = (IMAGE_SECTION_HEADER *)((char *)nt_hdrs32 + sizeof (IMAGE_NT_HEADERS32));
147 		} else {
148 			mod->sect_count = nt_hdrs->FileHeader.NumberOfSections;
149 			sect_hdr = (IMAGE_SECTION_HEADER *)((char *)nt_hdrs + sizeof (IMAGE_NT_HEADERS));
150 		}
151 		if ((char *)sect_hdr + (sizeof (IMAGE_SECTION_HEADER) * mod->sect_count) < ((char *)pe_hdr + sizeof (pe_hdr))) {
152 			mod->sect_hdr = (IMAGE_SECTION_HEADER *)malloc (sizeof (IMAGE_SECTION_HEADER) * mod->sect_count);
153 			if (mod->sect_hdr) {
154 				memcpy (mod->sect_hdr, sect_hdr, sizeof (IMAGE_SECTION_HEADER) * mod->sect_count);
155 				mod_inf_fill = 0;
156 			} else {
157 				perror ("malloc set_mod_inf()");
158 			}
159 		}
160 	}
161 	if (mod_inf_fill == -1) {
162 		R_FREE (mod->sect_hdr);
163 	}
164 	return mod_inf_fill;
165 }
166 
proc_mem_img(HANDLE h_proc,RList * map_list,RList * mod_list,RWinModInfo * mod,SYSTEM_INFO * si,MEMORY_BASIC_INFORMATION * mbi)167 static void proc_mem_img(HANDLE h_proc, RList *map_list, RList *mod_list, RWinModInfo *mod, SYSTEM_INFO *si, MEMORY_BASIC_INFORMATION *mbi) {
168 	ut64 addr = (ut64)(size_t)mbi->BaseAddress;
169 	ut64 len = (ut64)mbi->RegionSize;
170 	if (!mod->map || addr < mod->map->addr || (addr + len) > mod->map->addr_end) {
171 		RListIter *iter;
172 		RDebugMap *map;
173 
174 		free (mod->sect_hdr);
175 		memset (mod, 0, sizeof (RWinModInfo));
176 		r_list_foreach (mod_list, iter, map) {
177 			if (addr >= map->addr && addr <= map->addr_end) {
178 				mod->map = map;
179 				set_mod_inf (h_proc, map, mod);
180 				break;
181 			}
182 		}
183 	}
184 	if (mod->map && mod->sect_hdr && mod->sect_count > 0) {
185 		int sect_count;
186 		int i, p_mask;
187 
188 		sect_count = 0;
189 		p_mask = si->dwPageSize - 1;
190 		for (i = 0; i < mod->sect_count; i++) {
191 			IMAGE_SECTION_HEADER *sect_hdr = &mod->sect_hdr[i];
192 			ut64 sect_addr = mod->map->addr + (ut64)sect_hdr->VirtualAddress;
193 			ut64 sect_len = (((ut64)sect_hdr->Misc.VirtualSize) + p_mask) & ~p_mask;
194 			int sect_found = 0;
195 
196 			/* section in memory region? */
197 			if (sect_addr >= addr && (sect_addr + sect_len) <= (addr + len)) {
198 				sect_found = 1;
199 			/* memory region in section? */
200 			} else if (addr >= sect_addr && (addr + len) <= (sect_addr + sect_len)) {
201 				sect_found = 2;
202 			}
203 			if (sect_found) {
204 				char *map_name = r_str_newf ("%s | %.8s", mod->map->name, sect_hdr->Name);
205 				if (!map_name) {
206 					perror ("r_str_newf");
207 					return;
208 				}
209 				if (sect_found == 1) {
210 					add_map (map_list, map_name, sect_addr, sect_len, mbi);
211 				} else {
212 					add_map_reg (map_list, map_name, mbi);
213 				}
214 				free (map_name);
215 				sect_count++;
216 			}
217 		}
218 		if (sect_count == 0) {
219 			add_map_reg (map_list, mod->map->name, mbi);
220 		}
221 	} else {
222 		if (!mod->map) {
223 			add_map_reg (map_list, "", mbi);
224 		} else {
225 			add_map_reg (map_list, mod->map->name, mbi);
226 		}
227 	}
228 }
229 
proc_mem_map(HANDLE h_proc,RList * map_list,MEMORY_BASIC_INFORMATION * mbi)230 static void proc_mem_map(HANDLE h_proc, RList *map_list, MEMORY_BASIC_INFORMATION *mbi) {
231 	TCHAR f_name[MAX_PATH + 1];
232 
233 	DWORD len = GetMappedFileName (h_proc, mbi->BaseAddress, f_name, MAX_PATH);
234 	if (len > 0) {
235 		char *f_name_ = r_sys_conv_win_to_utf8 (f_name);
236 		add_map_reg (map_list, f_name_, mbi);
237 		free (f_name_);
238 	} else {
239 		add_map_reg (map_list, "", mbi);
240 	}
241 }
242 
r_w32_dbg_maps(RDebug * dbg)243 R_API RList *r_w32_dbg_maps(RDebug *dbg) {
244 	if (dbg->pid == -1) {
245 		return NULL;
246 	}
247 	SYSTEM_INFO si = {0};
248 	LPVOID cur_addr;
249 	MEMORY_BASIC_INFORMATION mbi;
250 	RWinModInfo mod_inf = {0};
251 	RList *map_list = r_list_newf ((RListFree)r_debug_map_free), *mod_list = NULL;
252 	W32DbgWInst *wrap = dbg->user;
253 
254 	GetSystemInfo (&si);
255 	cur_addr = si.lpMinimumApplicationAddress;
256 	/* get process modules list */
257 	mod_list = r_w32_dbg_modules (dbg);
258 	/* process memory map */
259 	while (cur_addr < si.lpMaximumApplicationAddress &&
260 		VirtualQueryEx (wrap->pi.hProcess, cur_addr, &mbi, sizeof (mbi)) != 0) {
261 		if (mbi.State != MEM_FREE) {
262 			switch (mbi.Type) {
263 			case MEM_IMAGE:
264 				proc_mem_img (wrap->pi.hProcess, map_list, mod_list, &mod_inf, &si, &mbi);
265 				break;
266 			case MEM_MAPPED:
267 				proc_mem_map (wrap->pi.hProcess, map_list, &mbi);
268 				break;
269 			default:
270 				add_map_reg (map_list, "", &mbi);
271 			}
272 		}
273 		cur_addr = (LPVOID)(size_t)((ut64)(size_t)mbi.BaseAddress + mbi.RegionSize);
274 	}
275 	free (mod_inf.sect_hdr);
276 	r_list_free (mod_list);
277 	return map_list;
278 }
279