0
# Static Analysis
1
2
Advanced static analysis capabilities including control flow analysis, call graph generation, method analysis, and cross-reference detection. The Analysis class provides comprehensive static analysis of Android applications.
3
4
## Capabilities
5
6
### Analysis Engine
7
8
The main analysis engine that provides comprehensive static analysis capabilities for Android applications.
9
10
```python { .api }
11
class Analysis:
12
def __init__(self, *args):
13
"""
14
Initialize analysis engine.
15
16
Parameters:
17
- *args: DEX objects to analyze (can be multiple DEX files)
18
"""
19
20
def get_classes(self) -> list:
21
"""Return list of all ClassAnalysis objects."""
22
23
def get_methods(self) -> list:
24
"""Return list of all MethodAnalysis objects."""
25
26
def get_fields(self) -> list:
27
"""Return list of all FieldAnalysis objects."""
28
29
def get_strings(self) -> list:
30
"""Return list of all StringAnalysis objects."""
31
32
def find_classes(self, class_name: str = ".*", no_external: bool = False) -> list:
33
"""
34
Find classes matching pattern.
35
36
Parameters:
37
- class_name: Regular expression pattern for class names
38
- no_external: Exclude external classes if True
39
40
Returns:
41
List of matching ClassAnalysis objects
42
"""
43
44
def find_methods(self, class_name: str = ".*", method_name: str = ".*", descriptor: str = ".*", accessflags: str = ".*", no_external: bool = False) -> list:
45
"""
46
Find methods matching criteria.
47
48
Parameters:
49
- class_name: Class name pattern
50
- method_name: Method name pattern
51
- descriptor: Method descriptor pattern
52
- accessflags: Access flags pattern
53
- no_external: Exclude external methods if True
54
55
Returns:
56
List of matching MethodAnalysis objects
57
"""
58
59
def find_strings(self, string: str = ".*") -> list:
60
"""
61
Find strings matching pattern.
62
63
Parameters:
64
- string: Regular expression pattern
65
66
Returns:
67
List of matching StringAnalysis objects
68
"""
69
70
def find_fields(self, class_name: str = ".*", field_name: str = ".*", field_type: str = ".*", accessflags: str = ".*") -> list:
71
"""
72
Find fields matching criteria.
73
74
Parameters:
75
- class_name: Class name pattern
76
- field_name: Field name pattern
77
- field_type: Field type pattern
78
- accessflags: Access flags pattern
79
80
Returns:
81
List of matching FieldAnalysis objects
82
"""
83
```
84
85
### Call Graph Analysis
86
87
Generate and analyze call graphs showing method invocation relationships.
88
89
```python { .api }
90
def get_call_graph(self, classname: str = ".*", methodname: str = ".*", descriptor: str = ".*", accessflags: str = ".*", no_isolated: bool = False, entry_points: list = None):
91
"""
92
Generate call graph for methods matching criteria.
93
94
Parameters:
95
- classname: Class name filter pattern
96
- methodname: Method name filter pattern
97
- descriptor: Method descriptor pattern
98
- accessflags: Access flags pattern
99
- no_isolated: Exclude isolated nodes
100
- entry_points: List of entry point methods
101
102
Returns:
103
NetworkX DiGraph object representing call graph
104
"""
105
106
def get_method(self, method) -> object:
107
"""
108
Get MethodAnalysis for EncodedMethod.
109
110
Parameters:
111
- method: EncodedMethod object
112
113
Returns:
114
MethodAnalysis object or None
115
"""
116
117
def get_method_by_idx(self, idx: int) -> object:
118
"""Get MethodAnalysis by index."""
119
120
def get_class_analysis(self, class_def) -> object:
121
"""
122
Get ClassAnalysis for ClassDefItem.
123
124
Parameters:
125
- class_def: ClassDefItem object
126
127
Returns:
128
ClassAnalysis object or None
129
"""
130
131
def get_field_analysis(self, field) -> object:
132
"""Get FieldAnalysis for EncodedField."""
133
```
134
135
## Method Analysis
136
137
Detailed analysis of individual methods including control flow and cross-references.
138
139
```python { .api }
140
class MethodAnalysis:
141
def get_method(self):
142
"""Return associated EncodedMethod object."""
143
144
def get_name(self) -> str:
145
"""Return method name."""
146
147
def get_descriptor(self) -> str:
148
"""Return method descriptor."""
149
150
def get_class_name(self) -> str:
151
"""Return containing class name."""
152
153
def get_access_flags_string(self) -> str:
154
"""Return access flags as readable string."""
155
156
def is_external(self) -> bool:
157
"""Return True if method is external/system method."""
158
159
def is_android_api(self) -> bool:
160
"""Return True if method is Android API."""
161
162
def get_length(self) -> int:
163
"""Return method code length."""
164
165
def get_basic_blocks(self) -> object:
166
"""
167
Get basic blocks for method.
168
169
Returns:
170
BasicBlocks object containing control flow blocks
171
"""
172
173
def get_xref_from(self) -> list:
174
"""
175
Get cross-references from this method.
176
177
Returns:
178
List of (ClassAnalysis, MethodAnalysis, offset) tuples
179
"""
180
181
def get_xref_to(self) -> list:
182
"""
183
Get cross-references to this method.
184
185
Returns:
186
List of (ClassAnalysis, MethodAnalysis, offset) tuples
187
"""
188
189
def get_xref_new_instance(self) -> list:
190
"""Get cross-references for new-instance instructions."""
191
192
def get_xref_const_class(self) -> list:
193
"""Get cross-references for const-class instructions."""
194
```
195
196
## Class Analysis
197
198
Comprehensive analysis of classes and their relationships.
199
200
```python { .api }
201
class ClassAnalysis:
202
def get_class(self):
203
"""Return associated ClassDefItem object."""
204
205
def get_name(self) -> str:
206
"""Return class name."""
207
208
def get_superclass_name(self) -> str:
209
"""Return superclass name."""
210
211
def get_interfaces(self) -> list[str]:
212
"""Return list of implemented interface names."""
213
214
def get_access_flags_string(self) -> str:
215
"""Return access flags as readable string."""
216
217
def is_external(self) -> bool:
218
"""Return True if class is external/system class."""
219
220
def is_android_api(self) -> bool:
221
"""Return True if class is Android API."""
222
223
def get_methods(self) -> list:
224
"""
225
Get all methods in class.
226
227
Returns:
228
List of MethodAnalysis objects
229
"""
230
231
def get_fields(self) -> list:
232
"""
233
Get all fields in class.
234
235
Returns:
236
List of FieldAnalysis objects
237
"""
238
239
def get_xref_from(self) -> list:
240
"""Get cross-references from this class."""
241
242
def get_xref_to(self) -> list:
243
"""Get cross-references to this class."""
244
245
def get_xref_new_instance(self) -> list:
246
"""Get new-instance references to this class."""
247
248
def get_xref_const_class(self) -> list:
249
"""Get const-class references to this class."""
250
```
251
252
### Field Analysis
253
254
Analysis of field usage and cross-references.
255
256
```python { .api }
257
class FieldAnalysis:
258
def get_field(self):
259
"""Return associated EncodedField object."""
260
261
def get_name(self) -> str:
262
"""Return field name."""
263
264
def get_descriptor(self) -> str:
265
"""Return field type descriptor."""
266
267
def get_class_name(self) -> str:
268
"""Return containing class name."""
269
270
def get_access_flags_string(self) -> str:
271
"""Return access flags as readable string."""
272
273
def is_external(self) -> bool:
274
"""Return True if field is external."""
275
276
def get_xref_read(self) -> list:
277
"""
278
Get cross-references for field reads.
279
280
Returns:
281
List of (ClassAnalysis, MethodAnalysis, offset) tuples
282
"""
283
284
def get_xref_write(self) -> list:
285
"""
286
Get cross-references for field writes.
287
288
Returns:
289
List of (ClassAnalysis, MethodAnalysis, offset) tuples
290
"""
291
```
292
293
### String Analysis
294
295
Analysis of string usage throughout the application.
296
297
```python { .api }
298
class StringAnalysis:
299
def get_orig_value(self) -> str:
300
"""Return original string value."""
301
302
def get_value(self) -> str:
303
"""Return string value (may be modified)."""
304
305
def set_value(self, value: str) -> None:
306
"""Set new string value."""
307
308
def get_xref_from(self) -> list:
309
"""
310
Get cross-references from this string.
311
312
Returns:
313
List of (ClassAnalysis, MethodAnalysis, offset) tuples where string is used
314
"""
315
```
316
317
## Control Flow Analysis
318
319
Detailed control flow analysis with basic blocks and exception handling.
320
321
```python { .api }
322
class BasicBlocks:
323
def get(self) -> list:
324
"""Return list of all basic blocks."""
325
326
def get_basic_block(self, idx: int):
327
"""Get basic block by index."""
328
329
def gets(self) -> list:
330
"""Return list of basic blocks with extra information."""
331
332
class DEXBasicBlock:
333
def get_name(self) -> str:
334
"""Return basic block name."""
335
336
def get_start(self) -> int:
337
"""Return start offset of block."""
338
339
def get_end(self) -> int:
340
"""Return end offset of block."""
341
342
def get_last_length(self) -> int:
343
"""Return length of last instruction."""
344
345
def get_nb_instructions(self) -> int:
346
"""Return number of instructions in block."""
347
348
def get_instructions(self) -> list:
349
"""Return list of instructions in basic block."""
350
351
def get_exception_analysis(self):
352
"""Return exception analysis for this block."""
353
354
def get_childs(self) -> list:
355
"""
356
Get child basic blocks.
357
358
Returns:
359
List of (next_block, condition) tuples
360
"""
361
362
def get_fathers(self) -> list:
363
"""
364
Get parent basic blocks.
365
366
Returns:
367
List of (prev_block, condition) tuples
368
"""
369
```
370
371
### Exception Analysis
372
373
Analysis of exception handling and flow.
374
375
```python { .api }
376
class ExceptionAnalysis:
377
def get_exception(self):
378
"""Return exception object."""
379
380
def get_catches(self) -> list:
381
"""Return list of catch handlers."""
382
383
def show_source(self) -> str:
384
"""Return formatted source representation."""
385
386
class Exceptions:
387
def get_exception(self, addr_start: int, addr_end: int) -> list:
388
"""
389
Get exceptions for address range.
390
391
Parameters:
392
- addr_start: Start address
393
- addr_end: End address
394
395
Returns:
396
List of exception handlers
397
"""
398
```
399
400
## Usage Examples
401
402
### Basic Static Analysis
403
404
```python
405
from androguard.core.dex import DEX
406
from androguard.core.analysis.analysis import Analysis
407
408
# Load and analyze DEX
409
dex = DEX(open("classes.dex", "rb").read())
410
dx = Analysis(dex)
411
412
# Get analysis statistics
413
print(f"Classes: {len(dx.get_classes())}")
414
print(f"Methods: {len(dx.get_methods())}")
415
print(f"Fields: {len(dx.get_fields())}")
416
print(f"Strings: {len(dx.get_strings())}")
417
418
# Find specific classes
419
activity_classes = dx.find_classes(r".*Activity$")
420
print(f"Activity classes: {len(activity_classes)}")
421
422
for cls in activity_classes:
423
print(f" {cls.get_name()}")
424
```
425
426
### Method Cross-Reference Analysis
427
428
```python
429
# Find onCreate methods
430
oncreate_methods = dx.find_methods(method_name="onCreate")
431
print(f"Found {len(oncreate_methods)} onCreate methods")
432
433
for method in oncreate_methods:
434
print(f"\nMethod: {method.get_class_name()}.{method.get_name()}")
435
436
# Get methods called by this method
437
xrefs_from = method.get_xref_from()
438
if xrefs_from:
439
print(" Calls to:")
440
for ref_class, ref_method, offset in xrefs_from:
441
print(f" {ref_class.get_name()}.{ref_method.get_name()} at offset {offset}")
442
443
# Get methods that call this method
444
xrefs_to = method.get_xref_to()
445
if xrefs_to:
446
print(" Called by:")
447
for ref_class, ref_method, offset in xrefs_to:
448
print(f" {ref_class.get_name()}.{ref_method.get_name()} at offset {offset}")
449
```
450
451
### String Usage Analysis
452
453
```python
454
# Find strings containing sensitive keywords
455
sensitive_strings = dx.find_strings(r".*(password|secret|key|token).*")
456
print(f"Found {len(sensitive_strings)} sensitive strings")
457
458
for string_analysis in sensitive_strings:
459
string_value = string_analysis.get_value()
460
print(f"\nString: '{string_value}'")
461
462
# Find where this string is used
463
xrefs = string_analysis.get_xref_from()
464
if xrefs:
465
print(" Used in:")
466
for ref_class, ref_method, offset in xrefs:
467
print(f" {ref_class.get_name()}.{ref_method.get_name()} at offset {offset}")
468
```
469
470
### Call Graph Generation
471
472
```python
473
import networkx as nx
474
import matplotlib.pyplot as plt
475
476
# Generate call graph for specific class
477
call_graph = dx.get_call_graph(classname=r".*MainActivity.*")
478
479
print(f"Call graph nodes: {call_graph.number_of_nodes()}")
480
print(f"Call graph edges: {call_graph.number_of_edges()}")
481
482
# Find most called methods
483
in_degree = dict(call_graph.in_degree())
484
most_called = sorted(in_degree.items(), key=lambda x: x[1], reverse=True)[:10]
485
486
print("Most called methods:")
487
for method, count in most_called:
488
print(f" {method}: {count} calls")
489
490
# Find methods that call the most other methods
491
out_degree = dict(call_graph.out_degree())
492
most_calling = sorted(out_degree.items(), key=lambda x: x[1], reverse=True)[:10]
493
494
print("Methods with most outgoing calls:")
495
for method, count in most_calling:
496
print(f" {method}: {count} calls")
497
```
498
499
### Control Flow Analysis
500
501
```python
502
# Analyze control flow for specific method
503
target_method = dx.find_methods(class_name=r".*MainActivity.*", method_name="onCreate")[0]
504
if target_method:
505
basic_blocks = target_method.get_basic_blocks()
506
507
print(f"Method: {target_method.get_name()}")
508
print(f"Basic blocks: {len(basic_blocks.get())}")
509
510
for i, bb in enumerate(basic_blocks.get()):
511
print(f"\nBasic Block {i}:")
512
print(f" Start: {bb.get_start():04x}")
513
print(f" End: {bb.get_end():04x}")
514
print(f" Instructions: {bb.get_nb_instructions()}")
515
516
# Get child blocks (control flow)
517
children = bb.get_childs()
518
if children:
519
print(" Children:")
520
for child, condition in children:
521
print(f" Block at {child.get_start():04x} (condition: {condition})")
522
523
# Check for exception handling
524
exception_analysis = bb.get_exception_analysis()
525
if exception_analysis:
526
print(" Exception handling present")
527
```
528
529
### Field Access Analysis
530
531
```python
532
# Find field access patterns
533
password_fields = dx.find_fields(field_name=r".*[Pp]assword.*")
534
print(f"Found {len(password_fields)} password-related fields")
535
536
for field in password_fields:
537
print(f"\nField: {field.get_class_name()}.{field.get_name()}")
538
print(f" Type: {field.get_descriptor()}")
539
540
# Get field read operations
541
reads = field.get_xref_read()
542
if reads:
543
print(" Read by:")
544
for ref_class, ref_method, offset in reads:
545
print(f" {ref_class.get_name()}.{ref_method.get_name()} at {offset}")
546
547
# Get field write operations
548
writes = field.get_xref_write()
549
if writes:
550
print(" Written by:")
551
for ref_class, ref_method, offset in writes:
552
print(f" {ref_class.get_name()}.{ref_method.get_name()} at {offset}")
553
```
554
555
### Advanced Search Patterns
556
557
```python
558
# Find crypto-related methods
559
crypto_methods = dx.find_methods(
560
class_name=r".*(Crypto|Cipher|Hash|Encrypt|Decrypt).*",
561
method_name=r".*(encrypt|decrypt|hash|sign|verify).*"
562
)
563
564
print(f"Found {len(crypto_methods)} crypto-related methods")
565
for method in crypto_methods:
566
print(f" {method.get_class_name()}.{method.get_name()}")
567
568
# Find network-related classes
569
network_classes = dx.find_classes(r".*(Http|Network|Socket|URL).*")
570
print(f"Found {len(network_classes)} network-related classes")
571
572
# Find potentially obfuscated methods (short names)
573
obfuscated_methods = dx.find_methods(method_name=r"^[a-c]$")
574
print(f"Potentially obfuscated methods: {len(obfuscated_methods)}")
575
576
# Find native methods
577
native_methods = dx.find_methods(accessflags=r".*native.*")
578
print(f"Native methods: {len(native_methods)}")
579
```
580
581
## Utility Functions
582
583
```python { .api }
584
def is_ascii_obfuscation(vm) -> bool:
585
"""
586
Detect ASCII-based obfuscation in DEX file.
587
588
Parameters:
589
- vm: DEX object to analyze
590
591
Returns:
592
True if ASCII obfuscation patterns detected
593
"""
594
```