1use crate::{
2 formats::dll::DllReadConfig,
3 program::{
4 ClrAccessFlags, ClrHeader, ClrMethod, ClrProgram, ClrType, ClrTypeReference, ClrVersion, DotNetAssemblyInfo,
5 MetadataHeader, StreamHeader,
6 },
7};
8use byteorder::{LittleEndian, ReadBytesExt};
9use gaia_types::{GaiaDiagnostics, GaiaError, SourceLocation};
10use pe_assembler::{
11 helpers::PeReader,
12 types::{PeHeader, PeProgram, SectionHeader},
13};
14use std::io::{Read, Seek, SeekFrom};
15use url::Url;
16
17#[derive(Debug)]
18pub struct DllReader<'config, R> {
19 options: &'config DllReadConfig,
21 reader: pe_assembler::formats::dll::reader::DllReader<R>,
22 clr_header: Option<ClrHeader>,
24 metadata_header: Option<MetadataHeader>,
26 stream_headers: Option<Vec<StreamHeader>>,
28 assembly_info: Option<DotNetAssemblyInfo>,
30 clr_program: Option<ClrProgram>,
32}
33
34impl<'config, R: Read + Seek> PeReader<R> for DllReader<'config, R> {
35 fn get_viewer(&mut self) -> &mut R {
36 self.reader.get_viewer()
37 }
38
39 fn add_diagnostics(&mut self, error: impl Into<GaiaError>) {
40 self.reader.add_diagnostics(error)
41 }
42
43 fn get_section_headers(&mut self) -> Result<&[SectionHeader], GaiaError> {
44 self.reader.get_section_headers()
45 }
46
47 fn get_pe_header(&mut self) -> Result<&PeHeader, GaiaError> {
48 self.reader.get_pe_header()
49 }
50
51 fn get_program(&mut self) -> Result<&PeProgram, GaiaError> {
52 self.reader.get_program()
53 }
54}
55
56impl<'config, R> DllReader<'config, R> {
57 pub fn new(reader: R, options: &'config DllReadConfig) -> Self {
61 Self {
62 reader: pe_assembler::formats::dll::reader::DllReader::new(reader),
63 clr_header: None,
64 metadata_header: None,
65 stream_headers: None,
66 assembly_info: None,
67 clr_program: None,
68 options,
69 }
70 }
71}
72
73impl<'config, R> DllReader<'config, R>
74where
75 R: Read + Seek,
76{
77 pub fn get_assembly_info(&mut self) -> Result<DotNetAssemblyInfo, GaiaError> {
117 if self.assembly_info.is_none() {
118 self.ensure_assembly_info_parsed()?;
119 }
120
121 self.assembly_info
122 .as_ref()
123 .cloned()
124 .ok_or_else(|| GaiaError::syntax_error("程序集信息未解析".to_string(), SourceLocation::default()))
125 }
126
127 pub fn to_clr_program(&mut self) -> Result<ClrProgram, GaiaError> {
136 if let Some(ref program) = self.clr_program {
137 return Ok(program.clone());
138 }
139
140 let program = self.parse_full_program()?;
142 self.clr_program = Some(program.clone());
143 Ok(program)
144 }
145
146 pub fn validate_assembly(&mut self) -> Result<Vec<String>, GaiaError> {
157 let mut warnings = Vec::new();
158
159 self.ensure_assembly_info_parsed()?;
161
162 if self.clr_header.is_none() {
164 warnings.push("缺少 CLR 头".to_string());
165 }
166
167 if self.metadata_header.is_none() {
169 warnings.push("缺少元数据头".to_string());
170 }
171
172 if self.stream_headers.as_ref().map_or(true, |h| h.is_empty()) {
174 warnings.push("缺少元数据流".to_string());
175 }
176
177 Ok(warnings)
178 }
179
180 pub fn get_assembly_summary(&mut self) -> String {
188 match self.get_assembly_info() {
189 Ok(info) => {
190 format!(
191 "程序集: {}\n版本: {}\n文化: {}\n公钥标记: {}\n运行时版本: {}",
192 info.name,
193 info.version,
194 info.culture.as_deref().unwrap_or("neutral"),
195 info.public_key_token.as_deref().unwrap_or("null"),
196 info.runtime_version.as_deref().unwrap_or("unknown")
197 )
198 }
199 Err(_) => "无法获取程序集信息".to_string(),
200 }
201 }
202
203 fn ensure_assembly_info_parsed(&mut self) -> Result<(), GaiaError> {
205 if self.assembly_info.is_some() {
206 return Ok(());
207 }
208
209 self.parse_clr_header()?;
211 self.parse_metadata()?;
212 self.extract_assembly_info()?;
213
214 Ok(())
215 }
216
217 fn parse_clr_header(&mut self) -> Result<(), GaiaError> {
226 eprintln!("开始解析 CLR 头");
227 self.clr_header = self.find_and_read_clr_header()?;
228 eprintln!("find_and_read_clr_header 返回: {:?}", self.clr_header.is_some());
229 if self.clr_header.is_none() {
230 eprintln!("CLR 头为空,返回错误");
231 return Err(GaiaError::syntax_error("缺少 CLR 头", SourceLocation::default()));
232 }
233 eprintln!("CLR 头解析成功");
234 Ok(())
235 }
236
237 fn parse_metadata(&mut self) -> Result<(), GaiaError> {
248 if let Some(ref clr_header) = self.clr_header {
249 let metadata_offset = self.rva_to_file_offset(clr_header.metadata_rva)?;
251 self.metadata_header = Some(self.read_metadata_header(metadata_offset)?);
253 self.stream_headers = Some(self.read_stream_headers(metadata_offset)?);
255 }
256
257 Ok(())
258 }
259
260 fn extract_assembly_info(&mut self) -> Result<(), GaiaError> {
269 let clr_header = match &self.clr_header {
271 Some(h) => *h,
272 None => return Ok(()),
273 };
274 let metadata_offset = self.rva_to_file_offset(clr_header.metadata_rva)?;
275
276 let mut tables_stream: Option<StreamHeader> = None;
278 let mut strings_stream: Option<StreamHeader> = None;
279 if let Some(ref stream_headers) = self.stream_headers {
280 for sh in stream_headers {
281 match sh.name.as_str() {
282 "#~" => tables_stream = Some(sh.clone()),
283 "#Strings" => strings_stream = Some(sh.clone()),
284 _ => {}
285 }
286 }
287 }
288 if tables_stream.is_none() || strings_stream.is_none() {
289 return Ok(());
290 }
291 let tables_stream = tables_stream.unwrap();
292 let strings_stream = strings_stream.unwrap();
293
294 let tables_start = metadata_offset + tables_stream.offset;
295 let strings_start = metadata_offset + strings_stream.offset;
296
297 let mut cur = self.reader.get_viewer();
299 cur.seek(SeekFrom::Start(tables_start as u64))
300 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://table").unwrap()))?;
301
302 let _reserved =
303 cur.read_u32::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_hdr").unwrap()))?;
304 let _major = cur.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_hdr").unwrap()))?;
305 let _minor = cur.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_hdr").unwrap()))?;
306 let heap_sizes = cur.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_hdr").unwrap()))?;
307 let _reserved2 = cur.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_hdr").unwrap()))?;
308 let valid_mask =
309 cur.read_u64::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_hdr").unwrap()))?;
310 let _sorted_mask =
311 cur.read_u64::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_hdr").unwrap()))?;
312
313 let str_idx_sz = if (heap_sizes & 0x01) != 0 { 4 } else { 2 };
315 let guid_idx_sz = if (heap_sizes & 0x02) != 0 { 4 } else { 2 };
316 let blob_idx_sz = if (heap_sizes & 0x04) != 0 { 4 } else { 2 };
317 let strings_size = strings_stream.size;
318
319 eprintln!("堆大小标志: 0x{:02x}", heap_sizes);
320 eprintln!("字符串索引大小: {}, GUID索引大小: {}, Blob索引大小: {}", str_idx_sz, guid_idx_sz, blob_idx_sz);
321 eprintln!("字符串流大小: {}", strings_size);
322 eprintln!("有效表掩码: 0x{:016x}", valid_mask);
323
324 let mut row_counts: [u32; 64] = [0; 64];
326 for tid in 0..64u8 {
327 if (valid_mask >> tid) & 1 == 1 {
328 row_counts[tid as usize] = cur
329 .read_u32::<LittleEndian>()
330 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_rows").unwrap()))?;
331 eprintln!("表 0x{:02x} 行数: {}", tid, row_counts[tid as usize]);
332 }
333 }
334
335 fn coded_size(rows: &[u32; 64], tags: &[u8]) -> u32 {
337 let max_rows = tags.iter().map(|&t| rows[t as usize]).max().unwrap_or(0);
338 let tag_bits = (tags.len() as f32).log2().ceil() as u32;
339 if (max_rows << tag_bits) < (1 << 16) {
340 2
341 }
342 else {
343 4
344 }
345 }
346 let type_def_or_ref_sz = coded_size(&row_counts, &[0x02, 0x01, 0x18]);
347 let resolution_scope_sz = coded_size(&row_counts, &[0x00, 0x01, 0x17, 0x23]);
348
349 let module_row_size = 2 + str_idx_sz + guid_idx_sz + guid_idx_sz + guid_idx_sz;
351 let type_def_row_size = 4
352 + str_idx_sz
353 + str_idx_sz
354 + type_def_or_ref_sz
355 + (if row_counts[0x04] < (1 << 16) { 2 } else { 4 })
356 + (if row_counts[0x06] < (1 << 16) { 2 } else { 4 });
357 let methoddef_row_size = 4 + 2 + 2 + str_idx_sz + blob_idx_sz + (if row_counts[0x07] < (1 << 16) { 2 } else { 4 });
358 let typeref_row_size = resolution_scope_sz + str_idx_sz + str_idx_sz;
359 let assembly_row_size = 4 + 2 + 2 + 2 + 2 + 4 + blob_idx_sz + str_idx_sz + str_idx_sz;
360
361 let tables_data_start =
363 cur.stream_position().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_data").unwrap()))? as u32;
364 eprintln!("表数据区起始位置: 0x{:x}", tables_data_start);
365 let mut table_start: [Option<u32>; 64] = [None; 64];
367 let mut table_row_size: [u32; 64] = [0; 64];
368 let mut running = tables_data_start;
369 for tid in 0..64u8 {
370 if (valid_mask >> tid) & 1 == 1 {
371 let rows = row_counts[tid as usize];
372 let row_size = match tid {
373 0x00 => module_row_size,
374 0x01 => typeref_row_size,
375 0x02 => type_def_row_size,
376 0x06 => methoddef_row_size,
377 0x20 => assembly_row_size, _ => 0,
379 } as u32;
380 table_start[tid as usize] = Some(running);
381 table_row_size[tid as usize] = row_size;
382 eprintln!(
383 "表 0x{:02x}: 起始=0x{:x}, 行数={}, 行大小={}, 总大小={}",
384 tid,
385 running,
386 rows,
387 row_size,
388 rows * row_size
389 );
390 running += rows * row_size;
391 }
392 }
393
394 let mut name = String::from("Unknown");
396 let mut version = ClrVersion { major: 0, minor: 0, build: 0, revision: 0 };
397
398 if let Some(asm_start) = table_start[0x20] {
400 if row_counts[0x20] > 0 {
401 let mut c = self.reader.get_viewer();
402 c.seek(SeekFrom::Start(asm_start as u64))
403 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
404
405 let hash_alg =
407 c.read_u32::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
408 version.major =
409 c.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
410 version.minor =
411 c.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
412 version.build =
413 c.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
414 version.revision =
415 c.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
416 let flags =
417 c.read_u32::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
418 let pk_idx = read_heap_index(&mut c, blob_idx_sz)?;
419 let name_idx = read_heap_index(&mut c, str_idx_sz)?;
420 let culture_idx = read_heap_index(&mut c, str_idx_sz)?;
421
422 if hash_alg > 0x10000 || version.major > 100 || name_idx > strings_size {
424 eprintln!("警告: Assembly表数据异常,可能表偏移计算错误");
425 eprintln!(
426 "HashAlg: 0x{:x}, Version: {}.{}.{}.{}, NameIdx: {}",
427 hash_alg, version.major, version.minor, version.build, version.revision, name_idx
428 );
429 }
430 else {
431 let n = self.read_string_from_strings_heap(strings_start, strings_size, name_idx)?;
432 if !n.is_empty() {
433 name = n;
434 }
435 }
436 }
437 }
438 else if let Some(mod_start) = table_start[0x00] {
439 if row_counts[0x00] > 0 {
441 let mut c = self.reader.get_viewer();
442 c.seek(SeekFrom::Start(mod_start as u64))
443 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://mod").unwrap()))?;
444 let _generation =
445 c.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://mod").unwrap()))?;
446 let name_idx = read_heap_index(&mut c, str_idx_sz)?;
447 let _mvid_idx = read_heap_index(&mut c, guid_idx_sz)?;
448 let _enc_id_idx = read_heap_index(&mut c, guid_idx_sz)?;
449 let _enc_base_id_idx = read_heap_index(&mut c, guid_idx_sz)?;
450 let n = self.read_string_from_strings_heap(strings_start, strings_size, name_idx)?;
451 if !n.is_empty() {
452 name = n;
453 }
454 }
455 }
456
457 let runtime_version = self.metadata_header.as_ref().map(|h| h.version_string.clone());
459
460 self.assembly_info = Some(DotNetAssemblyInfo {
462 name,
463 version: format!("{}.{}.{}.{}", version.major, version.minor, version.build, version.revision),
464 culture: None,
465 public_key_token: None,
466 runtime_version,
467 });
468
469 Ok(())
470 }
471
472 fn parse_full_program(&mut self) -> Result<ClrProgram, GaiaError> {
481 let metadata_rva = self
483 .clr_header
484 .as_ref()
485 .ok_or_else(|| GaiaError::syntax_error("缺少 CLR 头".to_string(), SourceLocation::default()))?
486 .metadata_rva;
487 let _version_string = self
488 .metadata_header
489 .as_ref()
490 .ok_or_else(|| GaiaError::syntax_error("缺少元数据头".to_string(), SourceLocation::default()))?
491 .version_string
492 .clone();
493
494 let metadata_base = self.rva_to_file_offset(metadata_rva)?;
496
497 let mut tables_stream: Option<StreamHeader> = None;
499 let mut strings_stream: Option<StreamHeader> = None;
500 if let Some(ref stream_headers) = self.stream_headers {
501 for sh in stream_headers {
502 match sh.name.as_str() {
503 "#~" | "#-" => tables_stream = Some(sh.clone()),
504 "#Strings" => strings_stream = Some(sh.clone()),
505 _ => {}
506 }
507 }
508 }
509
510 let tables_stream = tables_stream
511 .ok_or_else(|| GaiaError::syntax_error("缺少元数据表流(#~/#-)".to_string(), SourceLocation::default()))?;
512 let strings_stream = strings_stream
513 .ok_or_else(|| GaiaError::syntax_error("缺少字符串流(#Strings)".to_string(), SourceLocation::default()))?;
514
515 let mut cur = self.reader.get_viewer();
517 let tables_start = metadata_base + tables_stream.offset;
519 let strings_start = metadata_base + strings_stream.offset;
520
521 cur.seek(SeekFrom::Start(tables_start as u64))
523 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
524 let _reserved =
525 cur.read_u32::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
526 let _major = cur.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
527 let _minor = cur.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
528 let heap_sizes = cur.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
529 let _reserved2 = cur.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
530 let valid_mask =
531 cur.read_u64::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
532 let _sorted_mask =
533 cur.read_u64::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
534
535 let mut row_counts: [u32; 64] = [0; 64];
537 for tid in 0..64u8 {
538 if (valid_mask >> tid) & 1 == 1 {
539 let cnt = cur
540 .read_u32::<LittleEndian>()
541 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables").unwrap()))?;
542 row_counts[tid as usize] = cnt;
543 }
544 }
545
546 let str_idx_sz = if (heap_sizes & 0x01) != 0 { 4 } else { 2 };
548 let guid_idx_sz = if (heap_sizes & 0x02) != 0 { 4 } else { 2 };
549 let blob_idx_sz = if (heap_sizes & 0x04) != 0 { 4 } else { 2 };
550 let _ = guid_idx_sz; let tables_data_start =
554 cur.stream_position().map_err(|e| GaiaError::io_error(e, Url::parse("memory://tables_data").unwrap()))? as u32;
555
556 let mut simple_index_size = |table_id: u8| -> u32 {
558 let rows = row_counts[table_id as usize];
559 if rows < (1 << 16) {
560 2
561 }
562 else {
563 4
564 }
565 };
566
567 let param_index_sz = simple_index_size(0x07); let methoddef_row_size = 4 + 2 + 2 + str_idx_sz + blob_idx_sz + param_index_sz;
570
571 let field_row_size = 2 + str_idx_sz + blob_idx_sz ;
573 let fieldptr_row_size = simple_index_size(0x04);
574 let methodptr_row_size = simple_index_size(0x06);
575 let rs_candidates = [0x00u8, 0x17u8, 0x20u8, 0x01u8];
578 let mut max_rs_rows = 0u32;
579 for &t in &rs_candidates {
580 max_rs_rows = max_rs_rows.max(row_counts[t as usize]);
581 }
582 let rs_tag_bits = 2u32;
583 let resolution_scope_sz = if max_rs_rows < (1 << (16 - rs_tag_bits)) { 2 } else { 4 };
584 let typeref_row_size = resolution_scope_sz + str_idx_sz + str_idx_sz;
585 let tdr_candidates = [0x02u8, 0x01u8, 0x18u8];
588 let mut max_tdr_rows = 0u32;
589 for &t in &tdr_candidates {
590 max_tdr_rows = max_tdr_rows.max(row_counts[t as usize]);
591 }
592 let tdr_tag_bits = 2u32;
593 let type_def_or_ref_sz = if max_tdr_rows < (1 << (16 - tdr_tag_bits)) { 2 } else { 4 };
594 let type_def_row_size =
595 4 + str_idx_sz + str_idx_sz + type_def_or_ref_sz + simple_index_size(0x04) + simple_index_size(0x06);
596 let module_row_size = 2 + str_idx_sz + guid_idx_sz + guid_idx_sz + guid_idx_sz;
598
599 let mut table_start: [Option<u32>; 64] = [None; 64];
601 let mut table_row_size: [u32; 64] = [0; 64];
602 let mut running = tables_data_start;
603 for tid in 0..64u8 {
604 if (valid_mask >> tid) & 1 == 1 {
605 let rows = row_counts[tid as usize];
606 let row_size = match tid {
607 0x00 => module_row_size,
608 0x01 => typeref_row_size,
609 0x02 => type_def_row_size,
610 0x03 => fieldptr_row_size,
611 0x04 => field_row_size,
612 0x05 => methodptr_row_size,
613 0x06 => methoddef_row_size,
614 0x07 => 2 + str_idx_sz + blob_idx_sz, 0x08 => simple_index_size(0x02) + simple_index_size(0x01), 0x09 => resolution_scope_sz + str_idx_sz + blob_idx_sz, 0x0A => 2 + blob_idx_sz, 0x0B => simple_index_size(0x02) + simple_index_size(0x0A) + simple_index_size(0x0C), 0x0C => simple_index_size(0x04) + simple_index_size(0x07), 0x0D => 2 + blob_idx_sz, 0x0E => 2 + 4 + 4, 0x0F => simple_index_size(0x04) + 4, 0x10 => blob_idx_sz, 0x11 => simple_index_size(0x02) + simple_index_size(0x12), 0x12 => 2 + str_idx_sz + simple_index_size(0x10), 0x13 => simple_index_size(0x02) + simple_index_size(0x14), 0x14 => 2 + str_idx_sz + blob_idx_sz, 0x15 => 2 + simple_index_size(0x06) + simple_index_size(0x14), 0x16 => simple_index_size(0x02) + simple_index_size(0x06) + simple_index_size(0x01), 0x20 => 4 + 2 + 2 + 2 + 2 + 4 + blob_idx_sz + str_idx_sz + str_idx_sz, 0x21 => 4 + 4, 0x22 => 4 + 4 + 4, 0x23 => 2 + 2 + 2 + 2 + 4 + blob_idx_sz + str_idx_sz + str_idx_sz + blob_idx_sz, _ => 0,
635 } as u32;
636 table_start[tid as usize] = Some(running);
637 table_row_size[tid as usize] = row_size;
638 running += rows * row_size;
639 }
640 }
641 let methoddef_offset = table_start[0x06].unwrap_or(tables_data_start);
642
643 let mut program = ClrProgram::new("UnknownAssembly");
645 program.version = ClrVersion { major: 1, minor: 0, build: 0, revision: 0 };
646 program.access_flags =
647 ClrAccessFlags { is_public: true, is_private: false, is_security_transparent: false, is_retargetable: false };
648
649 if let Some(asm_start) = table_start[0x20] {
651 let asm_rows = row_counts[0x20];
653 if asm_rows > 0 {
654 let asm0 = asm_start; let mut c2 = self.reader.get_viewer();
656 c2.seek(SeekFrom::Start(asm0 as u64))
657 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
658 let _hash_alg =
659 c2.read_u32::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
660 let ver_major =
661 c2.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
662 let ver_minor =
663 c2.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
664 let ver_build =
665 c2.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
666 let ver_rev =
667 c2.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
668 let _flags =
669 c2.read_u32::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://asm").unwrap()))?;
670 let _pk_idx = read_heap_index(&mut c2, blob_idx_sz)?;
671 let name_idx = read_heap_index(&mut c2, str_idx_sz)?;
672 let culture_idx = read_heap_index(&mut c2, str_idx_sz)?;
673 let _hash_idx = read_heap_index(&mut c2, blob_idx_sz)?;
674
675 let name = self.read_string_from_strings_heap(strings_start, strings_stream.size, name_idx)?;
676 let culture = if culture_idx != 0 {
677 Some(self.read_string_from_strings_heap(strings_start, strings_stream.size, culture_idx)?)
678 }
679 else {
680 None
681 };
682
683 if !name.is_empty() {
684 program.name = name;
685 }
686 program.version = ClrVersion { major: ver_major, minor: ver_minor, build: ver_build, revision: ver_rev };
687 }
688 }
689 else if let Some(module_start) = table_start[0x00] {
690 let mut cm = self.reader.get_viewer();
692 cm.seek(SeekFrom::Start(module_start as u64))
693 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://module").unwrap()))?;
694 let _generation =
695 cm.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://module").unwrap()))?;
696 let name_idx = read_heap_index(&mut cm, str_idx_sz)?;
697 let _mvid_idx = read_heap_index(&mut cm, guid_idx_sz)?;
698 let _encid = read_heap_index(&mut cm, guid_idx_sz)?;
699 let _encbase = read_heap_index(&mut cm, guid_idx_sz)?;
700 let mod_name = self.read_string_from_strings_heap(strings_start, strings_stream.size, name_idx)?;
701 if !mod_name.is_empty() {
702 program.name = mod_name;
703 }
704 }
705
706 if let Some(typedef_start) = table_start[0x02] {
708 for i in 0..row_counts[0x02] {
709 let mut ct = self.reader.get_viewer();
710 ct.seek(SeekFrom::Start((typedef_start + i * type_def_row_size) as u64))
711 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://typedef").unwrap()))?;
712 let flags = ct
713 .read_u32::<LittleEndian>()
714 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://typedef").unwrap()))?;
715 let name_idx = read_heap_index(&mut ct, str_idx_sz)?;
716 let ns_idx = read_heap_index(&mut ct, str_idx_sz)?;
717 let _extends_idx = read_type_def_or_ref_index(&mut ct, type_def_or_ref_sz)?;
718 let _field_list_idx = read_heap_index(&mut ct, (if row_counts[0x04] < (1 << 16) { 2 } else { 4 }))?;
719 let _method_list_idx = read_heap_index(&mut ct, (if row_counts[0x06] < (1 << 16) { 2 } else { 4 }))?;
720
721 let type_name = self.read_string_from_strings_heap(strings_start, strings_stream.size, name_idx)?;
722 let namespace = if ns_idx != 0 {
723 Some(self.read_string_from_strings_heap(strings_start, strings_stream.size, ns_idx)?)
724 }
725 else {
726 None
727 };
728
729 if !type_name.is_empty() {
730 let mdef = ClrMethod::new(
731 "DefaultMethod".to_string(),
732 ClrTypeReference {
733 name: "Void".to_string(),
734 namespace: Some("System".to_string()),
735 assembly: Some("mscorlib".to_string()),
736 is_value_type: true,
737 is_reference_type: false,
738 generic_parameters: Vec::new(),
739 },
740 );
741 let mut clr_type = ClrType::new(type_name, namespace);
742 clr_type.access_flags.is_public = true;
743 clr_type.add_method(mdef);
744 }
745 }
746 }
747
748 if let Some(methoddef_start) = table_start[0x06] {
750 for i in 0..row_counts[0x06] {
751 let mut c3 = self.reader.get_viewer();
752 c3.seek(SeekFrom::Start((methoddef_start + i * methoddef_row_size) as u64))
753 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://methoddef").unwrap()))?;
754 let _rva = c3
755 .read_u32::<LittleEndian>()
756 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://methoddef").unwrap()))?;
757 let _impl_flags = c3
758 .read_u16::<LittleEndian>()
759 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://methoddef").unwrap()))?;
760 let _flags = c3
761 .read_u16::<LittleEndian>()
762 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://methoddef").unwrap()))?;
763 let name_idx = read_heap_index(&mut c3, str_idx_sz)?;
764 let _sig_idx = read_heap_index(&mut c3, blob_idx_sz)?;
765 let _param_list_idx = read_heap_index(&mut c3, (if row_counts[0x07] < (1 << 16) { 2 } else { 4 }))?;
766
767 let method_name = self.read_string_from_strings_heap(strings_start, strings_stream.size, name_idx)?;
768
769 if !method_name.is_empty() {
770 let _mdef = ClrMethod::new(
771 method_name,
772 ClrTypeReference {
773 name: "Void".to_string(),
774 namespace: Some("System".to_string()),
775 assembly: Some("mscorlib".to_string()),
776 is_value_type: true,
777 is_reference_type: false,
778 generic_parameters: Vec::new(),
779 },
780 );
781 }
783 }
784 }
785
786 if let Some(field_start) = table_start[0x04] {
788 for i in 0..row_counts[0x04] {
789 let mut c4 = self.reader.get_viewer();
790 c4.seek(SeekFrom::Start((field_start + i * field_row_size) as u64))
791 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://field").unwrap()))?;
792 let _flags =
793 c4.read_u16::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://field").unwrap()))?;
794 let name_idx = read_heap_index(&mut c4, str_idx_sz)?;
795 let _sig_idx = read_heap_index(&mut c4, blob_idx_sz)?;
796
797 let name = self.read_string_from_strings_heap(strings_start, strings_stream.size, name_idx)?;
798
799 if !name.is_empty() {
800 let _mdef = ClrMethod::new(
801 "DefaultMethod".to_string(),
802 ClrTypeReference {
803 name: "Void".to_string(),
804 namespace: Some("System".to_string()),
805 assembly: Some("mscorlib".to_string()),
806 is_value_type: true,
807 is_reference_type: false,
808 generic_parameters: Vec::new(),
809 },
810 );
811 let mut _clr_type = ClrType::new(name, None);
812 _clr_type.access_flags.is_public = true;
813 _clr_type.add_method(_mdef);
814 }
815 }
816 }
817
818 let mut external_assemblies: Vec<crate::program::ClrExternalAssembly> = Vec::new();
820 if let Some(asmref_start) = table_start[0x23] {
822 let assemblyref_rows = row_counts[0x23];
824
825 let row_size = table_row_size[0x23];
827 for i in 0..assemblyref_rows {
828 let row_off = asmref_start + i * row_size;
829 let mut c4 = self.reader.get_viewer();
830 c4.seek(SeekFrom::Start(row_off as u64))
831 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://asmref").unwrap()))?;
832 let ver_major = c4
833 .read_u16::<LittleEndian>()
834 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://asmref").unwrap()))?;
835 let ver_minor = c4
836 .read_u16::<LittleEndian>()
837 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://asmref").unwrap()))?;
838 let ver_build = c4
839 .read_u16::<LittleEndian>()
840 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://asmref").unwrap()))?;
841 let ver_rev = c4
842 .read_u16::<LittleEndian>()
843 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://asmref").unwrap()))?;
844 let _flags = c4
845 .read_u32::<LittleEndian>()
846 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://asmref").unwrap()))?;
847 let _pkt_idx = read_heap_index(&mut c4, blob_idx_sz)?;
848 let name_idx = read_heap_index(&mut c4, str_idx_sz)?;
849 let culture_idx = read_heap_index(&mut c4, str_idx_sz)?;
850 let _hash_idx = read_heap_index(&mut c4, blob_idx_sz)?;
851 let name = self.read_string_from_strings_heap(strings_start, strings_stream.size, name_idx)?;
852 if !name.is_empty() {
853 external_assemblies.push(crate::program::ClrExternalAssembly {
854 name,
855 version: ClrVersion { major: ver_major, minor: ver_minor, build: ver_build, revision: ver_rev },
856 public_key_token: None,
857 culture: None,
858 hash_algorithm: None,
859 });
860 }
861 }
862 }
863
864 if external_assemblies.is_empty() {
866 let cfg = &self.options.assembly_ref_fallback_names;
867 let heap = self.read_strings_heap_data(strings_start, strings_stream.size)?;
868 for name in cfg.iter() {
869 if find_subslice(&heap, name.as_bytes()) {
870 external_assemblies.push(crate::program::ClrExternalAssembly {
871 name: name.to_string(),
872 version: ClrVersion { major: 0, minor: 0, build: 0, revision: 0 },
873 public_key_token: None,
874 culture: None,
875 hash_algorithm: None,
876 });
877 }
878 }
879 }
880
881 for ea in external_assemblies {
882 program.add_external_assembly(ea);
883 }
884
885 let _ = _version_string.as_str();
887
888 Ok(program)
889 }
890
891 fn find_and_read_clr_header(&mut self) -> Result<Option<ClrHeader>, GaiaError> {
903 eprintln!("开始查找 CLR 头");
904
905 let pe_program = self.reader.get_program()?.clone();
907 eprintln!("获取 PE 程序成功");
908
909 let data_dirs_count = pe_program.header.optional_header.data_directories.len();
911 eprintln!("数据目录数量: {}", data_dirs_count);
912
913 if let Some(clr_dir) = pe_program.header.optional_header.data_directories.get(14) {
915 eprintln!("找到 CLR 数据目录 - RVA: 0x{:x}, 大小: {}", clr_dir.virtual_address, clr_dir.size);
916
917 if clr_dir.virtual_address == 0 || clr_dir.size == 0 {
918 eprintln!("CLR 数据目录为空");
919 return Ok(None);
920 }
921
922 let file_offset = self.rva_to_file_offset(clr_dir.virtual_address)?;
924 eprintln!("CLR 头文件偏移: 0x{:x}", file_offset);
925
926 let mut cursor = self.reader.get_viewer();
928 cursor
929 .seek(SeekFrom::Start(file_offset as u64))
930 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://clr_header").unwrap()))?;
931
932 let cb = cursor
933 .read_u32::<LittleEndian>()
934 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://clr_header").unwrap()))?;
935 let major_runtime_version = cursor
936 .read_u16::<LittleEndian>()
937 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://clr_header").unwrap()))?;
938 let minor_runtime_version = cursor
939 .read_u16::<LittleEndian>()
940 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://clr_header").unwrap()))?;
941 let metadata_rva = cursor
942 .read_u32::<LittleEndian>()
943 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://clr_header").unwrap()))?;
944 let metadata_size = cursor
945 .read_u32::<LittleEndian>()
946 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://clr_header").unwrap()))?;
947 let flags = cursor
948 .read_u32::<LittleEndian>()
949 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://clr_header").unwrap()))?;
950
951 eprintln!(
952 "成功读取 CLR 头 - cb: {}, 版本: {}.{}, 元数据 RVA: 0x{:x}, 大小: {}",
953 cb, major_runtime_version, minor_runtime_version, metadata_rva, metadata_size
954 );
955
956 Ok(Some(ClrHeader { cb, major_runtime_version, minor_runtime_version, metadata_rva, metadata_size, flags }))
957 }
958 else {
959 eprintln!("未找到 CLR 数据目录(索引 14)");
960 Ok(None)
961 }
962 }
963
964 fn read_metadata_header(&mut self, offset: u32) -> Result<MetadataHeader, GaiaError> {
981 let mut cursor = self.reader.get_viewer();
982 cursor
983 .seek(SeekFrom::Start(offset as u64))
984 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
985
986 let signature = cursor
988 .read_u32::<LittleEndian>()
989 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
990 let major_version = cursor
991 .read_u16::<LittleEndian>()
992 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
993 let minor_version = cursor
994 .read_u16::<LittleEndian>()
995 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
996 let reserved = cursor
997 .read_u32::<LittleEndian>()
998 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
999 let version_length = cursor
1000 .read_u32::<LittleEndian>()
1001 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
1002
1003 let mut version_bytes = vec![0u8; version_length as usize];
1005 cursor
1006 .read_exact(&mut version_bytes)
1007 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
1008 let version_string = String::from_utf8_lossy(&version_bytes).trim_end_matches('\0').to_string();
1009
1010 let flags = cursor
1012 .read_u16::<LittleEndian>()
1013 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
1014 let streams = cursor
1015 .read_u16::<LittleEndian>()
1016 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://metadata_header").unwrap()))?;
1017
1018 Ok(MetadataHeader { signature, major_version, minor_version, reserved, version_length, version_string, flags, streams })
1020 }
1021
1022 fn read_stream_headers(&mut self, metadata_offset: u32) -> Result<Vec<StreamHeader>, GaiaError> {
1047 let mut stream_headers = Vec::new();
1048
1049 if let Some(ref metadata_header) = self.metadata_header {
1050 let mut cursor = self.reader.get_viewer();
1051 let stream_start_offset = metadata_offset + 20 + metadata_header.version_length;
1053 cursor
1054 .seek(SeekFrom::Start(stream_start_offset as u64))
1055 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://stream_headers").unwrap()))?;
1056
1057 for _ in 0..metadata_header.streams {
1059 let offset = cursor
1060 .read_u32::<LittleEndian>()
1061 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://stream_headers").unwrap()))?;
1062 let size = cursor
1063 .read_u32::<LittleEndian>()
1064 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://stream_headers").unwrap()))?;
1065
1066 let mut name_bytes = Vec::new();
1068 loop {
1069 let byte =
1070 cursor.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://stream_headers").unwrap()))?;
1071 if byte == 0 {
1072 break;
1073 }
1074 name_bytes.push(byte);
1075 }
1076 let name = String::from_utf8_lossy(&name_bytes).to_string();
1077
1078 let current_pos = cursor
1080 .stream_position()
1081 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://stream_headers").unwrap()))?;
1082 let aligned_pos = (current_pos + 3) & !3;
1083 cursor
1084 .seek(SeekFrom::Start(aligned_pos))
1085 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://stream_headers").unwrap()))?;
1086
1087 stream_headers.push(StreamHeader { offset, size, name });
1088 }
1089 }
1090
1091 Ok(stream_headers)
1092 }
1093
1094 fn read_strings_heap_data(&mut self, strings_start: u32, strings_size: u32) -> Result<Vec<u8>, GaiaError> {
1096 let mut reader = self.reader.get_viewer();
1097 reader
1098 .seek(SeekFrom::Start(strings_start as u64))
1099 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://strings_heap").unwrap()))?;
1100
1101 let mut buffer = vec![0u8; strings_size as usize];
1102 reader.read_exact(&mut buffer).map_err(|e| GaiaError::io_error(e, Url::parse("memory://strings_heap").unwrap()))?;
1103
1104 Ok(buffer)
1105 }
1106
1107 fn read_string_from_strings_heap(
1109 &mut self,
1110 strings_start: u32,
1111 strings_size: u32,
1112 index: u32,
1113 ) -> Result<String, GaiaError> {
1114 eprintln!("读取字符串 - 起始: {}, 大小: {}, 索引: {}", strings_start, strings_size, index);
1115
1116 if index == 0 {
1117 return Ok(String::new());
1118 }
1119
1120 let base = strings_start + index;
1121 let end = strings_start + strings_size;
1122
1123 eprintln!("计算位置 - base: {}, end: {}", base, end);
1124
1125 if base >= end {
1126 eprintln!("索引越界 - base {} >= end {}", base, end);
1127 return Err(GaiaError::syntax_error(format!("字符串索引 {} 超出堆范围", index), SourceLocation::default()));
1128 }
1129
1130 let viewer = self.reader.get_viewer();
1132 viewer
1133 .seek(SeekFrom::Start(base as u64))
1134 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://strings_heap").unwrap()))?;
1135
1136 let mut bytes = Vec::new();
1138 loop {
1139 let byte = viewer.read_u8().map_err(|e| GaiaError::io_error(e, Url::parse("memory://strings_heap").unwrap()))?;
1140 if byte == 0 {
1141 break;
1142 }
1143 bytes.push(byte);
1144 }
1145
1146 let result = String::from_utf8_lossy(&bytes).to_string();
1147 eprintln!("成功读取字符串: '{}'", result);
1148 Ok(result)
1149 }
1150
1151 fn rva_to_file_offset(&mut self, rva: u32) -> Result<u32, GaiaError> {
1174 let pe_program = self.reader.get_program()?.clone();
1176
1177 for section in &pe_program.sections {
1179 let section_start = section.virtual_address;
1180 let section_end = section_start + section.virtual_size;
1181
1182 if rva >= section_start && rva < section_end {
1184 let offset_in_section = rva - section_start;
1186 return Ok(section.pointer_to_raw_data + offset_in_section);
1188 }
1189 }
1190
1191 Err(GaiaError::syntax_error(format!("无法将 RVA 0x{:x} 转换为文件偏移", rva), SourceLocation::default()))
1193 }
1194}
1195
1196fn read_type_def_or_ref_index<R: Read>(cursor: &mut R, idx_size: u32) -> Result<u32, GaiaError> {
1198 if idx_size == 2 {
1199 cursor
1200 .read_u16::<LittleEndian>()
1201 .map(|v| v as u32)
1202 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://type_def_or_ref_index").unwrap()))
1203 }
1204 else {
1205 cursor
1206 .read_u32::<LittleEndian>()
1207 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://type_def_or_ref_index").unwrap()))
1208 }
1209}
1210
1211fn read_heap_index<R: Read>(cursor: &mut R, idx_size: u32) -> Result<u32, GaiaError> {
1212 if idx_size == 2 {
1213 cursor
1214 .read_u16::<LittleEndian>()
1215 .map(|v| v as u32)
1216 .map_err(|e| GaiaError::io_error(e, Url::parse("memory://heap_index").unwrap()))
1217 }
1218 else if idx_size == 4 {
1219 cursor.read_u32::<LittleEndian>().map_err(|e| GaiaError::io_error(e, Url::parse("memory://heap_index").unwrap()))
1220 }
1221 else {
1222 Err(GaiaError::syntax_error("非法堆索引大小".to_string(), SourceLocation::default()))
1223 }
1224}
1225
1226fn read_string_from_heap(pe_data: &[u8], strings_start: u32, strings_size: u32, index: u32) -> Result<String, GaiaError> {
1228 if index == 0 {
1229 return Ok(String::new());
1230 }
1231 let base = strings_start + index;
1232 let end = strings_start + strings_size;
1233 if base >= end || (base as usize) >= pe_data.len() {
1234 return Ok(String::new());
1235 }
1236 let mut i = base as usize;
1237 let mut bytes = Vec::new();
1238 while i < pe_data.len() && (i as u32) < end {
1239 let b = pe_data[i];
1240 if b == 0 {
1241 break;
1242 }
1243 bytes.push(b);
1244 i += 1;
1245 }
1246 Ok(String::from_utf8_lossy(&bytes).to_string())
1247}
1248
1249fn find_subslice(haystack: &[u8], needle: &[u8]) -> bool {
1251 if needle.is_empty() {
1252 return true;
1253 }
1254 if haystack.len() < needle.len() {
1255 return false;
1256 }
1257 let n = needle.len();
1258 for i in 0..=haystack.len() - n {
1259 if &haystack[i..i + n] == needle {
1260 return true;
1261 }
1262 }
1263 false
1264}