func testparse(c *Class, members []member_info, method bool, t *testing.T) { for i := range members { var p descriptors.DESCRIPTORS desc := c.Constant_pool.Lut(members[i].Descriptor_index).String() if !p.Parse(desc) || p.RootNode().Range.End != len(desc) { t.Errorf("Failed to parse descriptor: %s\n%s\n%s", p.Error(), desc, p.RootNode()) } var p2 signatures.SIGNATURES for _, attr := range members[i].Attributes { if c.Constant_pool.Lut(attr.Attribute_name_index).String() == "Signature" { br := util.BinaryReader{bytes.NewReader(attr.Info), util.BigEndian} if i16, err := br.Uint16(); err != nil { t.Error(err) } else { sign := c.Constant_pool.Lut(u2(i16)).String() p2.SetData(sign) var ret bool if method { ret = p2.MethodTypeSignature() } else { ret = p2.FieldTypeSignature() } p2.RootNode().UpdateRange() if !ret || p2.RootNode().Range.End != len(sign) { t.Errorf("Failed to parse signature: %s\n%s\n%s", p2.Error(), desc, p2.RootNode()) } } } } } }
func (a *attribute_info) String(c *ConstantPool) (ret string) { ret = c.Lut(a.Attribute_name_index).String() switch n := c.Lut(a.Attribute_name_index).String(); n { case "Signature", "SourceFile": ret += "=" br := util.BinaryReader{bytes.NewReader(a.Info), util.BigEndian} if i16, err := br.Uint16(); err != nil { ret += err.Error() } else { ret += c.Lut(u2(i16)).String() } case "Code": ret += " (" var cl Code_attribute br := util.BinaryReader{bytes.NewReader(a.Info), util.BigEndian} if err := br.ReadInterface(&cl); err != nil { ret += err.Error() } else { for _, a2 := range cl.Attributes { ret += fmt.Sprintf(" %s", c.Lut(a2.Attribute_name_index)) } } ret += " )" } return ret }
func (m *MetadataUtil) ReadIndex(br *util.BinaryReader, size uint) (uint32, error) { if size == 2 { if v, e := br.Uint16(); e != nil { return 0, e } else { return uint32(v), nil } } return br.Uint32() }
func NewClass(reader io.ReadSeeker) (*Class, error) { r := util.BinaryReader{reader, binary.BigEndian} var c Class if err := r.ReadInterface(&c); err != nil { return nil, err } else if c.Magic != magic { return nil, errors.New(fmt.Sprintf("Magic isn't what's expected: %x", c.Magic)) } return &c, nil }
func (c *ConstantPool) Read(br *util.BinaryReader) error { var count uint16 if err := br.ReadInterface(&count); err != nil { return err } else { ic := int(count) ic-- c.constants = make([]Constant, ic, ic) for i := 0; i < len(c.constants); i++ { cc := &c.constants[i] cc.cp = c if err := c.readConstant(cc, br); err != nil { return err } if cc.Tag == CONSTANT_Double || cc.Tag == CONSTANT_Long { // All 8-byte constants take up two entries in the constant_pool table of the class file. i++ } } } return nil }
func LoadAssembly(r io.ReadSeeker) (*Assembly, error) { var ( br = util.BinaryReader{r, binary.LittleEndian} err error pe_offset uint32 coff coff_file_header cor20 image_cor20 t MetadataHeader ) if _, err := r.Seek(pe_signature_offset, 0); err != nil { return nil, err } if pe_offset, err = br.Uint32(); err != nil { return nil, err } else if _, err := r.Seek(int64(pe_offset), 0); err != nil { return nil, err } if err := br.ReadInterface(&coff); err != nil { return nil, err } net := coff.OptionalHeader.RVAS[14] off := coff.VirtualToFileOffset(net.VirtualAddress) if _, err := br.Seek(int64(off), 0); err != nil { return nil, err } if err := br.ReadInterface(&cor20); err != nil { return nil, err } off = coff.VirtualToFileOffset(cor20.MetaData.VirtualAddress) if _, err := br.Seek(int64(off), 0); err != nil { return nil, err } if err := br.ReadInterface(&t); err != nil { return nil, err } if _, err := br.Seek(int64(off), 0); err != nil { return nil, err } if md, err := t.MetadataUtil(&br); err != nil { return nil, err } else { return &Assembly{*md}, nil } }
func (m *MetadataUtil) Create(br *util.BinaryReader, v interface{}) error { t := reflect.ValueOf(v) if t.Kind() != reflect.Ptr { return errors.New(fmt.Sprintf("Expected a pointer not %s", t.Kind())) } v2 := t.Elem() name := v2.Type().Name() if name == "StringIndex" { size := m.StringHeap.RowSize index, err := m.ReadIndex(br, uint(size)) if err != nil { return err } data := m.StringHeap.data[index:m.StringHeap.Rows] for i := range data { if data[i] == '\u0000' { data = data[:i] break } } v2.SetString(string(data)) } else if name == "Guid" { size := m.GuidHeap.RowSize if index, err := m.ReadIndex(br, uint(size)); err != nil { return err } else if index != 0 { index = (index - 1) * 16 g := Guid(m.GuidHeap.data[index : index+16]) v2.Set(reflect.ValueOf(g)) } } else if strings.HasSuffix(name, "EncodedIndex") { if size, err := m.Size(v2.Type()); err != nil { return err } else { idx, err := m.ReadIndex(br, size) if err != nil { return err } var ( tables = enc_lut[idx_name_lut[name]] b = util.Bits(len(tables)) mask = uint32(0xffff << b) tbl = idx &^ mask ti ConcreteTableIndex ) idx = idx >> b ti.index = idx ti.table = tables[int(tbl)] ti.metadataUtil = m v2.Set(reflect.ValueOf(&ti)) } } else if strings.HasSuffix(name, "Index") { if size, err := m.Size(v2.Type()); err != nil { return err } else { var ti ConcreteTableIndex if ti.index, err = m.ReadIndex(br, size); err != nil { return err } if name == "BlobIndex" { ti.table = id_Blob } else { ti.table = idx_name_lut[name] } ti.metadataUtil = m v2.Set(reflect.ValueOf(&ti)) } } else { switch v2.Kind() { case reflect.Struct: for i := 0; i < v2.NumField(); i++ { f := v2.Field(i) a := f.Addr() if err := m.Create(br, a.Interface()); err != nil { return err } } default: return br.ReadInterface(v) } } return nil }
func (mh *MetadataHeader) MetadataUtil(br *util.BinaryReader) (*MetadataUtil, error) { var ( ret MetadataUtil ) off, err := br.Seek(0, 1) if err != nil { return nil, err } base := off for _, h := range mh.StreamHeaders { switch h.Name { case "#~": off += int64(h.Offset) case "#Strings": if _, err := br.Seek(base+int64(h.Offset), 0); err != nil { return nil, err } else if ret.StringHeap.data, err = br.Read(int(h.Size)); err != nil { return nil, err } ret.StringHeap.Rows = h.Size case "#Blob": if _, err := br.Seek(base+int64(h.Offset), 0); err != nil { return nil, err } else if ret.BlobHeap.data, err = br.Read(int(h.Size)); err != nil { return nil, err } ret.BlobHeap.Rows = h.Size case "#GUID": if _, err := br.Seek(base+int64(h.Offset), 0); err != nil { return nil, err } else if ret.GuidHeap.data, err = br.Read(int(h.Size)); err != nil { return nil, err } ret.GuidHeap.Rows = h.Size } } if _, err := br.Seek(off, 0); err != nil { return nil, err } h := hash_tilde_stream_header{} if err := br.ReadInterface(&h); err != nil { return nil, err } if h.HeapSizes&bit_stringHeapIndexSize != 0 { ret.StringHeap.RowSize = 4 } else { ret.StringHeap.RowSize = 2 } if h.HeapSizes&bit_blobHeapIndexSize != 0 { ret.BlobHeap.RowSize = 4 } else { ret.BlobHeap.RowSize = 2 } if h.HeapSizes&bit_guidHeapIndexSize != 0 { ret.GuidHeap.RowSize = 4 } else { ret.GuidHeap.RowSize = 2 } for i := range ret.Tables { if valid := (h.Valid >> uint(i)) & 1; valid != 0 { if ret.Tables[i].Rows, err = br.Uint32(); err != nil { return nil, err } ret.Tables[i].RowType = table_row_type_lut[i] } } for i := range ret.Tables { if ret.Tables[i].Rows != 0 { if size, err := ret.Size(ret.Tables[i].RowType); err != nil { return nil, err } else { ret.Tables[i].RowSize = uint32(size) if ret.Tables[i].data, err = br.Read(int(ret.Tables[i].RowSize * ret.Tables[i].Rows)); err != nil { return nil, err } } } } return &ret, nil }
func (cp *ConstantPool) readConstant(c *Constant, br *util.BinaryReader) error { if err := br.ReadInterface(&c.Tag); err != nil { return err } else { switch c.Tag { case CONSTANT_String: fallthrough case CONSTANT_MethodType: fallthrough case CONSTANT_Class: return br.ReadInterface(&c.Index[0]) case CONSTANT_Fieldref: fallthrough case CONSTANT_Methodref: fallthrough case CONSTANT_NameAndType: fallthrough case CONSTANT_InvokeDynamic: fallthrough case CONSTANT_InterfaceMethodref: if err := br.ReadInterface(&c.Index[0]); err != nil { return err } else { return br.ReadInterface(&c.Index[1]) } case CONSTANT_Integer: var v int32 return br.ReadInterface(&v) case CONSTANT_Float: var v float32 return br.ReadInterface(&v) case CONSTANT_Long: var v int64 return br.ReadInterface(&v) case CONSTANT_Double: var v float64 return br.ReadInterface(&v) case CONSTANT_Utf8: var length u2 if err := br.ReadInterface(&length); err != nil { return err } else if d, err := br.Read(int(length)); err != nil { return err } else { c.Value = string(d) } case CONSTANT_MethodHandle: var ref_kind u1 if err := br.ReadInterface(&ref_kind); err != nil { return err } else { c.Index[0] = u2(ref_kind) return br.ReadInterface(&c.Index[1]) } default: return errors.New(fmt.Sprintf("Unimplemented tag: %d", c.Tag)) } } return nil }