27
27
* #L%
28
28
*/
29
29
30
- import java .util .HashSet ;
31
30
import java .util .List ;
32
- import java .util .Set ;
33
31
34
32
import org .jf .dexlib2 .iface .instruction .Instruction ;
35
33
import org .jf .dexlib2 .iface .instruction .formats .ArrayPayload ;
36
- import org .jf .dexlib2 .iface .instruction .formats .Instruction22c ;
37
34
import org .jf .dexlib2 .iface .instruction .formats .Instruction31t ;
38
- import org .jf .dexlib2 .iface .reference .TypeReference ;
39
35
import org .slf4j .Logger ;
40
36
import org .slf4j .LoggerFactory ;
41
37
42
- import soot .ArrayType ;
43
- import soot .BooleanType ;
44
- import soot .ByteType ;
45
- import soot .CharType ;
46
- import soot .DoubleType ;
47
- import soot .FloatType ;
48
- import soot .IntType ;
49
38
import soot .Local ;
50
- import soot .LongType ;
51
- import soot .ShortType ;
52
- import soot .Type ;
53
39
import soot .dexpler .DexBody ;
54
- import soot .dexpler .DexType ;
40
+ import soot .dexpler .DexFillArrayDataTransformer ;
41
+ import soot .dexpler .typing .UntypedConstant ;
42
+ import soot .dexpler .typing .UntypedIntOrFloatConstant ;
43
+ import soot .dexpler .typing .UntypedLongOrDoubleConstant ;
55
44
import soot .jimple .ArrayRef ;
56
45
import soot .jimple .AssignStmt ;
57
- import soot .jimple .DoubleConstant ;
58
- import soot .jimple .FloatConstant ;
46
+ import soot .jimple .Constant ;
59
47
import soot .jimple .IntConstant ;
60
48
import soot .jimple .Jimple ;
61
- import soot .jimple .LongConstant ;
62
- import soot .jimple .NumericConstant ;
63
49
import soot .jimple .Stmt ;
64
50
51
+ /**
52
+ * Converts <code>fill-array-data</code> instructions and associated data blocks into a series of assignment instructions
53
+ * (one for each array index the data block contains a value).
54
+ *
55
+ * As the data block contains untyped data, only the number of bytes per element is known. Recovering the array type at the
56
+ * stage this class is used on would require a detailed analysis on the dex code. Therefore we save the data elements as
57
+ * {@link UntypedConstant} and later use {@link DexFillArrayDataTransformer} to convert the values to their final type.
58
+ */
65
59
public class FillArrayDataInstruction extends PseudoInstruction {
66
60
private static final Logger logger = LoggerFactory .getLogger (FillArrayDataInstruction .class );
67
61
@@ -95,13 +89,11 @@ public void jimplify(DexBody body) {
95
89
List <Number > elements = arrayTable .getArrayElements ();
96
90
int numElements = elements .size ();
97
91
92
+ int elementsWidth = arrayTable .getElementWidth ();
98
93
Stmt firstAssign = null ;
99
94
for (int i = 0 ; i < numElements ; i ++) {
100
95
ArrayRef arrayRef = Jimple .v ().newArrayRef (arrayReference , IntConstant .v (i ));
101
- NumericConstant element = getArrayElement (elements .get (i ), body , destRegister );
102
- if (element == null ) {
103
- break ;
104
- }
96
+ Constant element = getArrayElement (elements .get (i ), elementsWidth );
105
97
AssignStmt assign = Jimple .v ().newAssignStmt (arrayRef , element );
106
98
addTags (assign );
107
99
body .add (assign );
@@ -110,6 +102,8 @@ public void jimplify(DexBody body) {
110
102
}
111
103
}
112
104
if (firstAssign == null ) { // if numElements == 0. Is it possible?
105
+ logger .warn ("No assign statements created for array at address 0x{} - empty array data section?" ,
106
+ Integer .toHexString (targetAddress ));
113
107
firstAssign = Jimple .v ().newNopStmt ();
114
108
body .add (firstAssign );
115
109
}
@@ -122,80 +116,19 @@ public void jimplify(DexBody body) {
122
116
123
117
}
124
118
125
- private NumericConstant getArrayElement (Number element , DexBody body , int arrayRegister ) {
126
-
127
- List <DexlibAbstractInstruction > instructions = body .instructionsBefore (this );
128
- Set <Integer > usedRegisters = new HashSet <Integer >();
129
- usedRegisters .add (arrayRegister );
130
-
131
- Type elementType = null ;
132
- Outer : for (DexlibAbstractInstruction i : instructions ) {
133
- if (usedRegisters .isEmpty ()) {
134
- break ;
135
- }
136
-
137
- for (int reg : usedRegisters ) {
138
- if (i instanceof NewArrayInstruction ) {
139
- NewArrayInstruction newArrayInstruction = (NewArrayInstruction ) i ;
140
- Instruction22c instruction22c = (Instruction22c ) newArrayInstruction .instruction ;
141
- if (instruction22c .getRegisterA () == reg ) {
142
- ArrayType arrayType = (ArrayType ) DexType .toSoot ((TypeReference ) instruction22c .getReference ());
143
- elementType = arrayType .getElementType ();
144
- break Outer ;
145
- }
146
- }
147
- }
148
-
149
- // // look for obsolete registers
150
- // for (int reg : usedRegisters) {
151
- // if (i.overridesRegister(reg)) {
152
- // usedRegisters.remove(reg);
153
- // break; // there can't be more than one obsolete
154
- // }
155
- // }
156
-
157
- // look for new registers
158
- for (int reg : usedRegisters ) {
159
- int newRegister = i .movesToRegister (reg );
160
- if (newRegister != -1 ) {
161
- usedRegisters .add (newRegister );
162
- usedRegisters .remove (reg );
163
- break ; // there can't be more than one new
164
- }
165
- }
119
+ private Constant getArrayElement (Number element , int elementsWidth ) {
120
+ if (elementsWidth == 2 ) {
121
+ // For size = 2 the only possible array type is short[]
122
+ return IntConstant .v (element .shortValue ());
166
123
}
167
124
168
- if (elementType == null ) {
169
- // throw new InternalError("Unable to find array type to type array elements!");
170
- logger .warn ("Unable to find array type to type array elements! Array was not defined! (obfuscated bytecode?)" );
171
- return null ;
172
- }
173
-
174
- NumericConstant value ;
175
-
176
- if (elementType instanceof BooleanType ) {
177
- value = IntConstant .v (element .intValue ());
178
- IntConstant ic = (IntConstant ) value ;
179
- if (ic .value != 0 ) {
180
- value = IntConstant .v (1 );
181
- }
182
- } else if (elementType instanceof ByteType ) {
183
- value = IntConstant .v (element .byteValue ());
184
- } else if (elementType instanceof CharType || elementType instanceof ShortType ) {
185
- value = IntConstant .v (element .shortValue ());
186
- } else if (elementType instanceof DoubleType ) {
187
- value = DoubleConstant .v (Double .longBitsToDouble (element .longValue ()));
188
- } else if (elementType instanceof FloatType ) {
189
- value = FloatConstant .v (Float .intBitsToFloat (element .intValue ()));
190
- } else if (elementType instanceof IntType ) {
191
- value = IntConstant .v (element .intValue ());
192
- } else if (elementType instanceof LongType ) {
193
- value = LongConstant .v (element .longValue ());
194
- } else {
195
- throw new RuntimeException ("Invalid Array Type occured in FillArrayDataInstruction: " + elementType );
125
+ if (elementsWidth <= 4 ) {
126
+ // can be array of int, char, boolean, float
127
+ return UntypedIntOrFloatConstant .v (element .intValue ());
196
128
}
197
- return value ;
198
129
130
+ // can be array of long or double
131
+ return UntypedLongOrDoubleConstant .v (element .longValue ());
199
132
}
200
133
201
134
@ Override
0 commit comments