/// <summary> /// Fill jumps /// </summary> /// <param name="bag">Bag</param> /// <param name="ins">Instruction</param> /// <param name="offsetToIndexCache">Cache</param> public override void ProcessInstruction(InstructionCollection bag, Instruction ins, OffsetRelationCache offsetToIndexCache) { if (ins.OpCode == null) { return; } switch (ins.OpCode.Name) { // Detect bad property optimization case nameof(NeoOpCode.DROP): { /* * 0x03C5 PUSH0 Method 0x03C5 [R4S] * 0x03C6 NEWARRAY * 0x03C7 TOALTSTACK * That is the only valid > 0x03C8 PUSHBYTES3 0x523453 R4S * 0x03CC NOP * 0x03CD FROMALTSTACK * > 0x03CE DROP */ int y = 1; for (int x = (int)ins.Location.Index - 1; x >= 0 && y <= 6; x--, y++) { Instruction i = bag[x]; if (i == null || i.OpCode == null) { return; } switch (y) { case 1: { if (i.OpCode.Name != nameof(NeoOpCode.FROMALTSTACK)) { // Detect Push / Drop if (i.OpCode.Name.StartsWith("PUSH")) { ins.Flags = InstructionFlag.UnusableCode; ins.ApplyColorForFlags(); i.Flags = InstructionFlag.UnusableCode; i.ApplyColorForFlags(); } return; } break; } case 2: { if (i.OpCode.Name != nameof(NeoOpCode.NOP)) { return; } break; } case 3: { if (!i.OpCode.Name.StartsWith("PUSH")) { return; } break; } case 4: { if (i.OpCode.Name != nameof(NeoOpCode.TOALTSTACK)) { return; } break; } case 5: { if (i.OpCode.Name != nameof(NeoOpCode.NEWARRAY)) { return; } break; } case 6: { if (i.OpCode.Name != nameof(NeoOpCode.PUSH0)) { return; } break; } } } if (y == 7) { ins.Flags = InstructionFlag.UnusableCode; ins.ApplyColorForFlags(); y = 1; for (int x = (int)ins.Location.Index - 1, m = x - 6; x > m; x--, y++) { if (y == 3) { continue; } Instruction i = bag[x]; i.Flags = InstructionFlag.UnusableCode; i.ApplyColorForFlags(); } } break; } // Detect NOP case nameof(NeoOpCode.NOP): { ins.Flags = InstructionFlag.UnusableCode; ins.ApplyColorForFlags(); break; } // Detect To/From ALTSTACK case nameof(NeoOpCode.FROMALTSTACK): { if (ins.Location.Index != 0) { Instruction prev = bag[ins.Location.Index - 1]; if (prev != null && prev.OpCode != null && prev.OpCode.Name == nameof(NeoOpCode.TOALTSTACK)) { prev.Flags = InstructionFlag.UnusableCode; ins.Flags = InstructionFlag.UnusableCode; prev.ApplyColorForFlags(); ins.ApplyColorForFlags(); } } break; } case nameof(NeoOpCode.RET): { ins.Jump = new Jump(new OnJumpDelegate( (d, i) => { if (d == null || d.CurrentInstructionIndex != i.Location.Index || !(d is NeoDebugger neodebug)) { return(null); } try { return((uint)neodebug.Engine.InvocationStack.Peek().InstructionPointer); } catch { } return(null); }) ); break; } case nameof(NeoOpCode.CALL): case nameof(NeoOpCode.CALL_E): case nameof(NeoOpCode.CALL_ED): case nameof(NeoOpCode.CALL_EDT): case nameof(NeoOpCode.CALL_ET): case nameof(NeoOpCode.CALL_I): case nameof(NeoOpCode.JMP): { uint offset; if (ins.Argument is OpCodeShortArgument a) { offset = (uint)a.Value; } else { if (ins.Argument is OpCodeCall_IArgument c) { // TODO: Check this offset = (uint)c.Value - 2; } else { return; } } if (offset == 3) { // Detect JMP to next line ins.Flags = InstructionFlag.UnusableCode; ins.ApplyColorForFlags(); } offset = ins.Location.Offset + offset; if (offsetToIndexCache.TryGetValue(offset, out uint ix, OffsetIndexRelation.OffsetToIndex)) { ins.Jump = new Jump(offset, ix); }