exe.go (7203B)
1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package goversion 6 7 import ( 8 "bytes" 9 "debug/elf" 10 "debug/macho" 11 "debug/pe" 12 "encoding/binary" 13 "fmt" 14 "io" 15 "os" 16 ) 17 18 type sym struct { 19 Name string 20 Addr uint64 21 Size uint64 22 } 23 24 type exe interface { 25 AddrSize() int // bytes 26 ReadData(addr, size uint64) ([]byte, error) 27 Symbols() ([]sym, error) 28 SectionNames() []string 29 Close() error 30 ByteOrder() binary.ByteOrder 31 Entry() uint64 32 TextRange() (uint64, uint64) 33 RODataRange() (uint64, uint64) 34 } 35 36 func openExe(file string) (exe, error) { 37 f, err := os.Open(file) 38 if err != nil { 39 return nil, err 40 } 41 data := make([]byte, 16) 42 if _, err := io.ReadFull(f, data); err != nil { 43 return nil, err 44 } 45 f.Seek(0, 0) 46 if bytes.HasPrefix(data, []byte("\x7FELF")) { 47 e, err := elf.NewFile(f) 48 if err != nil { 49 f.Close() 50 return nil, err 51 } 52 return &elfExe{f, e}, nil 53 } 54 if bytes.HasPrefix(data, []byte("MZ")) { 55 e, err := pe.NewFile(f) 56 if err != nil { 57 f.Close() 58 return nil, err 59 } 60 return &peExe{f, e}, nil 61 } 62 if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) { 63 e, err := macho.NewFile(f) 64 if err != nil { 65 f.Close() 66 return nil, err 67 } 68 return &machoExe{f, e}, nil 69 } 70 return nil, fmt.Errorf("unrecognized executable format") 71 } 72 73 type elfExe struct { 74 os *os.File 75 f *elf.File 76 } 77 78 func (x *elfExe) AddrSize() int { return 0 } 79 80 func (x *elfExe) ByteOrder() binary.ByteOrder { return x.f.ByteOrder } 81 82 func (x *elfExe) Close() error { 83 return x.os.Close() 84 } 85 86 func (x *elfExe) Entry() uint64 { return x.f.Entry } 87 88 func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) { 89 for _, prog := range x.f.Progs { 90 // The following line was commented from the original code. 91 //fmt.Printf("%#x %#x %#x\n", addr, prog.Vaddr, prog.Vaddr+prog.Filesz) 92 if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 { 93 n := prog.Vaddr + prog.Filesz - addr 94 if n > size { 95 n = size 96 } 97 data := make([]byte, n) 98 _, err := prog.ReadAt(data, int64(addr-prog.Vaddr)) 99 if err != nil { 100 return nil, err 101 } 102 return data, nil 103 } 104 } 105 return nil, fmt.Errorf("address not mapped") 106 } 107 108 func (x *elfExe) Symbols() ([]sym, error) { 109 syms, err := x.f.Symbols() 110 if err != nil { 111 return nil, err 112 } 113 var out []sym 114 for _, s := range syms { 115 out = append(out, sym{s.Name, s.Value, s.Size}) 116 } 117 return out, nil 118 } 119 120 func (x *elfExe) SectionNames() []string { 121 var names []string 122 for _, sect := range x.f.Sections { 123 names = append(names, sect.Name) 124 } 125 return names 126 } 127 128 func (x *elfExe) TextRange() (uint64, uint64) { 129 for _, p := range x.f.Progs { 130 if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 { 131 return p.Vaddr, p.Vaddr + p.Filesz 132 } 133 } 134 return 0, 0 135 } 136 137 func (x *elfExe) RODataRange() (uint64, uint64) { 138 for _, p := range x.f.Progs { 139 if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_R|elf.PF_W|elf.PF_X) == elf.PF_R { 140 return p.Vaddr, p.Vaddr + p.Filesz 141 } 142 } 143 for _, p := range x.f.Progs { 144 if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_R|elf.PF_W|elf.PF_X) == (elf.PF_R|elf.PF_X) { 145 return p.Vaddr, p.Vaddr + p.Filesz 146 } 147 } 148 return 0, 0 149 } 150 151 type peExe struct { 152 os *os.File 153 f *pe.File 154 } 155 156 func (x *peExe) imageBase() uint64 { 157 switch oh := x.f.OptionalHeader.(type) { 158 case *pe.OptionalHeader32: 159 return uint64(oh.ImageBase) 160 case *pe.OptionalHeader64: 161 return oh.ImageBase 162 } 163 return 0 164 } 165 166 func (x *peExe) AddrSize() int { 167 if x.f.Machine == pe.IMAGE_FILE_MACHINE_AMD64 { 168 return 8 169 } 170 return 4 171 } 172 173 func (x *peExe) ByteOrder() binary.ByteOrder { return binary.LittleEndian } 174 175 func (x *peExe) Close() error { 176 return x.os.Close() 177 } 178 179 func (x *peExe) Entry() uint64 { 180 switch oh := x.f.OptionalHeader.(type) { 181 case *pe.OptionalHeader32: 182 return uint64(oh.ImageBase + oh.AddressOfEntryPoint) 183 case *pe.OptionalHeader64: 184 return oh.ImageBase + uint64(oh.AddressOfEntryPoint) 185 } 186 return 0 187 } 188 189 func (x *peExe) ReadData(addr, size uint64) ([]byte, error) { 190 addr -= x.imageBase() 191 data := make([]byte, size) 192 for _, sect := range x.f.Sections { 193 if uint64(sect.VirtualAddress) <= addr && addr+size-1 <= uint64(sect.VirtualAddress+sect.Size-1) { 194 _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress))) 195 if err != nil { 196 return nil, err 197 } 198 return data, nil 199 } 200 } 201 return nil, fmt.Errorf("address not mapped") 202 } 203 204 func (x *peExe) Symbols() ([]sym, error) { 205 base := x.imageBase() 206 var out []sym 207 for _, s := range x.f.Symbols { 208 if s.SectionNumber <= 0 || int(s.SectionNumber) > len(x.f.Sections) { 209 continue 210 } 211 sect := x.f.Sections[s.SectionNumber-1] 212 out = append(out, sym{s.Name, uint64(s.Value) + base + uint64(sect.VirtualAddress), 0}) 213 } 214 return out, nil 215 } 216 217 func (x *peExe) SectionNames() []string { 218 var names []string 219 for _, sect := range x.f.Sections { 220 names = append(names, sect.Name) 221 } 222 return names 223 } 224 225 func (x *peExe) TextRange() (uint64, uint64) { 226 // Assume text is first non-empty section. 227 for _, sect := range x.f.Sections { 228 if sect.VirtualAddress != 0 && sect.Size != 0 { 229 return uint64(sect.VirtualAddress) + x.imageBase(), uint64(sect.VirtualAddress+sect.Size) + x.imageBase() 230 } 231 } 232 return 0, 0 233 } 234 235 func (x *peExe) RODataRange() (uint64, uint64) { 236 return x.TextRange() 237 } 238 239 type machoExe struct { 240 os *os.File 241 f *macho.File 242 } 243 244 func (x *machoExe) AddrSize() int { 245 if x.f.Cpu&0x01000000 != 0 { 246 return 8 247 } 248 return 4 249 } 250 251 func (x *machoExe) ByteOrder() binary.ByteOrder { return x.f.ByteOrder } 252 253 func (x *machoExe) Close() error { 254 return x.os.Close() 255 } 256 257 func (x *machoExe) Entry() uint64 { 258 for _, load := range x.f.Loads { 259 b, ok := load.(macho.LoadBytes) 260 if !ok { 261 continue 262 } 263 // TODO: Other thread states. 264 bo := x.f.ByteOrder 265 const x86_THREAD_STATE64 = 4 266 cmd, siz := macho.LoadCmd(bo.Uint32(b[0:4])), bo.Uint32(b[4:8]) 267 if cmd == macho.LoadCmdUnixThread && siz == 184 && bo.Uint32(b[8:12]) == x86_THREAD_STATE64 { 268 return bo.Uint64(b[144:]) 269 } 270 } 271 return 0 272 } 273 274 func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) { 275 data := make([]byte, size) 276 for _, load := range x.f.Loads { 277 seg, ok := load.(*macho.Segment) 278 if !ok { 279 continue 280 } 281 if seg.Addr <= addr && addr+size-1 <= seg.Addr+seg.Filesz-1 { 282 if seg.Name == "__PAGEZERO" { 283 continue 284 } 285 _, err := seg.ReadAt(data, int64(addr-seg.Addr)) 286 if err != nil { 287 return nil, err 288 } 289 return data, nil 290 } 291 } 292 return nil, fmt.Errorf("address not mapped") 293 } 294 295 func (x *machoExe) Symbols() ([]sym, error) { 296 var out []sym 297 for _, s := range x.f.Symtab.Syms { 298 out = append(out, sym{s.Name, s.Value, 0}) 299 } 300 return out, nil 301 } 302 303 func (x *machoExe) SectionNames() []string { 304 var names []string 305 for _, sect := range x.f.Sections { 306 names = append(names, sect.Name) 307 } 308 return names 309 } 310 311 func (x *machoExe) TextRange() (uint64, uint64) { 312 // Assume text is first non-empty segment. 313 for _, load := range x.f.Loads { 314 seg, ok := load.(*macho.Segment) 315 if ok && seg.Name != "__PAGEZERO" && seg.Addr != 0 && seg.Filesz != 0 { 316 return seg.Addr, seg.Addr + seg.Filesz 317 } 318 } 319 return 0, 0 320 } 321 322 func (x *machoExe) RODataRange() (uint64, uint64) { 323 return x.TextRange() 324 }