道理越辨越明。我不是来吵架的,而是来澄清一些概念。赵劼的看法实在有些偏激,但凡与之意见向左的,一概穷追猛打至死。赵同学在社区的影响力在我之上,但这也正是其可怕之处——一旦有所偏差,必然会误导更多的朋友。有感于他的毁人不倦大多穿凿附会之说,于是,暂时搁下手上的工作,发此文以正视听。
综观赵劼《老赵谈IL:IL是什么,它又不是什么?那么汇编呢?》一文,对我的指责主要集中在2个地方:
其一:我曾经指出,UltraEdit32也可以观察IL中的一些数据,但是没有给出具体操作办法。于是赵劼就单方面理解为我是信口开河,并多次在公开场合抓住这个话柄对我进行诋毁。我其实不是很想提及这个办法,所以一直没有说破,因为这个法子太过BT。介绍如下:
首先,我们信手写一个简单的a.cs文件:
public class Bao
{
public static void Main()
{
System.Console.WriteLine("hello, Jianqiang!");
}
} 编译命令如下:
csc b.cs
于是生成b.exe文件。
我们用UltraEdit32打开它,
以上是第1到第9行,怎么看这个图呢?
开始的MZ是一个魔数,用来纪念设计DOS内存管理系统的人,所有exe文件都是以这两个字母作为开始的,也就是4D和5A,你可以去查ASCII表,但是有了UltraEdit32,我们可以只看右边对应的字母。接下来是一句话:This is program cannot be run in DOS mode。这句话是一句友好的错误信息,会在运行环境不对导致推出时向用户显示。有人会问,中间那些句点和乱码是什么?不要管它,有的时候右边的信息会给我们误导,因为有时我们要一次读2个字节,我们只按照微软文档的offset和size找出那些位于固定位置的信息就可以了。比如说,接下来是PE头的全部所有信息,比如说PE 头的魔数00(第80h行开始4个字节 50 45 00 00, 即PE00),只要按照偏移量和大小来找,都可以找到。
继续找下去,还能发现更多数据:比如说第80h行的4C 01,表示Machine 0x014C,而之后的03 00则表示有3个Section,等等。
看到这里,你也许会觉得很累,没错,我也很累,但是为了证明用UltraEdit32也能看IL中的数据,我只好半夜不睡觉眯着眼睛找这些东西,让某些人心服口服外带佩服。对于PE头,这法子百试百灵。这时候,某些人又会吹毛求屁了,说你有本事找个元数据给我看看啊?注意,我没有说过从UltraEdit32可以看到IL的所有数据,尤其是那些放在#~流中的压缩数据。但是,我另有办法,这法子是一位印度哥哥教我的,就是用C#中的IO操作来读取exe文件,只要按照微软文档定义的规格来做就可以:
还是刚才那个a.exe文件,编写如下代码:
Code
using System;
using System.IO;
using System.Reflection;
public class zzz
{
public static void Main()
{
zzz a = new zzz();
a.abc();
}
int tableoffset;
int[] rows;
int[] offset;
int[] ssize;
byte[] metadata;
byte[] strings;
long valid;
byte[][] names;
public void abc()
{
long startofmetadata;
FileStream s = new FileStream(@"C:\a.exe", FileMode.Open);
BinaryReader r = new BinaryReader(s);
s.Seek(360, SeekOrigin.Begin);
int rva, size;
rva = r.ReadInt32();
size = r.ReadInt32();
int where = rva % 0x2000 + 512;
s.Seek(where + 4 + 4, SeekOrigin.Begin);
rva = r.ReadInt32();
where = rva % 0x2000 + 512;
s.Seek(where, SeekOrigin.Begin);
startofmetadata = s.Position;
s.Seek(4 + 2 + 2 + 4 + 4 + 12 + 2, SeekOrigin.Current);
int streams = r.ReadInt16();
offset = new int[5];
ssize = new int[5];
names = new byte[5][];
names[0] = new byte[10];
names[1] = new byte[10];
names[2] = new byte[10];
names[3] = new byte[10];
names[4] = new byte[10];
int i = 0;
int j;
for (i = 0; i |