| shuai's profile娱乐精神PhotosBlog | Help |
|
11/29/2007 强暴.Net程序集 之十 (FieldDef 和 MethodDef 表结构)
警告:本系列文章为本人原创,只作技术研究之用,您可以引用链接传播,禁止其它的转载方式,禁止用于商业或非法目的, 对于造成的一切后果本人概不负责 FieldDef非常的简单, Partition II Metadata中描述为: 22.15 Field : 0x04 其中Flags 字段是一个位掩码, 描述了字段的属性 // field contract attributes. fdSpecialName = 0x0200, // field is special. Name describes how. // interop attributes // Reserved flags for runtime use only. 可以通过如下程序得到所有Field的属性, t为FieldDef表 for(DWORD i = 0; i < t.Rows; ++i) // Flags // Name // Signature MethodDef 表在Partition II Metadata中描述为: 对了, 别忘了Property(属性实际上就是get_和set_方法) // method contract attributes. // vtable layout mask - Use this mask to retrieve vtable attributes. // method implementation attributes. // interop attributes // Reserved flags for runtime use only. } CorMethodAttr; 值得说明的是ParamList字段 // RVA // ImplFlags // Flags // Name
// ParamList if(index < t.Rows - 1) if(index < t.Rows - 1) 11/9/2007 强暴.Net程序集 之九 (TypeDef表结构)警告:本系列文章为本人原创,只作技术研究之用,您可以引用链接传播,禁止其它的转载方式,禁止用于商业或非法目的, 对于造成的一切后果本人概不负责 现在我们来看一个非常重要的元数据表TypeDef, 它定义了类型信息
在Partition II Metadata中描述了它的格式: The TypeDef table has the following columns: • Flags (a 4-byte bitmask of type TypeAttributes, §23.1.15) • TypeName (an index into the String heap) • TypeNamespace (an index into the String heap) • Extends (an index into the TypeDef, TypeRef, or TypeSpec table; more precisely, a TypeDefOrRef (§24.2.6) coded index) • FieldList (an index into the Field table; it marks the first of a contiguous run of Fields owned by this Type). The run continues to the smaller of: o the last row of the Field table o the next run of Fields, found by inspecting the FieldList of the next row in this TypeDef table • MethodList (an index into the MethodDef table; it marks the first of a continguous run of Methods owned by this Type). The run continues to the smaller of: o the last row of the MethodDef table o the next run of Methods, found by inspecting the MethodList of the next row in this TypeDef table 其中:
Flags 是一个位掩码, 描述了类型的一些属性信息, 文档中的23.1.15 Flags for types [TypeAttributes]一节中详情描述 在corhdr.h中也有一个定义, 下面是一个节选的列表: typedef enum CorTypeAttr { // Use this mask to retrieve the type visibility information. tdVisibilityMask = 0x00000007, tdNotPublic = 0x00000000, // Class is not public scope. tdPublic = 0x00000001, // Class is public scope. // Use this mask to retrieve class semantics information.
tdClassSemanticsMask = 0x00000060, tdClass = 0x00000000, // Type is a class. tdInterface = 0x00000020, // Type is an interface. // end semantics mask // Special semantics in addition to class semantics.
tdAbstract = 0x00000080, // Class is abstract tdSealed = 0x00000100, // Class is concrete and may not be extended tdSpecialName = 0x00000400, // Class name is special. Name describes how. //其它略
} CorTypeAttr; 并且corhdr.h还有一系列宏, 用于方便的查询类型的一些属性,比如
#define IsTdClass(x) (((x) & tdClassSemanticsMask) == tdClass) TypeName和TypeNamespace 都是一个String 堆的索引值, 要注意它的长度随HeapSizes的大小而变
Extends 描述了类型的继承情况, 即指向基类的信息(接口为0), 但是这个值并不是一个元数据token, 而是一个对token进行压缩后的值, TypeDefOrRefEncoded一节中描述了这个值的算法
比如token为0x01000012,那么它的TypeDefOrRefEncoded 值为 encoded = ( 0x000012 << 2 ) | 0x01 (0x01 指 TypeRef 在TypeDefOrRef中的编号) = 0x48 | 0x01 = 0x49 其中TypeDefOrRef指将TypeDef, TypeRef, TypeSpec这一组号转为一个2位的编号: TypeDefOrRef Tag TypeDef 0 TypeRef 1 TypeSpec 2 可以看出, 这个压缩后的值, 最后两位描述了基类所处于的元数据表在TypeDefOrRef中的编号, 编号之前的位是在该在表中的索引号
FieldList 和MethodList是一个指向Field和Method表中的起始索引的值, 从此开始遍历都是它的Field和Method, 结束于下一个类型的Field和Method表中的起始索引(相当不能超过RowSize), 在Partition II Metadata 的 Field 表一节中有详细的说明
比如FieldList值为0x01, 而下一个类型的FieldList为0x03, 那么0x01和0x02都是该类型的Field索引 下面我们通过代码看如何得到TypeDef 表中的这些值
row = t.Address + t.RowSize * index; //每行的地址, index为类型在TypeDef中的索引
// Flags // Name // Extends // FieldList // MethodList 11/2/2007 强暴.Net程序集 之八 (元数据Token和指定程序入口方法)
警告:本系列文章为本人原创,只作技术研究之用,您可以引用链接传播,禁止其它的转载方式,禁止用于商业或非法目的, 对于造成的一切后果本人概不负责 一般的.net程序都是从一个静态的Main方法开法运行的,下面我将演示如何指定程序集中的另一个方法作为入口方法 假设有如下程序,我们要修改程序集让NewMain先运行 public static void NewMain() 回想一下IMAGE_COR20_HEADER的格式,字段EntryPointToken指定了程序入口 在Partition II Metadata中写道: 它的值不是一个地址,而是一个元数据Token 我们只需要修改此Token就能指定新的入口方法,在我们这个演示中改为NewMain方法的Token,即0x06000002 程序如下:
可以看到.entrypoint伪指令已经在我们指定的NewMain方法中了
11/1/2007 强暴.Net程序集 之七 (强命名的移除)警告:本系列文章为本人原创,只作技术研究之用,您可以引用链接传播,禁止其它的转载方式,禁止用于商业或非法目的, 对于造成的一切后果本人概不负责
先让我们重新看一下IMAGE_COR20_HEADER头的格式:
typedef struct IMAGE_COR20_HEADER { // Header versioning DWORD cb; WORD MajorRuntimeVersion; WORD MinorRuntimeVersion; // Symbol table and startup information IMAGE_DATA_DIRECTORY MetaData; DWORD Flags; DWORD EntryPointToken; // Binding information IMAGE_DATA_DIRECTORY Resources; IMAGE_DATA_DIRECTORY StrongNameSignature; // Regular fixup and binding information
IMAGE_DATA_DIRECTORY CodeManagerTable; IMAGE_DATA_DIRECTORY VTableFixups; IMAGE_DATA_DIRECTORY ExportAddressTableJumps; // Precompiled image info (internal use only - set to zero)
IMAGE_DATA_DIRECTORY ManagedNativeHeader; } IMAGE_COR20_HEADER, *PIMAGE_COR20_HEADER; 移除强名需要修改其中的这两个字段
Flags StrongNameSignature 其中Flags是一个按位或值,我们只需要移去COMIMAGE_FLAGS_STRONGNAMESIGNED
在winnt.h中有其定义: typedef enum ReplacesCorHdrNumericDefines { // COM+ Header entry point flags. COMIMAGE_FLAGS_ILONLY =0x00000001, COMIMAGE_FLAGS_32BITREQUIRED =0x00000002, COMIMAGE_FLAGS_IL_LIBRARY =0x00000004, COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008, COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000, //略 } 然后将StrongNameSignature和VirtualAddress和Size都置为0 第二步是修改Assembly表
将Flags字段的PublicKey位移去 在Partition II Metadata中有描述: PublicKey 0x0001 SideBySideCompatible 0x0000 <reserved> 0x0030 Retargetable 0x0100 EnableJITcompileTracking 0x8000 DisableJITcompileOptimizer 0x4000 另外修改PublicKey字段,将其置为0
代码为:
pCorHeader->Flags &= ~COMIMAGE_FLAGS_STRONGNAMESIGNED; pCorHeader->StrongNameSignature.VirtualAddress = 0; pCorHeader->StrongNameSignature.Size = 0; PMETA_ASSEMBLY_TABLE assemblyTable = (PMETA_ASSEMBLY_TABLE)(tables[TableType::Assembly].Address);
assemblyTable->Flags &= 0x1110; //PublicKey = 0x0001 assemblyTable->PublicKey = 0; 这样我们就将到了一个没有强名的程序集
在.net的非托管 API中提供了一系列和强名相关的函数: StrongNameCompareAssemblies 仅通过二进制签名确定两个指定的程序集是否不同。 StrongNameErrorInfo 获取由强名称方法引发的上一个错误代码。 StrongNameFreeBuffer 释放上一次调用强名称方法时分配的内存。 StrongNameGetBlob 通过位于指定内存地址的可执行文件的二进制表示形式填充指定的缓冲区。 StrongNameGetBlobFromImage 获取位于指定内存地址的程序集映像的二进制表示形式。 StrongNameGetPublicKey 从私钥/公钥对中检索公钥。 StrongNameHashSize 使用指定的哈希算法获取哈希值所需要的缓冲区大小。 StrongNameKeyDelete 删除具有指定容器名称的公钥-私钥对。 StrongNameKeyGen 创建一个用于强名称的公/私钥对。 StrongNameKeyGenEx 创建具有指定密钥大小的公钥/私钥对,以供强名称使用。 StrongNameKeyInstall 向容器中导入公钥-私钥对。 StrongNameSignatureGeneration 生成指定程序集的强名称签名。 StrongNameSignatureGenerationEx 使用指定的密钥容器名称获取指定程序集的强名称签名。 StrongNameSignatureSize 返回强名称签名的大小。 StrongNameSignatureVerification 获取一个指示所提供的可移植的可执行(.dll 或 .exe)文件的程序集清单是否包含强名称签名的值。 StrongNameSignatureVerificationEx 获取一个指示所提供的可移植的可执行(.dll 或 .exe)文件的程序集清单是否包含强名称签名的值。 StrongNameSignatureVerificationFromImage 验证已映射到内存的程序集对关联的公钥是否有效。 StrongNameTokenFromAssembly 从指定的程序集文件中创建强名称标记。 StrongNameTokenFromAssemblyEx 从指定的程序集文件创建强名称标记,并返回公钥。 StrongNameTokenFromPublicKey 返回表示公钥的标记。 |
|
|