Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Reverse-Engineering apps on the device - how far can we go? (Droidcon UK 2019)

0aa5e9706ca27fc5c8a100a627c20a16?s=47 jebstuart
October 24, 2019

Reverse-Engineering apps on the device - how far can we go? (Droidcon UK 2019)

0aa5e9706ca27fc5c8a100a627c20a16?s=128

jebstuart

October 24, 2019
Tweet

More Decks by jebstuart

Other Decks in Programming

Transcript

  1. @jebstuart — ware.to/reverse Reverse-Engineering on the Device:
 How Far Can

    We Go? Jeb Ware American Express
  2. @jebstuart — ware.to/reverse Reverse-Engineering on the Device:
 How Far Can

    We Go? Jeb Ware American Express
  3. @jebstuart — ware.to/reverse Views expressed here are my own 


    and do not necessarily reflect 
 the views of my employer.
  4. @jebstuart — ware.to/reverse Reverse-Engineering on Device? APK

  5. @jebstuart — ware.to/reverse Reverse-Engineering on Device? APK

  6. @jebstuart — ware.to/reverse # Reverse-Engineering on Device? APK

  7. @jebstuart — ware.to/reverse Reverse-Engineering on Device! APK APK

  8. @jebstuart — ware.to/reverse App Sandboxing APK Sandbox res dex so

    asset files db shared pref keys APK Sandbox res dex so asset files db shared pref keys APK Sandbox res dex so asset files db shared pref keys
  9. @jebstuart — ware.to/reverse /data/app/com.example.yourapp-1/base.apk

  10. @jebstuart — ware.to/reverse /data/app/com.example.yourapp-1/base.apk context.packageManager .getInstalledApplications(...) .map { it.publicSourceDir }

  11. @jebstuart — ware.to/reverse /data/app/com.example.yourapp-1/base.apk context.packageManager .getInstalledApplications(...) .map { it.publicSourceDir }

  12. @jebstuart — ware.to/reverse APK • AndroidManifest.xml • assets/ • …

    • classes.dex • classes2.dex • res/ • anim/ • color/ • drawable/ • layout/ • raw/ • …
  13. @jebstuart — ware.to/reverse val zip = ZipFile(appInfo.publicSourceDir)
 zip.entries().toList() .map {

    zip.getInputStream(it) } .onEach { ... }
  14. @jebstuart — ware.to/reverse Compiled XML ? @.;FP}?
 interpolatordurationshareInterpolator fromYDeltatoYDeltaandroid**http:// schemas.android.com/apk/res/androidset

    translate?A????????8????????????t???????????? ?????????????????????????????????
  15. @jebstuart — ware.to/reverse val appId = “com.example.yourapp" val res: Resources

    = packageManager.getResourcesForApplication(appId)
  16. @jebstuart — ware.to/reverse val res: Resources = packageManager.getResourcesForApplication(appId) res.getString(0x7f0e0003)

  17. @jebstuart — ware.to/reverse val res: Resources = packageManager.getResourcesForApplication(appId) res.getString(0x7f0e0003) “Hello,

    World!”
  18. @jebstuart — ware.to/reverse val res: Resources = packageManager.getResourcesForApplication(appId) res.getString(0x7f0e0003) “Hello,

    World!” ???
  19. @jebstuart — ware.to/reverse Resource IDs 0x7f0e0003

  20. @jebstuart — ware.to/reverse Resource IDs 0x7f0e0003 ??? ??? ???

  21. @jebstuart — ware.to/reverse

  22. @jebstuart — ware.to/reverse

  23. @jebstuart — ware.to/reverse Resource IDs 0x7f0e0003

  24. @jebstuart — ware.to/reverse 0e Resource IDs { const 0x7f 0003

  25. @jebstuart — ware.to/reverse 0e Resource IDs { { const type

    0x7f 0003
  26. @jebstuart — ware.to/reverse 0e Resource IDs { { { const

    type identifier 0x7f 0003
  27. @jebstuart — ware.to/reverse Enumerating Resources 0x7f 0000 01

  28. @jebstuart — ware.to/reverse Enumerating Resources 0x7f 0001 01

  29. @jebstuart — ware.to/reverse Enumerating Resources 0x7f 0002 01

  30. @jebstuart — ware.to/reverse Enumerating Resources 0x7f 0003 01

  31. @jebstuart — ware.to/reverse Enumerating Resources 0x7f 0003 01 ResourceNotFoundException

  32. @jebstuart — ware.to/reverse Enumerating Resources 0x7f 0000 02

  33. @jebstuart — ware.to/reverse Enumerating Resources val res: Resources = packageManager.getResourcesForApplication(appId)

    val name = res.getResourceName(0x7f0e0003) val type = res.getResourceTypeName(0x7f0e0003) val entry = res.getResourceEntryName(0x7f0e0003)
  34. @jebstuart — ware.to/reverse Enumerating Resources val res: Resources = packageManager.getResourcesForApplication(appId)

    val name = res.getResourceName(0x7f0e0003) val type = res.getResourceTypeName(0x7f0e0003) val entry = res.getResourceEntryName(0x7f0e0003) “anim” “abc_slide_out_top” “com.example:anim/abc_slide_out_top”
  35. @jebstuart — ware.to/reverse Loading Resource Values val res: Resources =

    packageManager.getResourcesForApplication(appId) res.getBoolean(0x7f0e0123) res.getColor(0x7f0e0123, null) res.getDimension(0x7f0e0123) res.getDrawable(0x7f0e0123, null) res.getInteger(0x7f0e0123) res.getString(0x7f0e0123)
  36. @jebstuart — ware.to/reverse Live demo!

  37. @jebstuart — ware.to/reverse Enumerating Assets val res: Resources = packageManager.getResourcesForApplication(appId)

    val fileNames = res.assets.list("")
  38. @jebstuart — ware.to/reverse Enumerating Assets val res: Resources = packageManager.getResourcesForApplication(appId)

    val fileNames = res.assets.list("") AMobileConfig.json bar.properties fonts html settings.json
  39. @jebstuart — ware.to/reverse Enumerating Assets val inputStream = res.assets.open(path) //

    for image val bitmap = BitmapFactory.decodeStream(inputStream) // for text file val text = inputStream.reader().readLines()
  40. @jebstuart — ware.to/reverse Live demo?

  41. @jebstuart — ware.to/reverse DEX files

  42. @jebstuart — ware.to/reverse DEX files

  43. @jebstuart — ware.to/reverse DEX files val apk = ZipFile(appInfo.publicSourceDir) val

    dexEntries = apk.entries().toList() .filter { it.name.startsWith("classes") && it.name.endsWith(".dex") }
  44. @jebstuart — ware.to/reverse

  45. @jebstuart — ware.to/reverse .class files

  46. @jebstuart — ware.to/reverse .dex file .class files

  47. @jebstuart — ware.to/reverse .dex file

  48. @jebstuart — ware.to/reverse .dex file header

  49. @jebstuart — ware.to/reverse .dex file header strings table

  50. @jebstuart — ware.to/reverse .dex file header strings table code ’n’

    stuff
  51. @jebstuart — ware.to/reverse .dex file header strings table code ’n’

    stuff
  52. @jebstuart — ware.to/reverse implementation 'com.jakewharton.android.repackaged:dalvik-dx:9.0.0_r3'

  53. @jebstuart — ware.to/reverse import com.android.dex.Dex val strings = dexFiles.flatMap {

    val dex = Dex(it.readBytes()) dex.strings() }
  54. @jebstuart — ware.to/reverse import com.android.dex.Dex val strings = dexFiles.flatMap {

    val dex = Dex(it.readBytes()) dex.strings() }
  55. @jebstuart — ware.to/reverse import com.android.dex.Dex val strings = dexFiles.flatMap {

    val dex = Dex(it.readBytes()) dex.strings() }
  56. @jebstuart — ware.to/reverse import com.android.dex.Dex val strings = dexFiles.flatMap {

    val dex = Dex(it.readBytes()) dex.strings() }
  57. @jebstuart — ware.to/reverse ¡Live demo!

  58. @jebstuart — ware.to/reverse .dex file header strings table code ’n’

    stuff
  59. @jebstuart — ware.to/reverse implementation 'org.smali:baksmali:2.3.4'

  60. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes )
  61. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes )
  62. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes )
  63. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes )
  64. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes )
  65. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes ) Baksmali.disassembleDexFile( dexFile, outputDir, 10, // jobs BaksmaliOptions() )
  66. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes ) Baksmali.disassembleDexFile( dexFile, outputDir, 10, // jobs BaksmaliOptions() )
  67. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes ) Baksmali.disassembleDexFile( dexFile, outputDir, 10, // jobs BaksmaliOptions() )
  68. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes ) Baksmali.disassembleDexFile( dexFile, outputDir, 10, // jobs BaksmaliOptions() )
  69. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes ) Baksmali.disassembleDexFile( dexFile, outputDir, 10, // jobs BaksmaliOptions() )
  70. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes ) Baksmali.disassembleDexFile( dexFile, outputDir, 10, // jobs BaksmaliOptions() )
  71. @jebstuart — ware.to/reverse ¿Live demo?

  72. @jebstuart — ware.to/reverse DexClassLoader classLoader = DexClassLoader( targetFile.absolutePath, null, null,

    classLoader)
  73. @jebstuart — ware.to/reverse val clazz = classLoader.loadClass("com.example.MyClass")

  74. @jebstuart — ware.to/reverse implementation 'com.jakewharton.dex:dex-member-list:3.3.0'

  75. @jebstuart — ware.to/reverse Enumerating Classes val members: List<DexMember> = DexParser.fromFile(dexFile).list()

    member.declaringType
  76. @jebstuart — ware.to/reverse val clazz = classLoader.loadClass(fqcn)
 val modifiers =

    clazz.getDeclaredField(fieldName).modifiers val public: Boolean = Modifier.isPublic(modifiers)
  77. @jebstuart — ware.to/reverse val field = clazz.getDeclaredField(fieldName) val instance =

    clazz.newInstance() 
 val value = field.get(instance)
  78. @jebstuart — ware.to/reverse val clazz = targetClassLoader.loadClass(declaringType) val instance =

    clazz.newInstance() val method = clazz.getDeclaredMethod(methodName, String::class.java, Boolean::class.java) val result = method.invoke(instance, "arg1", true)
  79. @jebstuart — ware.to/reverse Live demo?!

  80. @jebstuart — ware.to/reverse Loading Layouts

  81. @jebstuart — ware.to/reverse java.lang.ClassNotFoundException: Didn't find class "android.support.v7.widget.ActivityChooserView$InnerLayout" on path:

    DexPathList[ [zip file “/data/app/com.jebware.appspy-A_W1…2Q==/base.apk”], nativeLibraryDirectories=[ /data/app/com.jebware.appspy-A_W1…2Q==/lib/arm64, /system/lib64
 ] ]
  82. @jebstuart — ware.to/reverse val flags = CONTEXT_INCLUDE_CODE val targetContext =

    createPackageContext("com.example.app", flags)
  83. @jebstuart — ware.to/reverse val flags = CONTEXT_INCLUDE_CODE val targetContext =

    createPackageContext("com.example.app", flags) SecurityException
  84. @jebstuart — ware.to/reverse val flags = CONTEXT_INCLUDE_CODE or CONTEXT_IGNORE_SECURITY val

    targetContext = createPackageContext("com.example.app", flags)
  85. @jebstuart — ware.to/reverse val flags = CONTEXT_INCLUDE_CODE or CONTEXT_IGNORE_SECURITY val

    targetContext = createPackageContext(targetPackageName, flags)
  86. @jebstuart — ware.to/reverse val targetLayoutInflater = layoutInflater .cloneInContext(targetContext)

  87. @jebstuart — ware.to/reverse val targetLayout = targetLayoutInflater .inflate(targetLayoutId, null) setContentView(targetLayout)

  88. @jebstuart — ware.to/reverse Live Demo!!

  89. @jebstuart — ware.to/reverse APK Sandbox res dex so asset files

    db shared pref keys APK Sandbox res dex so asset files db shared pref keys APK Sandbox res dex so asset files db shared pref keys
  90. @jebstuart — ware.to/reverse APK Sandbox res dex so asset files

    db shared pref keys APK Sandbox res dex so asset files db shared pref keys APK Sandbox res dex so asset files db shared pref keys uid 10001 uid 10002 uid 10003
  91. @jebstuart — ware.to/reverse APK Sandbox res dex so asset files

    db shared pref keys APK Sandbox res dex so asset files db shared pref keys APK Sandbox res dex so asset files db shared pref keys uid 10001 uid 10002 uid 10003 APK
  92. @jebstuart — ware.to/reverse “external” storage

  93. @jebstuart — ware.to/reverse “external” storage Context.getExternalFilesDir()

  94. @jebstuart — ware.to/reverse “external” storage Context.getExternalFilesDir() 
 
 
 /storage/emulated/0/Android/data/com.example/files

    
 
 
 
 

  95. @jebstuart — ware.to/reverse “external” storage Context.getExternalFilesDir() 
 Environment.getExternalStoragePublicDirectory(
 Environment.DIRECTORY_PICTURES) 


    
 /storage/emulated/0/Android/data/com.example/files 
 
 
 /storage/emulated/0/Pictures
 

  96. @jebstuart — ware.to/reverse “external” storage Context.getExternalFilesDir() 
 Environment.getExternalStoragePublicDirectory(
 Environment.DIRECTORY_PICTURES) 


    Environment.getExternalStorageDirectory() 
 /storage/emulated/0/Android/data/com.example/files 
 
 
 /storage/emulated/0/Pictures
 
 
 /storage/emulated/0
 

  97. @jebstuart — ware.to/reverse “external” storage Context.getExternalFilesDir() 
 Environment.getExternalStoragePublicDirectory(
 Environment.DIRECTORY_PICTURES) 


    Environment.getExternalStorageDirectory() 
 System.getenv("EXTERNAL_STORAGE") /storage/emulated/0/Android/data/com.example/files 
 
 
 /storage/emulated/0/Pictures
 
 
 /storage/emulated/0
 
 
 /sdcard
  98. @jebstuart — ware.to/reverse “external” storage Context.getExternalFilesDir() 
 (no permission) 


    Environment.getExternalStorageDirectory() 
 android.Manifest.permission.READ_EXTERNAL_STORAGE /storage/emulated/0/Android/data/com.example/files 
 
 
 
 
 
 /storage/emulated/0
 
 

  99. @jebstuart — ware.to/reverse val path = file.toPath() // java.nio.file.Path

  100. @jebstuart — ware.to/reverse val path = file.toPath() // java.nio.file.Path val

    uid = Files.getAttribute(path, "unix:uid") as Int
  101. @jebstuart — ware.to/reverse val path = file.toPath() // java.nio.file.Path val

    uid = Files.getAttribute(path, "unix:uid") as Int // String[] val packages = packageManager.getPackagesForUid(uid)
 packageManager.getApplicationInfo(packages.first(), 0)
  102. @jebstuart — ware.to/reverse Live Demo!!

  103. @jebstuart — ware.to/reverse Takeaways • Sandbox protects private data, keys,

    etc. • Not code, resources, assets. • “External” storage is (effectively) world-readable • Many RE tools available - some will run inside another app
  104. @jebstuart — ware.to/reverse Questions? Jeb Ware
 American Express
 
 @jebstuart


    http://ware.to/reverse