feat: 可选头部已经解析

This commit is contained in:
381848900@qq.com 2024-12-11 01:36:29 +08:00
parent 7cf5a9c531
commit 45148ead6e
8 changed files with 614 additions and 38 deletions

View File

@ -1,17 +1,10 @@
use crate::{
app_error::AppError,
pe_parse::{header::ImageDosHeader, pe::PE},
services::{
self,
file::{
get_nt_headers_data, ResponseDOSHeaderData, ResponseFileHeaderData,
ResponseNTHeaderData,
},
GLOBAL_FILE_DATA,
},
pe_parse::pe::PE,
services::{self, file::*, GLOBAL_FILE_DATA},
};
use serde::Serialize;
use tauri::{async_runtime::Mutex, AppHandle, Manager, State};
use tauri::{AppHandle, Manager};
#[derive(Serialize)]
pub struct PeNodeTreeData {
@ -96,6 +89,15 @@ pub fn command_open_file(file_path: &str) -> Result<(), AppError> {
unsafe {
services::GLOBAL_FILE_PATH = Some(file_path.to_string());
}
// 判断文件是否是64位
// TODO: GLOBAL_IS_64_BIT
let binding = GLOBAL_FILE_DATA.lock().unwrap();
let file_data = binding.as_ref().unwrap();
let is64bit = file_data.is_64_bit()?;
unsafe {
services::GLOBAL_IS_64_BIT = Some(is64bit);
}
Ok(())
}
@ -125,3 +127,10 @@ pub fn command_get_pe_data_file_header() -> Result<ResponseFileHeaderData, AppEr
let result = services::file::get_file_header_data()?;
Ok(result)
}
// 命令,获取可选头数据
#[tauri::command]
pub fn command_get_pe_data_optional_header() -> Result<ResponseOptionalHeaderData, AppError> {
let result = services::file::get_optional_header_data()?;
Ok(result)
}

View File

@ -15,7 +15,8 @@ pub fn run() {
commands::command_get_pe_data_dos_header,
commands::command_get_pe_data_nt_header,
commands::command_get_pe_data_file_header,
commands::set_complete
commands::command_get_pe_data_optional_header,
commands::set_complete,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");

View File

@ -34,6 +34,21 @@ pub struct ImageNTHeaders32 {
pub optional_header: ImageOptionalHeader32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageNTHeaders64 {
pub signature: u32,
pub file_header: ImageFileHeader,
pub optional_header: ImageOptionalHeader64,
}
#[derive(Serialize, Clone, Copy)]
#[serde(untagged)]
pub enum ImageNTHeaders{
NTHeaders32(ImageNTHeaders32),
NTHeaders64(ImageNTHeaders64),
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageFileHeader {
@ -45,21 +60,31 @@ pub struct ImageFileHeader {
pub size_of_optional_header: u16,
pub characteristics: FileCharacteristics,
}
impl Serialize for FileCharacteristics{
impl Serialize for FileCharacteristics {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer {
// 直接返回bitflags的整数值
serializer.serialize_u16(self.bits())
S: serde::Serializer,
{
// 直接返回bitflags的整数值
serializer.serialize_u16(self.bits())
}
}
impl Serialize for DLLCharacteristics{
impl Serialize for DLLCharacteristics {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer {
serializer.serialize_u16(self.bits())
S: serde::Serializer,
{
serializer.serialize_u16(self.bits())
}
}
impl Serialize for SectionCharacteristics {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_u32(self.bits())
}
}
@ -102,6 +127,108 @@ bitflags! {
const GUARD_CF = 0x4000;
const TERMINAL_SERVER_AWARE = 0x8000;
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct SectionCharacteristics: u32 {
/// Reserved for future use.
const TYPE_REG = 0x00000000;
/// Reserved for future use.
const TYPE_DSECT = 0x00000001;
/// Reserved for future use.
const TYPE_NOLOAD = 0x00000002;
/// Reserved for future use.
const TYPE_GROUP = 0x00000004;
/// The section should not be padded to the next boundary.
/// This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES.
/// This is valid only for object files.
const TYPE_NO_PAD = 0x00000008;
/// Reserved for future use.
const TYPE_COPY = 0x00000010;
/// The section contains executable code.
const CNT_CODE = 0x00000020;
/// The section contains initialized data.
const CNT_INITIALIZED_DATA = 0x00000040;
/// The section contains uninitialized data.
const CNT_UNINITIALIZED_DATA = 0x00000080;
/// Reserved for future use.
const LNK_OTHER = 0x00000100;
/// The section contains comments or other information.
/// The .drectve section has this type. This is valid for object files only.
const LNK_INFO = 0x00000200;
/// Reserved for future use.
const TYPE_OVER = 0x00000400;
/// The section will not become part of the image.
/// This is valid only for object files.
const LNK_REMOVE = 0x00000800;
/// The section contains COMDAT data. This is valid only for object files.
const LNK_COMDAT = 0x00001000;
/// Unknown/Reserved.
const RESERVED = 0x00002000;
/// Unknown flag.
const MEM_PROTECTED = 0x00004000;
/// Unknown flag.
const NO_DEFER_SPEC_EXC = 0x00004000;
/// The section contains data referenced through the global pointer (GP).
const GPREL = 0x00008000;
/// Reserved for future use.
const MEM_FARDATA = 0x00008000;
/// Reserved for future use.
const MEM_SYSHEAP = 0x00010000;
/// Reserved for future use.
const MEM_PURGEABLE = 0x00020000;
/// Reserved for future use.
const MEM_16BIT = 0x00020000;
/// Reserved for future use.
const MEM_LOCKED = 0x00040000;
/// Reserved for future use.
const MEM_PRELOAD = 0x00080000;
/// Align data on a 1-byte boundary. Valid only for object files.
const ALIGN_1BYTES = 0x00100000;
/// Align data on a 2-byte boundary. Valid only for object files.
const ALIGN_2BYTES = 0x00200000;
/// Align data on a 4-byte boundary. Valid only for object files.
const ALIGN_4BYTES = 0x00300000;
/// Align data on an 8-byte boundary. Valid only for object files.
const ALIGN_8BYTES = 0x00400000;
/// Align data on a 16-byte boundary. Valid only for object files.
const ALIGN_16BYTES = 0x00500000;
/// Align data on a 32-byte boundary. Valid only for object files.
const ALIGN_32BYTES = 0x00600000;
/// Align data on a 64-byte boundary. Valid only for object files.
const ALIGN_64BYTES = 0x00700000;
/// Align data on a 128-byte boundary. Valid only for object files.
const ALIGN_128BYTES = 0x00800000;
/// Align data on a 256-byte boundary. Valid only for object files.
const ALIGN_256BYTES = 0x00900000;
/// Align data on a 512-byte boundary. Valid only for object files.
const ALIGN_512BYTES = 0x00A00000;
/// Align data on a 1024-byte boundary. Valid only for object files.
const ALIGN_1024BYTES = 0x00B00000;
/// Align data on a 2048-byte boundary. Valid only for object files.
const ALIGN_2048BYTES = 0x00C00000;
/// Align data on a 4096-byte boundary. Valid only for object files.
const ALIGN_4096BYTES = 0x00D00000;
/// Align data on an 8192-byte boundary. Valid only for object files.
const ALIGN_8192BYTES = 0x00E00000;
/// Mask for alignment.
const ALIGN_MASK = 0x00F00000;
/// The section contains extended relocations.
const LNK_NRELOC_OVFL = 0x01000000;
/// The section can be discarded as needed.
const MEM_DISCARDABLE = 0x02000000;
/// The section cannot be cached.
const MEM_NOT_CACHED = 0x04000000;
/// The section is not pageable.
const MEM_NOT_PAGED = 0x08000000;
/// The section can be shared in memory.
const MEM_SHARED = 0x10000000;
/// The section can be executed as code.
const MEM_EXECUTE = 0x20000000;
/// The section can be read.
const MEM_READ = 0x40000000;
/// The section can be written to.
const MEM_WRITE = 0x80000000;
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
@ -112,9 +239,9 @@ pub struct ImageOptionalHeader32 {
pub size_of_code: u32,
pub size_of_initialized_data: u32,
pub size_of_uninitialized_data: u32,
pub address_of_entry_point: RVA,
pub base_of_code: RVA,
pub base_of_data: RVA,
pub address_of_entry_point: u32,
pub base_of_code: u32,
pub base_of_data: u32,
pub image_base: u32,
pub section_alignment: u32,
pub file_alignment: u32,
@ -137,3 +264,58 @@ pub struct ImageOptionalHeader32 {
pub loader_flags: u32,
pub number_of_rva_and_sizes: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Serialize)]
pub struct ImageOptionalHeader64 {
pub magic: u16,
pub major_linker_version: u8,
pub minor_linker_version: u8,
pub size_of_code: u32,
pub size_of_initialized_data: u32,
pub size_of_uninitialized_data: u32,
pub address_of_entry_point: u32,
pub base_of_code: u32,
pub image_base: u64,
pub section_alignment: u32,
pub file_alignment: u32,
pub major_operating_system_version: u16,
pub minor_operating_system_version: u16,
pub major_image_version: u16,
pub minor_image_version: u16,
pub major_subsystem_version: u16,
pub minor_subsystem_version: u16,
pub win32_version_value: u32,
pub size_of_image: u32,
pub size_of_headers: u32,
pub checksum: u32,
pub subsystem: u16,
pub dll_characteristics: DLLCharacteristics,
pub size_of_stack_reserve: u64,
pub size_of_stack_commit: u64,
pub size_of_heap_reserve: u64,
pub size_of_heap_commit: u64,
pub loader_flags: u32,
pub number_of_rva_and_sizes: u32,
}
#[derive(Serialize, Clone, Copy)]
#[serde(untagged)]
pub enum ImageOptionalHeader {
OptionalHeader32(ImageOptionalHeader32),
OptionalHeader64(ImageOptionalHeader64),
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize)]
pub struct ImageSectionHeader {
pub name: [u8; 8],
pub virtual_size: u32,
pub virtual_address: u32,
pub size_of_raw_data: u32,
pub pointer_to_raw_data: u32,
pub pointer_to_relocations: u32,
pub pointer_to_linenumbers: u32,
pub number_of_relocations: u16,
pub number_of_linenumbers: u16,
pub characteristics: SectionCharacteristics,
}

View File

@ -1,5 +1,5 @@
use super::{error::PEParseError, header::*};
use std::ops::{Deref, DerefMut};
use std::{ops::{Deref, DerefMut}, option};
pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + Sized {
/// Get a reference to a type at a given offset.
@ -22,6 +22,16 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + Sized {
Ok(unsafe { &mut *ptr })
}
// 判断是64位还是32位
fn is_64_bit(&self) -> Result<bool, PEParseError> {
// 先以32位加载可选头通过可选头的Magic字段判断
let optional_header: &ImageOptionalHeader32 = self.get_optional_header_32()?;
let is_64_bit = optional_header.magic == 0x20b;
Ok(is_64_bit)
}
/// Get the DOS header without verifying its contents.
fn get_dos_header(&self) -> Result<&ImageDosHeader, PEParseError> {
let result = self.get_ref::<ImageDosHeader>(0)?;
@ -33,12 +43,26 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + Sized {
Ok(result)
}
/// Get the NT headers without verifying its contents.
fn get_nt_headers(&self) -> Result<&ImageNTHeaders32, PEParseError> {
fn get_nt_headers32(&self) -> Result<&ImageNTHeaders32, PEParseError> {
let nt_offset = self.get_nt_headers_offset()?;
let result = self.get_ref::<ImageNTHeaders32>(nt_offset)?;
Ok(result)
}
fn get_nt_headers64(&self) -> Result<&ImageNTHeaders64, PEParseError> {
let nt_offset = self.get_nt_headers_offset()?;
let result = self.get_ref::<ImageNTHeaders64>(nt_offset)?;
Ok(result)
}
fn get_nt_headers(&self) -> Result<ImageNTHeaders, PEParseError> {
let is_64_bit = self.is_64_bit()?;
let result = match is_64_bit {
true => ImageNTHeaders::NTHeaders64(*self.get_nt_headers64()?),
false => ImageNTHeaders::NTHeaders32(*self.get_nt_headers32()?),
};
Ok(result)
}
// 获取nt头的偏移
fn get_nt_headers_offset(&self) -> Result<usize, PEParseError> {
@ -76,5 +100,62 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + Sized {
Ok(result)
}
// 获取节区数量
fn get_number_of_sections(&self) -> Result<usize, PEParseError> {
let file_header = self.get_file_header()?;
Ok(file_header.number_of_sections as usize)
}
// 获取可选头大小
fn get_size_of_optional_header(&self) -> Result<usize, PEParseError> {
let file_header = self.get_file_header()?;
Ok(file_header.size_of_optional_header as usize)
}
fn get_optional_header_32(&self) -> Result<&ImageOptionalHeader32, PEParseError> {
let file_header_offset = self.get_file_header_offset()?;
let optional_header_offset = file_header_offset + std::mem::size_of::<ImageFileHeader>();
let result = self.get_ref::<ImageOptionalHeader32>(optional_header_offset)?;
Ok(result)
}
// 获取可选头
fn get_optional_header_64(&self) -> Result<&ImageOptionalHeader64, PEParseError> {
let file_header_offset = self.get_file_header_offset()?;
let optional_header_offset = file_header_offset + std::mem::size_of::<ImageFileHeader>();
let result = self.get_ref::<ImageOptionalHeader64>(optional_header_offset)?;
Ok(result)
}
fn get_optional_header(&self) -> Result<ImageOptionalHeader, PEParseError> {
let is_64_bit = self.is_64_bit()?;
let result = match is_64_bit {
true => ImageOptionalHeader::OptionalHeader64(*self.get_optional_header_64()?),
false => ImageOptionalHeader::OptionalHeader32(*self.get_optional_header_32()?),
};
Ok(result)
}
fn get_optional_header_offset(&self) -> Result<usize, PEParseError> {
let file_header_offset = self.get_file_header_offset()?;
let optional_header_offset = file_header_offset + std::mem::size_of::<ImageFileHeader>();
Ok(optional_header_offset)
}
// 获取所有节区头数据
fn get_image_section_headers(&self) -> Result<&[ImageSectionHeader], PEParseError> {
// 1. 获取节区数量
let number_of_sections = self.get_number_of_sections()?;
// 2. 找到节区头的偏移
// 节区头偏移在可选头之后,可选头大小是可变的,所以需要计算
let optional_header_size = self.get_size_of_optional_header()?;
let file_header_offset = self.get_file_header_offset()?;
let section_header_offset = file_header_offset + std::mem::size_of::<ImageFileHeader>() + optional_header_size;
// 3. 获取节区头数据
unsafe {
let ptr = self.as_ptr().wrapping_offset(section_header_offset as isize) as *const ImageSectionHeader;
let result = std::slice::from_raw_parts(ptr, number_of_sections);
Ok(result)
}
}
}

View File

@ -1,9 +1,9 @@
use memmap2::*;
use serde::Serialize;
use crate::{app_error::AppError, pe_parse::{header::{ImageDosHeader, ImageFileHeader, ImageNTHeaders32}, pe::PE}};
use crate::{app_error::AppError, pe_parse::{header::{ImageDosHeader, ImageFileHeader, ImageNTHeaders, ImageNTHeaders32, ImageOptionalHeader}, pe::PE}};
use super::GLOBAL_FILE_DATA;
use super::{GLOBAL_FILE_DATA, GLOBAL_IS_64_BIT};
// TODO: 打开文件,并将文件映射到内存
pub fn mmap_mut_file(file_path: &str) -> Result<Mmap, std::io::Error> {
@ -25,20 +25,22 @@ pub struct ResponseDOSHeaderData {
#[derive(Serialize)]
pub struct ResponseNTHeaderData {
fields: ImageNTHeaders32,
fields: ImageNTHeaders,
base_offset: usize,
}
pub fn get_nt_headers_data() -> Result<ResponseNTHeaderData, AppError> {
let binding = GLOBAL_FILE_DATA.lock().unwrap();
let file_data = binding.as_ref().unwrap();
let nt_header = file_data.get_nt_headers()?;
let nt_offset = file_data.get_nt_headers_offset()?;
let result = ResponseNTHeaderData {
fields: nt_header.clone(),
base_offset: nt_offset,
};
Ok(result)
pub fn get_nt_headers_data<'a>() -> Result<ResponseNTHeaderData, AppError> {
// pub static GLOBAL_FILE_DATA: Mutex<Option<PeData>> = Mutex::new(None);
let binding = GLOBAL_FILE_DATA.lock().unwrap();
// `binding` does not live long enough borrowed value does not live long enough
let file_data = binding.as_ref().unwrap();
let nt_header_enmu= file_data.get_nt_headers()?;
let nt_offset = file_data.get_nt_headers_offset()?;
let result = ResponseNTHeaderData {
fields: nt_header_enmu,
base_offset: nt_offset,
};
Ok(result)
}
// 获取文件头数据
@ -59,3 +61,22 @@ pub fn get_file_header_data() -> Result<ResponseFileHeaderData, AppError> {
};
Ok(result)
}
// 获取可选头数据
#[derive(Serialize)]
pub struct ResponseOptionalHeaderData {
pub fields: ImageOptionalHeader,
pub base_offset: usize,
}
pub fn get_optional_header_data() -> Result<ResponseOptionalHeaderData, AppError> {
let binding = GLOBAL_FILE_DATA.lock().unwrap();
let file_data = binding.as_ref().unwrap();
let optional_header = file_data.get_optional_header()?;
let optional_header_offset = file_data.get_optional_header_offset()?;
let result = ResponseOptionalHeaderData {
fields: optional_header.clone(),
base_offset: optional_header_offset,
};
Ok(result)
}

View File

@ -9,6 +9,8 @@ pub mod file;
// 全局文件路径
pub static mut GLOBAL_FILE_PATH: Option<String> = None;
// 文件是否是64位
pub static mut GLOBAL_IS_64_BIT: Option<bool> = None;
pub(crate) struct PeData(pub Vec<u8>);
// 实现Deref

View File

@ -0,0 +1,278 @@
import NodeTableComponent, {
DataTemplateInterface,
} from "../NodeTableComponent/NodeTableComponent";
export default function OptionalHeader() {
const dataTemplate: DataTemplateInterface = {
magic: {
name: "magic",
offset: 0,
size: 2,
value: null,
data_type: "hex",
description: "PE文件标志",
},
major_linker_version: {
name: "major_linker_version",
offset: 2,
size: 1,
value: null,
data_type: "hex",
description: "链接器主版本号",
},
minor_linker_version: {
name: "minor_linker_version",
offset: 3,
size: 1,
value: null,
data_type: "hex",
description: "链接器次版本号",
},
size_of_code: {
name: "size_of_code",
offset: 4,
size: 4,
value: null,
data_type: "hex",
description: "代码段大小",
},
size_of_initialized_data: {
name: "size_of_initialized_data",
offset: 8,
size: 4,
value: null,
data_type: "hex",
description: "初始化数据段大小",
},
size_of_uninitialized_data: {
name: "size_of_uninitialized_data",
offset: 12,
size: 4,
value: null,
data_type: "hex",
description: "未初始化数据段大小",
},
address_of_entry_point: {
name: "address_of_entry_point",
offset: 16,
size: 4,
value: null,
data_type: "hex",
description: "入口点地址",
},
base_of_code: {
name: "base_of_code",
offset: 20,
size: 4,
value: null,
data_type: "hex",
description: "代码段基址",
},
image_base: {
name: "image_base",
offset: 24,
size: 8,
value: null,
data_type: "hex",
description: "映像基址",
},
section_alignment: {
name: "section_alignment",
offset: 32,
size: 4,
value: null,
data_type: "hex",
description: "节对齐",
},
file_alignment: {
name: "file_alignment",
offset: 36,
size: 4,
value: null,
data_type: "hex",
description: "文件对齐",
},
major_operating_system_version: {
name: "major_operating_system_version",
offset: 40,
size: 2,
value: null,
data_type: "hex",
description: "操作系统主版本号",
},
minor_operating_system_version: {
name: "minor_operating_system_version",
offset: 42,
size: 2,
value: null,
data_type: "hex",
description: "操作系统次版本号",
},
major_image_version: {
name: "major_image_version",
offset: 44,
size: 2,
value: null,
data_type: "hex",
description: "映像主版本号",
},
minor_image_version: {
name: "minor_image_version",
offset: 46,
size: 2,
value: null,
data_type: "hex",
description: "映像次版本号",
},
major_subsystem_version: {
name: "major_subsystem_version",
offset: 48,
size: 2,
value: null,
data_type: "hex",
description: "子系统主版本号",
},
minor_subsystem_version: {
name: "minor_subsystem_version",
offset: 50,
size: 2,
value: null,
data_type: "hex",
description: "子系统次版本号",
},
win32_version_value: {
name: "win32_version_value",
offset: 52,
size: 4,
value: null,
data_type: "hex",
description: "Win32版本值",
},
size_of_image: {
name: "size_of_image",
offset: 56,
size: 4,
value: null,
data_type: "hex",
description: "映像大小",
},
size_of_headers: {
name: "size_of_headers",
offset: 60,
size: 4,
value: null,
data_type: "hex",
description: "头部大小",
},
checksum: {
name: "checksum",
offset: 64,
size: 4,
value: null,
data_type: "hex",
description: "校验和",
},
subsystem: {
name: "subsystem",
offset: 68,
size: 2,
value: null,
data_type: "hex",
description: "子系统",
},
dll_characteristics: {
name: "dll_characteristics",
offset: 70,
size: 2,
value: null,
data_type: "hex",
description: "DLL特性",
},
size_of_stack_reserve: {
name: "size_of_stack_reserve",
offset: 72,
size: 8,
value: null,
data_type: "hex",
description: "堆栈保留大小",
},
size_of_stack_commit: {
name: "size_of_stack_commit",
offset: 80,
size: 8,
value: null,
data_type: "hex",
description: "堆栈提交大小",
},
size_of_heap_reserve: {
name: "size_of_heap_reserve",
offset: 88,
size: 8,
value: null,
data_type: "hex",
description: "堆保留大小",
},
size_of_heap_commit: {
name: "size_of_heap_commit",
offset: 96,
size: 8,
value: null,
data_type: "hex",
description: "堆提交大小",
},
loader_flags: {
name: "loader_flags",
offset: 104,
size: 4,
value: null,
data_type: "hex",
description: "加载器标志",
},
number_of_rva_and_sizes: {
name: "number_of_rva_and_sizes",
offset: 108,
size: 4,
value: null,
data_type: "hex",
description: "RVA和大小数量",
},
};
const command = "command_get_pe_data_optional_header";
const columns = [
{
title: "字段名",
dataIndex: "name",
key: "name",
},
{
title: "偏移",
dataIndex: "offset",
key: "offset",
hexSwitch: true,
},
{
title: "大小",
dataIndex: "size",
key: "size",
},
{
title: "值",
dataIndex: "value",
key: "value",
hexSwitch: true,
editable: true,
},
{
title: "描述信息",
dataIndex: "description",
key: "description",
},
];
return (
<NodeTableComponent
dataTemplate={dataTemplate}
command={command}
columns={columns as any}
></NodeTableComponent>
);
}

View File

@ -9,6 +9,7 @@ import SiderTree from "../components/side_tree/SideTree";
import DosHeader from "../components/DosHeader/DosHeader";
import NtHeader from "../components/NTHeader/NTHeader";
import FileHeader from "../components/FileHeader/FileHeader";
import OptionalHeader from "../components/OptionalHeader/OptionalHeader";
import NodeTableComponent, {
DataTemplateInterface,
} from "../components/NodeTableComponent/NodeTableComponent";
@ -18,6 +19,7 @@ const SelectNodeMap = {
dos_header: <DosHeader />,
nt_header: <NtHeader />,
file_header: <FileHeader />,
optional_header: <OptionalHeader />,
};
export default function MainPage() {