Skip to content

Commit

Permalink
Add shorthand for declaring fields of the same type.
Browse files Browse the repository at this point in the history
Add 'obfuscated' attribute to generate static constructor for enums.
  • Loading branch information
rodit committed May 15, 2022
1 parent 4d69c0c commit f3fe22b
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 6 deletions.
9 changes: 8 additions & 1 deletion schema/SchemaGrammar.g4
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ BIND_EVENT_MODIFIER: 'previous'
| 'next' ;
BIND_EVENT_SOURCE: 'reference' ;

AUTO_FIELDS: '.fields' ;

BYTECODE_STRING: '.string' ;
BYTECODE_STRING_REGEX: 'regex' ;
BYTECODE_STRING_CONTAINS: 'contains' ;
Expand Down Expand Up @@ -127,6 +129,11 @@ definitionPrefix: schemaAttributes? annotation* ACCESS_FLAG* ;

name: DOLLAR? IDENTIFIER ;

autoField: definitionPrefix type? name ;
autoFieldList: autoField
| autoField (COMMA autoField)* ;

autoFieldsDefinition: definitionPrefix type AUTO_FIELDS OPEN_BRACE autoFieldList CLOSE_BRACE ;
fieldDefinition: definitionPrefix type name SEMICOLON ;

type: OPEN_TRI EXTENDS type CLOSE_TRI #extendsType
Expand Down Expand Up @@ -178,7 +185,7 @@ expectsStatement: EXPECTS javaTypeName ;
extendsStatement: EXTENDS type ;
implementsStatement: IMPLEMENTS type (COMMA type)* ;

classDefinition: definitionPrefix CLASS_TYPE name expectsStatement? extendsStatement? implementsStatement? OPEN_BRACE fieldDefinition* methodDefinition* CLOSE_BRACE ;
classDefinition: definitionPrefix CLASS_TYPE name expectsStatement? extendsStatement? implementsStatement? OPEN_BRACE autoFieldsDefinition? fieldDefinition* methodDefinition* CLOSE_BRACE ;

importStatement: IMPORT JAVA_TYPE_IDENTIFIER SEMICOLON ;

Expand Down
31 changes: 26 additions & 5 deletions src/main/java/xyz/rodit/dexsearch/parser/SchemaVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public EnumSet<Attribute> visitSchemaAttributes(SchemaGrammarParser.SchemaAttrib
public Annotation visitAnnotation(SchemaGrammarParser.AnnotationContext ctx) {
Object visitedType = super.visit(ctx.type());
if (visitedType instanceof Type annotationType) {
return new Annotation(annotationType, ctx.annotationArguments().constant().stream().map(super::visit).collect(Collectors.toList()));
return new Annotation(annotationType, ctx.annotationArguments().constant().stream().map(super::visit).toList());
}

return null;
Expand All @@ -98,7 +98,7 @@ public Annotation visitAnnotation(SchemaGrammarParser.AnnotationContext ctx) {
@Override
public ClassNode visitClassDefinition(SchemaGrammarParser.ClassDefinitionContext ctx) {
EnumSet<Attribute> attributes = visitSchemaAttributes(ctx.definitionPrefix().schemaAttributes(), Target.CLASS);
int accessModifiers = AccessUtils.getModifiers(ctx.definitionPrefix().ACCESS_FLAG().stream().map(ParseTree::getText).collect(Collectors.toList()))
int accessModifiers = AccessUtils.getModifiers(ctx.definitionPrefix().ACCESS_FLAG().stream().map(ParseTree::getText).toList())
| AccessUtils.getModifierValue(ctx.CLASS_TYPE().getText());
Name name = visitName(ctx.name());
String expected = ctx.expectsStatement() != null
Expand All @@ -111,15 +111,36 @@ public ClassNode visitClassDefinition(SchemaGrammarParser.ClassDefinitionContext
? ctx.implementsStatement().type().stream().map(this::visitType).toList()
: List.of();
List<Annotation> annotations = ctx.definitionPrefix().annotation().stream().map(this::visitAnnotation).toList();
List<FieldNode> fields = ctx.fieldDefinition().stream().map(this::visitFieldDefinition).toList();
List<FieldNode> fields = new ArrayList<>();
if (ctx.autoFieldsDefinition() != null) {
fields.addAll(visitAutoFieldsDefinition(ctx.autoFieldsDefinition()));
}
fields.addAll(ctx.fieldDefinition().stream().map(this::visitFieldDefinition).toList());
List<MethodNode> methods = ctx.methodDefinition().stream().map(this::visitMethodDefinition).toList();
return new ClassNode(attributes, accessModifiers, name, expected, annotations, extendsType, interfaceTypes, fields, methods);
}

@Override
public List<FieldNode> visitAutoFieldsDefinition(SchemaGrammarParser.AutoFieldsDefinitionContext ctx) {
EnumSet<Attribute> attributes = visitSchemaAttributes(ctx.definitionPrefix().schemaAttributes(), Target.FIELD);
int accessModifiers = AccessUtils.getModifiers(ctx.definitionPrefix().ACCESS_FLAG().stream().map(ParseTree::getText).toList());
Type type = visitType(ctx.type());
List<Annotation> annotations = ctx.definitionPrefix().annotation().stream().map(this::visitAnnotation).toList();
return ctx.autoFieldList().autoField().stream().map(f -> {
EnumSet<Attribute> fieldAttributes = visitSchemaAttributes(f.definitionPrefix().schemaAttributes(), Target.FIELD);
fieldAttributes.addAll(attributes);
int fieldAccessModifiers = AccessUtils.getModifiers(f.definitionPrefix().ACCESS_FLAG().stream().map(ParseTree::getText).toList()) | accessModifiers;
List<Annotation> fieldAnnotations = new ArrayList<>(annotations);
fieldAnnotations.addAll(f.definitionPrefix().annotation().stream().map(this::visitAnnotation).toList());
Type fieldType = f.type() != null ? visitType(f.type()) : type;
return new FieldNode(fieldAttributes, fieldAccessModifiers, fieldType, visitName(f.name()), fieldAnnotations);
}).toList();
}

@Override
public FieldNode visitFieldDefinition(SchemaGrammarParser.FieldDefinitionContext ctx) {
EnumSet<Attribute> attributes = visitSchemaAttributes(ctx.definitionPrefix().schemaAttributes(), Target.FIELD);
int accessModifiers = AccessUtils.getModifiers(ctx.definitionPrefix().ACCESS_FLAG().stream().map(ParseTree::getText).collect(Collectors.toList()));
int accessModifiers = AccessUtils.getModifiers(ctx.definitionPrefix().ACCESS_FLAG().stream().map(ParseTree::getText).toList());
Type type = visitType(ctx.type());
Name name = visitName(ctx.name());
List<Annotation> annotations = ctx.definitionPrefix().annotation().stream().map(this::visitAnnotation).toList();
Expand All @@ -129,7 +150,7 @@ public FieldNode visitFieldDefinition(SchemaGrammarParser.FieldDefinitionContext
@Override
public MethodNode visitMethodDefinition(SchemaGrammarParser.MethodDefinitionContext ctx) {
EnumSet<Attribute> attributes = visitSchemaAttributes(ctx.definitionPrefix().schemaAttributes(), Target.METHOD);
int accessModifiers = AccessUtils.getModifiers(ctx.definitionPrefix().ACCESS_FLAG().stream().map(ParseTree::getText).collect(Collectors.toList()));
int accessModifiers = AccessUtils.getModifiers(ctx.definitionPrefix().ACCESS_FLAG().stream().map(ParseTree::getText).toList());
Type type = visitType(ctx.type());
Name name = visitName(ctx.name());
List<Annotation> annotations = ctx.definitionPrefix().annotation().stream().map(this::visitAnnotation).toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum Attribute {
NOT(EnumSet.of(Target.FIELD, Target.METHOD)),
CONSERVE(EnumSet.of(Target.INSTRUCTION)),
STRICT(EnumSet.of(Target.INSTRUCTION)),
OBFUSCATED(EnumSet.of(Target.CLASS, Target.FIELD, Target.METHOD)),
// TODO: add support for markers in the future
MARKER(EnumSet.noneOf(Target.class));

Expand Down
30 changes: 30 additions & 0 deletions src/main/java/xyz/rodit/dexsearch/tree/nodes/ClassNode.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package xyz.rodit.dexsearch.tree.nodes;

import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Field;
import org.jf.dexlib2.iface.Member;
Expand All @@ -12,10 +13,14 @@
import xyz.rodit.dexsearch.tree.bindings.Reason;
import xyz.rodit.dexsearch.tree.bindings.options.AccessModifiers;
import xyz.rodit.dexsearch.tree.bindings.options.Option;
import xyz.rodit.dexsearch.tree.nodes.bytecode.BodyNode;
import xyz.rodit.dexsearch.tree.nodes.bytecode.events.*;
import xyz.rodit.dexsearch.tree.nodes.bytecode.matchers.StringMatcher;
import xyz.rodit.dexsearch.tree.properties.Annotation;
import xyz.rodit.dexsearch.tree.properties.Name;
import xyz.rodit.dexsearch.tree.properties.types.ExtendsType;
import xyz.rodit.dexsearch.tree.properties.types.ImplementsType;
import xyz.rodit.dexsearch.tree.properties.types.JavaType;
import xyz.rodit.dexsearch.tree.properties.types.Type;
import xyz.rodit.dexsearch.utils.CollectionUtils;

Expand Down Expand Up @@ -50,6 +55,8 @@ public ClassNode(EnumSet<Attribute> attributes, int accessModifiers, Name name,
CollectionUtils.separate(methods, this.notMethods, this.methods, m -> m.hasAttribute(Attribute.NOT));
lateFieldMap = this.fields.stream().filter(f -> f.hasAttribute(Attribute.LATE)).collect(Collectors.toMap(MemberNode::getName, f -> f));
lateMethodMap = this.methods.stream().filter(m -> m.hasAttribute(Attribute.LATE)).collect(Collectors.toMap(MemberNode::getName, m -> m));

processAttributes();
}

public String getName() {
Expand Down Expand Up @@ -120,4 +127,27 @@ private <T extends Member> void bindMembers(Resolver resolver, ClassBinding bind
}
}
}

private void processAttributes() {
if (hasAttribute(Attribute.OBFUSCATED)) {
if (AccessUtils.hasModifiers(accessModifiers, AccessFlags.ENUM.getValue())) {
methods.add(new MethodNode(
EnumSet.of(Attribute.DISCARD),
AccessFlags.STATIC.getValue(),
new JavaType("void"),
new Name("<clinit>", true),
Collections.emptySet(),
Collections.emptySet(),
fields.stream()
.filter(f ->
AccessUtils.hasModifiers(f.getAccessModifiers(), AccessFlags.STATIC.getValue())
&& f.hasAttribute(Attribute.LATE))
.map(f -> new BodyNode(
EnumSet.of(Attribute.STRICT),
new StringMatcher(f.getName(), false, false),
Collections.singleton(new BindEvent(Operation.BIND, EventTarget.FIELD, f.getName(), Modifiers.get("next"), EventSource.REFERENCE))
)).toList()));
}
}
}
}
4 changes: 4 additions & 0 deletions src/main/java/xyz/rodit/dexsearch/tree/nodes/MemberNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public MemberNode(EnumSet<Attribute> attributes, int accessModifiers, Type type,
this.annotations = new ArrayList<>(annotations);
}

public int getAccessModifiers() {
return accessModifiers;
}

public String getName() {
return name.getName();
}
Expand Down

0 comments on commit f3fe22b

Please sign in to comment.