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

Reverse-Engineering apps on the device - how f...

jebstuart
October 24, 2019

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

jebstuart

October 24, 2019
Tweet

More Decks by jebstuart

Other Decks in Programming

Transcript

  1. @jebstuart — ware.to/reverse Views expressed here are my own 


    and do not necessarily reflect 
 the views of my employer.
  2. @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
  3. @jebstuart — ware.to/reverse APK • AndroidManifest.xml • assets/ • …

    • classes.dex • classes2.dex • res/ • anim/ • color/ • drawable/ • layout/ • raw/ • …
  4. @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)
  5. @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”
  6. @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)
  7. @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
  8. @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()
  9. @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") }
  10. @jebstuart — ware.to/reverse val dexFile = DexFileFactory.loadDexEntry( File(appInfo.publicSourceDir), // APK

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

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

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

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

    file "classes.dex", // name of dex file within true, // exactMatch null // opcodes )
  15. @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() )
  16. @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() )
  17. @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() )
  18. @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() )
  19. @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() )
  20. @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() )
  21. @jebstuart — ware.to/reverse val clazz = classLoader.loadClass(fqcn)
 val modifiers =

    clazz.getDeclaredField(fieldName).modifiers val public: Boolean = Modifier.isPublic(modifiers)
  22. @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)
  23. @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
 ] ]
  24. @jebstuart — ware.to/reverse val flags = CONTEXT_INCLUDE_CODE val targetContext =

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

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

    targetContext = createPackageContext(targetPackageName, flags)
  27. @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
  28. @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
  29. @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
  30. @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
 

  31. @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
  32. @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
 
 

  33. @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)
  34. @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