Example #1
0
        // ReSharper restore UnusedParameter.Local

        private SparseSwitchData ExtractSparseSwitch(Instruction ins, int offset)
        {
            int baseOffset = offset;
            var result     = new SparseSwitchData();

            ProcessPseudoCode(PseudoOpCodes.SparseSwitch, ref offset);

            int targetcount = ReadShort(ref offset);

            var keys = new int[targetcount];

            for (var i = 0; i < targetcount; i++)
            {
                keys[i] = ReadInt(ref offset);
            }

            for (var i = 0; i < targetcount; i++)
            {
                var index  = i;                // used for closure
                var target = ReadInt(ref offset);
                LazyInstructionsSetters.Add(() => result.Targets.Add(keys[index], Lookup[ins.Offset + target]));
            }

            if (offset - baseOffset != targetcount * 4 + 2)
            {
                throw new MalformedException("Unexpected Sparse switch blocksize");
            }

            return(result);
        }
Example #2
0
        private PackedSwitchData ExtractPackedSwitch(Instruction ins, int offset)
        {
            int baseOffset = offset;
            var result     = new PackedSwitchData();

            ProcessPseudoCode(PseudoOpCodes.PackedSwitch, ref offset);

            int targetcount = ReadShort(ref offset);

            result.FirstKey = ReadInt(ref offset);

            for (var i = 0; i < targetcount; i++)
            {
                var target = ReadInt(ref offset);
                LazyInstructionsSetters.Add(() => result.Targets.Add(Lookup[(ushort)(ins.Offset + target)]));
            }

            if (offset - baseOffset != targetcount * 2 + 4)
            {
                throw new MalformedException("Unexpected Packed switch blocksize");
            }

            return(result);
        }
Example #3
0
        public void ReadFrom(BinaryReader reader)
        {
            var registers = MethodDefinition.Body.Registers;

            InstructionsSize = reader.ReadUInt32();

            Codes = new int[InstructionsSize];
            Lower = new int[InstructionsSize];
            Upper = new int[InstructionsSize];

            for (var i = 0; i < InstructionsSize; i++)
            {
                Codes[i] = reader.ReadUInt16();
                Lower[i] = Codes[i] & 0xFF;
                Upper[i] = Codes[i] >> 8;
            }

            while (_ip < InstructionsSize)
            {
                int offset;
                int registerCount;
                int registerMask;

                var ins = new Instruction {
                    OpCode = (OpCodes)Lower[_ip], Offset = _ip
                };

                Lookup.Add(_ip, ins);
                MethodDefinition.Body.Instructions.Add(ins);

                switch (ins.OpCode)
                {
                case OpCodes.Nop:
                case OpCodes.ReturnVoid:
                    _ip++;
                    break;

                case OpCodes.MoveResult:
                case OpCodes.MoveResultWide:
                case OpCodes.MoveResultObject:
                case OpCodes.MoveException:
                case OpCodes.Return:
                case OpCodes.ReturnWide:
                case OpCodes.ReturnObject:
                case OpCodes.MonitorEnter:
                case OpCodes.MonitorExit:
                case OpCodes.Throw:
                    // vAA
                    ReadvAA(ins);
                    break;

                case OpCodes.MoveObject:
                case OpCodes.MoveWide:
                case OpCodes.Move:
                case OpCodes.ArrayLength:
                case OpCodes.NegInt:
                case OpCodes.NotInt:
                case OpCodes.NegLong:
                case OpCodes.NotLong:
                case OpCodes.NegFloat:
                case OpCodes.NegDouble:
                case OpCodes.IntToLong:
                case OpCodes.IntToFloat:
                case OpCodes.IntToDouble:
                case OpCodes.LongToInt:
                case OpCodes.LongToFloat:
                case OpCodes.LongToDouble:
                case OpCodes.FloatToInt:
                case OpCodes.FloatToLong:
                case OpCodes.FloatToDouble:
                case OpCodes.DoubleToInt:
                case OpCodes.DoubleToLong:
                case OpCodes.DoubleToFloat:
                case OpCodes.IntToByte:
                case OpCodes.IntToChar:
                case OpCodes.IntToShort:
                case OpCodes.AddInt2Addr:
                case OpCodes.SubInt2Addr:
                case OpCodes.MulInt2Addr:
                case OpCodes.DivInt2Addr:
                case OpCodes.RemInt2Addr:
                case OpCodes.AndInt2Addr:
                case OpCodes.OrInt2Addr:
                case OpCodes.XorInt2Addr:
                case OpCodes.ShlInt2Addr:
                case OpCodes.ShrInt2Addr:
                case OpCodes.UshrInt2Addr:
                case OpCodes.AddLong2Addr:
                case OpCodes.SubLong2Addr:
                case OpCodes.MulLong2Addr:
                case OpCodes.DivLong2Addr:
                case OpCodes.RemLong2Addr:
                case OpCodes.AndLong2Addr:
                case OpCodes.OrLong2Addr:
                case OpCodes.XorLong2Addr:
                case OpCodes.ShlLong2Addr:
                case OpCodes.ShrLong2Addr:
                case OpCodes.UshrLong2Addr:
                case OpCodes.AddFloat2Addr:
                case OpCodes.SubFloat2Addr:
                case OpCodes.MulFloat2Addr:
                case OpCodes.DivFloat2Addr:
                case OpCodes.RemFloat2Addr:
                case OpCodes.AddDouble2Addr:
                case OpCodes.SubDouble2Addr:
                case OpCodes.MulDouble2Addr:
                case OpCodes.DivDouble2Addr:
                case OpCodes.RemDouble2Addr:
                    // vA, vB
                    ReadvA(ins);
                    ReadvB(ins);
                    break;

                case OpCodes.MoveWideFrom16:
                case OpCodes.MoveFrom16:
                case OpCodes.MoveObjectFrom16:
                    // vAA, vBBBB
                    ReadvAA(ins);
                    ReadvBBBB(ins);
                    break;

                case OpCodes.Move16:
                case OpCodes.MoveWide16:
                case OpCodes.MoveObject16:
                    // vAAAA, vBBBB
                    ReadvAAAA(ins);
                    ReadvBBBB(ins);
                    break;

                case OpCodes.Const4:
                    // vA, #+B
                    ReadvA(ins);
                    ins.Operand = (int)ReadNibble();
                    break;

                case OpCodes.Const16:
                    // vAA, #+BBBB
                    ReadvAA(ins);
                    ins.Operand = (int)ReadShort(ref _ip);
                    break;

                case OpCodes.ConstWide16:
                    // vAA, #+BBBB
                    ReadvAA(ins);
                    ins.Operand = (long)ReadShort(ref _ip);
                    break;

                case OpCodes.Const:
                    // vAA, #+BBBBBBBB
                    ReadvAA(ins);
                    ins.Operand = ReadInt(ref _ip);
                    break;

                case OpCodes.ConstWide32:
                    // vAA, #+BBBBBBBB
                    ReadvAA(ins);
                    ins.Operand = (long)ReadInt(ref _ip);
                    break;

                case OpCodes.FillArrayData:
                    // vAA, #+BBBBBBBB
                    ReadvAA(ins);
                    offset      = ReadInt(ref _ip);
                    ins.Operand = ExtractArrayData(ins.Offset + offset);
                    break;

                case OpCodes.ConstHigh16:
                    // vAA, #+BBBB0000
                    ReadvAA(ins);
                    ins.Operand = ((long)ReadShort(ref _ip)) << 16;
                    break;

                case OpCodes.ConstWide:
                    // vAA, #+BBBBBBBBBBBBBBBB
                    ReadvAA(ins);
                    ins.Operand = ReadLong(ref _ip);
                    break;

                case OpCodes.ConstWideHigh16:
                    // vAA, #+BBBB000000000000
                    ReadvAA(ins);
                    ins.Operand = ((long)ReadUShort(ref _ip)) << 48;
                    break;

                case OpCodes.ConstString:
                    // vAA, string@BBBB
                    ReadvAA(ins);
                    ins.Operand = Dex.Strings[ReadUShort(ref _ip)];
                    break;

                case OpCodes.ConstStringJumbo:
                    // vAA, string@BBBBBBBB
                    ReadvAA(ins);
                    ins.Operand = Dex.Strings[ReadInt(ref _ip)];
                    break;

                case OpCodes.ConstClass:
                case OpCodes.NewInstance:
                case OpCodes.CheckCast:
                    // vAA, type@BBBB
                    ReadvAA(ins);
                    ins.Operand = Dex.TypeReferences[ReadShort(ref _ip)];
                    break;

                case OpCodes.InstanceOf:
                case OpCodes.NewArray:
                    // vA, vB, type@CCCC
                    ReadvA(ins);
                    ReadvB(ins);
                    ins.Operand = Dex.TypeReferences[ReadShort(ref _ip)];
                    break;

                case OpCodes.FilledNewArray:
                    // {vD, vE, vF, vG, vA}, type@CCCC
                    registerMask  = Upper[_ip++] << 16;
                    ins.Operand   = Dex.TypeReferences[ReadShort(ref _ip)];
                    registerMask |= Codes[_ip++];
                    SetRegistersByMask(ins, registerMask);
                    break;

                case OpCodes.FilledNewArrayRange:
                    // {vCCCC .. vNNNN}, type@BBBB
                    registerCount = ReadUByte();
                    ins.Operand   = Dex.TypeReferences[ReadShort(ref _ip)];
                    ReadvBBBB(ins);
                    for (var i = 1; i < registerCount; i++)
                    {
                        ins.Registers.Add(registers[i + ins.Registers[0].Index]);
                    }
                    break;

                case OpCodes.Goto:
                    // +AA
                    offset = ReadSByte();
                    LazyInstructionsSetters.Add(() => ins.Operand = Lookup[(ushort)(ins.Offset + offset)]);
                    break;

                case OpCodes.Goto16:
                    // +AAAA
                    _ip++;
                    offset = ReadShort(ref _ip);
                    LazyInstructionsSetters.Add(() => ins.Operand = Lookup[(ushort)(ins.Offset + offset)]);
                    break;

                case OpCodes.Goto32:
                    // +AAAAAAAA
                    _ip++;
                    offset = ReadInt(ref _ip);
                    LazyInstructionsSetters.Add(() => ins.Operand = Lookup[(ushort)(ins.Offset + offset)]);
                    break;

                case OpCodes.PackedSwitch:
                    // vAA, +BBBBBBBB
                    ReadvAA(ins);
                    offset      = ReadInt(ref _ip);
                    ins.Operand = ExtractPackedSwitch(ins, ins.Offset + offset);
                    break;

                case OpCodes.SparseSwitch:
                    // vAA, +BBBBBBBB
                    ReadvAA(ins);
                    offset      = ReadInt(ref _ip);
                    ins.Operand = ExtractSparseSwitch(ins, ins.Offset + offset);
                    break;

                case OpCodes.CmplFloat:
                case OpCodes.CmpgFloat:
                case OpCodes.CmplDouble:
                case OpCodes.CmpgDouble:
                case OpCodes.CmpLong:
                case OpCodes.Aget:
                case OpCodes.AgetWide:
                case OpCodes.AgetObject:
                case OpCodes.AgetBoolean:
                case OpCodes.AgetByte:
                case OpCodes.AgetChar:
                case OpCodes.AgetShort:
                case OpCodes.Aput:
                case OpCodes.AputWide:
                case OpCodes.AputObject:
                case OpCodes.AputBoolean:
                case OpCodes.AputByte:
                case OpCodes.AputChar:
                case OpCodes.AputShort:
                case OpCodes.AddInt:
                case OpCodes.SubInt:
                case OpCodes.MulInt:
                case OpCodes.DivInt:
                case OpCodes.RemInt:
                case OpCodes.AndInt:
                case OpCodes.OrInt:
                case OpCodes.XorInt:
                case OpCodes.ShlInt:
                case OpCodes.ShrInt:
                case OpCodes.UshrInt:
                case OpCodes.AddLong:
                case OpCodes.SubLong:
                case OpCodes.MulLong:
                case OpCodes.DivLong:
                case OpCodes.RemLong:
                case OpCodes.AndLong:
                case OpCodes.OrLong:
                case OpCodes.XorLong:
                case OpCodes.ShlLong:
                case OpCodes.ShrLong:
                case OpCodes.UshrLong:
                case OpCodes.AddFloat:
                case OpCodes.SubFloat:
                case OpCodes.MulFloat:
                case OpCodes.DivFloat:
                case OpCodes.RemFloat:
                case OpCodes.AddDouble:
                case OpCodes.SubDouble:
                case OpCodes.MulDouble:
                case OpCodes.DivDouble:
                case OpCodes.RemDouble:
                    // vAA, vBB, vCC
                    ReadvAA(ins);
                    ReadvBB(ins);
                    ReadvCC(ins);
                    break;

                case OpCodes.IfEq:
                case OpCodes.IfNe:
                case OpCodes.IfLt:
                case OpCodes.IfGe:
                case OpCodes.IfGt:
                case OpCodes.IfLe:
                    // vA, vB, +CCCC
                    ReadvA(ins);
                    ReadvB(ins);
                    offset = ReadShort(ref _ip);
                    LazyInstructionsSetters.Add(() => ins.Operand = Lookup[(ushort)(ins.Offset + offset)]);
                    break;

                case OpCodes.IfEqz:
                case OpCodes.IfNez:
                case OpCodes.IfLtz:
                case OpCodes.IfGez:
                case OpCodes.IfGtz:
                case OpCodes.IfLez:
                    // vAA, +BBBB
                    ReadvAA(ins);
                    offset = ReadShort(ref _ip);
                    LazyInstructionsSetters.Add(() => ins.Operand = Lookup[(ushort)(ins.Offset + offset)]);
                    break;

                case OpCodes.Iget:
                case OpCodes.IgetWide:
                case OpCodes.IgetObject:
                case OpCodes.IgetBoolean:
                case OpCodes.IgetByte:
                case OpCodes.IgetChar:
                case OpCodes.IgetShort:
                case OpCodes.Iput:
                case OpCodes.IputWide:
                case OpCodes.IputObject:
                case OpCodes.IputBoolean:
                case OpCodes.IputByte:
                case OpCodes.IputChar:
                case OpCodes.IputShort:
                    // vA, vB, field@CCCC
                    ReadvA(ins);
                    ReadvB(ins);
                    ins.Operand = Dex.FieldReferences[ReadUShort(ref _ip)];
                    break;

                case OpCodes.Sget:
                case OpCodes.SgetWide:
                case OpCodes.SgetObject:
                case OpCodes.SgetBoolean:
                case OpCodes.SgetByte:
                case OpCodes.SgetChar:
                case OpCodes.SgetShort:
                case OpCodes.Sput:
                case OpCodes.SputWide:
                case OpCodes.SputObject:
                case OpCodes.SputBoolean:
                case OpCodes.SputByte:
                case OpCodes.SputChar:
                case OpCodes.SputShort:
                    // vAA, field@BBBB
                    ReadvAA(ins);
                    ins.Operand = Dex.FieldReferences[ReadUShort(ref _ip)];
                    break;

                case OpCodes.InvokeVirtual:
                case OpCodes.InvokeSuper:
                case OpCodes.InvokeDirect:
                case OpCodes.InvokeStatic:
                case OpCodes.InvokeInterface:
                    // {vD, vE, vF, vG, vA}, meth@CCCC
                    registerMask  = Upper[_ip++] << 16;
                    ins.Operand   = Dex.MethodReferences[ReadUShort(ref _ip)];
                    registerMask |= Codes[_ip++];
                    SetRegistersByMask(ins, registerMask);
                    break;

                case OpCodes.InvokeVirtualRange:
                case OpCodes.InvokeSuperRange:
                case OpCodes.InvokeDirectRange:
                case OpCodes.InvokeStaticRange:
                case OpCodes.InvokeInterfaceRange:
                    // {vCCCC .. vNNNN}, meth@BBBB
                    registerCount = ReadSByte();
                    ins.Operand   = Dex.MethodReferences[ReadUShort(ref _ip)];
                    ReadvBBBB(ins);
                    for (var i = 1; i < registerCount; i++)
                    {
                        ins.Registers.Add(registers[i + ins.Registers[0].Index]);
                    }
                    break;

                case OpCodes.AddIntLit16:
                case OpCodes.RsubInt:
                case OpCodes.MulIntLit16:
                case OpCodes.DivIntLit16:
                case OpCodes.RemIntLit16:
                case OpCodes.AndIntLit16:
                case OpCodes.OrIntLit16:
                case OpCodes.XorIntLit16:
                    // vA, vB, #+CCCC
                    ReadvA(ins);
                    ReadvB(ins);
                    ins.Operand = (int)ReadShort(ref _ip);
                    break;

                case OpCodes.AddIntLit8:
                case OpCodes.RsubIntLit8:
                case OpCodes.MulIntLit8:
                case OpCodes.DivIntLit8:
                case OpCodes.RemIntLit8:
                case OpCodes.AndIntLit8:
                case OpCodes.OrIntLit8:
                case OpCodes.XorIntLit8:
                case OpCodes.ShlIntLit8:
                case OpCodes.ShrIntLit8:
                case OpCodes.UshrIntLit8:
                    // vAA, vBB, #+CC
                    ReadvAA(ins);
                    ReadvBB(ins);
                    ins.Operand = ReadSByte();
                    break;

                default:
                    throw new NotImplementedException(string.Concat("Unknown opcode:", ins.OpCode));
                }

                LookupLast.Add(_ip - 1, ins);
            }

            if (_ip != InstructionsSize)
            {
                throw new MalformedException("Instruction pointer out of range");
            }

            foreach (var action in LazyInstructionsSetters)
            {
                action();
            }
        }