Primer paso de la investigacion. Se aportan el .apk, las carpetas con el apk extraido y el apk descompilado. El archivo API_DOCUMENTATION.md es un archivo donde se anotaran los descubrimientos del funcionamiento de la API, y los .py son scripts para probar la funcionalidad de la API con los métodos que vayamos encontrando. Finalmente, los archivos .js son scripts de Frida para extraer informacion de la APP durante la ejecucion.

This commit is contained in:
2025-12-04 13:59:54 +01:00
parent f2fd1c3bf5
commit e0133d2ca2
10432 changed files with 1019085 additions and 1 deletions

View File

@@ -0,0 +1,340 @@
package com.google.firebase.crashlytics.internal.persistence;
import C.w;
import L.b;
import N2.a;
import com.google.firebase.crashlytics.internal.Logger;
import com.google.firebase.crashlytics.internal.common.CrashlyticsAppQualitySessionsSubscriber;
import com.google.firebase.crashlytics.internal.common.CrashlyticsReportWithSessionId;
import com.google.firebase.crashlytics.internal.metadata.UserMetadata;
import com.google.firebase.crashlytics.internal.model.CrashlyticsReport;
import com.google.firebase.crashlytics.internal.model.serialization.CrashlyticsReportJsonTransform;
import com.google.firebase.crashlytics.internal.settings.SettingsProvider;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
/* loaded from: classes3.dex */
public class CrashlyticsReportPersistence {
private static final String EVENT_COUNTER_FORMAT = "%010d";
private static final int EVENT_COUNTER_WIDTH = 10;
private static final String EVENT_FILE_NAME_PREFIX = "event";
private static final int MAX_OPEN_SESSIONS = 8;
private static final String NORMAL_EVENT_SUFFIX = "";
private static final String PRIORITY_EVENT_SUFFIX = "_";
private static final String REPORT_FILE_NAME = "report";
private static final String SESSION_START_TIMESTAMP_FILE_NAME = "start-time";
private final AtomicInteger eventCounter = new AtomicInteger(0);
private final FileStore fileStore;
private final CrashlyticsAppQualitySessionsSubscriber sessionsSubscriber;
private final SettingsProvider settingsProvider;
private static final Charset UTF_8 = Charset.forName("UTF-8");
private static final int EVENT_NAME_LENGTH = 15;
private static final CrashlyticsReportJsonTransform TRANSFORM = new CrashlyticsReportJsonTransform();
private static final Comparator<? super File> LATEST_SESSION_ID_FIRST_COMPARATOR = new b(2);
private static final FilenameFilter EVENT_FILE_FILTER = new a(0);
public CrashlyticsReportPersistence(FileStore fileStore, SettingsProvider settingsProvider, CrashlyticsAppQualitySessionsSubscriber crashlyticsAppQualitySessionsSubscriber) {
this.fileStore = fileStore;
this.settingsProvider = settingsProvider;
this.sessionsSubscriber = crashlyticsAppQualitySessionsSubscriber;
}
private SortedSet<String> capAndGetOpenSessions(String str) {
this.fileStore.cleanupPreviousFileSystems();
SortedSet<String> openSessionIds = getOpenSessionIds();
if (str != null) {
openSessionIds.remove(str);
}
if (openSessionIds.size() > 8) {
while (openSessionIds.size() > 8) {
String last = openSessionIds.last();
Logger.getLogger().d("Removing session over cap: " + last);
this.fileStore.deleteSessionFiles(last);
openSessionIds.remove(last);
}
}
return openSessionIds;
}
private static int capFilesCount(List<File> list, int i) {
int size = list.size();
for (File file : list) {
if (size <= i) {
break;
}
FileStore.recursiveDelete(file);
size--;
}
return size;
}
private void capFinalizedReports() {
int i = this.settingsProvider.getSettingsSync().sessionData.maxCompleteSessionsCount;
List<File> allFinalizedReportFiles = getAllFinalizedReportFiles();
int size = allFinalizedReportFiles.size();
if (size <= i) {
return;
}
Iterator<File> it = allFinalizedReportFiles.subList(i, size).iterator();
while (it.hasNext()) {
it.next().delete();
}
}
private static long convertTimestampFromSecondsToMs(long j4) {
return j4 * 1000;
}
private void deleteFiles(List<File> list) {
Iterator<File> it = list.iterator();
while (it.hasNext()) {
it.next().delete();
}
}
private static String generateEventFilename(int i, boolean z3) {
return w.o(EVENT_FILE_NAME_PREFIX, String.format(Locale.US, EVENT_COUNTER_FORMAT, Integer.valueOf(i)), z3 ? PRIORITY_EVENT_SUFFIX : "");
}
private List<File> getAllFinalizedReportFiles() {
ArrayList arrayList = new ArrayList();
arrayList.addAll(this.fileStore.getPriorityReports());
arrayList.addAll(this.fileStore.getNativeReports());
Comparator<? super File> comparator = LATEST_SESSION_ID_FIRST_COMPARATOR;
Collections.sort(arrayList, comparator);
List<File> reports = this.fileStore.getReports();
Collections.sort(reports, comparator);
arrayList.addAll(reports);
return arrayList;
}
private static String getEventNameWithoutPriority(String str) {
return str.substring(0, EVENT_NAME_LENGTH);
}
private static boolean isHighPriorityEventFile(String str) {
return str.startsWith(EVENT_FILE_NAME_PREFIX) && str.endsWith(PRIORITY_EVENT_SUFFIX);
}
public static boolean isNormalPriorityEventFile(File file, String str) {
return str.startsWith(EVENT_FILE_NAME_PREFIX) && !str.endsWith(PRIORITY_EVENT_SUFFIX);
}
public static /* synthetic */ int lambda$static$0(File file, File file2) {
return file2.getName().compareTo(file.getName());
}
public static /* synthetic */ boolean lambda$static$1(File file, String str) {
return str.startsWith(EVENT_FILE_NAME_PREFIX);
}
public static int oldestEventFileFirst(File file, File file2) {
return getEventNameWithoutPriority(file.getName()).compareTo(getEventNameWithoutPriority(file2.getName()));
}
private static String readTextFile(File file) throws IOException {
byte[] bArr = new byte[8192];
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
FileInputStream fileInputStream = new FileInputStream(file);
while (true) {
try {
int read = fileInputStream.read(bArr);
if (read <= 0) {
String str = new String(byteArrayOutputStream.toByteArray(), UTF_8);
fileInputStream.close();
return str;
}
byteArrayOutputStream.write(bArr, 0, read);
} catch (Throwable th) {
try {
fileInputStream.close();
} catch (Throwable th2) {
th.addSuppressed(th2);
}
throw th;
}
}
}
private void synthesizeNativeReportFile(File file, CrashlyticsReport.FilesPayload filesPayload, String str, CrashlyticsReport.ApplicationExitInfo applicationExitInfo) {
String appQualitySessionId = this.sessionsSubscriber.getAppQualitySessionId(str);
try {
CrashlyticsReportJsonTransform crashlyticsReportJsonTransform = TRANSFORM;
writeTextFile(this.fileStore.getNativeReport(str), crashlyticsReportJsonTransform.reportToJson(crashlyticsReportJsonTransform.reportFromJson(readTextFile(file)).withNdkPayload(filesPayload).withApplicationExitInfo(applicationExitInfo).withAppQualitySessionId(appQualitySessionId)));
} catch (IOException e4) {
Logger.getLogger().w("Could not synthesize final native report file for " + file, e4);
}
}
private void synthesizeReport(String str, long j4) {
boolean z3;
List<File> sessionFiles = this.fileStore.getSessionFiles(str, EVENT_FILE_FILTER);
if (sessionFiles.isEmpty()) {
Logger.getLogger().v("Session " + str + " has no events.");
return;
}
Collections.sort(sessionFiles);
ArrayList arrayList = new ArrayList();
loop0: while (true) {
z3 = false;
for (File file : sessionFiles) {
try {
arrayList.add(TRANSFORM.eventFromJson(readTextFile(file)));
} catch (IOException e4) {
Logger.getLogger().w("Could not add event to report for " + file, e4);
}
if (z3 || isHighPriorityEventFile(file.getName())) {
z3 = true;
}
}
}
if (!arrayList.isEmpty()) {
synthesizeReportFile(this.fileStore.getSessionFile(str, REPORT_FILE_NAME), arrayList, j4, z3, UserMetadata.readUserId(str, this.fileStore), this.sessionsSubscriber.getAppQualitySessionId(str));
} else {
Logger.getLogger().w("Could not parse event files for session " + str);
}
}
private void synthesizeReportFile(File file, List<CrashlyticsReport.Session.Event> list, long j4, boolean z3, String str, String str2) {
try {
CrashlyticsReportJsonTransform crashlyticsReportJsonTransform = TRANSFORM;
CrashlyticsReport withEvents = crashlyticsReportJsonTransform.reportFromJson(readTextFile(file)).withSessionEndFields(j4, z3, str).withAppQualitySessionId(str2).withEvents(list);
CrashlyticsReport.Session session = withEvents.getSession();
if (session == null) {
return;
}
Logger.getLogger().d("appQualitySessionId: " + str2);
writeTextFile(z3 ? this.fileStore.getPriorityReport(session.getIdentifier()) : this.fileStore.getReport(session.getIdentifier()), crashlyticsReportJsonTransform.reportToJson(withEvents));
} catch (IOException e4) {
Logger.getLogger().w("Could not synthesize final report file for " + file, e4);
}
}
private int trimEvents(String str, int i) {
List<File> sessionFiles = this.fileStore.getSessionFiles(str, new a(1));
Collections.sort(sessionFiles, new b(3));
return capFilesCount(sessionFiles, i);
}
private static void writeTextFile(File file, String str) throws IOException {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file), UTF_8);
try {
outputStreamWriter.write(str);
outputStreamWriter.close();
} catch (Throwable th) {
try {
outputStreamWriter.close();
} catch (Throwable th2) {
th.addSuppressed(th2);
}
throw th;
}
}
public void deleteAllReports() {
deleteFiles(this.fileStore.getReports());
deleteFiles(this.fileStore.getPriorityReports());
deleteFiles(this.fileStore.getNativeReports());
}
public void finalizeReports(String str, long j4) {
for (String str2 : capAndGetOpenSessions(str)) {
Logger.getLogger().v("Finalizing report for session " + str2);
synthesizeReport(str2, j4);
this.fileStore.deleteSessionFiles(str2);
}
capFinalizedReports();
}
public void finalizeSessionWithNativeEvent(String str, CrashlyticsReport.FilesPayload filesPayload, CrashlyticsReport.ApplicationExitInfo applicationExitInfo) {
File sessionFile = this.fileStore.getSessionFile(str, REPORT_FILE_NAME);
Logger.getLogger().d("Writing native session report for " + str + " to file: " + sessionFile);
synthesizeNativeReportFile(sessionFile, filesPayload, str, applicationExitInfo);
}
public SortedSet<String> getOpenSessionIds() {
return new TreeSet(this.fileStore.getAllOpenSessionIds()).descendingSet();
}
public long getStartTimestampMillis(String str) {
return this.fileStore.getSessionFile(str, SESSION_START_TIMESTAMP_FILE_NAME).lastModified();
}
public boolean hasFinalizedReports() {
return (this.fileStore.getReports().isEmpty() && this.fileStore.getPriorityReports().isEmpty() && this.fileStore.getNativeReports().isEmpty()) ? false : true;
}
public List<CrashlyticsReportWithSessionId> loadFinalizedReports() {
List<File> allFinalizedReportFiles = getAllFinalizedReportFiles();
ArrayList arrayList = new ArrayList();
for (File file : allFinalizedReportFiles) {
try {
arrayList.add(CrashlyticsReportWithSessionId.create(TRANSFORM.reportFromJson(readTextFile(file)), file.getName(), file));
} catch (IOException e4) {
Logger.getLogger().w("Could not load report file " + file + "; deleting", e4);
file.delete();
}
}
return arrayList;
}
public void persistEvent(CrashlyticsReport.Session.Event event, String str) {
persistEvent(event, str, false);
}
public void persistReport(CrashlyticsReport crashlyticsReport) {
CrashlyticsReport.Session session = crashlyticsReport.getSession();
if (session == null) {
Logger.getLogger().d("Could not get session for report");
return;
}
String identifier = session.getIdentifier();
try {
writeTextFile(this.fileStore.getSessionFile(identifier, REPORT_FILE_NAME), TRANSFORM.reportToJson(crashlyticsReport));
writeTextFile(this.fileStore.getSessionFile(identifier, SESSION_START_TIMESTAMP_FILE_NAME), "", session.getStartedAt());
} catch (IOException e4) {
Logger.getLogger().d("Could not persist report for session " + identifier, e4);
}
}
public void persistEvent(CrashlyticsReport.Session.Event event, String str, boolean z3) {
int i = this.settingsProvider.getSettingsSync().sessionData.maxCustomExceptionEvents;
try {
writeTextFile(this.fileStore.getSessionFile(str, generateEventFilename(this.eventCounter.getAndIncrement(), z3)), TRANSFORM.eventToJson(event));
} catch (IOException e4) {
Logger.getLogger().w("Could not persist event for session " + str, e4);
}
trimEvents(str, i);
}
private static void writeTextFile(File file, String str, long j4) throws IOException {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file), UTF_8);
try {
outputStreamWriter.write(str);
file.setLastModified(convertTimestampFromSecondsToMs(j4));
outputStreamWriter.close();
} catch (Throwable th) {
try {
outputStreamWriter.close();
} catch (Throwable th2) {
th.addSuppressed(th2);
}
throw th;
}
}
}

View File

@@ -0,0 +1,167 @@
package com.google.firebase.crashlytics.internal.persistence;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import com.google.firebase.crashlytics.internal.Logger;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/* loaded from: classes3.dex */
public class FileStore {
private static final String CRASHLYTICS_PATH_V1 = ".com.google.firebase.crashlytics.files.v1";
private static final String CRASHLYTICS_PATH_V2 = ".com.google.firebase.crashlytics.files.v2";
private static final String NATIVE_REPORTS_PATH = "native-reports";
private static final String NATIVE_SESSION_SUBDIR = "native";
private static final String PRIORITY_REPORTS_PATH = "priority-reports";
private static final String REPORTS_PATH = "reports";
private static final String SESSIONS_PATH = "open-sessions";
private final File crashlyticsDir;
private final File filesDir;
private final File nativeReportsDir;
private final File priorityReportsDir;
private final File reportsDir;
private final File sessionsDir;
public FileStore(Context context) {
String str;
File filesDir = context.getFilesDir();
this.filesDir = filesDir;
if (useV2FileSystem()) {
str = CRASHLYTICS_PATH_V2 + File.pathSeparator + sanitizeName(Application.getProcessName());
} else {
str = CRASHLYTICS_PATH_V1;
}
File prepareBaseDir = prepareBaseDir(new File(filesDir, str));
this.crashlyticsDir = prepareBaseDir;
this.sessionsDir = prepareBaseDir(new File(prepareBaseDir, SESSIONS_PATH));
this.reportsDir = prepareBaseDir(new File(prepareBaseDir, REPORTS_PATH));
this.priorityReportsDir = prepareBaseDir(new File(prepareBaseDir, PRIORITY_REPORTS_PATH));
this.nativeReportsDir = prepareBaseDir(new File(prepareBaseDir, NATIVE_REPORTS_PATH));
}
private void cleanupDir(File file) {
if (file.exists() && recursiveDelete(file)) {
Logger.getLogger().d("Deleted previous Crashlytics file system: " + file.getPath());
}
}
private File getSessionDir(String str) {
return prepareDir(new File(this.sessionsDir, str));
}
private static synchronized File prepareBaseDir(File file) {
synchronized (FileStore.class) {
try {
if (file.exists()) {
if (file.isDirectory()) {
return file;
}
Logger.getLogger().d("Unexpected non-directory file: " + file + "; deleting file and creating new directory.");
file.delete();
}
if (!file.mkdirs()) {
Logger.getLogger().e("Could not create Crashlytics-specific directory: " + file);
}
return file;
} catch (Throwable th) {
throw th;
}
}
}
private static File prepareDir(File file) {
file.mkdirs();
return file;
}
public static boolean recursiveDelete(File file) {
File[] listFiles = file.listFiles();
if (listFiles != null) {
for (File file2 : listFiles) {
recursiveDelete(file2);
}
}
return file.delete();
}
private static <T> List<T> safeArrayToList(T[] tArr) {
return tArr == null ? Collections.EMPTY_LIST : Arrays.asList(tArr);
}
public static String sanitizeName(String str) {
return str.replaceAll("[^a-zA-Z0-9.]", "_");
}
@SuppressLint({"AnnotateVersionCheck"})
private static boolean useV2FileSystem() {
return true;
}
public void cleanupPreviousFileSystems() {
cleanupDir(new File(this.filesDir, ".com.google.firebase.crashlytics"));
cleanupDir(new File(this.filesDir, ".com.google.firebase.crashlytics-ndk"));
if (useV2FileSystem()) {
cleanupDir(new File(this.filesDir, CRASHLYTICS_PATH_V1));
}
}
public void deleteAllCrashlyticsFiles() {
recursiveDelete(this.crashlyticsDir);
}
public boolean deleteSessionFiles(String str) {
return recursiveDelete(new File(this.sessionsDir, str));
}
public List<String> getAllOpenSessionIds() {
return safeArrayToList(this.sessionsDir.list());
}
public File getCommonFile(String str) {
return new File(this.crashlyticsDir, str);
}
public List<File> getCommonFiles(FilenameFilter filenameFilter) {
return safeArrayToList(this.crashlyticsDir.listFiles(filenameFilter));
}
public File getNativeReport(String str) {
return new File(this.nativeReportsDir, str);
}
public List<File> getNativeReports() {
return safeArrayToList(this.nativeReportsDir.listFiles());
}
public File getNativeSessionDir(String str) {
return prepareDir(new File(getSessionDir(str), NATIVE_SESSION_SUBDIR));
}
public File getPriorityReport(String str) {
return new File(this.priorityReportsDir, str);
}
public List<File> getPriorityReports() {
return safeArrayToList(this.priorityReportsDir.listFiles());
}
public File getReport(String str) {
return new File(this.reportsDir, str);
}
public List<File> getReports() {
return safeArrayToList(this.reportsDir.listFiles());
}
public File getSessionFile(String str, String str2) {
return new File(getSessionDir(str), str2);
}
public List<File> getSessionFiles(String str, FilenameFilter filenameFilter) {
return safeArrayToList(getSessionDir(str).listFiles(filenameFilter));
}
}