Skip to content

Commit

Permalink
[DEX] Abstracting smali and dex classes with similar structure
Browse files Browse the repository at this point in the history
  • Loading branch information
REAndroid committed Dec 2, 2024
1 parent 7849c2f commit f7f01e3
Show file tree
Hide file tree
Showing 54 changed files with 1,435 additions and 604 deletions.
26 changes: 26 additions & 0 deletions src/main/java/com/reandroid/dex/common/AccessFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
import com.reandroid.dex.smali.SmaliReader;
import com.reandroid.utils.collection.ArrayCollection;
import com.reandroid.utils.collection.ArrayIterator;
import com.reandroid.utils.collection.EmptyIterator;

import java.lang.annotation.ElementType;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -117,6 +119,18 @@ private AccessFlag(int value, String name, boolean validForClass, boolean validF
public boolean isSet(int accessFlags) {
return (getValue() & accessFlags) != 0;
}
public boolean isSet(ElementType elementType, int accessFlags) {
if (elementType == ElementType.TYPE) {
return isSetForClass(accessFlags);
}
if (elementType == ElementType.FIELD) {
return isSetForField(accessFlags);
}
if (elementType == ElementType.METHOD) {
return isSetForMethod(accessFlags);
}
return false;
}
private boolean isSetForField(int value) {
return validForField && (getValue() & value) != 0;
}
Expand All @@ -127,6 +141,18 @@ private boolean isSetForClass(int value) {
return validForClass && (getValue() & value) != 0;
}

public static Iterator<AccessFlag> valuesOf(ElementType elementType, int value) {
if (elementType == ElementType.TYPE) {
return valuesOfClass(value);
}
if (elementType == ElementType.FIELD) {
return valuesOfField(value);
}
if (elementType == ElementType.METHOD) {
return valuesOfMethod(value);
}
return EmptyIterator.of();
}
public static Iterator<AccessFlag> valuesOfClass(int value) {
return getValues(accessFlag -> accessFlag.isSetForClass(value));
}
Expand Down
22 changes: 3 additions & 19 deletions src/main/java/com/reandroid/dex/common/IdDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,10 @@
package com.reandroid.dex.common;

import com.reandroid.dex.id.IdItem;
import com.reandroid.dex.program.AccessibleProgram;

import java.util.Iterator;
public interface IdDefinition<T extends IdItem> extends AccessibleProgram {

public interface IdDefinition<T extends IdItem> extends AnnotatedItem {
T getId();
int getAccessFlagsValue();
Iterator<? extends Modifier> getAccessFlags();
default Iterator<? extends Modifier> getModifiers(){
return getAccessFlags();
}
void setAccessFlagsValue(int value);
default void addAccessFlag(AccessFlag flag) {
int current = getAccessFlagsValue();
int value = flag.getValue();
if((value & 0x7) != 0){
current = current & ~0x7;
}
setAccessFlagsValue(current | value);
}
default void removeAccessFlag(AccessFlag flag) {
setAccessFlagsValue(getAccessFlagsValue() & ~flag.getValue());
}

}
7 changes: 7 additions & 0 deletions src/main/java/com/reandroid/dex/common/Modifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,11 @@ public static int combineValues(Modifier[] modifiers){
}
return result;
}
public static int combineValues(Iterator<? extends Modifier> iterator) {
int result = 0;
while (iterator.hasNext()) {
result += iterator.next().getValue();
}
return result;
}
}
61 changes: 61 additions & 0 deletions src/main/java/com/reandroid/dex/dalvik/DalvikAnnotation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.dex.dalvik;

import com.reandroid.dex.program.ProgramElement;
import com.reandroid.dex.key.AnnotationItemKey;
import com.reandroid.dex.key.Key;
import com.reandroid.dex.key.TypeKey;

public class DalvikAnnotation {

private final ProgramElement programElement;
private final TypeKey annotationType;

protected DalvikAnnotation(ProgramElement programElement, TypeKey annotationType) {
this.programElement = programElement;
this.annotationType = annotationType;
}

public AnnotationItemKey getKey() {
return getProgramElement().getAnnotation(getAnnotationType());
}
public void setKey(AnnotationItemKey key) {
if (!getAnnotationType().equals(key.getType())) {
throw new IllegalArgumentException("Different annotation type: "
+ getAnnotationType() + ", " + key.getType());
}
getProgramElement().addAnnotation(key);
}
public TypeKey getAnnotationType() {
return annotationType;
}
public ProgramElement getProgramElement() {
return programElement;
}

Key readValue(String name) {
return getKey().getValue(name);
}
void writeValue(String name, Key value) {
setKey(getKey().add(name, value));
}

@Override
public String toString() {
return getKey().toString();
}
}
61 changes: 61 additions & 0 deletions src/main/java/com/reandroid/dex/dalvik/DalvikEnclosing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.dex.dalvik;

import com.reandroid.dex.key.Key;
import com.reandroid.dex.key.NullValueKey;
import com.reandroid.dex.key.TypeKey;
import com.reandroid.dex.program.ProgramElement;
import com.reandroid.utils.ObjectsUtil;

public abstract class DalvikEnclosing<T extends Key> extends DalvikAnnotation {

public DalvikEnclosing(ProgramElement programElement, TypeKey annotationType) {
super(programElement, annotationType);
}

public T getEnclosing() {
Key value = readValue(Key.DALVIK_value);
if (value == null || (value instanceof NullValueKey)) {
return null;
}
return ObjectsUtil.cast(value);
}
public void setEnclosing(T enclosing) {
Key value = enclosing == null ? NullValueKey.INSTANCE : enclosing;
writeValue(Key.DALVIK_value, value);
}
public TypeKey getEnclosingClass() {
Key key = getEnclosing();
if (key != null) {
return key.getDeclaring();
}
return null;
}

@Override
public String toString() {
return String.valueOf(getEnclosing());
}

public static DalvikEnclosing<?> of(ProgramElement programElement) {
DalvikEnclosing<?> enclosing = DalvikEnclosingClass.of(programElement);
if (enclosing == null) {
enclosing = DalvikEnclosingMethod.of(programElement);
}
return enclosing;
}
}
47 changes: 47 additions & 0 deletions src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingClass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.dex.dalvik;

import com.reandroid.dex.common.AnnotationVisibility;
import com.reandroid.dex.key.*;
import com.reandroid.dex.program.ProgramElement;

public class DalvikEnclosingClass extends DalvikEnclosing<TypeKey> {

private DalvikEnclosingClass(ProgramElement programElement) {
super(programElement, TypeKey.DALVIK_EnclosingClass);
}

public static DalvikEnclosingClass of(ProgramElement programElement) {
if (programElement.hasAnnotation(TypeKey.DALVIK_EnclosingClass)) {
return new DalvikEnclosingClass(programElement);
}
return null;
}
public static DalvikEnclosingClass getOrCreate(ProgramElement programElement) {
if (!programElement.hasAnnotation(TypeKey.DALVIK_EnclosingClass)) {
TypeKey typeKey = (TypeKey) programElement.getKey();
typeKey = typeKey.getEnclosingClass();
programElement.addAnnotation(AnnotationItemKey.create(
AnnotationVisibility.SYSTEM,
TypeKey.DALVIK_EnclosingClass,
AnnotationElementKey.create(Key.DALVIK_value, typeKey)
)
);
}
return of(programElement);
}
}
45 changes: 45 additions & 0 deletions src/main/java/com/reandroid/dex/dalvik/DalvikEnclosingMethod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.dex.dalvik;

import com.reandroid.dex.common.AnnotationVisibility;
import com.reandroid.dex.key.*;
import com.reandroid.dex.program.ProgramElement;

public class DalvikEnclosingMethod extends DalvikEnclosing<MethodKey> {

private DalvikEnclosingMethod(ProgramElement programElement) {
super(programElement, TypeKey.DALVIK_EnclosingMethod);
}

public static DalvikEnclosingMethod of(ProgramElement programElement) {
if (programElement.hasAnnotation(TypeKey.DALVIK_EnclosingMethod)) {
return new DalvikEnclosingMethod(programElement);
}
return null;
}
public static DalvikEnclosingMethod getOrCreate(ProgramElement programElement) {
if (!programElement.hasAnnotation(TypeKey.DALVIK_EnclosingMethod)) {
programElement.addAnnotation(AnnotationItemKey.create(
AnnotationVisibility.SYSTEM,
TypeKey.DALVIK_EnclosingMethod,
AnnotationElementKey.create(Key.DALVIK_value, NullValueKey.INSTANCE)
)
);
}
return of(programElement);
}
}
76 changes: 76 additions & 0 deletions src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.dex.dalvik;

import com.reandroid.dex.common.AccessFlag;
import com.reandroid.dex.common.AnnotationVisibility;
import com.reandroid.dex.key.*;
import com.reandroid.dex.program.ProgramElement;

import java.util.Iterator;

public class DalvikInnerClass extends DalvikAnnotation {

private DalvikInnerClass(ProgramElement programElement) {
super(programElement, TypeKey.DALVIK_InnerClass);
}

public Iterator<AccessFlag> getAccessFlags() {
return AccessFlag.valuesOfClass(getAccessFlagsValue());
}
public int getAccessFlagsValue() {
PrimitiveKey key = (PrimitiveKey) readValue(Key.DALVIK_accessFlags);
return (int) key.getValueAsLong();
}
public void setAccessFlags(int flags) {
writeValue(Key.DALVIK_accessFlags, PrimitiveKey.of(flags));
}
public String getName() {
Key key = getKey().getValue(Key.DALVIK_name);
if (key instanceof StringKey) {
return ((StringKey) key).getString();
}
return null;
}
public void setName(String name) {
Key key = name == null? NullValueKey.INSTANCE : StringKey.create(name);
writeValue(Key.DALVIK_name, key);
}

@Override
public String toString() {
return AccessFlag.toString(getAccessFlags()) + getName();
}

public static DalvikInnerClass of(ProgramElement programElement) {
if (programElement.hasAnnotation(TypeKey.DALVIK_InnerClass)) {
return new DalvikInnerClass(programElement);
}
return null;
}
public static DalvikInnerClass getOrCreate(ProgramElement programElement) {
if (!programElement.hasAnnotation(TypeKey.DALVIK_InnerClass)) {
programElement.addAnnotation(AnnotationItemKey.create(
AnnotationVisibility.SYSTEM,
TypeKey.DALVIK_InnerClass,
AnnotationElementKey.create(Key.DALVIK_accessFlags, PrimitiveKey.of(0)),
AnnotationElementKey.create(Key.DALVIK_name, NullValueKey.INSTANCE)
)
);
}
return of(programElement);
}
}
Loading

0 comments on commit f7f01e3

Please sign in to comment.