This commit is contained in:
Jean-Marie Mineau 2025-04-02 11:17:56 +02:00
parent bd725ba91b
commit a0cb49fd77
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
2 changed files with 63 additions and 19 deletions

View file

@ -32,6 +32,9 @@ def spinner(symbs: str = "-\\|/"):
yield s
CLASSLOADER_DONE = False
# Define handler to event generated by the scripts
def on_message(message, data, data_storage: dict, file_storage: Path):
if message["type"] == "error":
@ -47,6 +50,9 @@ def on_message(message, data, data_storage: dict, file_storage: Path):
handle_load_dex(message["payload"]["data"], data_storage, file_storage)
elif message["type"] == "send" and message["payload"]["type"] == "classloader":
handle_classloader_data(message["payload"]["data"], data_storage)
elif message["type"] == "send" and message["payload"]["type"] == "classloader-done":
global CLASSLOADER_DONE
CLASSLOADER_DONE = True
else:
print("[-] message:", message)
@ -362,24 +368,65 @@ def collect_runtime(apk: Path, device_name: str, file_storage: Path, output: Tex
# Resume the execution of the APK
device.resume(pid)
script.post({"type": "dump-class-loaders"})
print("==> Press ENTER to finish the analysis <==")
print("==> Press ENTER to end the analysis <==")
input()
# Dump all known classloaders
global CLASSLOADER_DONE
CLASSLOADER_DONE = False
script.post({"type": "dump-class-loaders"})
t = spinner()
while not CLASSLOADER_DONE:
print(
f"[{t.__next__()}] Waiting for the list of classloaders to be sent",
end="\r",
)
time.sleep(0.3)
print(f"[*] Classloader list received" + " " * 20)
# Try to find the Main class loader
main_class_loader: str | None = None
cls = {d["id"]: d for d in data_storage["classloaders"]}
for load_data in data_storage["dyn_code_load"]:
if load_data["classloader"] in cls:
del cls[load_data["classloader"]]
for id_ in list(cls.keys()):
if (
'dalvik.system.PathClassLoader[DexPathList[[directory "."],'
in cls[id_]["str"]
):
del cls[id_]
elif cls[id_]["cname"] == "java.lang.BootClassLoader":
del cls[id_]
# cls = {d["id"]: d for d in data_storage["classloaders"]}
# for load_data in data_storage["dyn_code_load"]:
# if load_data["classloader"] in cls:
# del cls[load_data["classloader"]]
# for id_ in list(cls.keys()):
# if (
# 'dalvik.system.PathClassLoader[DexPathList[[directory "."],'
# in cls[id_]["str"]
# ):
# del cls[id_]
# elif cls[id_]["cname"] == "java.lang.BootClassLoader":
# del cls[id_]
cls = {}
for cl in data_storage["classloaders"]:
# This is verry doubious
if cl["cname"] == "dalvik.system.PathClassLoader":
zip_files = list(
map(
lambda s: s.removeprefix('zip file "').removesuffix('"'),
filter(
lambda s: s.startswith('zip file "'),
(
w
for b in cl["str"].split("]")
for a in b.split("[")
for w in a.split(",")
),
),
)
)
if len(zip_files) == 1:
zip_path = Path(zip_files[0])
if (
len(zip_path.parts) == 6
and zip_path.parts[0] == "/"
and zip_path.parts[1] == "data"
and zip_path.parts[2] == "app"
and zip_path.parts[4].startswith(app + "-")
and zip_path.parts[5] == "base.apk"
):
cls[cl["id"]] = cl
if len(cls) == 0:
print("[!] No classloader found for the main APK")
elif len(cls) > 1:
@ -401,10 +448,6 @@ def collect_runtime(apk: Path, device_name: str, file_storage: Path, output: Tex
main_class_loader = list(cls.keys())[0]
data_storage["apk_cl_id"] = main_class_loader
# Dump all known classloaders
script.post({"type": "dump-class-loaders"})
time.sleep(1) # TODO: wait for ack from frida
json.dump(data_storage, output, indent=" ")

View file

@ -10,10 +10,11 @@ function dump_classloaders() {
"cname": cl.$className
}});
}
send({"type": "classloader-done"})
});
}
recv('dump-class-loaders', function onMessage(msg) {dump_classloaders()});
// recv('dump-class-loaders', function onMessage(msg) {dump_classloaders()});
Java.perform(() => {