public void Phase3(MetadataProcessor.MetadataAccessor accessor)
            {
                MethodTable tbl = accessor.TableHeap.GetTable <MethodTable>(Table.Method);

                accessor.Codes.Position = 0;
                codes = accessor.Codes.ReadBytes(accessor.Codes.Length);
                accessor.Codes.Reset(null);
                accessor.Codes.Position = 0;

                uint          bas = accessor.Codebase;
                List <object> o   = new List <object>();

                for (int i = 0; i < tbl.Length; i++)
                {
                    if (tbl[i].Col1 == 0)
                    {
                        continue;
                    }
                    if (excludes.Contains(i) || (tbl[i].Col2 & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.IL)
                    {
                        if ((tbl[i].Col2 & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.IL)
                        {
                            accessor.Codes.WriteBytes(((accessor.Codes.Position + 15) & ~15) - accessor.Codes.Position);
                        }
                        tbl[i].Col1 = (uint)accessor.Codes.Position + bas;

                        Range  range = accessor.BodyRanges[new MetadataToken(TokenType.Method, i + 1)];
                        byte[] buff  = new byte[range.Length];
                        Buffer.BlockCopy(codes, (int)(range.Start - bas), buff, 0, buff.Length);
                        accessor.Codes.WriteBytes(buff);
                        accessor.Codes.WriteBytes(((accessor.Codes.Position + 3) & ~3) - accessor.Codes.Position);
                    }
                    else
                    {
                        tbl[i].Col2 |= MethodImplAttributes.NoInlining;

                        Range range = accessor.BodyRanges[new MetadataToken(TokenType.Method, i + 1)];
                        range = new Range(range.Start - bas, range.Length);
                        ExtractRefs(bodies[i], i, o);
                        var dat = Transform(bodies[i], i, codes, range);
                        o.Add(dat);
                    }
                }

                int[] randArray = new int[o.Count];
                for (int i = 0; i < o.Count; i++)
                {
                    randArray[i] = Confuser.Random.Next();
                }
                object[] objs = o.ToArray();
                Array.Sort(randArray, objs);

                var mtdDats = new Dictionary <int, MethodData>();

                foreach (var i in objs)
                {
                    if (i is MethodData)
                    {
                        MethodData mtdDat = i as MethodData;
                        mtdDats[mtdDat.Index] = mtdDat;
                        mtdDat.BufferOffset   = finalDat.Position;
                        finalDat.WriteBytes(mtdDat.Serialize(fieldLayout));

                        Confuser.Database.AddEntry("AntiTamper", (0x06000001 + mtdDat.Index).ToString("X"), mtdDat.BufferOffset);
                    }
                    else
                    {
                        StringData strDat = i as StringData;
                        strDat.BufferOffset = finalDat.Position;
                        finalDat.WriteBytes(strDat.Serialize(key5));

                        Confuser.Database.AddEntry("AntiTamper", strDat.String, strDat.BufferOffset);
                    }
                }

                foreach (var i in objs)
                {
                    if (i is StringData)
                    {
                        StringData dat   = i as StringData;
                        uint       token = 0x70800000;
                        token |= (uint)dat.BufferOffset;
                        Buffer.BlockCopy(BitConverter.GetBytes(token), 0, mtdDats[dat.Index].ILCodes, dat.Offset, 4);
                    }
                }

                byte[] randBuff = new byte[4];
                foreach (var i in mtdDats)
                {
                    uint ptr = (uint)i.Value.BufferOffset;

                    Confuser.Random.NextBytes(randBuff);
                    uint key = BitConverter.ToUInt32(randBuff, 0);
                    tbl[i.Key].Col1 = (uint)accessor.Codes.Position + bas;
                    byte[] buff = i.Value.Serialize(fieldLayout);
                    Crypt(buff, key * (uint)key4, key);
                    finalDat.Position = i.Value.BufferOffset;
                    finalDat.WriteBytes(buff);

                    accessor.Codes.WriteByte(0x46); //flags
                    accessor.Codes.WriteByte(0x21); //ldc.i8
                    accessor.Codes.WriteUInt64(((ulong)key << 32) | (ptr ^ key));
                    accessor.Codes.WriteByte(0x20); //ldc.i4
                    accessor.Codes.WriteUInt32(~(uint)buff.Length ^ key);
                    accessor.Codes.WriteByte(0x26);

                    accessor.BlobHeap.Position = (int)tbl[i.Key].Col5;
                    accessor.BlobHeap.ReadCompressedUInt32();
                    byte flags = accessor.BlobHeap.ReadByte();
                    if ((flags & 0x10) != 0)
                    {
                        accessor.BlobHeap.ReadCompressedUInt32();
                    }
                    accessor.BlobHeap.ReadCompressedUInt32();
                    bool hasRet = false;
                    do
                    {
                        byte t = accessor.BlobHeap.ReadByte();
                        if (t == 0x1f || t == 0x20)
                        {
                            continue;
                        }
                        hasRet = t != 0x01;
                    } while (false);

                    accessor.Codes.WriteByte(hasRet ? (byte)0x00 : (byte)0x26);
                    accessor.Codes.WriteByte(0x2a); //ret
                    accessor.Codes.WriteBytes(((accessor.Codes.Position + 3) & ~3) - accessor.Codes.Position);
                }

                accessor.USHeap.Reset(new byte[0]);
            }