private string FormatInstruction(DisassembleEntry e) { if (e.data != null) { if (IsAscii(e.data)) { if (e.name == "SYSCALL") { return($"{e.opcode:X}\t{e.name} {Encoding.UTF8.GetString(e.data)}"); } else { return($"{e.opcode:X}\t{e.name} \"{Encoding.UTF8.GetString(e.data)}\""); } } else { return($"{e.opcode:X}\t{e.name} {e.data.ToHexString()}"); } } else { return($"{e.opcode:X}\t{e.name}"); } }
public static AVMDisassemble Disassemble(byte[] script) { InitHints(); var output = new List <DisassembleEntry>(); using (var stream = new MemoryStream(script)) { using (var reader = new BinaryReader(stream)) { while (reader.BaseStream.Position != reader.BaseStream.Length) { var entry = new DisassembleEntry(); output.Add(entry); entry.startOfs = (int)reader.BaseStream.Position; var opcode = (OpCode)reader.ReadByte(); entry.opcode = opcode; entry.name = opcode.ToString(); entry.comment = hints.ContainsKey(opcode) ? hints[opcode] : ""; if (opcode >= OpCode.PUSHBYTES1 && opcode <= OpCode.PUSHBYTES75) { var len = (byte)opcode; entry.data = reader.ReadBytes(len); entry.name = "PUSHBYTES" + len; entry.comment = "Pushes " + len + " bytes into the stack: $$"; } else { switch (opcode) { // Push value //case OpCode.PUSH0: case OpCode.PUSHDATA1: { var len = reader.ReadByte(); entry.data = reader.ReadBytes(len); entry.comment = "Pushes " + len + " bytes into the stack: $$"; break; } case OpCode.PUSHDATA2: { var len = reader.ReadUInt16(); entry.data = reader.ReadBytes(len); entry.comment = "Pushes " + len + " bytes into the stack: $$"; break; } case OpCode.PUSHDATA4: { var len = reader.ReadInt32(); entry.data = reader.ReadBytes(len); entry.comment = "Pushes " + len + " bytes into the stack: $$"; break; } /*case OpCode.PUSHM1: * case OpCode.PUSH1: * case OpCode.PUSH2: * case OpCode.PUSH3: * case OpCode.PUSH4: * case OpCode.PUSH5: * case OpCode.PUSH6: * case OpCode.PUSH7: * case OpCode.PUSH8: * case OpCode.PUSH9: * case OpCode.PUSH10: * case OpCode.PUSH11: * case OpCode.PUSH12: * case OpCode.PUSH13: * case OpCode.PUSH14: * case OpCode.PUSH15: * case OpCode.PUSH16:*/ // Control //case OpCode.NOP: case OpCode.CALL: case OpCode.CALL_I: { int other = reader.ReadInt16(); int offset = reader.ReadInt16(); break; } case OpCode.CALL_E: case OpCode.CALL_ET: { int other = reader.ReadInt16(); byte[] script_hash = reader.ReadBytes(20); entry.data = script_hash.Reverse().ToArray(); entry.comment = "NEP8-calls script with hash: $XX"; break; } case OpCode.CALL_ED: case OpCode.CALL_EDT: case OpCode.JMP: case OpCode.JMPIF: case OpCode.JMPIFNOT: { int offset = reader.ReadInt16(); //offset = context.InstructionPointer + offset - 3; break; } /*case OpCode.CALL: * InvocationStack.Push(context.Clone()); * context.InstructionPointer += 2; * ExecuteOp(OpCode.JMP, CurrentContext); * break;*/ /*case OpCode.RET: * InvocationStack.Pop().Dispose(); * if (InvocationStack.Count == 0) * State |= VMState.HALT; * break;*/ case OpCode.APPCALL: case OpCode.TAILCALL: { byte[] script_hash = reader.ReadBytes(20); entry.data = script_hash.Reverse().ToArray(); entry.comment = "Calls script with hash: $XX"; break; } case OpCode.SYSCALL: { entry.data = reader.ReadVarBytes(252); entry.comment = "System call with data: $$"; break; } // Stack ops /*case OpCode.DUPFROMALTSTACK: * case OpCode.TOALTSTACK: * case OpCode.FROMALTSTACK: * case OpCode.XDROP: * case OpCode.XSWAP: * case OpCode.XTUCK: * case OpCode.DEPTH: * case OpCode.DROP: * case OpCode.DUP: * case OpCode.NIP: * case OpCode.OVER: * case OpCode.PICK: * case OpCode.ROLL: * case OpCode.ROT: * case OpCode.SWAP: * case OpCode.TUCK: * case OpCode.CAT: * case OpCode.SUBSTR: * case OpCode.LEFT: * case OpCode.RIGHT: * case OpCode.SIZE: */ // Bitwise logic /*case OpCode.INVERT: * case OpCode.AND: * case OpCode.OR: * case OpCode.XOR: * case OpCode.EQUAL: | */ // Numeric /*case OpCode.INC: * case OpCode.DEC: * case OpCode.SIGN: * case OpCode.NEGATE: * case OpCode.ABS: * case OpCode.NOT: * case OpCode.NZ: * case OpCode.ADD: * case OpCode.SUB: * case OpCode.MUL: * case OpCode.DIV: * case OpCode.MOD: * case OpCode.SHL: * case OpCode.SHR: * case OpCode.BOOLAND: * case OpCode.BOOLOR: * case OpCode.NUMEQUAL: * case OpCode.NUMNOTEQUAL: * case OpCode.LT: * case OpCode.GT: * case OpCode.LTE: * case OpCode.GTE: * case OpCode.MIN: * case OpCode.MAX: * case OpCode.WITHIN: */ // Crypto /* * case OpCode.SHA1: * case OpCode.SHA256: * case OpCode.HASH160: * case OpCode.HASH256: * case OpCode.CHECKSIG: * case OpCode.CHECKMULTISIG: * case OpCode.ARRAYSIZE: * case OpCode.PACK: * case OpCode.UNPACK: * case OpCode.PICKITEM: * case OpCode.SETITEM: * case OpCode.NEWARRAY: * case OpCode.NEWSTRUCT: */ // Exceptions /*case OpCode.THROW: * case OpCode.THROWIFNOT: */ default: { if (!Enum.IsDefined(typeof(OpCode), opcode)) { var s = ((byte)opcode).ToString(); Console.WriteLine($"Invalid opcode {s} at {entry.startOfs}"); } break; } } } entry.endOfs = (int)(reader.BaseStream.Position - 1); } } } return(new AVMDisassemble(output)); }
private string DisassembleInstruction(int offset) { DisassembleEntry e = InstructionAt(offset); return(FormatInstruction(e)); }