github.com/pkujhd/goloader@v0.0.0-20240411034752-1a28096bd7bd/registerInExe.go (about)

     1  package goloader
     2  
     3  import (
     4  	"cmd/objfile/objfile"
     5  	"debug/elf"
     6  	"debug/gosym"
     7  	"debug/macho"
     8  	"debug/pe"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"reflect"
    12  	"runtime"
    13  	"unsafe"
    14  )
    15  
    16  type typedata struct {
    17  	data      []byte
    18  	saddr     uintptr
    19  	naddr     uintptr
    20  	byteOrder binary.ByteOrder
    21  	adapted   map[int32]int32
    22  }
    23  
    24  func (td *typedata) adaptPtr(dataOff int) uintptr {
    25  	ptr := uintptr(td.byteOrder.Uint64(td.data[dataOff:]))
    26  	if PtrSize == Uint32Size {
    27  		ptr = uintptr(td.byteOrder.Uint32(td.data[dataOff:]))
    28  	}
    29  	putAddress(td.byteOrder, td.data[dataOff:], uint64(ptr+td.naddr-td.saddr))
    30  	return ptr + td.naddr - td.saddr
    31  }
    32  
    33  func (td *typedata) adaptType(tl int32) {
    34  	if _, ok := td.adapted[tl]; ok {
    35  		return
    36  	}
    37  	td.adapted[tl] = tl
    38  	t := (*_type)(adduintptr(td.naddr, int(tl)))
    39  	switch t.Kind() {
    40  	case reflect.Array, reflect.Ptr, reflect.Chan, reflect.Slice:
    41  		//Element
    42  		addr := td.adaptPtr(int(tl) + _typeSize)
    43  		td.adaptType(int32(addr - td.naddr))
    44  	case reflect.Func:
    45  		f := (*funcType)(unsafe.Pointer(t))
    46  		inOutCount := f.inCount + f.outCount&(1<<15-1)
    47  		uadd := funcTypeSize
    48  		if f.tflag&tflagUncommon != 0 {
    49  			uadd += uncommonTypeSize
    50  		}
    51  		uadd += int(tl)
    52  		for i := 0; i < int(inOutCount); i++ {
    53  			addr := td.adaptPtr(int(uadd + i*PtrSize))
    54  			td.adaptType(int32(addr - td.naddr))
    55  		}
    56  	case reflect.Interface:
    57  		//pkgPath
    58  		td.adaptPtr(int(tl + int32(_typeSize)))
    59  		//imethod slice.Data
    60  		td.adaptPtr(int(tl + int32(_typeSize+PtrSize)))
    61  	case reflect.Map:
    62  		//Key
    63  		addr := td.adaptPtr(int(tl) + _typeSize)
    64  		td.adaptType(int32(addr - td.naddr))
    65  		//Elem
    66  		addr = td.adaptPtr(int(tl) + _typeSize + PtrSize)
    67  		td.adaptType(int32(addr - td.naddr))
    68  		//Bucket
    69  		addr = td.adaptPtr(int(tl) + _typeSize + PtrSize + PtrSize)
    70  		td.adaptType(int32(addr - td.naddr))
    71  	case reflect.Struct:
    72  		//PkgPath
    73  		td.adaptPtr(int(tl + int32(_typeSize)))
    74  		s := (*sliceHeader)(unsafe.Pointer(&td.data[tl+int32(_typeSize+PtrSize)]))
    75  		for i := 0; i < s.Len; i++ {
    76  			//Filed Name
    77  			off := s.Data - td.saddr + +uintptr(3*i)*PtrSize
    78  			td.adaptPtr(int(off))
    79  			//Field Type
    80  			addr := td.adaptPtr(int(off + PtrSize))
    81  			td.adaptType(int32(addr - td.naddr))
    82  		}
    83  		s.Data = s.Data + td.naddr - td.saddr
    84  	case reflect.Bool,
    85  		reflect.Int, reflect.Uint,
    86  		reflect.Int64, reflect.Uint64,
    87  		reflect.Int32, reflect.Uint32,
    88  		reflect.Int16, reflect.Uint16,
    89  		reflect.Int8, reflect.Uint8,
    90  		reflect.Float64, reflect.Float32,
    91  		reflect.Complex64, reflect.Complex128,
    92  		reflect.String, reflect.UnsafePointer,
    93  		reflect.Uintptr:
    94  		//noting todo
    95  	default:
    96  		panic(fmt.Errorf("not deal reflect type:%s", t.Kind()))
    97  	}
    98  }
    99  
   100  func registerTypesInMacho(path string, symPtr map[string]uintptr) error {
   101  	machoFile, _ := macho.Open(path)
   102  	typeLinkSect := machoFile.Section("__typelink")
   103  	typeLinkSectData, err := typeLinkSect.Data()
   104  	if err != nil {
   105  		return err
   106  	}
   107  	roDataSect := machoFile.Section("__rodata")
   108  	roDataSectData, err := roDataSect.Data()
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	byteOrder := machoFile.ByteOrder
   114  	typelinks := *ptr2uint32slice(uintptr(unsafe.Pointer(&typeLinkSectData[0])), len(typeLinkSectData)/Uint32Size)
   115  	_registerTypesInExe(symPtr, byteOrder, typelinks, roDataSectData, uintptr(roDataSect.Addr))
   116  	return nil
   117  }
   118  
   119  func registerTypesInElf(path string, symPtr map[string]uintptr) error {
   120  	elfFile, _ := elf.Open(path)
   121  	typeLinkSect := elfFile.Section(".typelink")
   122  	typeLinkSectData, err := typeLinkSect.Data()
   123  	if err != nil {
   124  		return err
   125  	}
   126  	roDataSect := elfFile.Section(".rodata")
   127  	roDataSectData, err := roDataSect.Data()
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	byteOrder := elfFile.ByteOrder
   133  	typelinks := *ptr2uint32slice(uintptr(unsafe.Pointer(&typeLinkSectData[0])), len(typeLinkSectData)/Uint32Size)
   134  	_registerTypesInExe(symPtr, byteOrder, typelinks, roDataSectData, uintptr(roDataSect.Addr))
   135  	return nil
   136  }
   137  
   138  func registerTypesInPE(path string, symPtr map[string]uintptr) error {
   139  	peFile, _ := pe.Open(path)
   140  	getSymbolInPe := func(symbols []*pe.Symbol, symbolName string) *pe.Symbol {
   141  		for _, sym := range symbols {
   142  			if sym.Name == symbolName {
   143  				return sym
   144  			}
   145  		}
   146  		return nil
   147  	}
   148  	typelinkSym := getSymbolInPe(peFile.Symbols, "runtime.typelink")
   149  	moduledataSym := getSymbolInPe(peFile.Symbols, "runtime.firstmoduledata")
   150  
   151  	roDataSect := peFile.Section(".rdata")
   152  	roDataSectData, err := roDataSect.Data()
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	dataSect := peFile.Section(".data")
   158  	dataSectData, err := dataSect.Data()
   159  	if err != nil {
   160  		return err
   161  	}
   162  
   163  	md := (*moduledata)(unsafe.Pointer(&dataSectData[moduledataSym.Value]))
   164  	typelinks := *ptr2uint32slice(uintptr(unsafe.Pointer(&roDataSectData[typelinkSym.Value])), len(md.typelinks))
   165  
   166  	getImageBase := func(peFile *pe.File) uintptr {
   167  		_, pe64 := peFile.OptionalHeader.(*pe.OptionalHeader64)
   168  		if pe64 {
   169  			return uintptr(peFile.OptionalHeader.(*pe.OptionalHeader64).ImageBase)
   170  		} else {
   171  			return uintptr(peFile.OptionalHeader.(*pe.OptionalHeader32).ImageBase)
   172  		}
   173  	}
   174  	_registerTypesInExe(symPtr, binary.LittleEndian, typelinks, roDataSectData, uintptr(roDataSect.VirtualAddress)+getImageBase(peFile))
   175  	return nil
   176  }
   177  
   178  func _registerTypesInExe(symPtr map[string]uintptr, byteOrder binary.ByteOrder, typelinks []int32, data []byte, addr uintptr) {
   179  	md := &moduledata{typelinks: typelinks}
   180  	md.types = uintptr(unsafe.Pointer(&data[0]))
   181  	md.etypes = md.types + uintptr(len(data))
   182  
   183  	td := typedata{
   184  		data:      data,
   185  		saddr:     addr,
   186  		naddr:     md.types,
   187  		byteOrder: byteOrder,
   188  		adapted:   make(map[int32]int32),
   189  	}
   190  	modulesLock.Lock()
   191  	addModule(md)
   192  	modulesLock.Unlock()
   193  	for _, tl := range md.typelinks {
   194  		td.adaptType(tl)
   195  	}
   196  	for _, tl := range md.typelinks {
   197  		registerType((*_type)(adduintptr(md.types, int(tl))), symPtr)
   198  	}
   199  	modulesLock.Lock()
   200  	removeModule(md)
   201  	modulesLock.Unlock()
   202  }
   203  
   204  func registerTypesInExe(symPtr map[string]uintptr, path string) error {
   205  	f, err := objfile.Open(path)
   206  	if err != nil {
   207  		return err
   208  	}
   209  	defer f.Close()
   210  	pcLineTable, err := f.PCLineTable()
   211  	if err != nil {
   212  		return err
   213  	}
   214  	for _, f := range pcLineTable.(*gosym.Table).Funcs {
   215  		symPtr[f.Name] = uintptr(f.Entry)
   216  	}
   217  
   218  	switch runtime.GOOS {
   219  	case "linux", "android":
   220  		return registerTypesInElf(path, symPtr)
   221  	case "darwin":
   222  		return registerTypesInMacho(path, symPtr)
   223  	case "windows":
   224  		return registerTypesInPE(path, symPtr)
   225  	default:
   226  		panic(fmt.Errorf("unsupported platform:%s", runtime.GOOS))
   227  	}
   228  }