Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 为部件(NASM)中的PE文件创建和使用节_Assembly_Crash_Nasm_Portable Executable_Sections - Fatal编程技术网

Assembly 为部件(NASM)中的PE文件创建和使用节

Assembly 为部件(NASM)中的PE文件创建和使用节,assembly,crash,nasm,portable-executable,sections,Assembly,Crash,Nasm,Portable Executable,Sections,我正在尝试完成这个仅用汇编生成的PE文件,它应该在控制台中显示一条消息。我希望以这样的方式组织它,以便以后可以轻松添加更多内容(知道在何处添加代码、数据、导入的函数)。 我现在为代码、数据、未初始化数据和导入元素创建了4个部分。我现阶段的主要问题是: 节头中的某些值使可执行文件无效(没有有效的win32) 数据段中指向元素的指针错误 某些涉及首选绝对地址、节对齐和文件对齐的计算可能是错误的 首先,我将在下面显示我的所有代码。为了节省时间和便于阅读,将不添加一些真正无关紧要的内容 这是NASM代码

我正在尝试完成这个仅用汇编生成的PE文件,它应该在控制台中显示一条消息。我希望以这样的方式组织它,以便以后可以轻松添加更多内容(知道在何处添加代码、数据、导入的函数)。
我现在为代码数据未初始化数据和导入元素创建了4个部分。我现阶段的主要问题是:

  • 节头中的某些值使可执行文件无效(没有有效的win32)
  • 数据段中指向元素的指针错误
  • 某些涉及首选绝对地址、节对齐和文件对齐的计算可能是错误的
  • 首先,我将在下面显示我的所有代码。为了节省时间和便于阅读,将不添加一些真正无关紧要的内容 这是NASM代码

    ; Constants (use '$' as prefix)
    $SECTION_ALIGNMENT equ 4096     ; Each section is aligned to 4096 in memory
    $FILE_ALIGNMENT    equ 512      ; Each section is aligned to 512 on disk
    $PREFERRED_ADDRESS equ 4194304  ; Preffered address for EXE is 4 MB
    $TOTAL_PE_SECTIONS equ 4        ; Code, Data, Bss and IData
    ; Image size = headers aligned to section alignment + sections size aligned 
    ; to next multiple of section alignment, everything aligned, too
    $IMAGE_SIZE        equ $SECTION_ALIGNMENT + (HEADERS_SIZE/$SECTION_ALIGNMENT) + \
                           $TOTAL_PE_SECTIONS * $SECTION_ALIGNMENT
    
    
    ; Will help us align some of the values to the next specified multiple
    %define Round(Number, Multiple)  Multiple+(Number/Multiple)
    
    section .header progbits vstart=0
    
        ; This is the MZ header
        DOS_HEADER:
            db             "MZ"         ; MZ signature
    
            ; ...
            ; Here we have all the members of the DOS header, in 4 paragraphs
            ; ...
    
            db             PE_HEADER    ; The last one is pointing to the PE header
    
    
        DOS_STUB:
            ; ...
            ; A small DOS program to display a simple message in DOS (64 bytes)
            ; ...
    
        ; This is the PE header
        PE_HEADER:
            db             "PE", 0, 0   ; PE signature
            dw              0x014C      ; Platform Intel I386
            dw              $TOTAL_PE_SECTIONS
            dd              1371668450  ; Creation timestamp
            dd              0           ; No symbols table
            dd              0           ; No symbols
            dw              SECTIONS_TABLE - OPT_HEADER  ; Optional header size
            dw              0x0002|0x0004|0x0008|0x0100|0x0200 ; Characteristics
    
        ; Optional header
        OPT_HEADER:
            dw              0x010B      ; Signature
            db              0           ; Linker version
            db              0           ; Minor linker version
            dd              CODE_SIZE
            dd              DATA_SIZE   ; Initialized data size
            dd              BSS_SIZE    ; Uninitiated data size
            dd              CODE        ; Entry point
            dd              CODE        ; Code RVA
            dd              DATA        ; Data RVA
            dd              $PREFERRED_ADDRESS ; Preferred address in memory
            dd              $SECTION_ALIGNMENT
            dd              $FILE_ALIGNMENT
            dw              4           ; OS version
            dw              0           ; Minor OS version
            dw              0           ; Image version
            dw              0           ; Minor image version
            dw              3           ; Subsystem version
            dw              10          ; Minor subsystem version
            dd              0           ; WIN32 version
            dd              $IMAGE_SIZE ; Image size calculated above
            dd              Round(HEADERS_SIZE, $SECTION_ALIGNMENT) ; Headers size
            dd              0           ; Checksum
            dw              3           ; System interface CUI
            dw              0           ; DLL characteristics
            dd              4096        ; Reserved stack
            dd              4096        ; Still not        ??
            dd              65536       ; sure about       ??
            dd              0           ; these            ??
            dd              0 
            dd              2           ; Data directory entries
            dd              0           ; Export table pointer
            dd              0           ; Export table size
            dd              I_TABLE     ; Import table pointer
            dd              I_TABLE_S   ; Size of import table
            dq              0           ; Reserved
    
        SECTIONS_TABLE:
            CODE_SECTION_HEADER:
                db          ".code", 0, 0, 0
                dd          Round(CODE_SIZE, $SECTION_ALIGNMENT) ; Size in memory
                dd          CODE
                dd          Round(CODE_SIZE, $FILE_ALIGNMENT) ; Size on disk
                dd          Round(0, $FILE_ALIGNMENT) ; Real start address
                dd          0
                dd          0
                dw          0
                dw          0
                dd          0x00000020|0x20000000|0x40000000|0x80000000
    
           DATA_SECTION_HEADER:
                db          ".data", 0, 0, 0
                dd          Round(DATA_SIZE, $SECTION_ALIGNMENT) ; Size in memory
                dd          $SECTION_ALIGNMENT * 2
                dd          Round(DATA_SIZE, $FILE_ALIGNMENT) ; Size on disk
                dd          Round(0, $FILE_ALIGNMENT) ; Real start address
                dd          0
                dd          0
                dw          0
                dw          0
                dd          0x00000040|0x40000000|0x80000000
    
           BSS_SECTION_HEADER:
                db          ".bss", 0, 0, 0, 0
                dd          Round(BSS_SIZE, $SECTION_ALIGNMENT) ; Size in memory
                dd          $SECTION_ALIGNMENT * 3
                dd          0
                dd          0
                dd          0
                dd          0
                dw          0
                dw          0
                dd          0x00000080|0x40000000|0x80000000
    
    
           IDATA_SECTION_HEADER:
                db          ".idata", 0, 0
                dd          Round(IDATA_SIZE, $SECTION_ALIGNMENT) ; Size in memory
                dd          $SECTION_ALIGNMENT * 4
                dd          0
                dd          Round(0, $FILE_ALIGNMENT) ; Real start address
                dd          0
                dd          0
                dw          0
                dw          0
                dd          0x00000040|0x40000000|0x80000000
    
        HEADERS_SIZE equ $$ - DOS_HEADER
    
        align   512 ; Align to 512 bytes in memory
    
    section .scode vstart=$SECTION_ALIGNMENT align=16
    
        use32
    
        CODE:
            push -11
            call dword [$PREFERRED_ADDRESS + F_GetStdHandle]
            push 0  
            push 0x402000
            push 6  
            push $PREFERRED_ADDRESS + hello
            push eax  
            call dword [$PREFERRED_ADDRESS + F_WriteConsole]  
            push -1  
            call dword [$PREFERRED_ADDRESS + F_Sleep]  
            ret
    
        CODE_SIZE equ $$ - CODE
    
    section .sdata vstart=$SECTION_ALIGNMENT*2 progbits align=4
            DATA:
                hello: db 'Hello!'
            DATA_SIZE equ $$ - DATA
    
    section .sbss vstart=$SECTION_ALIGNMENT*3  align=4
        BSS:
            dd 5
        BSS_SIZE equ $$ - BSS
    
    section .sidata vstart=$SECTION_ALIGNMENT*4 align=4
        IDATA:
            F_Sleep:          dd I_Sleep
            F_WriteConsole:   dd I_WriteConsole
            F_GetStdHandle:   dd I_GetStdHandle
            dd                0
    
            I_TABLE:  
                .originalfthk     dd 0
                .timedate         dd 0  
                .forwarder        dd 0  
                .name             dd kernel32
                .firstthunk       dd IDATA
    
            I_TABLE_S equ $$ - I_TABLE
    
            times 20 db 0
    
            kernel32:             db 'kernel32.dll', 0
            I_Sleep:           
                dw                0  
                db                'Sleep', 0  
                align             2  
            I_WriteConsole:    
                dw                0  
                db                'WriteConsoleA', 0
                align             2  
            I_GetStdHandle:
                dw                0  
                db                'GetStdHandle', 0
    
        IDATA_SIZE equ $$ - IDATA
    
    这里的主要问题是,由于代码部分的指针错误,可执行文件崩溃。我说的是从
    .sdata
    指向hello消息的指针,以及从
    .sidata
    部分指向导入函数的指针。如果我将hello变量和
    .sidata
    的全部内容复制到
    .scode
    (bellow
    ret
    )中,它就会工作,但只要我将每个内容复制到它的适当部分,exe就会中断。
    看来地址算错了。从这里开始,节标题或其他地方可能有错误的值。你觉得怎么样

    更新:
    在实施了下面的更改之后,我现在遇到了一个问题。只要
    .data
    部分小于512字节,一切正常。一旦超过该值,我就会出现“奇怪的无效win32应用程序”错误

    这里有两个由PEInfo导出的HTML文件。第一个包含工作文件的信息(其中
    .data
    部分小于512字节):
    .data
    部分包含超过512字节时,第二个包含损坏的EXE的信息:


    也许有人能发现崩溃的区别和原因。

    我现在有机会详细查看代码,并实际运行它。下面是我发现的所有问题

    首先,你的尺寸计算似乎都不起作用。你可以这样做:

    CODE_SIZE equ $$ - CODE
    
    %define Round(Number, Multiple)  Multiple+(Number/Multiple)
    
    align   512 ; Align to 512 bytes in memory
    
    db  ".code", 0, 0, 0
    dd  Round(CODE_SIZE, $SECTION_ALIGNMENT) ; Size in memory
    dd  RVA(CODE)                            ; Start address in memory
    dd  Round(CODE_SIZE, $FILE_ALIGNMENT)    ; Size on disk
    dd  CODE                                 ; Start address on disk
    
    db  ".bss", 0, 0, 0, 0
    dd  Round(BSS_SIZE, $SECTION_ALIGNMENT) ; Size in memory
    dd  RVA(IMAGE_END)                      ; Start address in memory
    dd  0                                   ; Size on disk
    dd  0                                   ; Start address on disk
    
    但是您尝试在定义它的行之前引用
    code\u SIZE
    ,因此它的计算结果为零

    我的解决方案是添加端点标签,例如,
    code\u end:
    ,无论您通常在哪里执行这些计算。然后在代码的最开始,在使用这些值之前,计算每个块的结束标签和开始标签之间的差异大小

    HEADERS_SIZE  equ HEADERS_END - DOS_HEADER
    CODE_SIZE     equ CODE_END - CODE
    DATA_SIZE     equ DATA_END - DATA
    IDATA_SIZE    equ IDATA_END - IDATA
    I_TABLE_SIZE  equ I_TABLE_END - I_TABLE
    
    下一个大问题是您的
    Round
    宏,它如下所示:

    CODE_SIZE equ $$ - CODE
    
    %define Round(Number, Multiple)  Multiple+(Number/Multiple)
    
    align   512 ; Align to 512 bytes in memory
    
    db  ".code", 0, 0, 0
    dd  Round(CODE_SIZE, $SECTION_ALIGNMENT) ; Size in memory
    dd  RVA(CODE)                            ; Start address in memory
    dd  Round(CODE_SIZE, $FILE_ALIGNMENT)    ; Size on disk
    dd  CODE                                 ; Start address on disk
    
    db  ".bss", 0, 0, 0, 0
    dd  Round(BSS_SIZE, $SECTION_ALIGNMENT) ; Size in memory
    dd  RVA(IMAGE_END)                      ; Start address in memory
    dd  0                                   ; Size on disk
    dd  0                                   ; Start address on disk
    
    我不确定你认为你在那里做什么,但这更像是你需要的:

    %define Round(Number, Multiple) (Number+Multiple-1)/Multiple*Multiple
    
    您需要确保该数字是倍数的倍数,因此是除法-乘法序列。您还需要将
    Multiple-1
    添加到原始数字,以强制其向上取整

    下一个大问题是RVA计算,或者说缺乏RVA计算。文件结构中有很多地方需要将偏移量指定为相对虚拟地址(RVA),这是内存中的相对偏移量。当您只按原样获取标签的值时,这就是磁盘上的偏移量

    对于截面偏移,基本上需要将该偏移除以文件对齐方式,然后再乘以截面对齐方式。此外,代码块将在一个截面对齐偏移处加载,因此所有内容都应相对于代码块进行计算,然后将一个截面对齐添加到结果中

    %define RVA(BaseAddress) (BaseAddress - CODE)/$FILE_ALIGNMENT*$SECTION_ALIGNMENT+$SECTION_ALIGNMENT
    
    现在,这适用于分区边界上的地址。对于其他内容,您需要计算它们相对于节基址的内部偏移量,然后将其添加到该节的RVA中

    %define RVA(Address,BaseAddress) RVA(BaseAddress)+(Address-BaseAddress)
    
    这些计算假设各个部分已经与
    $FILE\u ALIGNMENT
    值对齐,但事实并非如此。代码部分前面有一个
    align
    ,如下所示:

    CODE_SIZE equ $$ - CODE
    
    %define Round(Number, Multiple)  Multiple+(Number/Multiple)
    
    align   512 ; Align to 512 bytes in memory
    
    db  ".code", 0, 0, 0
    dd  Round(CODE_SIZE, $SECTION_ALIGNMENT) ; Size in memory
    dd  RVA(CODE)                            ; Start address in memory
    dd  Round(CODE_SIZE, $FILE_ALIGNMENT)    ; Size on disk
    dd  CODE                                 ; Start address on disk
    
    db  ".bss", 0, 0, 0, 0
    dd  Round(BSS_SIZE, $SECTION_ALIGNMENT) ; Size in memory
    dd  RVA(IMAGE_END)                      ; Start address in memory
    dd  0                                   ; Size on disk
    dd  0                                   ; Start address on disk
    
    但是你需要在每一节之前以及在文件末尾的每一节之前都这样做。我还建议使用
    $FILE\u对齐
    常量,否则就没有意义了

    align   $FILE_ALIGNMENT ; Align to 512 bytes in memory
    
    除此之外,您还需要去掉所有的
    部分
    声明。例如,所有这些行都需要删除

    section .header progbits vstart=0
    section .scode vstart=$SECTION_ALIGNMENT align=16
    section .sdata vstart=$SECTION_ALIGNMENT*2 progbits align=4
    section .sbss vstart=$SECTION_ALIGNMENT*3  align=4
    section .sidata vstart=$SECTION_ALIGNMENT*4 align=4
    
    因为您是手动构建整个文件格式,所以它们没有任何用途,并且它们阻止您使用横截面边界的标签进行偏移计算(这是我们几乎到处都需要的)

    现在我们已经将所有内容正确对齐,并且有了两个RVA宏,我们可以开始修复需要使用RVA的代码的各个部分

    首先在可选的头中,我们有代码RVA、数据RVA和入口点。此外,在这里,我认为各种尺寸值应指定为截面线形的倍数

    dd  Round(CODE_SIZE, $SECTION_ALIGNMENT)
    dd  Round(DATA_SIZE, $SECTION_ALIGNMENT) ; Initialized data size
    dd  Round(BSS_SIZE, $SECTION_ALIGNMENT)  ; Uninitiated data size
    dd  RVA(CODE)                            ; Entry point
    dd  RVA(CODE)                            ; Code RVA
    dd  RVA(DATA)                            ; Data RVA
    
    dd  Round(HEADERS_SIZE, $FILE_ALIGNMENT) ; Headers size
    
    另外,在可选标题中,当我认为应该四舍五入到文件对齐方式时,您可以将标题大小四舍五入到节对齐方式

    dd  Round(CODE_SIZE, $SECTION_ALIGNMENT)
    dd  Round(DATA_SIZE, $SECTION_ALIGNMENT) ; Initialized data size
    dd  Round(BSS_SIZE, $SECTION_ALIGNMENT)  ; Uninitiated data size
    dd  RVA(CODE)                            ; Entry point
    dd  RVA(CODE)                            ; Code RVA
    dd  RVA(DATA)                            ; Data RVA
    
    dd  Round(HEADERS_SIZE, $FILE_ALIGNMENT) ; Headers size
    
    这是事实上没有任何区别的事情之一——代码将以任何方式工作——但我仍然认为这是错误的,应该予以纠正

    类似地,正如我在第一个回答中指出的,即使没有使用所有16个条目,数据目录表的大小也应该始终设置为16。如果你不这样做,它看起来确实有效,但我再次建议你正确地这样做

    dd  16                 ; Data directory entries
    dd  0                  ; Export table pointer
    dd  0                  ; Export table size
    dd  RVA(I_TABLE,IDATA) ; Import table pointer
    dd  I_TABLE_SIZE       ; Size of import table
    times 14 dq 0          ; Space the other 14 entries
    
    另外,请注意,I_表偏移已更新为使用相对于IDATA节的RVA

    下一步在表中,