Can I import Type from external libaries

Jun 16, 2011 at 1:26 AM

I wonder whether this is possible:

Suppose I have an assembly with following code:

A.dll:

using Log;

Class A{

...

Log.info("exception thrown");

}

If I have to replace with something like below:

using NewLog;

Class A

{

...

NewLog.info("exception thrown");

..

}

Here, NewLog is contained in another library say NewLog.dll. Can I import this assembly in A.dll and modify all refernces of Log to NewLog. 

I was looking at codebase and seems like I have to load external library using

var logAssemblyRef =
                       new Microsoft.Cci.Immutable.AssemblyReference(host,
                       new AssemblyIdentity(host.NameTable.GetNameFor("NewLog"), ""new Version("1.0.0.0"), null@"K:\NewLog\bin\Debug\NewLog.dll"));
and then create types using this logAssemblyRef. Is it the right direction? please confirm.

 

Coordinator
Jun 16, 2011 at 10:44 PM

This seems to be the right direction. Perhaps the easiest way to do this is just to load NewLog.dll, find the NewLog.info method in it (using the various helper methods in MetadataHelper), and then rewrite A.dll, systematically replacing any reference to Log.info with NewLog.Info. You may even be able to get away without having to make a copy of NewLog.info.

Jun 21, 2011 at 4:50 AM
Edited Jun 21, 2011 at 4:51 AM

Thanks for the reply. I have tried sth like this:

var logAssemblyRef = new Microsoft.Cci.Immutable.AssemblyReference(host,
                     new AssemblyIdentity(host.NameTable.GetNameFor("NewLog"), ""new Version("0.0.0.0"), new byte[] { }, @"G:\projects\utility\NewLog.dll"));
var nameTable =      host.NameTable;
var newLogType = new Microsoft.Cci.Immutable.NamespaceTypeReference(host,
                        new Microsoft.Cci.Immutable.RootUnitNamespaceReference(logAssemblyRef),
                        nameTable.GetNameFor("Log2.NewLog"),
                        0, falsefalse,
                        PrimitiveTypeCode.NotPrimitive);

Then in my mutator I have:

  public override Operation Mutate(Operation operation)
        {
            if (operation.OperationCode == OperationCode.Call)
            {
                if (operation.Value is IMethodReference)
                {
                    IMethodReference m = operation.Value as IMethodReference;
                    if (m != null)
                    {
                         // this is dirty method
                        if (m.IsStatic && m.Name.Value.Contains("info"))
                        {
 
                            IMethodReference consoleDotWriteLine = new Microsoft.Cci.MethodReference(
                              host, newLogType , CallingConvention.Default,
                              host.PlatformType.SystemVoid, host.NameTable.GetNameFor("Info"),
                              0, host.PlatformType.SystemString);
 
                            operation.Value = consoleDotWriteLine;
                        }
                    }
                }
            }
            return operation;
        }

When I run the exe produced by this, I get following error:

Unhandled Exception: System.TypeLoadException: Could not load type 'NewLog.Log2' from assembly 'Log2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. 

Seems like there is sth wrong in the way I have reference the external assembly and the way I created the new Type. Specially I was confused regarding how to load and specify namespace for new type (in this case "NewLog" which is in namespace "Log2"). 

Coordinator
Jun 26, 2011 at 6:10 AM

I'm afraid that it is difficult to figure things out from your description. One good way to debug these things is to run peverify over the rewritten assembly. Another way to proceed is to construct a very simple test case for your idea, possibly by cutting down your current code to the bare minimum. Hopefully, at some point things will either start working (and then you can concentrate on finding the single change that turns things from working to not working) or you'll end up with an example that is so simple that you can post it here and get a definitive answer.

Jun 28, 2011 at 2:06 AM

Thanks for the reply. It seems like I have found the problem in above code:

The problem was in following code:

 var newLogType = new Microsoft.Cci.Immutable.NamespaceTypeReference(
                        host,
                        new Microsoft.Cci.Immutable.RootUnitNamespaceReference(logAssemblyRef),
                        nameTable.GetNameFor("MyLog.Log2"),
                        0, false, false,
PrimitiveTypeCode.NotPrimitive);

I did not create the namespaces properly. Since the new Log class lies in "NewLog" namespace, I have to create NestedUnitNamespaceReference in a loop as done in "PlatformType.cs".

I had to derived a new class from PlatfromType.cs and add a method to create new NamespaceTypeRef as below:

this.CreateRefrence(logAssemblyReffalse, 0, PrimitiveTypeCode.NotPrimitive, new string[] { "MyLog""Log2" });

Now I can execute my mutated exe.

I have another small question. In the code below:

 var logAssemblyRef =
                       new Microsoft.Cci.Immutable.AssemblyReference(host,
                       new AssemblyIdentity(host.NameTable.GetNameFor("MyLog"), "", new Version("1.0.0.0"), new byte[] { }, @"G:\kiran\projects\Guide\StaticAnalysis\MyLog\bin\Debug\MyLog.dll"));

It seems like the last parameter (which is location) is not verified. I gave invalid location and still my program was executing without any error. Is it because the application 
finds the dll at runtime.





Coordinator
Jun 28, 2011 at 2:29 AM

I am not sure what you mean by "is not verified". To put it another way, what did you expect to happen?

Jun 28, 2011 at 2:53 AM

Well what I meant was, when we create AssemblyReference, the parameters are not checked for consistencies. I tried tinkering with location and version and it seems like they are not checked at runtime

whether they are valid or not. For example, the same above can be replaced as

var logAssemblyRef =
                    new Microsoft.Cci.Immutable.AssemblyReference(host,
                    ew AssemblyIdentity(host.NameTable.GetNameFor("MyLog"), "", new Version("2.0.0.0"), new byte[] { }, @"G:\kiran\projects\Guide\StaticAnalysis\MyLog\bin\Debug\MyLogZZZ.dll"));

Both the version and location are incorrect with respect to location and version of MyLog.dll. But still no warning is shown at runtime and final mutated code still runs.

I was just surprise to see this behavior. I expected CCI to cross check these parameters for consistencies.

Coordinator
Jun 28, 2011 at 2:58 AM

The object model does little more than provide structure. Semantic consistency checks are in the domain of visitors over the object model. MetadataHelper has a partial implementation of a visitor that walks an object model and reports semantic errors for it. But unfortunately it is far from complete and not in a critical path for me. Nevertheless, it may be useful to incorporate it.

Ultimately, however, peverify is your friend. But even it is not going to complain about the path of an assembly reference not being valid. In fact, the path is not even persisted in the to PE file.

Jun 28, 2011 at 3:08 AM

Thanks for quick reply. I was just a bit curious. 

As u said this is not that critical. If I need I should be able to add few lines to verify the assembly.