flat assembler
Message board for the users of flat assembler.

Index > Compiler Internals > Bug with stub in fasm 1.7.3+

Author
Thread Post new topic Reply to topic
^_^



Joined: 29 Apr 2013
Posts: 4
^_^ 29 Apr 2013, 13:02
Thats it. Fasm 1.67 assembles this to 1024 bytes, while with fasm 1.7.3/1.7.10 I get 1536.


Description:
Download
Filename: next_crysis.zip
Filesize: 14.99 KB
Downloaded: 785 Time(s)

Post 29 Apr 2013, 13:02
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20343
Location: In your JS exploiting you and your system
revolution 29 Apr 2013, 13:25
If you change the 3rd byte in your stub.bin to 0x04 then you get a 1k executable.

I'm not sure if this is a bug or is something Tomasz has deliberately changed. But it appears as though the 16-bit code is lost when the stub is written.
Post 29 Apr 2013, 13:25
View user's profile Send private message Visit poster's website Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 29 Apr 2013, 17:35
revolution,

With EXE_file.exe_len_mod_512 == 4 code in stub becomes overlay (maybe you meant 40h instead?), then fasm uses only 0x1C bytes of header, adjusting it for correct header-only MZ stub.

----8<----
^_^,

If that field contains 0, it means that stub is 512 bytes long (1.66 ignores that case and recognize stub as invalid MZ; 1.67.37, earliest build of 1.67 I have, does recognize this and handles it correctly), hence PE will be 1536 bytes total.

Another option is to put 0x24 there (header 32 bytes + code 4 bytes), in that case PE will start at 0x48 (header is extended to 64 bytes, code is copied afterwards, PE signature is 8-aligned). fasm 1.66 and 1.67.37+ behave identically. In fact, relevant change is four-line insert in FORMATS.INC after stub_from_file: next to movzx edx, word [esi+2].

What is your exact 1.67 build? Can you upload it somewhere?
Post 29 Apr 2013, 17:35
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4043
Location: vpcmpistri
bitRAKE 29 Apr 2013, 18:56
Code:
format pe gui on "nul"    
Because DOS people know already. Twisted Evil

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 29 Apr 2013, 18:56
View user's profile Send private message Visit poster's website Reply with quote
^_^



Joined: 29 Apr 2013
Posts: 4
^_^ 30 Apr 2013, 02:37
baldr
That's weird because Microsoft's Link.exe thinks it's valid, but it extends stub to 120 bytes (looks like it extends every stub to 120 b), but I always linked with /align:4 so I missed that.
Quote:
What is your exact 1.67 build?

It's 1.67.21. And it lacks that 4 lines in format.inc. If you still want it http://rghost.ru/45652866 (only exe+source).

I will compile to MS COFF anyway. 120 bytes stub kinda suck but it suck less than inability to specify section align, and I have more fun things to do than assemble PE manually.
Post 30 Apr 2013, 02:37
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 30 Apr 2013, 21:58
^_^,

I think MS linker doesn't bother to analyze stub as long as it starts with 'MZ' (it accepts even 'MZ'*32). If you eliminate DanS/Rich block, stub will remain 64 bytes long, only IMAGE_DOS_HEADER.e_lfanew gets patched with PE offset.

You don't have to assemble PE manually, fasm can be used even to replace stub with anything you want:
Code:
;;; Source file names
filename equ "4k.exe"
stubname equ "stub.bin"

include "Macro\Struct.Inc"

;;; Some utility macros
struc reequ [value] {
common
  restore .
  . equ value
}

;;; Define BYTE/WORD/etc. macros to use struct definitions from SDK almost as-is
irp pair, BYTE db, WORD dw, DWORD dd, ULONGLONG dq {
  match c_type fasm_directive, pair \{
    macro c_type [name*] \\{
      _name equ name
      _value equ ?
      match .name[.count], name \\\{; handle array syntax
        _name reequ .name
        _value reequ .count dup ?
      \\\}
      match .name .value, _name _value \\\{ .name fasm_directive .value \\\}
      restore _name, _value
    \\}
  \}
}

struct IMAGE_FILE_HEADER
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
ends

struct IMAGE_OPTIONAL_HEADER
    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    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;
;    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
ends

struct IMAGE_OPTIONAL_HEADER64
    WORD        Magic;
    BYTE        MajorLinkerVersion;
    BYTE        MinorLinkerVersion;
    DWORD       SizeOfCode;
    DWORD       SizeOfInitializedData;
    DWORD       SizeOfUninitializedData;
    DWORD       AddressOfEntryPoint;
    DWORD       BaseOfCode;
    ULONGLONG   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;
    ULONGLONG   SizeOfStackReserve;
    ULONGLONG   SizeOfStackCommit;
    ULONGLONG   SizeOfHeapReserve;
    ULONGLONG   SizeOfHeapCommit;
    DWORD       LoaderFlags;
    DWORD       NumberOfRvaAndSizes;
;    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
ends

struct IMAGE_DATA_DIRECTORY
    DWORD   VirtualAddress;
    DWORD   Size;
ends

define IMAGE_SIZEOF_SHORT_NAME 8

struct IMAGE_SECTION_HEADER
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    ends
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
ends

macro getdata name*, [spec*] {; getdata MZ.e_magic word, "pe_file.exe":0,2
common; 'spec' may contain comma
  virtual
    file spec
    load name from $$
  end virtual
}

irp pair, byte 1, word 2, dword 4, qword 8 {
  match !type !size, pair \{
    macro get\#!type name*, offset* \\{ getdata name !type, filename:offset, !size \\}
    macro assert\#!type name*, offset*, value* \\{
      get\#!type name, offset
      assert name=value
    \\}
  \}
}

macro copydata [spec*] { common file filename:spec }
struc copydata [spec*] { common .: copydata spec }
struc copystruct struct_name*, offset* {; accepts 'struct[count]' as 'struct_name'
common
  _name equ struct_name
  _count equ 1
  match !name[!count], struct_name \{
    _name reequ !name
    _count reequ !count
  \}
  match !name !count, _name _count \{
    virtual
      . !name
      sizeof.#. = $-.; actually it's 'count' times bigger
    end virtual
    copydata offset, sizeof.\#!name*!count
  \}
  restore _name, _count
}

macro load [arg*] {; accepts 'array[index].field' as an address
  _arg equ arg
  match !name !type =from !array[!index]!field, arg \{
    _arg reequ !name !type from !array\#!field+(!index)*sizeof.\#!array
  \}
  load _arg
  restore _arg
}

macro store arg* {; accepts 'array[index].field' as an address
  _arg equ arg
  match !name !type =at !array[!index]!field, arg \{
    _arg reequ !name !type at !array\#!field+(!index)*sizeof.\#!array
  \}
  store _arg
  restore _arg
}

macro align value { rb (value-1)-($+value-1) mod value }

;;; Ready, set, GO!
format binary as "Exe"

assertword MZ.signature, 0, 'MZ'
getdword PE, 0x3C
assertdword PE.signature, PE, 'PE'
PE.FileHeader = PE+4
PE.OptionalHeader = PE.FileHeader+sizeof.IMAGE_FILE_HEADER

file stubname
store dword newPE at 0x3C

;;; Copy signature and file header
newPE copydata PE, 4
newPE.FileHeader copystruct IMAGE_FILE_HEADER, PE.FileHeader

;;; Copy optional header (w/o data directory)
getword PE.Magic, PE.OptionalHeader
if PE.Magic=0x010B
  newPE.OptionalHeader copystruct IMAGE_OPTIONAL_HEADER, PE.OptionalHeader
else if PE.Magic=0x020B
  newPE.OptionalHeader copystruct IMAGE_OPTIONAL_HEADER64, PE.OptionalHeader
else
  err "Only PE32 and PE32+ are supported"
end if

;;; Copy data directory
PE.OptionalHeader.DataDirectory = PE.OptionalHeader+$-newPE.OptionalHeader
load newPE.NumberOfRvaAndSizes dword from newPE.OptionalHeader.NumberOfRvaAndSizes
newPE.OptionalHeader.DataDirectory copystruct IMAGE_DATA_DIRECTORY[newPE.NumberOfRvaAndSizes], PE.OptionalHeader.DataDirectory
sizeof.newPE.OptionalHeader = $-newPE.OptionalHeader

;;; Copy section headers
load newPE.NumberOfSections word from newPE.FileHeader.NumberOfSections
PE.SectionHeaders = PE.OptionalHeader+sizeof.newPE.OptionalHeader
newPE.SectionHeaders copystruct IMAGE_SECTION_HEADER[newPE.NumberOfSections], PE.SectionHeaders

;;; Copy sections
load newPE.FileAlignment dword from newPE.OptionalHeader.FileAlignment
repeat newPE.NumberOfSections
  align newPE.FileAlignment
  load SizeOfRawData dword from newPE.SectionHeaders[%-1].SizeOfRawData
  load PointerToRawData dword from newPE.SectionHeaders[%-1].PointerToRawData
  store dword $ at newPE.SectionHeaders[%-1].PointerToRawData; patch section header
  copydata PointerToRawData, SizeOfRawData
end repeat

;;; Patch OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress, if present
;;; Signature'll become invalid anyway
IMAGE_DIRECTORY_ENTRY_SECURITY = 4
if newPE.NumberOfRvaAndSizes>IMAGE_DIRECTORY_ENTRY_SECURITY
  load PE.Certificate.VirtualAddress dword\
       from newPE.OptionalHeader.DataDirectory.VirtualAddress+sizeof.IMAGE_DATA_DIRECTORY*IMAGE_DIRECTORY_ENTRY_SECURITY
  if PE.Certificate.VirtualAddress
    store dword PE.Certificate.VirtualAddress+$-(PointerToRawData+SizeOfRawData)\
          at newPE.OptionalHeader.DataDirectory.VirtualAddress+sizeof.IMAGE_DATA_DIRECTORY*IMAGE_DIRECTORY_ENTRY_SECURITY
  end if
end if

;;; Copy trailer
copydata PointerToRawData+SizeOfRawData    
Have fun! Wink
Post 30 Apr 2013, 21:58
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.