Skip to content

Commit

Permalink
Merge pull request #38 from virusdefender/master
Browse files Browse the repository at this point in the history
parse field tag and interface method name
  • Loading branch information
stevemk14ebr authored Oct 6, 2023
2 parents 50c1f83 + ce406e4 commit 49f4186
Showing 1 changed file with 91 additions and 32 deletions.
123 changes: 91 additions & 32 deletions objfile/objfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ package objfile
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"github.com/mandiant/GoReSym/objabi"
"io"
"os"
"sort"
Expand Down Expand Up @@ -841,7 +843,7 @@ func (e *Entry) readVarint(address uint64) (int, int, error) {
}
}

func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr uint64, is64bit bool, littleendian bool) (name string, err error) {
func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr uint64, is64bit bool, littleendian bool) (name string, tag string, err error) {
// name str (for <= 1.16 encodes length like this, beyond it uses a varint encoding)
// The first byte is a bit field containing:
//
Expand Down Expand Up @@ -874,23 +876,24 @@ func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr ui
case "1.5":
fallthrough
case "1.6":
// TODO: parse field tag
// pointer to GoString
nameLen, err := e.ReadPointerSizeMem(namePtr+ptrSize, is64bit, littleendian)
if err != nil {
return "", fmt.Errorf("Failed to read name")
return "", "", fmt.Errorf("Failed to read name")
}

deref, err := e.ReadPointerSizeMem(namePtr, is64bit, littleendian)
if err != nil {
return "", fmt.Errorf("Failed to read name")
return "", "", fmt.Errorf("Failed to read name")
}

name_raw, err := e.raw.read_memory(deref, nameLen)
if err != nil {
return "", fmt.Errorf("Failed to read name")
return "", "", fmt.Errorf("Failed to read name")
}

return string(name_raw), nil
return string(name_raw), "", nil
case "1.7": // types flags exists >= 1.7
fallthrough
case "1.8": // type flag tflagExtraStart exists >= 1.8
Expand All @@ -910,22 +913,41 @@ func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr ui
case "1.15":
fallthrough
case "1.16":
name_len_raw, err := e.raw.read_memory(namePtr, 3)
flag, err := e.raw.read_memory(namePtr, 1)
if err != nil {
return "", fmt.Errorf("Failed to read name")
return "", "", errors.New("Failed to read flag")
}

name_len := uint16(uint16(name_len_raw[1])<<8 | uint16(name_len_raw[2]))
name_len_raw, err := e.raw.read_memory(namePtr+1, 2)
if err != nil {
return "", "", fmt.Errorf("Failed to read name")
}

name_len := uint16(uint16(name_len_raw[0])<<8 | uint16(name_len_raw[1]))
name_raw, err := e.raw.read_memory(namePtr+3, uint64(name_len))
if err != nil {
return "", fmt.Errorf("Failed to read name")
return "", "", fmt.Errorf("Failed to read name")
}

name := string(name_raw)

if flag[0] == 3 {
tag_len_raw, err := e.raw.read_memory(namePtr+3+uint64(name_len), 2)
if err != nil {
return "", "", errors.New("Failed to read tag")
}

tag_len := uint16(uint16(tag_len_raw[0])<<8 | uint16(tag_len_raw[1]))
tag_raw, err := e.raw.read_memory(namePtr+3+uint64(name_len)+2, uint64(tag_len))
if err != nil {
return "", "", errors.New("Failed to read tag")
}
tag = string(tag_raw)
}
if typeFlags&tflagExtraStar != 0 {
return name[1:], nil
return name[1:], tag, nil
} else {
return name, nil
return name, tag, nil
}
case "1.17":
fallthrough
Expand All @@ -938,22 +960,33 @@ func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr ui
case "1.21":
varint_len, namelen, err := e.readVarint(namePtr + 1)
if err != nil {
return "", fmt.Errorf("Failed to read name")
// TODO: replace all misuses of fmt.Errorf to errors.New
return "", "", fmt.Errorf("Failed to read name")
}

name_raw, err := e.raw.read_memory(namePtr+1+uint64(varint_len), uint64(namelen))
if err != nil {
return "", fmt.Errorf("Failed to read name")
return "", "", fmt.Errorf("Failed to read name")
}

name := string(name_raw)

if flag[0] == 3 {
varint_len, taglen, err := e.readVarint(namePtr + 1 + uint64(varint_len) + uint64(namelen))
if err != nil {
return "", "", errors.New("Failed to read tag")
}
tag_raw, err := e.raw.read_memory(namePtr+1+uint64(varint_len)+uint64(namelen)+uint64(varint_len), uint64(taglen))
if err != nil {
return "", "", errors.New("Failed to read tag")
}
tag = string(tag_raw)
}
if typeFlags&tflagExtraStar != 0 {
return name[1:], nil
return name[1:], tag, nil
} else {
return name, nil
return name, tag, nil
}
}
return "", fmt.Errorf("Failed to read name")
return "", "", fmt.Errorf("Failed to read name")
}

func decodePtrSizeBytes(data []byte, is64bit bool, littleendian bool) (result uint64) {
Expand Down Expand Up @@ -1060,7 +1093,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
return parsedTypesIn, fmt.Errorf("Failed to parse type")
}

name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
name, _, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1078,7 +1111,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
return parsedTypesIn, fmt.Errorf("Failed to parse type")
}

name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
name, _, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1097,7 +1130,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
return parsedTypesIn, fmt.Errorf("Failed to parse type")
}

name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
name, _, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1114,7 +1147,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
return parsedTypesIn, fmt.Errorf("Failed to parse type")
}

name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
name, _, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand Down Expand Up @@ -1144,7 +1177,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
return parsedTypesIn, fmt.Errorf("Failed to parse type")
}
name_ptr := moduleData.Types + uint64(rtype.Str)
name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
name, _, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1160,7 +1193,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
return parsedTypesIn, fmt.Errorf("Failed to parse type")
}
name_ptr := moduleData.Types + uint64(rtype.Str)
name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
name, _, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand Down Expand Up @@ -1192,7 +1225,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
return parsedTypesIn, fmt.Errorf("Failed to parse type")
}
name_ptr := moduleData.Types + uint64(rtype.Str)
name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
name, _, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1208,7 +1241,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
return parsedTypesIn, fmt.Errorf("Failed to parse type")
}
name_ptr := moduleData.Types + uint64(rtype.Str)
name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
name, _, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand Down Expand Up @@ -1449,6 +1482,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn)
methodfunc, found := parsedTypesIn.Get(typeAddr)
if found {
// TODO: parse method name
interfaceDef += "\nmethod" + strconv.Itoa(i) + " " + methodfunc.(Type).Str
cinterfaceDef += methodfunc.(Type).CStr + "method" + strconv.Itoa(i) + ";\n"
}
Expand Down Expand Up @@ -1538,11 +1572,16 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty

typeAddr := moduleData.Types + uint64(method.Typ)
parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn)
name_ptr := moduleData.Types + uint64(method.Name)
name, _, err := e.readRTypeName(runtimeVersion, 0, name_ptr, is64bit, littleendian)
if err != nil {
name = "method" + strconv.Itoa(i)
}

methodfunc, found := parsedTypesIn.Get(typeAddr)
if found {
interfaceDef += "\nmethod" + strconv.Itoa(i) + " " + methodfunc.(Type).Str
cinterfaceDef += methodfunc.(Type).CStr + " method" + strconv.Itoa(i) + ";\n"
interfaceDef += name + strings.TrimPrefix(methodfunc.(Type).Str, "func") + "\n"
cinterfaceDef += methodfunc.(Type).CStr + " " + name + ";\n"
}
}
interfaceDef += "\n}"
Expand Down Expand Up @@ -1605,9 +1644,19 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
field, found := parsedTypesIn.Get(typeAddr)
if found {
typeNameAddr := decodePtrSizeBytes(data[0:ptrSize], is64bit, littleendian)
typeName, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian)
typeName, tag, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian)
if err == nil {
structDef += fmt.Sprintf("\n %-10s %s", typeName, field.(Type).Str)
var fieldStr string
if field.(Type).kindEnum == objabi.KindStruct {
fieldStr = strings.TrimPrefix(field.(Type).Reconstructed, "type ")
} else {
fieldStr = field.(Type).Str
}
if tag != "" {
structDef += fmt.Sprintf("\n %-10s %s `%s`", typeName, fieldStr, tag)
} else {
structDef += fmt.Sprintf("\n %-10s %s", typeName, fieldStr)
}
cstructDef += fmt.Sprintf(" %-10s %s;\n", field.(Type).CStr, replace_cpp_keywords(typeName))
}
}
Expand Down Expand Up @@ -1700,9 +1749,19 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
field, found := parsedTypesIn.Get(typeAddr)
if found {
typeNameAddr := decodePtrSizeBytes(data[0:ptrSize], is64bit, littleendian)
typeName, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian)
typeName, tag, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian)
if err == nil {
structDef += fmt.Sprintf("\n %-10s %s", typeName, field.(Type).Str)
var fieldStr string
if field.(Type).kindEnum == objabi.KindStruct {
fieldStr = strings.TrimPrefix(field.(Type).Reconstructed, "type ")
} else {
fieldStr = field.(Type).Str
}
if tag != "" {
structDef += fmt.Sprintf("\n %-10s %s `%s`", typeName, fieldStr, tag)
} else {
structDef += fmt.Sprintf("\n %-10s %s", typeName, fieldStr)
}
cstructDef += fmt.Sprintf(" %-10s %s;\n", field.(Type).CStr, replace_cpp_keywords(typeName))
}
}
Expand Down

0 comments on commit 49f4186

Please sign in to comment.