diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/EncValueParser.java b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/EncValueParser.java index 17fbabba3..0ae5bb082 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/EncValueParser.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/EncValueParser.java @@ -22,7 +22,7 @@ public class EncValueParser extends EncodedValueReader { } public Object parseValue() throws DecodeException { - int argAndType = in.readByte() & 0xFF; + int argAndType = readByte(); int type = argAndType & 0x1F; int arg = (argAndType & 0xE0) >> 5; int size = arg + 1; @@ -39,28 +39,29 @@ public class EncValueParser extends EncodedValueReader { case ENCODED_SHORT: return (short) parseNumber(size, true); case ENCODED_CHAR: - return (char) parseNumber(size, false); + return (char) parseUnsignedInt(size); case ENCODED_INT: return (int) parseNumber(size, true); case ENCODED_LONG: return parseNumber(size, true); + case ENCODED_FLOAT: - return Float.intBitsToFloat((int) parseNumber(size, false)); + return Float.intBitsToFloat((int) parseNumber(size, false, 4)); case ENCODED_DOUBLE: - return Double.longBitsToDouble(parseNumber(size, false)); + return Double.longBitsToDouble(parseNumber(size, false, 8)); case ENCODED_STRING: - return dex.getString((int) parseNumber(size, false)); + return dex.getString(parseUnsignedInt(size)); case ENCODED_TYPE: - return dex.getType((int) parseNumber(size, false)); + return dex.getType(parseUnsignedInt(size)); case ENCODED_METHOD: - return MethodInfo.fromDex(dex, (int) parseNumber(size, false)); + return MethodInfo.fromDex(dex, parseUnsignedInt(size)); case ENCODED_FIELD: case ENCODED_ENUM: - return FieldInfo.fromDex(dex, (int) parseNumber(size, false)); + return FieldInfo.fromDex(dex, parseUnsignedInt(size)); case ENCODED_ARRAY: int count = Leb128Utils.readUnsignedLeb128(in); @@ -76,18 +77,36 @@ public class EncValueParser extends EncodedValueReader { throw new DecodeException("Unknown encoded value type: 0x" + Integer.toHexString(type)); } + private int parseUnsignedInt(int byteCount) { + return (int) parseNumber(byteCount, false, 0); + } + private long parseNumber(int byteCount, boolean isSignExtended) { + return parseNumber(byteCount, isSignExtended, 0); + } + + private long parseNumber(int byteCount, boolean isSignExtended, int fillOnRight) { long result = 0; - int shift = 8; - int first = in.readByte() & 0xFF; - if (isSignExtended && (first & 0x80) != 0) { - result = ~result << shift; + long last = 0; + for (int i = 0; i < byteCount; i++) { + last = readByte(); + result |= last << i * 8; } - result |= (long) first; - for (int i = 1; i < byteCount; i++) { - result |= (long) (in.readByte() & 0xFF) << shift; - shift += 8; + if (fillOnRight != 0) { + for (int i = byteCount; i < fillOnRight; i++) { + result <<= 8; + } + } else { + if (isSignExtended && (last & 0x80) != 0) { + for (int i = byteCount; i < 8; i++) { + result |= (long) 0xFF << i * 8; + } + } } return result; } + + private int readByte() { + return in.readByte() & 0xFF; + } } diff --git a/jadx-core/src/test/java/jadx/tests/internal/TestAnnotations.java b/jadx-core/src/test/java/jadx/tests/internal/TestAnnotations.java index 2ed2c5c60..59d001e12 100644 --- a/jadx-core/src/test/java/jadx/tests/internal/TestAnnotations.java +++ b/jadx-core/src/test/java/jadx/tests/internal/TestAnnotations.java @@ -17,7 +17,15 @@ public class TestAnnotations extends InternalJadxTest { } @A(a = -1) - public void method1() { + public void methodA1() { + } + + @A(a = -253) + public void methodA2() { + } + + @A(a = -11253) + public void methodA3() { } private static @interface V { @@ -25,7 +33,7 @@ public class TestAnnotations extends InternalJadxTest { } @V(false) - public void method2() { + public void methodV() { } private static @interface D { @@ -33,7 +41,7 @@ public class TestAnnotations extends InternalJadxTest { } @D - public void method3() { + public void methodD() { } } @@ -41,9 +49,12 @@ public class TestAnnotations extends InternalJadxTest { public void test() { ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); + System.out.println(code); assertThat(code, not(containsString("@A(a = 255)"))); assertThat(code, containsString("@A(a = -1)")); + assertThat(code, containsString("@A(a = -253)")); + assertThat(code, containsString("@A(a = -11253)")); assertThat(code, containsString("@V(false)")); assertThat(code, not(containsString("@D()"))); } diff --git a/jadx-samples/src/main/java/jadx/samples/AbstractTest.java b/jadx-samples/src/main/java/jadx/samples/AbstractTest.java index 3f8d290c4..61dede9f6 100644 --- a/jadx-samples/src/main/java/jadx/samples/AbstractTest.java +++ b/jadx-samples/src/main/java/jadx/samples/AbstractTest.java @@ -28,6 +28,12 @@ public abstract class AbstractTest { } } + public static void assertEquals(float a1, float a2) { + if (Float.compare(a1, a2) != 0) { + throw new AssertionError(a1 + " != " + a2); + } + } + public static void assertEquals(Object a1, Object a2) { if (a1 == null) { if (a2 != null) diff --git a/jadx-samples/src/main/java/jadx/samples/TestAnnotationsParser.java b/jadx-samples/src/main/java/jadx/samples/TestAnnotationsParser.java new file mode 100644 index 000000000..cfb364d17 --- /dev/null +++ b/jadx-samples/src/main/java/jadx/samples/TestAnnotationsParser.java @@ -0,0 +1,42 @@ +package jadx.samples; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +public class TestAnnotationsParser extends AbstractTest { + + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public static @interface A { + int i(); + + float f(); + } + + @A(i = -1, f = C1.FLOAT_CONST) + public static class C1 { + public static final float FLOAT_CONST = 3.14f; + } + + @A(i = -1025, f = C2.FLOAT_CONST) + public static class C2 { + public static final float FLOAT_CONST = 0xFF0000; + } + + public boolean testRun() { + A c1 = C1.class.getAnnotation(A.class); + assertEquals(c1.i(), -1); + assertEquals(c1.f(), C1.FLOAT_CONST); + + A c2 = C2.class.getAnnotation(A.class); + assertEquals(c2.i(), -1025); + assertEquals(c2.f(), C2.FLOAT_CONST); + return true; + } + + public static void main(String[] args) throws Exception { + new TestAnnotationsParser().testRun(); + } +}