capacitor-dex-editor 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -424,6 +424,14 @@ public class DexEditorPluginPlugin extends Plugin {
424
424
  ));
425
425
  break;
426
426
 
427
+ case "getClassSmali":
428
+ result.put("data", dexManager.getClassSmaliFromApk(
429
+ params.getString("apkPath"),
430
+ params.getString("dexPath"),
431
+ params.getString("className")
432
+ ));
433
+ break;
434
+
427
435
  default:
428
436
  result.put("success", false);
429
437
  result.put("error", "Unknown action: " + action);
@@ -1387,6 +1387,8 @@ public class DexManager {
1387
1387
  JSObject result = new JSObject();
1388
1388
  JSArray results = new JSArray();
1389
1389
 
1390
+ Log.d(TAG, "searchInDexFromApk: apkPath=" + apkPath + ", dexPath=" + dexPath + ", query=" + query);
1391
+
1390
1392
  if (query == null || query.isEmpty()) {
1391
1393
  result.put("results", results);
1392
1394
  result.put("count", 0);
@@ -1400,12 +1402,29 @@ public class DexManager {
1400
1402
 
1401
1403
  try {
1402
1404
  zipFile = new java.util.zip.ZipFile(apkPath);
1405
+
1406
+ // 尝试多种可能的 dexPath 格式
1403
1407
  java.util.zip.ZipEntry dexEntry = zipFile.getEntry(dexPath);
1408
+ if (dexEntry == null && !dexPath.startsWith("/")) {
1409
+ // 如果没有找到,尝试去掉开头的斜杠
1410
+ dexEntry = zipFile.getEntry(dexPath.replaceFirst("^/+", ""));
1411
+ }
1412
+ if (dexEntry == null) {
1413
+ // 如果还是没找到,尝试只用文件名
1414
+ String fileName = dexPath;
1415
+ if (dexPath.contains("/")) {
1416
+ fileName = dexPath.substring(dexPath.lastIndexOf("/") + 1);
1417
+ }
1418
+ dexEntry = zipFile.getEntry(fileName);
1419
+ }
1404
1420
 
1405
1421
  if (dexEntry == null) {
1422
+ Log.e(TAG, "DEX file not found in APK: " + dexPath);
1406
1423
  throw new IOException("DEX file not found in APK: " + dexPath);
1407
1424
  }
1408
1425
 
1426
+ Log.d(TAG, "Found DEX entry: " + dexEntry.getName());
1427
+
1409
1428
  dexInputStream = zipFile.getInputStream(dexEntry);
1410
1429
 
1411
1430
  // 读取 DEX 文件到内存
@@ -1491,4 +1510,250 @@ public class DexManager {
1491
1510
  }
1492
1511
  return className.replace("/", ".");
1493
1512
  }
1513
+
1514
+ /**
1515
+ * 将 Java 类名格式转换为 DEX 类型格式
1516
+ * 例如: com.example.Class -> Lcom/example/Class;
1517
+ */
1518
+ private String convertClassNameToType(String className) {
1519
+ if (className == null) return "";
1520
+ return "L" + className.replace(".", "/") + ";";
1521
+ }
1522
+
1523
+ /**
1524
+ * 从 APK 中的 DEX 文件获取类的 Smali 代码
1525
+ */
1526
+ public JSObject getClassSmaliFromApk(String apkPath, String dexPath, String className) throws Exception {
1527
+ JSObject result = new JSObject();
1528
+ StringBuilder smali = new StringBuilder();
1529
+
1530
+ Log.d(TAG, "getClassSmaliFromApk: apkPath=" + apkPath + ", dexPath=" + dexPath + ", className=" + className);
1531
+
1532
+ if (className == null || className.isEmpty()) {
1533
+ result.put("smali", "# 未指定类名");
1534
+ return result;
1535
+ }
1536
+
1537
+ String targetType = convertClassNameToType(className);
1538
+
1539
+ java.util.zip.ZipFile zipFile = null;
1540
+ java.io.InputStream dexInputStream = null;
1541
+
1542
+ try {
1543
+ zipFile = new java.util.zip.ZipFile(apkPath);
1544
+
1545
+ // 尝试多种可能的 dexPath 格式
1546
+ java.util.zip.ZipEntry dexEntry = zipFile.getEntry(dexPath);
1547
+ if (dexEntry == null) {
1548
+ dexEntry = zipFile.getEntry(dexPath.replaceFirst("^/+", ""));
1549
+ }
1550
+ if (dexEntry == null) {
1551
+ String fileName = dexPath;
1552
+ if (dexPath.contains("/")) {
1553
+ fileName = dexPath.substring(dexPath.lastIndexOf("/") + 1);
1554
+ }
1555
+ dexEntry = zipFile.getEntry(fileName);
1556
+ }
1557
+
1558
+ if (dexEntry == null) {
1559
+ result.put("smali", "# DEX 文件未找到: " + dexPath);
1560
+ return result;
1561
+ }
1562
+
1563
+ dexInputStream = zipFile.getInputStream(dexEntry);
1564
+
1565
+ // 读取 DEX 文件到内存
1566
+ java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
1567
+ byte[] buffer = new byte[8192];
1568
+ int len;
1569
+ while ((len = dexInputStream.read(buffer)) != -1) {
1570
+ baos.write(buffer, 0, len);
1571
+ }
1572
+ byte[] dexBytes = baos.toByteArray();
1573
+
1574
+ // 解析 DEX 文件
1575
+ DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.getDefault(), dexBytes);
1576
+
1577
+ // 查找目标类
1578
+ ClassDef targetClass = null;
1579
+ for (ClassDef classDef : dexFile.getClasses()) {
1580
+ if (classDef.getType().equals(targetType)) {
1581
+ targetClass = classDef;
1582
+ break;
1583
+ }
1584
+ }
1585
+
1586
+ if (targetClass == null) {
1587
+ result.put("smali", "# 类未找到: " + className + "\n# 目标类型: " + targetType);
1588
+ return result;
1589
+ }
1590
+
1591
+ // 生成 Smali 代码
1592
+ smali.append(".class ");
1593
+ // 访问标志
1594
+ int accessFlags = targetClass.getAccessFlags();
1595
+ if ((accessFlags & 0x0001) != 0) smali.append("public ");
1596
+ if ((accessFlags & 0x0010) != 0) smali.append("final ");
1597
+ if ((accessFlags & 0x0020) != 0) smali.append("super ");
1598
+ if ((accessFlags & 0x0200) != 0) smali.append("interface ");
1599
+ if ((accessFlags & 0x0400) != 0) smali.append("abstract ");
1600
+ if ((accessFlags & 0x1000) != 0) smali.append("synthetic ");
1601
+ if ((accessFlags & 0x2000) != 0) smali.append("annotation ");
1602
+ if ((accessFlags & 0x4000) != 0) smali.append("enum ");
1603
+ smali.append(targetClass.getType()).append("\n");
1604
+
1605
+ // 父类
1606
+ String superClass = targetClass.getSuperclass();
1607
+ if (superClass != null) {
1608
+ smali.append(".super ").append(superClass).append("\n");
1609
+ }
1610
+
1611
+ // 源文件
1612
+ String sourceFile = targetClass.getSourceFile();
1613
+ if (sourceFile != null) {
1614
+ smali.append(".source \"").append(sourceFile).append("\"\n");
1615
+ }
1616
+
1617
+ // 实现的接口
1618
+ for (String iface : targetClass.getInterfaces()) {
1619
+ smali.append(".implements ").append(iface).append("\n");
1620
+ }
1621
+
1622
+ smali.append("\n");
1623
+
1624
+ // 字段
1625
+ smali.append("# ========== 字段 ==========\n");
1626
+ for (Field field : targetClass.getFields()) {
1627
+ smali.append(".field ");
1628
+ int fFlags = field.getAccessFlags();
1629
+ if ((fFlags & 0x0001) != 0) smali.append("public ");
1630
+ if ((fFlags & 0x0002) != 0) smali.append("private ");
1631
+ if ((fFlags & 0x0004) != 0) smali.append("protected ");
1632
+ if ((fFlags & 0x0008) != 0) smali.append("static ");
1633
+ if ((fFlags & 0x0010) != 0) smali.append("final ");
1634
+ if ((fFlags & 0x0040) != 0) smali.append("volatile ");
1635
+ if ((fFlags & 0x0080) != 0) smali.append("transient ");
1636
+ if ((fFlags & 0x1000) != 0) smali.append("synthetic ");
1637
+ if ((fFlags & 0x4000) != 0) smali.append("enum ");
1638
+ smali.append(field.getName()).append(":").append(field.getType()).append("\n");
1639
+ }
1640
+
1641
+ smali.append("\n");
1642
+
1643
+ // 方法
1644
+ smali.append("# ========== 方法 ==========\n");
1645
+ for (Method method : targetClass.getMethods()) {
1646
+ smali.append("\n.method ");
1647
+ int mFlags = method.getAccessFlags();
1648
+ if ((mFlags & 0x0001) != 0) smali.append("public ");
1649
+ if ((mFlags & 0x0002) != 0) smali.append("private ");
1650
+ if ((mFlags & 0x0004) != 0) smali.append("protected ");
1651
+ if ((mFlags & 0x0008) != 0) smali.append("static ");
1652
+ if ((mFlags & 0x0010) != 0) smali.append("final ");
1653
+ if ((mFlags & 0x0020) != 0) smali.append("synchronized ");
1654
+ if ((mFlags & 0x0040) != 0) smali.append("bridge ");
1655
+ if ((mFlags & 0x0080) != 0) smali.append("varargs ");
1656
+ if ((mFlags & 0x0100) != 0) smali.append("native ");
1657
+ if ((mFlags & 0x0400) != 0) smali.append("abstract ");
1658
+ if ((mFlags & 0x0800) != 0) smali.append("strictfp ");
1659
+ if ((mFlags & 0x1000) != 0) smali.append("synthetic ");
1660
+ if ((mFlags & 0x10000) != 0) smali.append("constructor ");
1661
+ if ((mFlags & 0x20000) != 0) smali.append("declared-synchronized ");
1662
+
1663
+ smali.append(method.getName());
1664
+ smali.append("(");
1665
+ for (CharSequence param : method.getParameterTypes()) {
1666
+ smali.append(param);
1667
+ }
1668
+ smali.append(")");
1669
+ smali.append(method.getReturnType());
1670
+ smali.append("\n");
1671
+
1672
+ MethodImplementation impl = method.getImplementation();
1673
+ if (impl != null) {
1674
+ smali.append(" .registers ").append(impl.getRegisterCount()).append("\n");
1675
+
1676
+ // 输出指令
1677
+ for (Instruction instruction : impl.getInstructions()) {
1678
+ smali.append(" ").append(instruction.getOpcode().name.toLowerCase());
1679
+ smali.append(" ").append(formatInstruction(instruction));
1680
+ smali.append("\n");
1681
+ }
1682
+ }
1683
+
1684
+ smali.append(".end method\n");
1685
+ }
1686
+
1687
+ result.put("smali", smali.toString());
1688
+
1689
+ } finally {
1690
+ if (dexInputStream != null) {
1691
+ try { dexInputStream.close(); } catch (Exception ignored) {}
1692
+ }
1693
+ if (zipFile != null) {
1694
+ try { zipFile.close(); } catch (Exception ignored) {}
1695
+ }
1696
+ }
1697
+
1698
+ return result;
1699
+ }
1700
+
1701
+ /**
1702
+ * 格式化指令参数
1703
+ */
1704
+ private String formatInstruction(Instruction instruction) {
1705
+ StringBuilder sb = new StringBuilder();
1706
+
1707
+ // 处理寄存器指令
1708
+ if (instruction instanceof com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction) {
1709
+ com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction regInstr =
1710
+ (com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction) instruction;
1711
+ sb.append("v").append(regInstr.getRegisterA());
1712
+ }
1713
+
1714
+ if (instruction instanceof com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction) {
1715
+ com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction regInstr =
1716
+ (com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction) instruction;
1717
+ if (sb.length() > 0) sb.append(", ");
1718
+ sb.append("v").append(regInstr.getRegisterB());
1719
+ }
1720
+
1721
+ if (instruction instanceof com.android.tools.smali.dexlib2.iface.instruction.ThreeRegisterInstruction) {
1722
+ com.android.tools.smali.dexlib2.iface.instruction.ThreeRegisterInstruction regInstr =
1723
+ (com.android.tools.smali.dexlib2.iface.instruction.ThreeRegisterInstruction) instruction;
1724
+ if (sb.length() > 0) sb.append(", ");
1725
+ sb.append("v").append(regInstr.getRegisterC());
1726
+ }
1727
+
1728
+ // 处理引用指令
1729
+ if (instruction instanceof com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction) {
1730
+ com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction refInstr =
1731
+ (com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction) instruction;
1732
+ if (sb.length() > 0) sb.append(", ");
1733
+ sb.append(refInstr.getReference().toString());
1734
+ }
1735
+
1736
+ // 处理字面量指令
1737
+ if (instruction instanceof com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction) {
1738
+ com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction litInstr =
1739
+ (com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction) instruction;
1740
+ if (sb.length() > 0) sb.append(", ");
1741
+ sb.append("0x").append(Long.toHexString(litInstr.getWideLiteral()));
1742
+ } else if (instruction instanceof com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction) {
1743
+ com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction litInstr =
1744
+ (com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction) instruction;
1745
+ if (sb.length() > 0) sb.append(", ");
1746
+ sb.append("0x").append(Integer.toHexString(litInstr.getNarrowLiteral()));
1747
+ }
1748
+
1749
+ // 处理偏移指令
1750
+ if (instruction instanceof com.android.tools.smali.dexlib2.iface.instruction.OffsetInstruction) {
1751
+ com.android.tools.smali.dexlib2.iface.instruction.OffsetInstruction offInstr =
1752
+ (com.android.tools.smali.dexlib2.iface.instruction.OffsetInstruction) instruction;
1753
+ if (sb.length() > 0) sb.append(", ");
1754
+ sb.append(":label_").append(offInstr.getCodeOffset());
1755
+ }
1756
+
1757
+ return sb.toString();
1758
+ }
1494
1759
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-dex-editor",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "Capacitor-plugin-for-editing-DEX-files-in-APK",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",