Verifiable .exe impossible using managed C++?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

It should be possible to build a verifiable assembly using the managed
extensions for C++. It may be possible if the target is a library, but as far
as I can determine it cannot be done for an application. Hopefully it is
possible, and I just need someone to explain what I'm doing wrong.

1. Using the "New Projects" wizard, create a new Visual C++ .NET Windows
Forms Application.
2. Add NOTHING to the project.
3. Build it, run it. No problem.
4. Confirm that peverify reports that it is unverifiable. This is expected
at this stage.
5. Add the following code to Form1.cpp:

extern "C" {
int _fltused=1;
void _cdecl _check_commonlanguageruntime_version(){}
}

and this code to AssemblyInfo.cpp:

using namespace System::Security::Permissions;
[assembly: SecurityPermissionAttribute(
SecurityAction::RequestMinimum,
SkipVerification=false)];

6. In the project settings, disable optimisations (/Od) and confirm /clr is
set.
7. Build it. Run it. Still no problem.
8. Confirm that peverify still reports it is unverifiable.
9. Use silo (after finding and building the SetILOnly sample project) to
set the "IL only" bit in the assembly (the .exe file).
10. The app should now be verifiable, shouldn't it? But ...
11. Run peverify on it again: observe that it is still unverifiable.
12. Run the app: observe that the runtime now complains: "Application failed
to initialize properly (0xC000007B)"

Note that peverify always reports the same errors:
[IL]: Error: Unverifiable PE Header/native stub.
[IL]: Error: Unverifiable image '' can not be run.
It fails if it is run with or without the "/IL" switch, but it always
succeeds if run with the "/MD" switch.

Steps 5 to 9 above are a fuzzy union of instructions given in:
1. Visual Studio .NET help topic: "Producing Verifiable Components with
Managed Extensions for C++"
2. The usually accurate and informative "Programming with managed extensions
for MS VC++ .NET", by Richard Grimes.
Unfortunately, both of these sources (and all the random advice I've found
elsewhere) are focused to some extent on building verifiable libraries, not
applications, and my suspicion is it only works for dlls.

Can anyone set me straight?

Allan
 
Richard Grimes has offered some useful information on the subject in a
separate thread "why Assembly.LoadFrom() function does'nt load VC++ Project
exe" which probably makes my long-winded post here redundant.

Thanks, Richard:

In your opinion, is the following summary accurate?
1. There are known issues generating managed code in .NET 2003 that have not
been fixed and for which there is no reliable workaround.
2. There is no such problem in .NET 2005.

If this is the case I'll stop fighting with .NET 2003 over the issue. But if
there is indeed a way to reliably generate verifiable applications (.exe's)
with 2003, I'd still really appreciate hereing about it.

Allan
 
Hi,

I don't know wether this is still an issue, since this has been resolved by
VisualStudio 2005/.NET 2.0 Framework SDK. But, for the sake of completeness and
the fact that there is some amount of code written in managed extensions for C++
(Visual Studio .NET 2003), I would like to present my solution to produce a
verifyable type-safe executable and assembly using managed extensions for C++
(Visual Studio .NET 2003). This might be usefull to those, who do not want to or
cannot (large code base) port to the new C++/CLI syntax, which is a must
condition to exploit the new functionality of Visual Studio 2005/.NET 2.0
Framework SDK to build a verifyable type-safe code.

In fact, I did not find the mysterious SetILOnly (silo.exe) example, neither on
my Visual Studio .NET 2003 CDs nor the net. So, what I actually did, was to
compile a simple hello world application with Visual Studio 2005/.NET 2.0
Framework SDK exploiting the functionality to build a verifyable type-safe
executable/assembly and compare the assebler listing, map file and MSIL
disassembly with those produced by Visual Studio .NET 2003.

I will give a cooking book recept here.

1. All rules of writing managed code stated in
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/vcmex/html/vclrfproducingverifiablecomponentswithmanagedc.asp still apply,
since one must not let native code find its way into an executable/assembly.

2. You may either include _check_commonlanguageruntime_version() into your code
or link against nochkclr.obj instead. You do not need to set the
SecurityPermissionAttribute, but it might be necessary for Assembly.LoadFrom()
(I do not know, have not tried yet).

3. Compile your code with these switches:

cl.exe -nologo -c -Ox -GA -clr -FA <Application.cpp>

These are at least the switches I used. This produces two files. An .obj and a
cod file. The .cod file is necessary to get the decorated symbol name to export
the entry point for your application. You should be able to use dumpbin.exe for
this task as well. Hence, your managed entry point is e.g.
HelloWorld::Main(String*[]), search for a .global directive in the .cod file
containing the names HelloWorld and Main. It should look like this:
?Main@HelloWorld@@$$FSMXP$01AP$AAVString@System@@@Z. This is the decorated
symbol name of your entry point. You will need this for the linking process.
As you can see, this approach even works with optimizations on!

4. Link your .obj files into an assembly (DLL), no matter you wish to get an
executable or assembly, this is decided later. Link using switches to create a
DLL, get rid of the default entry point, get rid of the C/C++ runtime, generate
a relocation section, remove unused references and export your entry point
specifying it as decorated symbol name:

link.exe -nologo -release -subsystem:console -opt:ref -dll -base:0x00400000 -
nodefaultlib -fixed:no -noentry -export:<decorated symbol name>
<Application.obj> <other.obj | otherAssembly.dll> nochkclr.obj mscoree.lib

Again, these are the switches I used.
I do not know wether it works with the -debug switch.
You may specify -subsystem:windows for a GUI application.
It should be possible to use any other -opt switch, especially if you wish to
retain debug symbols.
The -dll switch eliminates the necessity to resolve the _mainCRTStartup symbol,
which is usually covered by the C runtime (msvcrt.lib).
-base:0x00400000 moves the base of the PE file for an executable. If you wish to
get an assembly just drop the -base switch.
-nodefaultlib gives you the possibility to explicitly specify the object files
and libraries you want to link aganst.
-fixed:no generates a relocation section. This is necessary for the CLR to be
able to put your executable/assembly into its process address space on the fly.
-noentry removes the default entry point for a DLL in this case (_DllMain@12).
You must at least export your entry point for managed applications. This should
look like this -entry:?Main@HelloWorld@@$$FSMXP$01AP$AAVString@System@@@Z.
I am not sure wether this is a must, but follow the -export: switch with the
decorated symbol name aquired from the .cod file in step 1. Remember, if you
rename the class your entry point method is in, rename the method or move the
class into an other namespace, you will have to reaquire the name from the .cod
file.
Put your application object file and perhaps some other object files required
for your application on the line. It should be possible to specify assemblies as
well.
If you have not included the code to skip the CLR version check into your source
code, you may provide nochkclr.obj to the linker instead, which is provieded
with Visual Studio .NET 2003.
mscoree.lib is here just to make the linker happy by resolving the
__CorDllMain@12 symbol. Though this pours in native code into the DLL, don't
worry, this is removed automatically in the next step.

5. Dump an IL disassembly by using ildasm.exe of your DLL. You do not need to
set any extra options to dump, but you must have the IL dump box checked (it is
by default).
Here is where it becomes difficult.
Open the IL disassembly file with your favourite plain text editor.
Navigate to your entry point. For a hello world application it should look like
this:

class public auto ansi HelloWorld
extends [mscorlib]System.Object
{
...
} // end of class HelloWorld

Insert into your entry point method a .entrypoint directive. So, your IL
assembly code should look like this:

class public auto ansi HelloWorld
extends [mscorlib]System.Object
{
.method public static void Main(string[] args) cil managed
{
.entrypoint
// CodegrӇe 11 (0xb)
.maxstack 1
IL_0000: ldstr "Hello World!"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
} // end of method HelloWorld::Main
...
} // end of class HelloWorld

You may want to remove the dependency on the Microsoft.VisualC assembly as well.
Simply cut the entire

assembly extern Microsoft.VisualC
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
.hash = (FA D4 FB A8 39 90 F9 05 C0 39 A3 20 C0 CD FA DD BD 57 E0 C4 )
.ver 7:0:5000:0
}

block out. Save the IL disassembly file.

6. Reassemble the IL disassembly dump into an executable/assembly with
ilasm.exe. So, your call could look like this:

ilasm.exe -nologo -flags:0x00000001 <Application.il>

This should produce you a verifyable type-safe executable. If you wish to get an
assembly use the -dll switch instead.
IMPORTANT: You MUST specify the -flags:0x00000001 switch. It forces the IL
assembler to produce a IL only executable/assembly, since that is what it is all
about :). This switch incorporates the functionality, which should have been
provided by SetILOnly.

7. Verify your executable/assembly with the PEverify.exe tool.

That's it! At least PEverify does not complain about the files beeing not
verifyable type-safe.
This way ist odd, but it works and it can be automated to a large degree. Of
course, you may set the appropriate switches, object files and libraries in
Visual Studio .NET 2003 as well, but you will need to intergrate the ildasm and
ilasm steps somehow into your build process.
If somebody discovers an error or something that is wrong in this process,
please let me know.
Have fun!

Jakob Wisor

ps.: There might be a way to easy this process by creating modules and linking
them by the assembly linker al.exe.
 
A mistake has slipped into step 4. So here is step 4 again and it is correct
this time.

4. Link your .obj files into an assembly (DLL), no matter you wish to get an
executable or assembly, this is decided later. Link using switches to create a
DLL, get rid of the default entry point, get rid of the C/C++ runtime, generate
a relocation section, remove unused references and export your entry point
specifying it as decorated symbol name:

link.exe -nologo -release -subsystem:console -opt:ref -dll -base:0x00400000 -
nodefaultlib -fixed:no -noentry -export:<decorated symbol name>
<Application.obj> <other.obj | otherAssembly.dll> nochkclr.obj mscoree.lib

Again, these are the switches I used.
I do not know wether it works with the -debug switch.
You may specify -subsystem:windows for a GUI application.
It should be possible to use any other -opt switch, especially if you wish to
retain debug symbols.
The -dll switch eliminates the necessity to resolve the _mainCRTStartup symbol,
which is usually covered by the C runtime (msvcrt.lib).
-base:0x00400000 moves the base of the PE file for an executable. If you wish to
get an assembly just drop the -base switch.
-nodefaultlib gives you the possibility to explicitly specify the object files
and libraries you want to link aganst.
-fixed:no generates a relocation section. This is necessary for the CLR to be
able to put your executable/assembly into its process address space on the fly.
-noentry removes the default entry point for a DLL in this case (_DllMain@12).
You must at least export your entry point for managed applications. This should
look like this -export:?Main@HelloWorld@@$$FSMXP$01AP$AAVString@System@@@Z.
I am not sure wether this is a must, but follow the -export: switch with the
decorated symbol name aquired from the .cod file in step 1. Remember, if you
rename the class your entry point method is in, rename the method or move the
class into an other namespace, you will have to reaquire the name from the .cod
file.
Put your application object file and perhaps some other object files required
for your application on the line. It should be possible to specify assemblies as
well.
If you have not included the code to skip the CLR version check into your source
code, you may provide nochkclr.obj to the linker instead, which is provieded
with Visual Studio .NET 2003.
mscoree.lib is here just to make the linker happy by resolving the
__CorDllMain@12 symbol. Though this pours in native code into the DLL, don't
worry, this is removed automatically in the next step.

=============================

The error referes to the -export switch. *DO NOT* set the -entry:<decorated
symbol name> switch or you will end up with an ambiguous symbol resolve issue,
that is the linker will be assuming two entry points.

Jakob Wisor
 
Thanks for doing the work, Jakob,

I decided it would be too painful and time-consuming to explore a hack like
you have described, which is when I posted my query instead. I was hoping
there was already a real fix for this bug.
I don't know wether this is still an issue, since this has been resolved by
VisualStudio 2005/.NET 2.0 Framework SDK.

It seems to me it remains an issue as long as VS 2003 remains a supported
product (and especially until all other SDKs have post VS 2005 releases: for
example DirectX SDK, Platform SDK ...) so I'm sure your post is helpful to
others.
 
Back
Top