【文章标题】: .net 2.0下利用动态Assembly与Reflect机制向DHTML暴露.net应用里的对象与.net framework
【文章作者】: dreaman
【作者邮箱】: dreaman_163@163.com
【作者主页】: http://dreaman.haolinju.net
【作者声明】: 主要用于为WebBrowser控件提供扩展对象,不过涉及动态代码编写,也许对crack有用。
--------------------------------------------------------------------------------
【详细过程】
.net 2.0提供的WebBrowser控件对IE的封装十分酷,特别是其ObjectForScripting特性,只要将一个.net里的对象实例赋给它,就可以在DHTML中用window.external访问该.net对象了(有一个限制是该.net对象必须使用ComVisible属性修饰成COM可见的),如果用IE作界面,DHTML可以认为是UI与控制器,.NET中则实现对象模型,如果可以在DHTML中自由的访问.NET里的对象,那会让人很舒服.
我想到的方法是在external上提供一个CreateObject方法,直接由脚本来创建.net里的对象实例,但是有一个问题,.net里有许多对象并不是COM可见的,这样的对象实例无法返回给DHTML,所以必须对这样的对象作些处理.
对非COM可见的对象,要让DHTML来访问,必须作一个代理,代理对象设成COM可见的,然后代理对象具有原对象一样的访问接口.因为目标客户是javascript脚本,它访问对象是通过IDispatch[Ex]接口来实现的,所以我们的代理对象实际上并不需要与原对象有完全一致的接口,这样,有三种可能的方式:
1、直接修原.NET对象,让它变成COM可见的;
2、在.NET中实现一个对象,它实现IDispatch接口,实现的功能是访问原.net对象的属性与方法;
3、利用动态装配与反射,动态的生成一个代理类,接口与原.net类相同,并设置为COM可见的。
方法1我不知道如何做,因为.net框架没有提供对现有类的修改的方式,如果是cracker的方式,我想可能会比较复杂并且不通用(更重要的是,我不知道怎么弄,谁要是知道,请告诉我,谢了)。
方法2理论上是绝对可行的,但是我打算用C#来写,也就是说企图用托管代码实现IDispatch接口,实验失败,MSDN上好象是说,CLR总是会替.net对象实现IUnknown与IDispatch接口;如果是用C++,我想IDispatch实现成非托管的,然后其实现功能利用C++互操作调.NET的相关实现,然后将非托管IDispatch实例返回并使用自己的定制Marshal应该是可行的(没有试验过,只是想法)。
现在只剩下方法3了,我试验了这种方法,可行。
不多说了,直接看代码(试验性的,其中的定制Marshal是试验用的,现在的实现与.NET默认的Marshal是一样的,所以是可以去掉的)
//定制Marshal,实现与.net运行时作的工作一样,可以去掉
public class MyMarshal : ICustomMarshaler
{
#region ICustomMarshaler 成员
public void CleanUpManagedData(object ManagedObj)
{}
public void CleanUpNativeData(IntPtr pNativeData)
{}
public int GetNativeDataSize()
{
return -1;
}
public IntPtr MarshalManagedToNative(object o)
{
IntPtr i = Marshal.GetIDispatchForObject(o);
return i;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
static public ICustomMarshaler GetInstance(string pstrCookie)
{
return ins;
}
static private MyMarshal ins = new MyMarshal();
}
//扩展对象的实现
[ComVisible(true)]
public class External
{
//判断一个.net对象实例是否是COM可见的,如果不可见则实时生成一个COM可见的代理类,并返回代理类的实例。
[method: ComVisible(false)]
static private object WrapAsComVisible(Type t, object o)
{
Attribute[] attrs = Attribute.GetCustomAttributes(t);
foreach (Attribute a in attrs)
{
if (a is ComVisibleAttribute)
{
ComVisibleAttribute cva = a as ComVisibleAttribute;
if (cva.Value)
return o;
}
}
//现在开始生成COM可见的代理类
AssemblyName an = new AssemblyName("__" + t.Namespace + "_" + t.Name + "_" + t.GetHashCode());
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder mob = ab.DefineDynamicModule("_" + t.Name + "_" + t.GetHashCode());
TypeBuilder tb = mob.DefineType(t.Name + "_" + t.GetHashCode(), TypeAttributes.Public);
Type[] cts = new Type[] { typeof(bool) };
ConstructorInfo ci = typeof(ComVisibleAttribute).GetConstructor(cts);
CustomAttributeBuilder cab = new CustomAttributeBuilder(ci, new object[] { true });
tb.SetCustomAttribute(cab);
tb.DefineDefaultConstructor(MethodAttributes.Public);
FieldBuilder innerFieldInfo = tb.DefineField("innerObj", t, FieldAttributes.Public);
MemberInfo[] memberInfos = t.GetMembers();
foreach (MemberInfo memberInfo in memberInfos)
{
switch (memberInfo.MemberType)
{
case MemberTypes.Field:
{
FieldInfo fi = memberInfo as FieldInfo;
PropertyBuilder pb = tb.DefineProperty(fi.Name, System.Reflection.PropertyAttributes.None, fi.FieldType, null);
if (true)
{
MethodBuilder getMB = tb.DefineMethod("get_" + fi.Name, MethodAttributes.Public | MethodAttributes.SpecialName, fi.FieldType, null);
ILGenerator ilg = getMB.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Ldfld, innerFieldInfo);
ilg.Emit(OpCodes.Ldfld, fi);
ilg.Emit(OpCodes.Ret);
pb.SetGetMethod(getMB);
}
if (true)
{
Type[] tis = new Type[] { fi.FieldType };
MethodBuilder setMB = tb.DefineMethod("set_" + fi.Name, MethodAttributes.Public | MethodAttributes.SpecialName, typeof(void), tis);
ILGenerator ilg = setMB.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Ldfld, innerFieldInfo);
ilg.Emit(OpCodes.Ldarg_1);
ilg.Emit(OpCodes.Stfld, fi);
ilg.Emit(OpCodes.Ret);
pb.SetSetMethod(setMB);
}
}
break;
case MemberTypes.Property:
{
PropertyInfo pi = memberInfo as PropertyInfo;
ParameterInfo[] paras = pi.GetIndexParameters();
Type[] tis0 = new Type[paras.Length];
for (int i = 0; i < tis0.Length; i++)
{
tis0[i] = paras[i].ParameterType;
}
PropertyBuilder pb = tb.DefineProperty(pi.Name, System.Reflection.PropertyAttributes.None, pi.PropertyType, tis0);
if (pi.CanRead)
{
if (paras.Length > 0)
{
Type[] tis = new Type[paras.Length];
for (int i = 0; i < tis.Length; i++)
{
tis[i] = paras[i].ParameterType;
}
MethodBuilder getMB = tb.DefineMethod("get_Item", MethodAttributes.Public | MethodAttributes.SpecialName, pi.PropertyType, tis);
ILGenerator ilg = getMB.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Ldfld, innerFieldInfo);
for (int i = 0; i < tis.Length; i++)
{
switch (i)
{
case 0:
{
ilg.Emit(OpCodes.Ldarg_1);
}
break;
case 1:
{
ilg.Emit(OpCodes.Ldarg_2);
}
break;
case 2:
{
ilg.Emit(OpCodes.Ldarg_3);
}
break;
default:
{
ilg.Emit(OpCodes.Ldarg_S, i + 1);
}
break;
}
}
ilg.EmitCall(OpCodes.Call, pi.GetGetMethod(), tis);
ilg.Emit(OpCodes.Ret);
pb.SetGetMethod(getMB);
}
else
{
MethodBuilder getMB = tb.DefineMethod("get_" + pi.Name, MethodAttributes.Public | MethodAttributes.SpecialName, pi.PropertyType, null);
ILGenerator ilg = getMB.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Ldfld, innerFieldInfo);
ilg.EmitCall(OpCodes.Call, pi.GetGetMethod(), null);
ilg.Emit(OpCodes.Ret);
pb.SetGetMethod(getMB);
}
}
if (pi.CanWrite)
{
if (paras.Length > 0)
{
Type[] tis = new Type[paras.Length + 1];
for (int i = 0; i < tis.Length; i++)
{
if (i < paras.Length)
tis[i] = paras[i].ParameterType;
else
tis[i] = pi.PropertyType;
}
MethodBuilder setMB = tb.DefineMethod("set_Item", MethodAttributes.Public | MethodAttributes.SpecialName, typeof(void), tis);
ILGenerator ilg = setMB.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Ldfld, innerFieldInfo);
for (int i = 0; i < tis.Length; i++)
{
switch (i)
{
case 0:
{
ilg.Emit(OpCodes.Ldarg_1);
}
break;
case 1:
{
ilg.Emit(OpCodes.Ldarg_2);
}
break;
case 2:
{
ilg.Emit(OpCodes.Ldarg_3);
}
break;
default:
{
ilg.Emit(OpCodes.Ldarg_S, i + 1);
}
break;
}
}
ilg.EmitCall(OpCodes.Call, pi.GetSetMethod(), tis);
ilg.Emit(OpCodes.Ret);
pb.SetSetMethod(setMB);
}
else
{
Type[] tis = new Type[] { pi.PropertyType };
MethodBuilder setMB = tb.DefineMethod("set_" + pi.Name, MethodAttributes.Public | MethodAttributes.SpecialName, typeof(void), tis);
ILGenerator ilg = setMB.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Ldfld, innerFieldInfo);
ilg.Emit(OpCodes.Ldarg_1);
ilg.EmitCall(OpCodes.Call, pi.GetSetMethod(), tis);
ilg.Emit(OpCodes.Ret);
pb.SetSetMethod(setMB);
}
}
}
break;
case MemberTypes.Method:
{
MethodInfo mi = memberInfo as MethodInfo;
MethodBuilder mb = tb.DefineMethod(mi.Name, MethodAttributes.Public);
ParameterInfo[] paras = mi.GetParameters();
Type[] tis = new Type[paras.Length];
for (int i = 0; i < tis.Length; i++)
{
tis[i] = paras[i].ParameterType;
}
mb.SetReturnType(mi.ReturnType);
mb.SetParameters(tis);
ILGenerator ilg = mb.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Ldfld, innerFieldInfo);
for (int i = 0; i < tis.Length; i++)
{
switch (i)
{
case 0:
{
ilg.Emit(OpCodes.Ldarg_1);
}
break;
case 1:
{
ilg.Emit(OpCodes.Ldarg_2);
}
break;
case 2:
{
ilg.Emit(OpCodes.Ldarg_3);
}
break;
default:
{
ilg.Emit(OpCodes.Ldarg_S, i + 1);
}
break;
}
}
ilg.EmitCall(OpCodes.Call, t.GetMethod(mi.Name), tis);
ilg.Emit(OpCodes.Ret);
}
break;
}
}
Type tt = tb.CreateType();
//创建代理类实例并初始化指向原.net类实例的指针。
object oo = Activator.CreateInstance(tt);
tt.InvokeMember("innerObj", BindingFlags.SetField, null, oo, new object[] { o });
return oo;
}
[method: ComVisible(false)]
static private object CreateObjectFromFileX(string aname, string tname,params object[] args)
{
Assembly a = Assembly.LoadFile(aname);
Type t = a.GetType(tname);
object o=Activator.CreateInstance(t, args);
return WrapAsComVisible(t,o);
}
[method: ComVisible(false)]
static private object CreateObjectX(string tname, params object[] args)
{
Type t = Type.GetType(tname);
object o = Activator.CreateInstance(t, args);
return WrapAsComVisible(t,o);
}
/*
后续的方法是前面两个方法的特定参数数的版本,因为客户是用访问COM对象的方式访问External,我们
为其提供参数固定的访问形式。
*/
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile0(string aname,string tname)
{
return CreateObjectFromFileX(aname,tname);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject0(string tname)
{
return CreateObjectX(tname);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile1(string aname, string tname, object arg1)
{
return CreateObjectFromFileX(aname, tname, arg1);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject1(string tname, object arg1)
{
return CreateObjectX(tname, arg1);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile2(string aname, string tname, object arg1, object arg2)
{
return CreateObjectFromFileX(aname, tname, arg1, arg2);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject2(string tname, object arg1, object arg2)
{
return CreateObjectX(tname, arg1, arg2);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile3(string aname, string tname, object arg1, object arg2, object arg3)
{
return CreateObjectFromFileX(aname, tname, arg1, arg2, arg3);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject3(string tname, object arg1, object arg2, object arg3)
{
return CreateObjectX(tname, arg1, arg2, arg3);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile4(string aname, string tname, object arg1, object arg2, object arg3, object arg4)
{
return CreateObjectFromFileX(aname, tname, arg1, arg2, arg3, arg4);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject4(string tname, object arg1, object arg2, object arg3, object arg4)
{
return CreateObjectX(tname, arg1, arg2, arg3, arg4);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile5(string aname, string tname, object arg1, object arg2, object arg3, object arg4, object arg5)
{
return CreateObjectFromFileX(aname, tname, arg1, arg2, arg3, arg4, arg5);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject5(string tname, object arg1, object arg2, object arg3, object arg4, object arg5)
{
return CreateObjectX(tname, arg1, arg2, arg3, arg4, arg5);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile6(string aname, string tname, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6)
{
return CreateObjectFromFileX(aname, tname, arg1, arg2, arg3, arg4, arg5, arg6);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject6(string tname, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6)
{
return CreateObjectX(tname, arg1, arg2, arg3, arg4, arg5, arg6);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile7(string aname, string tname, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7)
{
return CreateObjectFromFileX(aname, tname, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject7(string tname, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7)
{
return CreateObjectX(tname, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObjectFromFile8(string aname, string tname, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8)
{
return CreateObjectFromFileX(aname, tname, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
public object CreateObject8(string tname, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8)
{
return CreateObjectX(tname, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
}
用法很简单,实例化一个External并将它赋给WebBrowser控件实例的ObjectForScripting,然后在DHTML里用window.external.CreateObject系列方法来创建.net里的对象(包括当前EXE中实现的与.net框架库及dll的),可以看出,相当于向DHTML暴露了整个.net framework,呵呵。
代理的实现在WrapAsComVisible中。
--------------------------------------------------------------------------------
【经验总结】
.net中的reflect与动态装配使得我们可以在运行时构造并执行代码(相当于win32程序里在内存
中写入并执行指令),不过我不知道如何修改已经存在的代码与数据,如果可以,则目前win32代
码钩子所能做的一切.NET里都可以做到(如果哪位知道怎么在运行时修改.net现行的IL与元数据
,请告诉我)。
--------------------------------------------------------------------------------
2006年05月22日 12:24:28
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)