Beispiel #1
0
        /// <summary>
        /// Get instructions from stream
        /// </summary>
        /// <param name="initClass">Init class</param>
        /// <param name="result">Result</param>
        public virtual bool TryParse(object initClass, ref ReverseResult result)
        {
            uint insNumber = 0;
            uint offset    = 0;

            if (result == null)
            {
                result = new ReverseResult()
                {
                }
            }
            ;

            if (initClass == null || !(initClass is IInitClassStream ics))
            {
                return(false);
            }

            byte[] all;
            OffsetRelationCache offsetCache = new OffsetRelationCache();
            List <Instruction>  recallJump  = new List <Instruction>();
            List <Instruction>  calls       = new List <Instruction>();

            PrapareResultForOcurrences(result);

            using (MemoryStream ms = new MemoryStream())
            {
                foreach (StreamModule module in ics.GetStream())
                {
                    Types.Module mAdd = new Types.Module()
                    {
                        Name  = module.Name,
                        Start = new IndexOffset()
                        {
                            Offset = (uint)ms.Position,
                            Index  = (uint)result.Instructions.Count
                        },
                        Color = module.Color
                    };

                    Method mEntryPoint = new Method()
                    {
                        Start = mAdd.Start,
                        Name  = "EntryPoint of " + module.Name,
                    };

                    Instruction lastIns = null;

                    try
                    {
                        if (module.Stream is FileStream fi && Path.GetExtension(fi.Name).ToLowerInvariant() == ".json")
                        {
                            #region load file if are json FileStream
                            long originalPos = module.Stream.Position;
                            all = new byte[module.Stream.Length - originalPos];
                            module.Stream.Read(all, 0, all.Length);

                            string json = Encoding.UTF8.GetString(all, 0, all.Length);

                            result = JsonHelper.Deserialize <ReverseResult>(json, true);
                            if (result != null)
                            {
                                // Prepare ocurrences
                                PrapareResultForOcurrences(result);

                                // Fill cache
                                offsetCache.FillWith(result.Instructions);

                                // Process instructions (Jumps)
                                using (MemoryStream msX = new MemoryStream())
                                {
                                    foreach (Instruction i in result.Instructions)
                                    {
                                        ProcessInstruction(result.Instructions, i, offsetCache);

                                        // Recall jumps
                                        if (i.Jump != null && i.Jump.To != null &&
                                            offsetCache.TryGetValue(i.Jump.To.Offset, out uint index, OffsetIndexRelation.OffsetToIndex))
                                        {
                                            i.Jump.To.Index = index;
                                        }

                                        i.Write(msX);
                                    }
                                    result.Bytes = msX.ToArray();
                                }

                                // Regenerate borders
                                result.StyleMethodBorders();
                                // Regenerate ocurrences
                                result.GenerateOcurrences();
                                return(result.Instructions.Count > 0);
                            }

                            module.Stream.Seek(originalPos, SeekOrigin.Begin);
                            #endregion
                        }

                        long max = module.Stream.Length;
                        int  percent = 0, newPercent = 0;

                        while (true)
                        {
                            byte[] opCode = new byte[OpCodeSize];

                            if (module.Stream.Read(opCode, 0, OpCodeSize) != OpCodeSize)
                            {
                                break;
                            }

                            string key = opCode.ToHexString();

                            if (!OpCodeCache.TryGetValue(key, out OpCodeArgumentAttribute read) || read == null)
                            {
                                throw (new OpCodeNotFoundException()
                                {
                                    Offset = offset,
                                    OpCode = opCode,
                                });
                            }

                            OpCodeEmptyArgument arg = read.Create();
                            uint rBytes             = arg.Read(module.Stream);

                            lastIns = new Instruction()
                            {
                                OpCode = new OpCode()
                                {
                                    RawValue    = opCode,
                                    Name        = read.OpCode,
                                    Description = read.Description,
                                    Flags       = read.Flags
                                },
                                Argument = arg.GetType() == typeof(OpCodeEmptyArgument) ? null : arg,
                                Comment  = arg.ASCIIValue,
                                Color    = mAdd.Color,
                            };

                            lastIns.Location.Index  = insNumber;
                            lastIns.Location.Offset = offset;

                            offsetCache.Add(lastIns.Location);

                            ProcessInstruction(result.Instructions, lastIns, offsetCache);

                            if (lastIns.OpCode.Flags.HasFlag(OpCodeFlag.IsCall))
                            {
                                calls.Add(lastIns);
                            }
                            else
                            {
                                if (mEntryPoint != null && lastIns.OpCode.Flags.HasFlag(OpCodeFlag.IsRet))
                                {
                                    mEntryPoint.End = lastIns.Location;

                                    mAdd.Methods.Add(mEntryPoint);
                                    mEntryPoint = null;
                                }
                            }

                            // Recall jumps
                            if (lastIns.Jump != null && !lastIns.Jump.IsDynamic && lastIns.Jump.To.Index == uint.MaxValue)
                            {
                                recallJump.Add(lastIns);
                            }

                            result.Instructions.Add(lastIns);

                            offset += (uint)(rBytes + OpCodeSize);
                            insNumber++;

                            newPercent = (int)((module.Stream.Position * 100) / max);
                            if (percent != newPercent)
                            {
                                percent = newPercent;
                                OnParseProgress?.Invoke(this, percent);
                            }

                            lastIns.Write(ms);
                        }

                        if (mEntryPoint != null)
                        {
                            mEntryPoint.End = lastIns.Location;

                            mAdd.Methods.Add(mEntryPoint);
                            mEntryPoint = null;
                        }
                    }
                    catch (Exception er)
                    {
                        result = null;
                        throw (er);
                    }
                    finally
                    {
                        if (module != null)
                        {
                            module.Dispose();
                        }
                    }

                    long pos = ms.Position;
                    mAdd.End  = lastIns.Location;
                    mAdd.Size = (uint)(pos - mAdd.Start.Offset);

                    ms.Seek(mAdd.Start.Offset, SeekOrigin.Begin);

                    all = new byte[mAdd.Size];
                    ms.Read(all, 0, all.Length);

                    using (SHA1 sha = SHA1.Create())
                        mAdd.Hash = sha.ComputeHash(all, 0, all.Length).ToHexString();

                    result.Modules.Add(mAdd);
                }

                result.Bytes = ms.ToArray();
            }

            // Recall jumps
            foreach (Instruction j in recallJump)
            {
                if (offsetCache.TryGetValue(j.Jump.To.Offset, out uint index, OffsetIndexRelation.OffsetToIndex))
                {
                    j.Jump.To.Index = index;
                }
                else
                {
                    // If enter here, there will be an error
                    j.Jump = null;
                }
            }
Beispiel #2
0
        /// <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);
                }