Skip to content
This repository has been archived by the owner on Mar 19, 2021. It is now read-only.

ILMERGE x64 exe output is possible? #84

Open
elraz opened this issue May 6, 2020 · 10 comments
Open

ILMERGE x64 exe output is possible? #84

elraz opened this issue May 6, 2020 · 10 comments

Comments

@elraz
Copy link

elraz commented May 6, 2020

I'm trying to merge 3 dlls to 1 dll, I compiled the dlls in x64, and when I use dumpbin to see their header, the header is 0x180000000 as expected, but in the output dll the base header is 0x400000 image base as in x32 exe file.

I did the same thing with an exe file, I try to merge the same 3 dlls to the exe file, before the merge the exe file base header is 0x140000000, as expected, but after the merge, the base image address is 0x400000 and not 0x140000000. Thank you very much.
command :
ILMerge.exe /log /out:%APP_NAME%.%APP_TYPE% orig_%APP_NAME%.%APP_TYPE% /internalize %DLLS% /targetplatform:v4 /wildcards /allowDup /closed /keyfile:"%KEY_FILE_PATH%"

this is the log from the ILmerge: we have exeFile, dll1 ,dll2 ,and dll3.

Starting "Merging dll1.dll dll2.dll dll3.dll to exeFile"

Starting "Merging dll1.dll dll2.dll dll3.dll to exeFile"
3> .
3> ILMerge version 2.12.803.0
3> Copyright (C) Microsoft Corporation 2004-2006. All rights reserved.
3> ILMerge /log /out:exeFile.exe orig_exeFile.exe /internalize dll1.dll dll2.dll dll3.dll /targetplatform:v4 /wildcards /allowDup /closed /keyfile:C:\TBT\Driver\source\folder\BuildTools\keyPair.snk
3> Set platform to 'v4', using directory 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319' for mscorlib.dll
3> Running on Microsoft (R) .NET Framework v2.0.50727
3> mscorlib.dll version = 2.0.0.0
3> The list of input assemblies is:
3> orig_exeFile.exe
3> dll1.dll
3> dll2.dll
3> dll3.dll
3> The number of files matching the pattern orig_exeFile.exe is 1.
3> C:\TBT\Driver\source\folder\exeFile\bin\x64\Debug\TEMP_MERGE_DIRECTORY\orig_exeFile.exe
3> Trying to read assembly from the file 'C:\TBT\Driver\source\folder\exeFile\bin\x64\Debug\TEMP_MERGE_DIRECTORY\orig_exeFile.exe'.
3> Can not find PDB file. Debug info will not be available for assembly 'orig_exeFile.exe'.
3> Successfully read in assembly.
3> There were no errors reported in exeFile's metadata.
3> The number of files matching the pattern dll1.dll is 1.
3> C:\TBT\Driver\source\folder\exeFile\bin\x64\Debug\TEMP_MERGE_DIRECTORY\dll1.dll
3> Trying to read assembly from the file 'C:\TBT\Driver\source\folder\exeFile\bin\x64\Debug\TEMP_MERGE_DIRECTORY\dll1.dll'.
3> Can not find PDB file. Debug info will not be available for assembly 'dll1.dll'.
3> Successfully read in assembly.
3> There were no errors reported in dll1's metadata.
3> The number of files matching the pattern dll2.dll is 1.
3> C:\TBT\Driver\source\folder\exeFile\bin\x64\Debug\TEMP_MERGE_DIRECTORY\dll2.dll
3> Trying to read assembly from the file 'C:\TBT\Driver\source\folder\exeFile\bin\x64\Debug\TEMP_MERGE_DIRECTORY\dll2.dll'.
3> Can not find PDB file. Debug info will not be available for assembly 'dll2.dll'.
3> Successfully read in assembly.
3> There were no errors reported in dll2's metadata.
3> The number of files matching the pattern dll3.dll is 1.
3> C:\TBT\Driver\source\folder\exeFile\bin\x64\Debug\TEMP_MERGE_DIRECTORY\dll3.dll
3> Trying to read assembly from the file 'C:\TBT\Driver\source\folder\exeFile\bin\x64\Debug\TEMP_MERGE_DIRECTORY\dll3.dll'.
3> Can not find PDB file. Debug info will not be available for assembly 'dll3.dll'.
3> Successfully read in assembly.
3> There were no errors reported in dll3's metadata.
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.Runtime'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.Runtime'.
3> Resolved assembly reference 'System.Runtime' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.Runtime.dll'. (Used framework directory.)
3> AssemblyResolver: Assembly 'System.Runtime' is referencing assembly 'System.ComponentModel.Composition'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.ComponentModel.Composition'.
3> Resolved assembly reference 'System.ComponentModel.Composition' to 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.ComponentModel.Composition.dll'. (Used referencing Module's directory.)
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.Collections'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.Collections'.
3> Resolved assembly reference 'System.Collections' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.Collections.dll'. (Used framework directory.)
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.IO'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.IO'.
3> Resolved assembly reference 'System.IO' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.IO.dll'. (Used framework directory.)
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.Diagnostics.Debug'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.Diagnostics.Debug'.
3> Resolved assembly reference 'System.Diagnostics.Debug' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.Diagnostics.Debug.dll'. (Used framework directory.)
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.Threading'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.Threading'.
3> Resolved assembly reference 'System.Threading' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.Threading.dll'. (Used framework directory.)
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.Runtime.InteropServices'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.Runtime.InteropServices'.
3> Resolved assembly reference 'System.Runtime.InteropServices' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.Runtime.InteropServices.dll'. (Used framework directory.)
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.Runtime.Extensions'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.Runtime.Extensions'.
3> Resolved assembly reference 'System.Runtime.Extensions' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.Runtime.Extensions.dll'. (Used framework directory.)
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.Text.Encoding'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.Text.Encoding'.
3> Resolved assembly reference 'System.Text.Encoding' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.Text.Encoding.dll'. (Used framework directory.)
3> AssemblyResolver: Assembly 'dll2' is referencing assembly 'System.Linq'.
3> AssemblyResolver: Attempting referencing assembly's directory.
3> AssemblyResolver: Did not find assembly in referencing assembly's directory.
3> AssemblyResolver: Attempting input directory.
3> AssemblyResolver: Did not find assembly in input directory.
3> AssemblyResolver: Attempting user-supplied directories.
3> AssemblyResolver: No user-supplied directories.
3> AssemblyResolver: Attempting framework directory.
3> Can not find PDB file. Debug info will not be available for assembly 'System.Linq'.
3> Resolved assembly reference 'System.Linq' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727..\v4.0.30319\System.Linq.dll'. (Used framework directory.)
3> In order to close the target assembly, the number of assemblies to be added to the input is 0.
3> Checking to see that all of the input assemblies have a compatible PeKind.
3> exeFile.PeKind = ILonly, Requires64bits, AMD
3> dll1.PeKind = ILonly, Requires64bits, AMD
3> dll2.PeKind = ILonly, Requires64bits, AMD
3> dll3.PeKind = ILonly, Requires64bits, AMD
3> All input assemblies have a compatible PeKind value.
3> Using assembly 'exeFile' for assembly-level attributes for the target assembly.
3> Merging assembly 'exeFile' into target assembly.
3> Merging assembly 'dll1' into target assembly.
3> Merging assembly 'dll2' into target assembly.
3> Merging assembly 'dll3' into target assembly.
3> Copying 2 Win32 Resources from assembly 'exeFile' into target assembly.
3> Transferring entry point 'exeFile.Program.Main' from assembly 'exeFile' to assembly 'exeFile'.
3> ILMerge: Signing assembly with the key file 'C:\TBT\Driver\source\folder\BuildTools\keyPair.snk'.
3> There were no errors reported in the target assembly's metadata.
3> ILMerge: Writing target assembly 'exeFile.exe'.
3> ILMerge: Signed assembly 'exeFile.exe' with a strong name.
3> Location for referenced module 'advapi32.dll' is ''
3> Location for referenced module 'kernel32.dll' is ''
3> Location for referenced module 'WTSAPI32.DLL' is ''
3> Location for referenced module 'setupapi.dll' is ''
3> Location for referenced module 'CfgMgr32.dll' is ''
3> Location for referenced assembly 'mscorlib' is 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll'
3> There were no errors reported in mscorlib's metadata.
3> Location for referenced assembly 'System.ServiceProcess' is 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.ServiceProcess.dll'
3> There were no errors reported in System.ServiceProcess's metadata.
3> Location for referenced assembly 'System' is 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\system.dll'
3> There were no errors reported in System's metadata.
3> Location for referenced assembly 'System.Core' is 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Core.dll'
3> There were no errors reported in System.Core's metadata.
3> Location for referenced assembly 'System.Configuration.Install' is 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Configuration.Install.dll'
3> There were no errors reported in System.Configuration.Install's metadata.
3> ILMerge: Done.

@mike-barnett
Copy link
Contributor

I'm not sure I understand your problem. ILMerge is for completely managed IL assemblies. So those (afaik) should be independent of being 32-bit or 64-bit. Does the merged assembly run correctly? You can also use ILMerge on just a single input assembly to investigate these kinds of issues. If you can provide me with a single assembly (or its source) that shows the problem, then I can look into it.

@elraz
Copy link
Author

elraz commented May 6, 2020 via email

@mike-barnett
Copy link
Contributor

Sorry, that really doesn't help. I meant that it would be helpful if you could create a toy (and very tiny) single assembly that showed the same problem. I'm still unclear on how it is 64-bit. ILMerge should work on totally managed code in which case it doesn't matter what bit-width it was compiled for.

@elraz
Copy link
Author

elraz commented May 6, 2020 via email

@hrumhurum
Copy link

hrumhurum commented May 7, 2020

Probably the topic starter talks about PE32+ executable file format which is a 64-bit version of 32-bit PE.

While .NET assemblies are usually architecture agnostic, they may be both produced in PE or PE32+ formats depending on C# compiler settings.

For example, when user selects x64 platform in a C# project settings via Project -> Context Menu -> Properties ->Build -> Platform target in Visual Studio, the output assembly gets produced in PE32+ executable file format. Interestingly enough, both Any CPU and x86 platform targets use the usual (32-bit) PE format. It is only the x64 target that does PE32+ (64 bits): https://stackoverflow.com/a/32981918/2102379

P.S. It's only my guess, but it seems that original poster implies that ILMerge breaks x64 managed assemblies by creating the output in PE format instead of PE32+.

@mike-barnett
Copy link
Contributor

What I need is a repro where I can see why ILMerge is not preserving the corflags properly. What I see is that if I compile the following code class C {} with "csc /t:library /platform:x64", I get a PE32+ assembly with CorFlags 0x1 (ILONLY: 1, 32BITREQ: 0, 32BITPREF: 0). When I run that assembly through ILMerge, the value of the CorFlags does not change.

@elraz
Copy link
Author

elraz commented May 11, 2020

l

can you do the same flow, but now, take a dump using the dumpbin?
https://docs.microsoft.com/en-us/cpp/build/reference/dumpbin-reference?view=vs-2019
using the developer command prompt
dumpbin test.dll /HEADERS /OUT:test.txt
do this before the merge, and after the merge and see what is the base image offset?

@elraz
Copy link
Author

elraz commented May 11, 2020

I did addition test with the CorFlags

dll 1
Version : v4.0.30319
CLR Header: 2.5
PE : PE32+
CorFlags : 0x9
ILONLY : 1
32BITREQ : 0
32BITPREF : 0
Signed : 1

dll2
Version : v4.0.30319
CLR Header: 2.5
PE : PE32+
CorFlags : 0x9
ILONLY : 1
32BITREQ : 0
32BITPREF : 0
Signed : 1

dll3
Version : v4.0.30319
CLR Header: 2.5
PE : PE32+
CorFlags : 0x9
ILONLY : 1
32BITREQ : 0
32BITPREF : 0
Signed : 1

exefile
Before Merge:
140000000 image base

Version : v4.0.30319
CLR Header: 2.5
PE : PE32+
CorFlags : 0x1
ILONLY : 1
32BITREQ : 0
32BITPREF : 0
Signed : 1

the imerge command :call "%ILMERGE_DIR%\ILMerge.exe" /out:%APP_NAME%.%APP_TYPE% orig_%APP_NAME%.%APP_TYPE% /internalize %DLLS% /targetplatform:v4 /wildcards /allowDup /closed /keyfile:"%KEY_FILE_PATH%"
After Merge:

400000 image base
Version : v4.0.30319
CLR Header: 2.5
PE : PE32+
CorFlags : 0x9
ILONLY : 1
32BITREQ : 0
32BITPREF : 0
Signed : 1

you can notice that in the ext file the PE didn't change, but the CorFlags changed from 0x1 to 0x9

@mike-barnett
Copy link
Contributor

mike-barnett commented May 11, 2020

It looks to me as if the dlls are strongly named (hence their CorFlags is 0x9) while your exe is delay-signed. And the output is fully signed, so it is also 0x9. See Kirill's answer in this SO post for details on the interpretation of the CorFlags.

Also, I did do "dumpbin" to see the difference in the headers. I agree that they are different (in many places, not just in the base image offset), but I am not sure that it makes any functional difference. If you see a problem where the output of ILMerge does not behave properly compared to the behavior of the unmerged assemblies, then please let me know.

@SerjKh
Copy link

SerjKh commented Jun 24, 2020

@mike-barnett, @hrumhurum
Hi Mike,

Thank you for taking the time to look into this issue!

I work with Elraz and also interested in resolving this. It is a demand from our security team, that our assemblies will have base address above the 0x140000000 boundary. Their justification is a follows:

Having a preferred base address below this boundary triggers a compatibility mode in Address Space Layout Randomization (ASLR) on recent versions of Windows that reduces the number of possible locations to which ASLR may relocate the binary

I prepared a sample solution to show you the problem. See:
ILMerge_BaseAddress_Issue_Sample_Project.zip

You need to build it and look at the SampleSolution\ConsoleApp2\bin\x64\Debug\MergedConsolApp2.exe PE headers.

Here is the relevant snapshot from Visual Studio Terminal:


dumpbin /headers .\ConsoleApp2\bin\x64\Debug\ConsoleApp2.exe
Microsoft (R) COFF/PE Dumper Version 14.26.28806.0
Copyright (C) Microsoft Corporation. All rights reserved.

Dump of file .\ConsoleApp2\bin\x64\Debug\ConsoleApp2.exe

PE signature found

File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
8664 machine (x64)
2 number of sections
F8F801FF time date stamp
0 file pointer to symbol table
0 number of symbols
F0 size of optional header
22 characteristics
Executable
Application can handle large (>2GB) addresses

OPTIONAL HEADER VALUES
20B magic # (PE32+)
48.00 linker version
800 size of code
600 size of initialized data
0 size of uninitialized data
0 entry point
2000 base of code
140000000 image base (0000000140000000 to 0000000140005FFF)
...


dumpbin /headers .\ConsoleApp2\bin\x64\Debug\ConsoleApp2.exe
Microsoft (R) COFF/PE Dumper Version 14.26.28806.0
Copyright (C) Microsoft Corporation. All rights reserved.

Dump of file .\ConsoleApp2\bin\x64\Debug\ConsoleApp2.exe

PE signature found

File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
8664 machine (x64)
2 number of sections
F8F801FF time date stamp
0 file pointer to symbol table
0 number of symbols
F0 size of optional header
22 characteristics
Executable
Application can handle large (>2GB) addresses

OPTIONAL HEADER VALUES
20B magic # (PE32+)
48.00 linker version
800 size of code
600 size of initialized data
0 size of uninitialized data
0 entry point
2000 base of code
140000000 image base (0000000140000000 to 0000000140005FFF)


dumpbin /headers .\ConsoleApp2\bin\x64\Debug\MergedConsolApp2.exe
Microsoft (R) COFF/PE Dumper Version 14.26.28806.0
Copyright (C) Microsoft Corporation. All rights reserved.

Dump of file .\ConsoleApp2\bin\x64\Debug\MergedConsolApp2.exe

PE signature found

File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
8664 machine (x64)
3 number of sections
5EF3610A time date stamp Wed Jun 24 17:19:54 2020
0 file pointer to symbol table
0 number of symbols
F0 size of optional header
22 characteristics
Executable
Application can handle large (>2GB) addresses

OPTIONAL HEADER VALUES
20B magic # (PE32+)
8.00 linker version
800 size of code
800 size of initialized data
0 size of uninitialized data
26BE entry point (00000000004026BE)
2000 base of code
400000 image base (0000000000400000 to 0000000000407FFF)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants