初始手工分析helloworld.exe的PE文件

这里我们拥有到一个工具:winhex 15.8的版本,十六进制编辑器
我们看一下源代码 ,源代码中在代码段中只调用了两个函数,1:messagebox(),这里传四个参数,2:ExitProcess(),传一个参数
对源代码进行编辑,得到PE文件(helloworld.exe)

这里写自定义目录标题


图1
在这里插入图片描述

用winhex打开helloworld.exe,如图2,3,4,5 是整个文件(其中填充完全是0的没有截图,关键位置的截图了)
不要急,下面我们一步一步拆分图2,3,4,5部分

在这里插入图片描述

																					图2

在这里插入图片描述
图3
在这里插入图片描述
图4
在这里插入图片描述

																	图5

在这里插入图片描述
在这里先做一个总的说明:
查找PE资料,得到如图PE的结构,所有我们先看PE头部(从下面图2开始)
查结构体IMAGE_DOS_HEADER得到PE头的结构
下面我们从dos头开始

dos头

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

在PE的头部中只有两个字段是最重要的,其他的可以不用管,这两个分别是e_magic,e_lfanew,前者指明是DOS文件,后者指明PE的首地址,或者说PE标志

PE头
PE有由三个部分组成,又叫NT头

在这里插入图片描述

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;



004000B0    50 45 00 00      ASCII "PE"           ; PE signature (PE)


其中 DWORD Signature; 就是PE的头地址

IMAGE_FILE_HEADER FileHeader;为文件头结构体

IMAGE_OPTIONAL_HEADER32 OptionalHeader;为扩展头结构体 

文件头结构体

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;   2H 
    WORD    NumberOfSections;  4H 
    DWORD   TimeDateStamp;    8H
    DWORD   PointerToSymbolTable;  12H
    DWORD   NumberOfSymbols;	10H
    WORD    SizeOfOptionalHeader;	12H 
    WORD    Characteristics;		14H  
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
004000B4    4C01        DW 014C              ; Machine = IMAGE_FILE_MACHINE_I386    
004000B6    0300        DW 0003              ;  NumberOfSections = 0x3			
004000B8    FD002465    DD 652400FD          ;  TimeDateStamp = 0x652400FD
004000BC    00000000    DD 00000000          ;  PointerToSymbolTable = 0x0
004000C0    00000000    DD 00000000          ;  NumberOfSymbols = 0x0
004000C4    E000        DW 00E0              ;  SizeOfOptionalHeader = E0 (224.)		
004000C6    0F01        DW 010F              ;  Characteristics = EXECUTABLE_IMAGE|32BIT_MACHINE|RELOCS_STRIPPED|LINE_NUMS_STRIPPED|LOCAL_SYMS_STRIPPED  
 

扩展头结构体
扩展头结构体32位和64位的还不一样这里暂时介绍32位的结构体(64位的多16个字节并且还有点小小的区别)

typedef struct _IMAGE_OPTIONAL_HEADER {
    WORD    Magic;			
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;		
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;  程序执行入口RVA地址 必须
    DWORD   BaseOfCode;   
    DWORD   BaseOfData;	
    DWORD   ImageBase;	内存中基址
    DWORD   SectionAlignment;   
    DWORD   FileAlignment;   	
    WORD    MajorOperatingSystemVersion; 
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion; 可运行的操作系统的主版本号  需要
    WORD    MinorImageVersion;     
    WORD    MajorSubsystemVersion; 
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;  
    DWORD   SizeOfImage;   ;装入内存中的总大小  需要
    DWORD   SizeOfHeaders;   所有头+区块表的尺寸的大小 需要
    DWORD   CheckSum;
    WORD    Subsystem;    需要  
    WORD    DllCharacteristics;  
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;堆
    DWORD   SizeOfHeapCommit;堆
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;   需要 64位必须要16个全要,32位的序号2个也上
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;  60H 

004000C8    0B01             DW 010B              ; MagicNumber = PE32 ROM映像文件:(0107h)
004000CA    05               DB 05                ;  MajorLinkerVersion = 0x5
004000CB    0C               DB 0C                ;  MinorLinkerVersion = C (12.)
004000CC    00020000         DD 00000200          ;  SizeOfCode = 200 (512.)  		
004000D0    00040000         DD 00000400          ;  SizeOfInitializedData = 400 (1024.)	12h
004000D4    00000000         DD 00000000          ;  SizeOfUninitializedData = 0x0 	10h
004000D8    00100000         DD 00001000          ;  AddressOfEntryPoint = 0x1000	14
004000DC    00100000         DD 00001000          ;  BaseOfCode = 0x1000
004000E0    00200000         DD 00002000          ;  BaseOfData = 0x2000
004000E4    00004000         DD 00400000          ; ImageBase = 0x400000
004000E8    00100000         DD 00001000          ;  SectionAlignment = 0x1000
004000EC    00020000         DD 00000200          ;  FileAlignment = 0x200
004000F0    0400             DW 0004              ;  MajorOSVersion = 0x4
004000F2    0000             DW 0000              ;  MinorOSVersion = 0x0
004000F4    0000             DW 0000              ;  MajorImageVersion = 0x0
004000F6    0000             DW 0000              ;  MinorImageVersion = 0x0
004000F8    0400             DW 0004              ;  MajorSubsystemVersion = 0x4
004000FA    0000             DW 0000              ;  MinorSubsystemVersion = 0x0
004000FC    00000000         DD 00000000          ;  Reserved
00400100    00400000         DD 00004000          ;  SizeOfImage = 4000 (16384.)
00400104    00040000         DD 00000400          ;  SizeOfHeaders = 400 (1024.)
00400108    00000000         DD 00000000          ;  CheckSum = 0x0
0040010C    0200             DW 0002              ;  Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
0040010E    0000             DW 0000              ;  DLLCharacteristics = 0x0
00400110    00001000         DD 00100000          ;  SizeOfStackReserve = 100000 (1048576.)
00400114    00100000         DD 00001000          ;  SizeOfStackCommit = 1000 (4096.)
00400118    00001000         DD 00100000          ;  SizeOfHeapReserve = 100000 (1048576.)
0040011C    00100000         DD 00001000          ;  SizeOfHeapCommit = 1000 (4096.)
00400120    00000000         DD 00000000          ;  LoaderFlags = 0x0
00400124    10000000         DD 00000010          ;  NumberOfRvaAndSizes = 10 (16.)(数据目录项,这里32位可可以等于2,但64位不可以)


以上就是PE节表之前的内容,DOS头+PE头的全部内容

下面看节表的内容

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

004001A8    2E 74 65 78 74 0>ASCII ".text"        ; SECTION    (可以改的)
004001B0    24000000         DD 00000024          ;  VirtualSize = 24 (36.);内存中大小(内存对齐前的长度)可以改的
004001B4    00100000         DD 00001000          ;  VirtualAddress = 0x1000;内存中偏移(必须要)
004001B8    00020000         DD 00000200          ;  SizeOfRawData = 200 (512.)文件中大小(文件对齐后的长度)这个不能改为0即可以
004001BC    00040000         DD 00000400          ;  PointerToRawData = 0x400;文件中大小(文件对齐后的长度)必须要
004001C0    00000000         DD 00000000          ;  PointerToRelocations = 0x0
004001C4    00000000         DD 00000000          ;  PointerToLineNumbers = 0x0
004001C8    0000             DW 0000              ;  NumberOfRelocations = 0x0
004001CA    0000             DW 0000              ;  NumberOfLineNumbers = 0x0
004001CC    20000060         DD 60000020          ;  Characteristics = CODE|EXECUTE|READ
004001D0    2E 72 64 61 74 6>ASCII ".rdata"       ; SECTION
004001D8    92000000         DD 00000092          ;  VirtualSize = 92 (146.)
004001DC    00200000         DD 00002000          ;  VirtualAddress = 0x2000
004001E0    00020000         DD 00000200          ;  SizeOfRawData = 200 (512.)
004001E4    00060000         DD 00000600          ;  PointerToRawData = 0x600
004001E8    00000000         DD 00000000          ;  PointerToRelocations = 0x0
004001EC    00000000         DD 00000000          ;  PointerToLineNumbers = 0x0
004001F0    0000             DW 0000              ;  NumberOfRelocations = 0x0
004001F2    0000             DW 0000              ;  NumberOfLineNumbers = 0x0
004001F4    40000040         DD 40000040          ;  Characteristics = INITIALIZED_DATA|READ
004001F8    2E 64 61 74 61 0>ASCII ".data"        ; SECTION
00400200    0B000000         DD 0000000B          ;  VirtualSize = B (11.)
00400204    00300000         DD 00003000          ;  VirtualAddress = 0x3000
00400208    00020000         DD 00000200          ;  SizeOfRawData = 200 (512.)
0040020C    00080000         DD 00000800          ;  PointerToRawData = 0x800
00400210    00000000         DD 00000000          ;  PointerToRelocations = 0x0
00400214    00000000         DD 00000000          ;  PointerToLineNumbers = 0x0
00400218    0000             DW 0000              ;  NumberOfRelocations = 0x0
0040021A    0000             DW 0000              ;  NumberOfLineNumbers = 0x0
0040021C    400000C0         DD C0000040          ;  Characteristics = INITIALIZED_DATA|READ|WRITE


暂时只介绍到这里不过现在只是粗略的介绍了一下还没仔细分析这里面的逻辑

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 好的,我来帮你完成这个任务。 首先进入 /opt/chaincode/ 目录,执行以下命令来初始化项目: ``` go mod init HelloWorld ``` 接着,执行以下命令来安装所需的依赖: ``` go get github.com/hyperledger/[email protected] ``` 然后,执行以下命令来创建 HelloWorld.go 文件: ``` vim HelloWorld.go ``` 在文件中输入以下代码: ```go package main import ( "fmt" "github.com/hyperledger/fabric-contract-api-go/contractapi" ) type HelloWorldContract struct { contractapi.Contract } func (c *HelloWorldContract) InitLedger(ctx contractapi.TransactionContextInterface) error { fmt.Println("Initializing Ledger") err := ctx.GetStub().PutState("Hello", []byte("World")) if err != nil { return fmt.Errorf("Failed to initialize world state: %v", err) } return nil } func (c *HelloWorldContract) ReadLedger(ctx contractapi.TransactionContextInterface) (string, error) { worldBytes, err := ctx.GetStub().GetState("Hello") if err != nil { return "", fmt.Errorf("Failed to read world state: %v", err) } if worldBytes == nil { return "", fmt.Errorf("The value of world is nil") } return string(worldBytes), nil } func (c *HelloWorldContract) WriteLedger(ctx contractapi.TransactionContextInterface, newWorld string) error { fmt.Println("Writing to Ledger") err := ctx.GetStub().PutState("Hello", []byte(newWorld)) if err != nil { return fmt.Errorf("Failed to write world state: %v", err) } return nil } func main() { chaincode, err := contractapi.NewChaincode(&HelloWorldContract{}) if err != nil { fmt.Printf("Error creating HelloWorld chaincode: %v\n", err) return } if err := chaincode.Start(); err != nil { fmt.Printf("Error starting HelloWorld chaincode: %v\n", err) } } ``` 这份代码实现了一个 HelloWorld 合约,提供了三个方法: - InitLedger:初始化账本,将 "Hello" 和 "World" 的键值对写入账本。 - ReadLedger:读取账本,返回 "Hello" 对应的值。 - WriteLedger:修改账本数据,将 "Hello" 对应的值改为传入的参数。 保存并退出 vim。 接着,使用以下命令来构建和打包合约: ``` cd /opt/chaincode/ GO111MODULE=on go mod vendor cd .. peer lifecycle chaincode package HelloWorld.tar.gz --path /opt/chaincode/ --lang golang --label HelloWorld_1.0 ``` 最后,你可以将打包好的合约安装到你的 Fabric 网络中。 ### 回答2: 在 /opt/chaincode/ 目录下执行 go mod init HelloWorld 是为了初始化一个名为 HelloWorld 的新的 Go module,并获取其所需的依赖包。这将创建一个 go.mod 文件,其中包含模块的名称和其所需的所有依赖项。 接下来执行 vim HelloWorld.go 是为了使用 vim 编辑器创建一个名为 HelloWorld.go 的新文件。在这个文件中,我们可以编写代码来实现初始化账本、读取账本和修改账本数据的功能。 示例代码如下: ```go package main import ( "fmt" "github.com/hyperledger/fabric-chaincode-go/shim" "github.com/hyperledger/fabric-protos-go/peer" ) type HelloWorld struct{} func (h *HelloWorld) Init(stub shim.ChaincodeStubInterface) peer.Response { err := stub.PutState("Hello", []byte("World")) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } func (h *HelloWorld) Invoke(stub shim.ChaincodeStubInterface) peer.Response { function, args := stub.GetFunctionAndParameters() if function == "Read" { return h.Read(stub, args) } else if function == "Write" { return h.Write(stub, args) } return shim.Error("Invalid function name.") } func (h *HelloWorld) Read(stub shim.ChaincodeStubInterface, args []string) peer.Response { value, err := stub.GetState(args[0]) if err != nil { return shim.Error(err.Error()) } return shim.Success(value) } func (h *HelloWorld) Write(stub shim.ChaincodeStubInterface, args []string) peer.Response { err := stub.PutState(args[0], []byte(args[1])) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } func main() { if err := shim.Start(new(HelloWorld)); err != nil { fmt.Printf("Error starting chaincode: %s", err) } } ``` 上面的代码创建了一个 HelloWorld 结构体,实现了 Init()、Invoke()、Read() 和 Write() 函数来初始化账本、读取账本以及修改账本数据。在 main() 函数中,使用 shim.Start() 函数启动了这个链码。 通过这样的方式,我们可以在 /opt/chaincode/ 目录下创建一个新的 HelloWorld.go 文件,并使用上面的示例代码来实现我们所需的功能。 ### 回答3: 在/opt/chaincode/目录下,执行go mod init HelloWorld可以获取依赖并初始化一个名为HelloWorld的模块。然后可以执行vim HelloWorld.go命令来新建一个名为HelloWorld.go的文件,并在其中编写相关代码来实现初始化账本、读取账本和修改账本数据的功能。 以下是一个简单的示例代码: ``` package main import ( "fmt" "github.com/hyperledger/fabric-contract-api-go/contractapi" ) // HelloWorldContract 定义了一个智能合约 type HelloWorldContract struct { contractapi.Contract } // InitLedger 初始化账本 func (c *HelloWorldContract) InitLedger(ctx contractapi.TransactionContextInterface) error { // 在这里实现账本的初始化操作,可以添加一些初始数据到账本中 fmt.Println("账本已初始化") return nil } // ReadLedger 读取账本 func (c *HelloWorldContract) ReadLedger(ctx contractapi.TransactionContextInterface) (string, error) { // 在这里实现从账本中读取数据的操作 data := "读取到的账本数据" fmt.Println(data) return data, nil } // ModifyLedger 修改账本数据 func (c *HelloWorldContract) ModifyLedger(ctx contractapi.TransactionContextInterface, newData string) error { // 在这里实现修改账本数据的操作 fmt.Println("账本数据已修改为:", newData) return nil } // 主函数 func main() { chaincode, err := contractapi.NewChaincode(&HelloWorldContract{}) if err != nil { fmt.Printf("Error creating HelloWorld chaincode: %s", err.Error()) return } if err := chaincode.Start(); err != nil { fmt.Printf("Error starting HelloWorld chaincode: %s", err.Error()) } } ``` 以上代码是一个简单的智能合约示例,其中HelloWorldContract定义了一个智能合约,包括了初始化账本、读取账本和修改账本数据的相关函数。在调用合约的InitLedger、ReadLedger和ModifyLedger函数时,可以在其中实现具体的账本操作逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值