decompress right pl0x

master
Jordan Orelli 9 years ago
parent ac944ad6be
commit 7e088dfe61

@ -2,9 +2,9 @@ package main
import (
"fmt"
"io"
"github.com/golang/protobuf/proto"
"github.com/golang/snappy"
"github.com/jordanorelli/hyperstone/bit"
"github.com/jordanorelli/hyperstone/dota"
)
@ -12,17 +12,16 @@ import (
// datagram represents the top-level envelope in the dota replay format. All
// data in the replay file is packed into datagram frames of at most 65kb.
type dataGram struct {
cmd dota.EDemoCommands
tick int64
compressed bool
body []byte
cmd dota.EDemoCommands
tick int64
body []byte
}
func (g dataGram) String() string {
if len(g.body) > 30 {
return fmt.Sprintf("{dataGram cmd: %v tick: %v compressed: %t size: %d body: %q...}", g.cmd, g.tick, g.compressed, len(g.body), g.body[:27])
return fmt.Sprintf("{dataGram cmd: %v tick: %v size: %d body: %q...}", g.cmd, g.tick, len(g.body), g.body[:27])
}
return fmt.Sprintf("{dataGram cmd: %v tick: %v compressed: %t size: %d body: %q}", g.cmd, g.tick, g.compressed, len(g.body), g.body)
return fmt.Sprintf("{dataGram cmd: %v tick: %v size: %d body: %q}", g.cmd, g.tick, len(g.body), g.body)
}
func (g *dataGram) check(dump bool) error {
@ -30,42 +29,36 @@ func (g *dataGram) check(dump bool) error {
return fmt.Errorf("wrong command type in openPacket: %v", g.cmd)
}
if g.compressed {
buf, err := snappy.Decode(nil, g.body)
if err != nil {
return wrap(err, "open packet error: could not decode body")
}
g.body = buf
g.compressed = false
}
packet := new(dota.CDemoPacket)
if err := proto.Unmarshal(g.body, packet); err != nil {
return wrap(err, "onPacket unable to unmarshal message body")
}
if dump {
br := bit.NewBytesReader(packet.GetData())
for {
t := br.ReadUBitVar()
s := br.ReadVarInt()
b := make([]byte, s)
br.Read(b)
if br.Err() != nil {
break
}
br := bit.NewBytesReader(packet.GetData())
for {
t := br.ReadUBitVar()
s := br.ReadVarInt()
b := make([]byte, s)
br.Read(b)
switch err := br.Err(); err {
case nil:
break
case io.EOF:
return nil
default:
return err
}
if dump {
fmt.Printf("\t%v\n", entity{t: uint32(t), size: uint32(s), body: b})
e := entFactory.BuildMessage(int(t))
if e == nil {
fmt.Printf("\tno known entity for type id %d\n", int(t))
continue
}
err := proto.Unmarshal(b, e)
if err != nil {
fmt.Printf("entity unmarshal error: %v\n", err)
} else {
fmt.Printf("\t\t%v\n", e)
}
}
e := entFactory.BuildMessage(int(t))
if e == nil {
fmt.Printf("\tno known entity for type id %d\n", int(t))
continue
}
err := proto.Unmarshal(b, e)
if err != nil {
fmt.Printf("entity unmarshal error: %v\n", err)
}
}
return nil

@ -40,11 +40,11 @@ var (
"EDotaUserMessages_DOTA_UM_": "CDOTAUserMsg_",
}
specials = map[string]string{
"EDemoCommands_DEM_SignonPacket": "CDemoPacket",
"EDotaUserMessages_DOTA_UM_StatsHeroDetails": "CDOTAUserMsg_StatsHeroMinuteDetails",
"EDotaUserMessages_DOTA_UM_CombatLogDataHLTV": "CMsgDOTACombatLogEntry",
"EDotaUserMessages_DOTA_UM_TournamentDrop": "CMsgGCToClientTournamentItemDrop",
"EDotaUserMessages_DOTA_UM_MatchMetadata": "CDOTAClientMsg_MatchMetadata",
"ETEProtobufIds_TE_EffectDispatchId": "CMsgTEEffectDispatch",
}
skipped = map[string]bool{
"EDemoCommands_DEM_IsCompressed": true,
@ -59,31 +59,30 @@ var (
}
// EBaseUserMessages_UM_HandHapticPulse
tpl = `package main
/*------------------------------------------------------------------------------
.aMMMb .aMMMb dMMMMb dMMMMMP
dMP"VMP dMP"dMP dMP VMP dMP
dMP dMP dMP dMP dMP dMMMP
dMP.aMP dMP.aMP dMP.aMP dMP
VMMMP" VMMMP" dMMMMP" dMMMMMP
.aMMMMP dMMMMMP dMMMMb dMMMMMP dMMMMb .aMMMb dMMMMMMP dMMMMMP dMMMMb
dMP" dMP dMP dMP dMP dMP.dMP dMP"dMP dMP dMP dMP VMP
dMP MMP"dMMMP dMP dMP dMMMP dMMMMK" dMMMMMP dMP dMMMP dMP dMP
dMP.dMP dMP dMP dMP dMP dMP"AMF dMP dMP dMP dMP dMP.aMP
VMMMP" dMMMMMP dMP dMP dMMMMMP dMP dMP dMP dMP dMP dMMMMMP dMMMMP"
This code was generated by a code-generation program. It was NOT written by
hand. Do not edit this file by hand! Your edits will be destroyed!
This file can be regenerated by running "go generate"
The generator program is defined in "gen/main.go"
------------------------------------------------------------------------------*/
////////////////////////////////////////////////////////////////////////////////
//
// .aMMMb .aMMMb dMMMMb dMMMMMP
// dMP"VMP dMP"dMP dMP VMP dMP
// dMP dMP dMP dMP dMP dMMMP
// dMP.aMP dMP.aMP dMP.aMP dMP
// VMMMP" VMMMP" dMMMMP" dMMMMMP
//
// .aMMMMP dMMMMMP dMMMMb dMMMMMP dMMMMb .aMMMb dMMMMMMP dMMMMMP dMMMMb
// dMP" dMP dMP dMP dMP dMP.dMP dMP"dMP dMP dMP dMP VMP
// dMP MMP"dMMMP dMP dMP dMMMP dMMMMK" dMMMMMP dMP dMMMP dMP dMP
// dMP.dMP dMP dMP dMP dMP dMP"AMF dMP dMP dMP dMP dMP.aMP
// VMMMP" dMMMMMP dMP dMP dMMMMMP dMP dMP dMP dMP dMP dMMMMMP dMMMMP"
//
//
// This code was generated by a code-generation program. It was NOT written by
// hand. Do not edit this file by hand! Your edits will be destroyed!
//
// This file can be regenerated by running "go generate"
//
// The generator program is defined in "gen/main.go"
//
////////////////////////////////////////////////////////////////////////////////
import (
"github.com/golang/protobuf/proto"

@ -1,28 +1,28 @@
package main
/*------------------------------------------------------------------------------
.aMMMb .aMMMb dMMMMb dMMMMMP
dMP"VMP dMP"dMP dMP VMP dMP
dMP dMP dMP dMP dMP dMMMP
dMP.aMP dMP.aMP dMP.aMP dMP
VMMMP" VMMMP" dMMMMP" dMMMMMP
.aMMMMP dMMMMMP dMMMMb dMMMMMP dMMMMb .aMMMb dMMMMMMP dMMMMMP dMMMMb
dMP" dMP dMP dMP dMP dMP.dMP dMP"dMP dMP dMP dMP VMP
dMP MMP"dMMMP dMP dMP dMMMP dMMMMK" dMMMMMP dMP dMMMP dMP dMP
dMP.dMP dMP dMP dMP dMP dMP"AMF dMP dMP dMP dMP dMP.aMP
VMMMP" dMMMMMP dMP dMP dMMMMMP dMP dMP dMP dMP dMP dMMMMMP dMMMMP"
This code was generated by a code-generation program. It was NOT written by
hand. Do not edit this file by hand! Your edits will be destroyed!
This file can be regenerated by running "go generate"
The generator program is defined in "gen/main.go"
------------------------------------------------------------------------------*/
////////////////////////////////////////////////////////////////////////////////
//
// .aMMMb .aMMMb dMMMMb dMMMMMP
// dMP"VMP dMP"dMP dMP VMP dMP
// dMP dMP dMP dMP dMP dMMMP
// dMP.aMP dMP.aMP dMP.aMP dMP
// VMMMP" VMMMP" dMMMMP" dMMMMMP
//
// .aMMMMP dMMMMMP dMMMMb dMMMMMP dMMMMb .aMMMb dMMMMMMP dMMMMMP dMMMMb
// dMP" dMP dMP dMP dMP dMP.dMP dMP"dMP dMP dMP dMP VMP
// dMP MMP"dMMMP dMP dMP dMMMP dMMMMK" dMMMMMP dMP dMMMP dMP dMP
// dMP.dMP dMP dMP dMP dMP dMP"AMF dMP dMP dMP dMP dMP.aMP
// VMMMP" dMMMMMP dMP dMP dMMMMMP dMP dMP dMP dMP dMP dMMMMMP dMMMMP"
//
//
// This code was generated by a code-generation program. It was NOT written by
// hand. Do not edit this file by hand! Your edits will be destroyed!
//
// This file can be regenerated by running "go generate"
//
// The generator program is defined in "gen/main.go"
//
////////////////////////////////////////////////////////////////////////////////
import (
"github.com/golang/protobuf/proto"
@ -48,7 +48,6 @@ var cmdFactory = protoFactory{
5: func() proto.Message { return new(dota.CDemoClassInfo) },
6: func() proto.Message { return new(dota.CDemoStringTables) },
7: func() proto.Message { return new(dota.CDemoPacket) },
8: func() proto.Message { return new(dota.CDemoPacket) },
9: func() proto.Message { return new(dota.CDemoConsoleCmd) },
10: func() proto.Message { return new(dota.CDemoCustomData) },
11: func() proto.Message { return new(dota.CDemoCustomDataCallbacks) },

@ -49,7 +49,7 @@ type options struct {
f string // input file
memprofile string
cpuprofile string
messages bool // dump messages or no
datagrams bool // dump datagrams or no
packets bool // dump packets or no
}
@ -105,7 +105,7 @@ func main() {
flag.BoolVar(&opts.b, "b", false, "input is expected to be bzip-compressed")
flag.BoolVar(&opts.v, "v", false, "verbose mode")
flag.StringVar(&opts.f, "f", "--", "input file to be used. -- means stdin")
flag.BoolVar(&opts.messages, "messages", false, "dump top-level messages to stdout")
flag.BoolVar(&opts.datagrams, "datagrams", false, "dump top-level datagram info to stdout")
flag.BoolVar(&opts.packets, "packets", false, "dump packets to stdout")
flag.StringVar(&opts.memprofile, "memprofile", "", "memory profile destination")
flag.StringVar(&opts.cpuprofile, "cpuprofile", "", "cpu profile destination")
@ -125,7 +125,7 @@ func main() {
}
p := newParser(r)
p.dumpMessages = opts.messages
p.dumpDatagrams = opts.datagrams
p.dumpPackets = opts.packets
if err := p.start(); err != nil {
bail(1, "parse error: %v", err)

@ -4,8 +4,10 @@ import (
"bufio"
"fmt"
"io"
"reflect"
"github.com/golang/protobuf/proto"
"github.com/golang/snappy"
"github.com/jordanorelli/hyperstone/dota"
)
@ -13,8 +15,8 @@ type parser struct {
// the source of replay bytes. Must NOT be compressed.
source *bufio.Reader
dumpMessages bool
dumpPackets bool
dumpDatagrams bool
dumpPackets bool
}
func newParser(r io.Reader) *parser {
@ -38,26 +40,29 @@ func (p *parser) start() error {
func (p *parser) run() error {
for {
msg, err := p.readMessage()
gram, err := p.readDatagram()
if err != nil {
return wrap(err, "read message error in run loop")
return wrap(err, "read datagram error in run loop")
}
if p.dumpMessages {
fmt.Println(msg)
if p.dumpDatagrams {
fmt.Println(gram)
}
switch msg.cmd {
if len(gram.body) == 0 {
continue
}
switch gram.cmd {
case dota.EDemoCommands_DEM_Packet:
if err := msg.check(p.dumpPackets); err != nil {
if err := gram.check(p.dumpPackets); err != nil {
fmt.Printf("error: %v\n", err)
}
default:
m := cmdFactory.BuildMessage(int(msg.cmd))
m := cmdFactory.BuildMessage(int(gram.cmd))
if m != nil {
err := proto.Unmarshal(msg.body, m)
err := proto.Unmarshal(gram.body, m)
if err != nil {
fmt.Printf("cmd unmarshal error: %v\n", err)
} else {
fmt.Println(m)
fmt.Printf("cmd unmarshal error unpacking data of length %d with cmd type %s into message type %v: %v\n", len(gram.body), gram.cmd, reflect.TypeOf(m), err)
}
}
}
@ -133,31 +138,39 @@ func (p *parser) readCommand() (dota.EDemoCommands, bool, error) {
return dota.EDemoCommands(n), compressed, nil
}
func (p *parser) readMessage() (*dataGram, error) {
func (p *parser) readDatagram() (*dataGram, error) {
cmd, compressed, err := p.readCommand()
if err != nil {
return nil, wrap(err, "readMessage couldn't get a command")
return nil, wrap(err, "readDatagram couldn't get a command")
}
tick, err := p.decodeVarint()
if err != nil {
return nil, wrap(err, "readMessage couldn't read the tick value")
return nil, wrap(err, "readDatagram couldn't read the tick value")
}
size, err := p.decodeVarint()
if err != nil {
return nil, wrap(err, "readMessage couldn't read the size value")
return nil, wrap(err, "readDatagram couldn't read the size value")
}
if size > 0 {
buf := make([]byte, int(size))
if _, err := io.ReadFull(p.source, buf); err != nil {
return nil, wrap(err, "readMessage couldn't read message body")
return nil, wrap(err, "readDatagram couldn't read datagram body")
}
if compressed {
var err error
buf, err = snappy.Decode(nil, buf)
if err != nil {
return nil, wrap(err, "readDatagram couldn't snappy decode body")
}
}
// TODO: pool these!
return &dataGram{cmd, int64(tick), compressed, buf}, nil
return &dataGram{cmd, int64(tick), buf}, nil
}
// TODO: pool these!
return &dataGram{cmd, int64(tick), compressed, nil}, nil
return &dataGram{cmd, int64(tick), nil}, nil
}

Loading…
Cancel
Save