ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PeExport.C
Go to the documentation of this file.
1 /* Windows PE Export Sections (SgAsmPEExportSection and related classes) */
2 
3 #include "sage3basic.h"
4 #include "MemoryMap.h"
5 
6 /* Constructor */
7 void
9 {
11  ROSE_ASSERT(fhdr!=NULL);
12  set_parent(section);
13 
14  /* Read disk-formatted export directory */
16  try {
17  section->read_content(fhdr->get_loader_map(), section->get_mapped_actual_va(), &disk, sizeof disk);
18  } catch (const MemoryMap::NotMapped &e) {
19  fprintf(stderr, "SgAsmPEExportDirectory::ctor: error: export directory at rva 0x%08"PRIx64
20  " contains unmapped virtual address 0x%08"PRIx64"\n", section->get_mapped_actual_va(), e.va);
21  if (e.map) {
22  fprintf(stderr, "Memory map in effect at time of error:\n");
23  e.map->dump(stderr, " ");
24  }
25  memset(&disk, 0, sizeof disk);
26  }
27 
28  /* Convert disk-format data members to native format */
40 
41  /* Read the name */
42  std::string name;
43  try {
44  name = section->read_content_str(fhdr->get_loader_map(), p_name_rva.get_va());
45  } catch (const MemoryMap::NotMapped &e) {
46  fprintf(stderr, "SgAsmPEExportDirectory::ctor: warning: directory name at rva 0x%08"PRIx64
47  " contains unmapped virtual address 0x%08"PRIx64"\n", p_name_rva.get_rva(), e.va);
48  if (e.map) {
49  fprintf(stderr, "Memory map in effect at time of error:\n");
50  e.map->dump(stderr, " ");
51  }
52  memset(&disk, 0, sizeof disk);
53  }
54  p_name = new SgAsmBasicString(name);
55  p_name->set_parent(this);
56 }
57 
58 /* Print debugging info */
59 void
60 SgAsmPEExportDirectory::dump(FILE *f, const char *prefix, ssize_t idx) const
61 {
62  char p[4096];
63  if (idx>=0) {
64  sprintf(p, "%sPEExportDirectory[%zd].", prefix, idx);
65  } else {
66  sprintf(p, "%sPEExportDirectory.", prefix);
67  }
68  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
69 
70  fprintf(f, "%s%-*s = \"%s\"\n", p, w, "name", p_name->get_string(true).c_str());
71  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "res1", p_res1, p_res1);
72  fprintf(f, "%s%-*s = %lu %s", p, w, "timestamp", (unsigned long)p_timestamp, ctime(&p_timestamp));
73  fprintf(f, "%s%-*s = %u\n", p, w, "vmajor", p_vmajor);
74  fprintf(f, "%s%-*s = %u\n", p, w, "vminor", p_vminor);
75  fprintf(f, "%s%-*s = %s\n", p, w, "name_rva", p_name_rva.to_string().c_str());
76  fprintf(f, "%s%-*s = %u\n", p, w, "ord_base", p_ord_base);
77  fprintf(f, "%s%-*s = %zu\n", p, w, "expaddr_n", p_expaddr_n);
78  fprintf(f, "%s%-*s = %zu\n", p, w, "nameptr_n", p_nameptr_n);
79  fprintf(f, "%s%-*s = %s\n", p, w, "expaddr_rva", p_expaddr_rva.to_string().c_str());
80  fprintf(f, "%s%-*s = %s\n", p, w, "nameptr_rva", p_nameptr_rva.to_string().c_str());
81  fprintf(f, "%s%-*s = %s\n", p, w, "ordinals_rva", p_ordinals_rva.to_string().c_str());
82 }
83 
84 /* Constructor */
85 void
86 SgAsmPEExportEntry::ctor(SgAsmGenericString *fname, unsigned ordinal, rose_rva_t expaddr, SgAsmGenericString *forwarder)
87 {
88  set_name(fname);
89  if (fname)
90  fname->set_parent(this);
91 
92  set_ordinal(ordinal);
93  set_export_rva(expaddr);
94  set_forwarder(forwarder);
95 }
96 
97 /* Print debugging info */
98 void
99 SgAsmPEExportEntry::dump(FILE *f, const char *prefix, ssize_t idx) const
100 {
101  char p[4096];
102  if (idx>=0) {
103  sprintf(p, "%sPEExportEntry[%zd].", prefix, idx);
104  } else {
105  sprintf(p, "%sPEExportEntry.", prefix);
106  }
107  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
108 
109  fprintf(f, "%s%-*s = [ord %u] rva=%s \"%s\"", p, w, "info",
110  p_ordinal, p_export_rva.to_string().c_str(), p_name->get_string(true).c_str());
111  if (p_forwarder)
112  fprintf(f, " -> \"%s\"", p_forwarder->get_string(true).c_str());
113  fputc('\n', f);
114 }
115 
116 /* Override ROSETTA to set parent */
117 void
119 {
120  if (p_name!=fname)
121  set_isModified(true);
122  p_name = fname;
123  if (p_name) p_name->set_parent(this);
124 }
125 void
127 {
128  if (p_forwarder!=forwarder)
129  set_isModified(true);
130  p_forwarder = forwarder;
131  if (p_forwarder) p_forwarder->set_parent(this);
132 }
133 
134 /* Constructor */
135 void
137 {
138  ROSE_ASSERT(p_exports == NULL);
140  p_exports->set_parent(this);
141 }
142 
145 {
147 
148  SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
149  ROSE_ASSERT(fhdr!=NULL);
150 
152 
153  /* The export directory points to three parallel arrays:
154  * 1. An array of RVAs that point to NUL-terminated names.
155  * 2. An array of "ordinals" which serve as indices into the Export Address Table.
156  * 3. An array of export addresses (see note below). */
157  for (size_t i=0; i<p_export_dir->get_nameptr_n(); i++) {
158  /* Function name RVA (nameptr)*/
159  ExportNamePtr_disk nameptr_disk = 0;
160  rose_addr_t nameptr_va = p_export_dir->get_nameptr_rva().get_va() + i*sizeof(nameptr_disk);
161  try {
162  read_content(fhdr->get_loader_map(), nameptr_va, &nameptr_disk, sizeof nameptr_disk);
163  } catch (const MemoryMap::NotMapped &e) {
164  fprintf(stderr, "SgAsmPEExportSection::parse: error: export name #%zu at va 0x%08"PRIx64
165  " contains unmapped va 0x%08"PRIx64"\n", i, nameptr_va, e.va);
166  if (e.map) {
167  fprintf(stderr, "Memory map in effect at time of error:\n");
168  e.map->dump(stderr, " ");
169  }
170  nameptr_disk = 0;
171  }
172  rose_addr_t fname_rva = ByteOrder::le_to_host(nameptr_disk);
173  rose_addr_t fname_va = fname_rva + fhdr->get_base_va();
174 
175  /* Function name (fname) */
176  std::string s;
177  try {
178  s = read_content_str(fhdr->get_loader_map(), fname_va);
179  } catch (const MemoryMap::NotMapped &e) {
180  fprintf(stderr, "SgAsmPEExportSection::parse: error: export name %zu at va 0x%08"PRIx64
181  " contains unmapped virtual address 0x%08"PRIx64"\n", i, fname_va, e.va);
182  if (e.map) {
183  fprintf(stderr, "Memory map in effect at time of error:\n");
184  e.map->dump(stderr, " ");
185  }
186  }
187  SgAsmGenericString *fname = new SgAsmBasicString(s);
188 
189  /* Ordinal (sort of an index into the Export Address Table) */
190  ExportOrdinal_disk ordinal_disk = 0;
191  rose_addr_t ordinal_va = p_export_dir->get_ordinals_rva().get_va() + i*sizeof(ordinal_disk);
192  try {
193  read_content(fhdr->get_loader_map(), ordinal_va, &ordinal_disk, sizeof ordinal_disk);
194  } catch (const MemoryMap::NotMapped &e) {
195  fprintf(stderr, "SgAsmPEExportSection::parse: error: ordinal #%zu at va 0x%08"PRIx64
196  " contains unmapped va 0x%08"PRIx64"\n", i, ordinal_va, e.va);
197  if (e.map) {
198  fprintf(stderr, "Memory map in effect at time of error:\n");
199  e.map->dump(stderr, " ");
200  }
201  ordinal_disk = 0;
202  }
203  unsigned ordinal = ByteOrder::le_to_host(ordinal_disk);
204 
205  /* Export address. Convert the symbol's Ordinal into an index into the Export Address Table. The spec says to subtract
206  * the ord_base from the Ordinal to get the index, but testing has shown this to be off by one (e.g., Windows-XP file
207  * /WINDOWS/system32/msacm32.dll's Export Table's first symbol has the name "XRegThunkEntry" with an Ordinal of zero
208  * and the ord_base is one. The index according to spec would be -1 rather than the correct value of zero.) */
209  rose_rva_t expaddr = 0;
210  if (ordinal >= (p_export_dir->get_ord_base()-1)) {
211  unsigned expaddr_idx = ordinal - (p_export_dir->get_ord_base()-1);
212  ROSE_ASSERT(expaddr_idx < p_export_dir->get_expaddr_n());
213  ExportAddress_disk expaddr_disk = 0;
214  rose_addr_t expaddr_va = p_export_dir->get_expaddr_rva().get_va() + expaddr_idx*sizeof(expaddr_disk);
215  try {
216  read_content(fhdr->get_loader_map(), expaddr_va, &expaddr_disk, sizeof expaddr_disk);
217  } catch (const MemoryMap::NotMapped &e) {
218  fprintf(stderr, "SgAsmPEExportSection::parse: error: export address #%zu at va 0x%08"PRIx64
219  " contains unmapped va 0x%08"PRIx64"\n", i, expaddr_va, e.va);
220  if (e.map) {
221  fprintf(stderr, "Memory map in effect at time of error:\n");
222  e.map->dump(stderr, " ");
223  }
224  }
225  expaddr = ByteOrder::le_to_host(expaddr_disk);
226  expaddr.bind(fhdr);
227  } else {
228  expaddr = 0xffffffff; /*Ordinal out of range!*/
229  }
230 
231  /* If export address is within this section then it points to a NUL-terminated forwarder name.
232  * FIXME: Is this the proper precondition? [RPM 2009-08-20] */
233  SgAsmGenericString *forwarder = NULL;
234  if (expaddr.get_va()>=get_mapped_actual_va() && expaddr.get_va()<get_mapped_actual_va()+get_mapped_size()) {
235  std::string s;
236  try {
237  s = read_content_str(fhdr->get_loader_map(), expaddr.get_va());
238  } catch (const MemoryMap::NotMapped &e) {
239  fprintf(stderr, "SgAsmPEExportSection::parse: error: forwarder %zu at rva 0x%08"PRIx64
240  " contains unmapped virtual address 0x%08"PRIx64"\n", i, expaddr.get_rva(), e.va);
241  if (e.map) {
242  fprintf(stderr, "Memory map in effect at time of error:\n");
243  e.map->dump(stderr, " ");
244  }
245  }
246  forwarder = new SgAsmBasicString(s);
247  }
248 
249  SgAsmPEExportEntry *entry = new SgAsmPEExportEntry(fname, ordinal, expaddr, forwarder);
250  add_entry(entry);
251  }
252  return this;
253 }
254 
255 void
257 {
258  ROSE_ASSERT(p_exports!=NULL);
259  p_exports->set_isModified(true);
260  p_exports->get_exports().push_back(entry);
261 }
262 
263 /* Print debugging info */
264 void
265 SgAsmPEExportSection::dump(FILE *f, const char *prefix, ssize_t idx) const
266 {
267  char p[4096];
268  if (idx>=0) {
269  sprintf(p, "%sPEExportSection[%zd].", prefix, idx);
270  } else {
271  sprintf(p, "%sPEExportSection.", prefix);
272  }
273 
274  SgAsmPESection::dump(f, p, -1);
275 
276  if (p_export_dir)
277  p_export_dir->dump(f, p, -1);
278  for (size_t i=0; i<p_exports->get_exports().size(); i++)
279  p_exports->get_exports()[i]->dump(f, p, i);
280 
281  if (variantT() == V_SgAsmPEExportSection) //unless a base class
282  hexdump(f, 0, std::string(p)+"data at ", p_data);
283 }