News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

GoLink produces non-standard PE files?

Started by Shtuka, March 01, 2011, 08:29:45 PM

Previous topic - Next topic

Shtuka

Hi all,

I was digging into the PE (i.e. Microsoft Portable Executable and Common Object File Format) Specification recently. I used the following program for testing:


DATA SECTION
;
KEEP DD 0
;
CODE SECTION
;
START:
        PUSH -11
        CALL GetStdHandle
        PUSH 0,ADDR KEEP
        PUSH 24, 'Hello World (from GoAsm)'
        PUSH EAX
        CALL WriteFile
        XOR EAX,EAX
        RET


Using


GoAsm.exe test.asm
GoLink.exe /console Kernel32.dll test.obj


I produced a console executable. The program runs fine and all, however the .exe file does not seem to comply to PE File Format Specification. More specifically, the .idata section (starting at 0x600h) seems to be corrupt. For instance, the ImportLookupTable RVA is 0x303425ff, which is absurd. Also the Date/Time stamp field isn't set to zero, as it should be.

jorgon

Hi Shtuka

Looking at the PE file specs it says about the TimeDateStamp as follows:-
QuoteThe low 32 bits of the number of seconds since 00:00 January 1, 1970 (a C run-time time_t value), that indicates when the file was created.

So this value should not be zero, but should contain the time when the exe was made by GoLink.

The idata section cannot be corrupt if the exe works (it has imports).  You say that ImportLookupTableRVA contains a certain value.  However whatever tool you are using may not be looking at the value containing ImportLookupTableRVA.  In the specifications this value is pointed to by the Import Directory Table.  The position of the Import Lookup Table will vary from linker to linker - it is not always in the same place in the PE file.

A really good tool to look at PE files is Wayne Radburn's PEView available from www.magma.ca/~wjr/.  This tool allows for variations which can occur within different types of exe's whilst still complying with the PE specification.

Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

donkey

Hi Shtuka,

I have dismantled a lot of GoAsm executables, including with the DbgHelp DLL functions and have had no issues with it at all. Both the import/export tables and the symbol tables are fine. If you download WinExplorer from my website you will find a routine to dump the PE header as well as imports and exports and it works equally well with GoAsm and other executables. Also, PEBrowsePro from Smidgeon, which I use quite often, and OllyDbg have no issues with GoAsm files.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Shtuka

@jorgon:
I am not sure what exactly you are referring to, but the relevant part of the MS PE & COFF File Format Specification (page 76 in revision 8.2) reads:
QuoteThe stamp that is set to zero until the image is bound. After the image is bound, this field is set to the time/data stamp of the DLL.

As I said, the program executes. I don't see how this proves that the PE file conforms to the specification. Having experimented with some other linkers, it seems to me that the Win32 Process Loader is rather tolerant. For instance, the alink linker puts the import section under "imports" instead of ".idata" as it should be, but the PL does not mind.l

@donkey:
I have used PE Explorer on this particular PE file, and it ran without problems. It seems to simply ignore the "bad part" of the .idata section, even though it escapes me how it does that.

clive

Could you post the EXE.

The PE file has evolved over the years along with the Microsoft Linkers (C700, Win95, WinNT, and beyond), and Borland variants. The structures and sections have also been constructed in various forms, assuming a ridged interpretation of the specs tends to ignore the facts on the ground. For that matter WinXP will refuse to handle files which are arguably valid.
It could be a random act of randomness. Those happen a lot as well.

Shtuka

Okay, here you go. As I already mentioned, the problem (to me) is in the import section starting at 0x600h. The file should have exactly two imports, but it first seems to start with some bogus import named "Y0", which has an invalid Import Lookup RVA.

clive

Quote from: Shtuka on March 05, 2011, 05:34:06 PM
Okay, here you go. As I already mentioned, the problem (to me) is in the import section starting at 0x600h. The file should have exactly two imports, but it first seems to start with some bogus import named "Y0", which has an invalid Import Lookup RVA.

I think you're just confused, the 0x600 is a RAW FILE OFFSET for the data, as the file data is aligned on 0x200 (Sector) boundaries within the file. This is not the ADDRESS where it is LOADED, which is 0x3000. All the other addresses within the file refer to those in memory. More recently Microsoft uses 0x1000 (Page) boundaries, simply because those provide direct mapping when pinned into the page file and memory.

test2.exe                          (hex)           (dec)

.EXE size (bytes)                     6C             108
Minimum load size (bytes)             4C              76
Overlay number                         0               0
Initial CS:IP                  0000:0011
Initial SS:SP                  0000:0000               0
Minimum allocation (para)              0               0
Maximum allocation (para)           FFFF           65535
Header size (para)                     2               2
Relocation table offset               40              64
Relocation entries                     0               0

Portable Executable starts at                 60
Signature                               00004550 (PE)
Machine                                     014C (Intel 386)
Sections                                    0003
Time Date Stamp                         4D6D61A0 Tue Mar 01 15:14:08 2011
Symbol Table                            00000000
Number of Symbols                       00000000
Optional header size                        00E0
Characteristics                             010F
Relocation information stripped
Executable Image
Line numbers stripped
Local symbols stripped
32 bit word machine
Magic                                       010B
Linker Version                              0.38
Size of Code                            00000200
Size of Initialized Data                00000400
Size of Uninitialized Data              00000000
Address of Entry Point                  00001000
Base of Code                            00001000
Base of Data                            00002000
Image Base                              00400000
Section Alignment                       00001000
File Alignment                          00000200
Operating System Version                    4.00
Image Version                               0.00
Subsystem Version                           4.00
reserved                                00000000
Image Size                              00004000
Header Size                             00000200
Checksum                                00008D32
Subsystem                                   0003 (Console)
DLL Characteristics                         0000
Size Of Stack Reserve                   00100000
Size Of Stack Commit                    00010000
Size Of Heap Reserve                    00100000
Size Of Heap Commit                     00001000
Loader Flags                            00000000
Number of Directories                   00000010

Directory Name                          VirtAddr  VirtSize
--------------------------------------  --------  --------
Export                                  00000000  00000000
Import                                  0000300C  00000028
Resource                                00000000  00000000
Exception                               00000000  00000000
Security                                00000000  00000000
Base Relocation                         00000000  00000000
Debug                                   00000000  00000000
Decription/Architecture                 00000000  00000000
Machine Value (MIPS GP)                 00000000  00000000
Thread Storage                          00000000  00000000
Load Configuration                      00000000  00000000
Bound Import                            00000000  00000000
Import Address Table                    00003034  0000000C
Delay Import                            00000000  00000000
COM Runtime Descriptor                  00000000  00000000
(reserved)                              00000000  00000000

Section Table
-------------
01  code    Virtual Address         00001000
Virtual Size            00000020
Raw Data Offset         00000200
Raw Data Size           00000200
Relocation Offset       00000000
Relocation Count        0000
Line Number Offset      00000000
Line Number Count       0000
Characteristics         60000020
Code
Executable
Readable

02  data    Virtual Address         00002000
Virtual Size            00000020
Raw Data Offset         00000400
Raw Data Size           00000200
Relocation Offset       00000000
Relocation Count        0000
Line Number Offset      00000000
Line Number Count       0000
Characteristics         C0000040
Initialized Data
Readable
Writeable

03  .idata  Virtual Address         00003000
Virtual Size            00000074
Raw Data Offset         00000600
Raw Data Size           00000200
Relocation Offset       00000000
Relocation Count        0000
Line Number Offset      00000000
Line Number Count       0000
Characteristics         60000020
Code
Executable
Readable


Imp Addr Hint Import Name from KERNEL32.dll - Not Bound
-------- ---- ---------------------------------------------------------------
00003034  1B0 GetStdHandle
00003038  390 WriteFile

IAT Entry

00000000: 00003059 00003068 - 00000000

Disassembly


00401000                    start:
00401000 6AF5                   push    0FFFFFFF5h
00401002 E8F91F0000             call    jmp_GetStdHandle
00401007 6A00                   push    0
00401009 6800204000             push    offset off_00402000
0040100E 6A18                   push    18h
00401010 6804204000             push    offset off_00402004 ; 'Hello World (from GoAsm)',000h
00401015 50                     push    eax
00401016 E8EB1F0000             call    jmp_WriteFile
0040101B 31C0                   xor     eax,eax
0040101D C3                     ret

0040101E 0000                   db      2 dup (000h)

00402000                    off_00402000:               ; Xref 00401009
00402000 00 00 00 00                                        ....
00402004                    off_00402004:               ; Xref 00401010
00402004 48656C6C6F20576F726C.. db      'Hello World (from GoAsm)',000h
0040201D 00 00 00                                           ...

00403000                    jmp_GetStdHandle:           ; Xref 00401002
00403000 FF2534304000           jmp     dword ptr [GetStdHandle]

00403006                    jmp_WriteFile:              ; Xref 00401016
00403006 FF2538304000           jmp     dword ptr [WriteFile]

0040300C                    KERNEL32_Characteristics:
0040300C 40304000               dd      offset GetStdHandle_ByName
00403010                    KERNEL32_TimeDateStamp:
00403010 00000000               dd      00000000h
00403014                    KERNEL32_ForwarderChain:
00403014 00000000               dd      00000000h
00403018                    KERNEL32_Name:
00403018 4C304000               dd      offset KERNEL32 ; 'KERNEL32.dll',000h
0040301C                    KERNEL32_FirstThunk:
0040301C 34304000               dd      offset GetStdHandle
00403020                    NULL_Characteristics:
00403020 00000000               dd      00000000h
00403024                    NULL_TimeDateStamp:
00403024 00000000               dd      00000000h
00403028                    NULL_ForwarderChain:
00403028 00000000               dd      00000000h
0040302C                    NULL_Name:
0040302C 00000000               dd      00000000h
00403030                    NULL_FirstThunk:
00403030 00000000               dd      00000000h
00403034                    GetStdHandle:               ; Xref 00403000 0040301C
00403034 59304000               dd      offset GetStdHandle_Hint
00403038                    WriteFile:                  ; Xref 00403006
00403038 68304000               dd      offset WriteFile_Hint
0040303C                    NULL_Thunk_KERNEL32:
0040303C 00000000               dd      00000000h
00403040                    GetStdHandle_ByName:        ; Xref 0040300C
00403040 59304000               dd      offset GetStdHandle_Hint
00403044                    WriteFile_ByName:
00403044 68304000               dd      offset WriteFile_Hint
00403048                    NULL_Characteristics_KERNEL32:
00403048 00000000               dd      00000000h
0040304C                    KERNEL32:                   ; Xref 00403018
0040304C 4B45524E454C33322E64.. db      'KERNEL32.dll',000h
00403059                    GetStdHandle_Hint:          ; Xref 00403034 00403040
00403059 B001                   dw      001B0h
0040305B                    GetStdHandle_Name:
0040305B 47657453746448616E64.. db      'GetStdHandle',000h
00403068                    WriteFile_Hint:             ; Xref 00403038 00403044
00403068 9003                   dw      00390h
0040306A                    WriteFile_Name:
0040306A 577269746546696C6500   db      'WriteFile',000h

End of Disassembly
It could be a random act of randomness. Those happen a lot as well.

Shtuka

Quote from: clive on March 05, 2011, 09:52:27 PM
I think you're just confused, the 0x600 is a RAW FILE OFFSET for the data, as the file data is aligned on 0x200 (Sector) boundaries within the file. This is not the ADDRESS where it is LOADED, which is 0x3000.

I didn't suppose that the raw file offset would be equal to the relative virtual address where the section is loaded into memory. I think I should clarify what exactly is the problem. The problem is that the first entry in the Import Directory Table has 0x303425ff in the ImportLookupTable RVA field. But this points nowhere, since the file has only three sections as follows:

SectionName: code VirtualAddress: 0x1000 VirtualSize: 0x20
SectionName: data VirtualAddress: 0x2000 VirtualSize: 0x20
SectionName: .idata VirtualAddress: 0x3000 VirtualSize: 0x74

So 0x303425ff does not point into any of these sections when loaded into memory.

clive

Quote from: Shtuka on March 07, 2011, 07:41:44 PM
I didn't suppose that the raw file offset would be equal to the relative virtual address where the section is loaded into memory. I think I should clarify what exactly is the problem. The problem is that the first entry in the Import Directory Table has 0x303425ff in the ImportLookupTable RVA field. But this points nowhere, since the file has only three sections as follows:

SectionName: code VirtualAddress: 0x1000 VirtualSize: 0x20
SectionName: data VirtualAddress: 0x2000 VirtualSize: 0x20
SectionName: .idata VirtualAddress: 0x3000 VirtualSize: 0x74

So 0x303425ff does not point into any of these sections when loaded into memory.

None of the tables point to 0x3000 (0xFF 0x25, 0x34, 0x30, 0x40, 0x00 - jmp [0x00403034]) , the import table starts at 0x0040300C (0x300C - Import Directory), and is preceded by two indirect jumps that reference imported address fields fixed up by the loader. They reference inside the import address table (0x3034 - IAT).
It could be a random act of randomness. Those happen a lot as well.

Shtuka

Ah, I see. I think I figured it out now: The loader finds the relevant data (e.g. import table) through the optional header data directories, and hence they (the tables) can be located anywhere, in particular in a section different from ".idata". The PE Spec however is rather fuzzy at this point, it suggests the ".idata" section would have a fixed structure and/or would contain the import table.

Thanks for you help!