Advertisement
Guest User

Untitled

a guest
Jul 21st, 2017
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.31 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "bytes"
  5.     "encoding/binary"
  6.     "flag"
  7.     "fmt"
  8.     "./qvm"
  9.     "os"
  10. )
  11.  
  12. var OpcodeTable = [...]string {
  13.     "UNDEF     ", "IGNORE    ", "BREAK     ", "ENTER     ", "LEAVE     ", "CALL      ",
  14.     "PUSH      ", "POP       ", "CONST     ", "LOCAL     ", "JUMP      ", "EQ        ",
  15.     "NE        ", "LTI       ", "LEI       ", "GTI       ", "GEI       ", "LTU       ",
  16.     "LEU       ", "GTU       ", "GEU       ", "EQF       ", "NEF       ", "LTF       ",
  17.     "LEF       ", "GTF       ", "GEF       ", "LOAD1     ", "LOAD2     ", "LOAD4     ",
  18.     "STORE1    ", "STORE2    ", "STORE4    ", "ARG       ", "BLOCK_COPY", "SEX8      ",
  19.     "SEX16     ", "NEGI      ", "ADD       ", "SUB       ", "DIVI      ", "DIVU      ",
  20.     "MODI      ", "MODU      ", "MULI      ", "MULU      ", "BAND      ", "BOR       ",
  21.     "BXOR      ", "BCOM      ", "LSH       ", "RSHI      ", "RSHU      ", "NEGF      ",
  22.     "ADDF      ", "SUBF      ", "DIVF      ", "MULF      ", "CVIF      ", "CVFI      "}
  23.  
  24. const ( OP_ENTER = 3
  25.     OP_CALL = 5
  26.     OP_CONST = 8
  27.     OP_JUMP = 10 )
  28.  
  29. var ArgTable = []byte {
  30.     0, 0, 0, 4, 4, 0,
  31.     0, 0, 4, 4, 0, 4,
  32.     4, 4, 4, 4, 4, 4,
  33.     4, 4, 4, 4, 4, 4,
  34.     4, 4, 4, 0, 0, 0,
  35.     0, 0, 0, 1, 4, 0,
  36.     0, 0, 0, 0, 0, 0,
  37.     0, 0, 0, 0, 0, 0,
  38.     0, 0, 0, 0, 0, 0,
  39.     0, 0, 0, 0, 0, 0}
  40.  
  41. type instruction struct {
  42.     op uint8
  43.     arg []byte
  44.     valid bool
  45. }
  46.  
  47. type procedure struct {
  48.     name string
  49.     startInstruction, offset int
  50.     instructionCount int
  51.     callees []*procedure
  52.     callers []*procedure
  53. }
  54.  
  55. var insns []instruction
  56. var procs map[int]*procedure
  57. var strs map[int]string
  58.  
  59. func printHeader(qvmFile *qvm.QVMFile) {
  60.     version := "unknown"
  61.     switch qvmFile.Header.Magic {
  62.         case qvm.VM_MAGIC_VER1:
  63.             version = "Ver1"
  64.         case qvm.VM_MAGIC_VER2:
  65.             version = "Ver2"
  66.     }
  67.     fmt.Printf("            Magic: 0x%x[%s]\n", qvmFile.Header.Magic, version)
  68.     fmt.Printf("Instruction Count: 0x%x\n", qvmFile.Header.InstructionCount)
  69.     fmt.Printf("      Code Offset: 0x%x\n", qvmFile.Header.CodeOffset)
  70.     fmt.Printf("      Code Length: 0x%x\n", qvmFile.Header.CodeLength)
  71.     fmt.Printf("      Data Offset: 0x%x\n", qvmFile.Header.DataOffset)
  72.     fmt.Printf("      Data Length: 0x%x\n", qvmFile.Header.DataLength)
  73.     fmt.Printf("       Lit Length: 0x%x\n", qvmFile.Header.LitLength)
  74.     fmt.Printf("       Bss Length: 0x%x\n", qvmFile.Header.BssLength)
  75.     if qvmFile.Header.Magic == qvm.VM_MAGIC_VER2 {
  76.         fmt.Printf("Jump Table Length: 0x%x\n", qvmFile.Header.JumpTableLength)
  77.     }
  78. }
  79.  
  80. func parseInstructions(qvmFile *qvm.QVMFile) {
  81.     codeOffset := int(qvmFile.Header.CodeOffset)
  82.     for i, off := 0, 0; i < int(qvmFile.Header.InstructionCount); i++ {
  83.         op := qvmFile.Code[off]
  84.         if op < 0 || op > 59 {
  85.             fmt.Println("Illegal opcode: %d at 0x%x\n", op, off + codeOffset)
  86.             insns = append(insns, instruction{op, []byte{}, false})
  87.             off++
  88.             continue
  89.         }
  90.         switch ArgTable[op] {
  91.             case 0:
  92.                 insns = append(insns, instruction{op, []byte{}, true})
  93.                 off++
  94.             case 1:
  95.                 insns = append(insns, instruction{op, []byte{qvmFile.Code[off + 1]}, true})
  96.                 off += 2
  97.             case 4:
  98.                 insns = append(insns, instruction{op, []byte{qvmFile.Code[off + 1],
  99.                                          qvmFile.Code[off + 2],
  100.                                          qvmFile.Code[off + 3],
  101.                                          qvmFile.Code[off + 4]}, true})
  102.                 off += 5
  103.         }
  104.     }
  105. }
  106.  
  107. func parseProcedures() {
  108.     procs = make(map[int]*procedure, 0)
  109.     lastIndex := 0
  110.     for i, off:= 0, 0; i < len(insns); i++ {
  111.         if insns[i].op == OP_ENTER {
  112.             procs[i] = &procedure{fmt.Sprintf("sub_%08x", off), i, off, 0, nil, nil}
  113.             procs[lastIndex].instructionCount = i - procs[lastIndex].startInstruction
  114.             lastIndex = i
  115.         }
  116.         off = off + 1 + int(ArgTable[insns[i].op])
  117.     }
  118.     procs[lastIndex].instructionCount = len(insns) - procs[lastIndex].startInstruction
  119. }
  120.  
  121. func parseCodeXRefs() {
  122.     for _, proc := range procs {
  123.         for i := proc.startInstruction; i < proc.startInstruction + proc.instructionCount; i++ {
  124.             if insns[i].op == OP_CONST && insns[i+1].op == OP_CALL {
  125.                 var target int32
  126.                 bufArg := bytes.NewBuffer(insns[i].arg)
  127.                 binary.Read(bufArg, binary.LittleEndian, &target)
  128.                 if target > 0 {
  129.                     proc.callees = append(proc.callees, procs[int(target)])
  130.                     procs[int(target)].callers = append(procs[int(target)].callers, proc)
  131.                 }
  132.             }
  133.         }
  134.     }
  135. }
  136.  
  137. func parseStrings(qvmFile *qvm.QVMFile) {
  138.     strs = make(map[int]string, 0)
  139.     firstChar := 0
  140.     foundFirstChar := false
  141.     for i, char := range qvmFile.Lit {
  142.         if !foundFirstChar && char != '\x00' {
  143.             firstChar = i
  144.             foundFirstChar = true
  145.         } else if foundFirstChar && char == '\x00' {
  146.             str := string(qvmFile.Lit[firstChar:i])
  147.             strs[firstChar + int(qvmFile.Header.DataOffset + qvmFile.Header.DataLength)] = str
  148.             firstChar = i
  149.             foundFirstChar = false
  150.         }
  151.     }
  152. }
  153.  
  154. func disassemble() {
  155.     for _, proc := range procs {
  156.         for j := proc.startInstruction; j < proc.startInstruction + proc.instructionCount; j++ {
  157.             arg := ""
  158.             comment := ""
  159.             mnemonic := ""
  160.             if insns[j].valid {
  161.                 mnemonic = OpcodeTable[insns[j].op]
  162.                 switch ArgTable[insns[j].op] {
  163.                     case 1:
  164.                         arg = fmt.Sprintf("0x%02x", insns[j].arg[0])
  165.                     case 4:
  166.                         var target int32
  167.                         bufArg := bytes.NewBuffer(insns[j].arg)
  168.                         binary.Read(bufArg, binary.LittleEndian, &target)
  169.                         arg = fmt.Sprintf("0x%08x", uint32(target))
  170.                         if insns[j].op == OP_CONST && insns[j+1].op == OP_CALL {
  171.                             if target < 0 {
  172.                                 //Syscall...
  173.                                 comment = fmt.Sprintf("; Syscall: %d", target)
  174.                             } else {
  175.                                 //Code xref...
  176.                                 comment = fmt.Sprintf("; %s", procs[int(target)].name)
  177.                             }
  178.                         }
  179.                 }
  180.             } else {
  181.                 //Invalid opcode...
  182.                 mnemonic = fmt.Sprint(".byte 0x%02x", insns[j].op)
  183.             }
  184.             fmt.Printf("<0x%08x>: %s %s%s\n", j, mnemonic, arg, comment);
  185.         }
  186.     }
  187. }
  188.  
  189. func main() {
  190.     var syscallsFile string
  191.     var commentsFile string
  192.     flag.StringVar(&syscallsFile, "s", "", "Specify a file defining the system calls for this QVM.")
  193.     flag.StringVar(&commentsFile, "c", "", "Specify a file containing comments from a previous disassembly.")
  194.     flag.Parse()
  195.  
  196.     if flag.NArg() != 1 {
  197.         fmt.Println("Must specify one QVM!")
  198.     }
  199.     file, err := os.Open(flag.Arg(0), os.O_RDONLY, 0444)
  200.     if err != nil {
  201.         fmt.Println(err.String())
  202.         os.Exit(-1)
  203.     }
  204.     qvmFile, err := qvm.NewQVMFile(file)
  205.     parseInstructions(qvmFile)
  206.     parseProcedures()
  207.     parseCodeXRefs()
  208.     parseStrings(qvmFile)
  209.     printHeader(qvmFile)
  210.     disassemble()
  211. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement