or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

apk-processing.mdbytecode-utilities.mdcli-tools.mddecompilation.mddex-analysis.mddynamic-analysis.mdindex.mdsession-management.mdstatic-analysis.mdutility-functions.mdxml-resources.md

static-analysis.mddocs/

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

```