Skip to content
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
<a href="https://github.com/rooootdev/lara/actions">
<img src="https://img.shields.io/github/actions/workflow/status/rooootdev/lara/build.yml?branch=main&style=flat&logo=github" alt="GitHub Actions">
</a>
<a href="https://laraapp.netlify.app">
<img src="https://img.shields.io/badge/Website-blue" alt="website">
</a>
</p>

<p align="center">
Expand Down Expand Up @@ -91,7 +94,7 @@ Important Notes:
- OTA Update Disabler
- Screen Time Disabler
- App Decrypt

- Clean Cache

### Coming Soon
- FTP Server
Expand Down
1 change: 1 addition & 0 deletions lara/kexploit/pe/sbx.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <stdint.h>

uint64_t sbx_ucredbyproc(uint64_t proc);
int sbx_escape(uint64_t self_proc);
void sbx_setlogcallback(void (*callback)(const char *message));
uint64_t sbx_gettoken(pid_t pid);
Expand Down
2 changes: 2 additions & 0 deletions lara/kexploit/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ uint64_t proc_self(void);
uint64_t task_self(void);

int crashproc(const char* pid);
int proc_pause_resume(const char *name, bool resume);
int count_pids(uint64_t allproc);

#ifdef __cplusplus
}
Expand Down
47 changes: 47 additions & 0 deletions lara/kexploit/utils.m
Original file line number Diff line number Diff line change
Expand Up @@ -853,3 +853,50 @@ int crashproc(const char* name) {
ds_kwrite64(state + offsetof(struct arm_saved_state64, sp), 0x1337133713371337);
return 0;
}

int proc_pause_resume(const char *name, bool resume) {
if (!name) {
return -1;
}

uint64_t proc = procbyname(name);
if (!proc) {
printf("(signal) process not found: %s\n", name);
return -1;
}

uint32_t pid = ds_kread32(proc + PROC_PID_OFFSET);
int result;

if (resume) {
result = kill(pid, SIGCONT);
} else {
result = kill(pid, SIGSTOP);
}

if (result != 0) {
perror("(signal) kill failed");
return -1;
}

printf("(signal) %s %s\n",
name,
resume ? "resumed" : "paused");
return 0;
}

int count_pids(uint64_t allproc) {
int count = 0;
uint64_t proc = allproc;

for (int i = 0; i < 12000 && proc; i++) {
int pid = ds_kread32(proc + off_proc_p_pid);
if (pid > 0 && pid < 99999)
count++;
uint64_t next = ds_kread64(proc + off_proc_p_list_le_next);
if (next == 0 || next == proc)
break;
proc = next;
}
return count;
}
33 changes: 31 additions & 2 deletions lara/views/tweaks/ToolsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ struct ToolsView: View {
@State private var pid: pid_t = getpid()
@State private var status: String?
@State private var crashname: String = "SpringBoard"
@State private var pausedProcesses: Set<String> = []
@State private var proc_sbx: UInt64 = 0

private enum tokenclass: String, CaseIterable, Identifiable {
case read = "com.apple.app-sandbox.read"
Expand Down Expand Up @@ -156,10 +158,37 @@ struct ToolsView: View {
}
}
.disabled(crashname.isEmpty)
Button("Pause") {
crashname.withCString { _ = proc_pause_resume($0, false) }
pausedProcesses.insert(crashname)
}
.disabled(crashname.isEmpty || pausedProcesses.contains(crashname))

Button("Resume") {
crashname.withCString { _ = proc_pause_resume($0, true) }
pausedProcesses.remove(crashname)
}
.disabled(crashname.isEmpty || !pausedProcesses.contains(crashname))

Button("SBX Escape Helper") {
crashname.withCString { cstr in
proc_sbx = procbyname(cstr)
}

if proc_sbx == 0 {
status = "Failed to get proc"
return
}

let errorcheck = sbx_escape(proc_sbx)
status = errorcheck == 0 ? nil : "Failure"
}
.disabled(crashname.isEmpty)

} header: {
Text("Crasher")
Text("Task Manager")
} footer: {
Text("Crashes the selected process")
Text("Manages The Selected Process")
}

Section {
Expand Down
1 change: 1 addition & 0 deletions lara/views/tweaks/TweaksView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct TweaksView: View {
.disabled(!mgr.vfsready)
NavigationLink("OTA Updates", destination: OTAView(mgr: mgr))
NavigationLink("Screen Time", destination: ScreenTimeView(mgr: mgr))
NavigationLink("Clean Cache", destination: CacheView())
}

Section(header: HeaderLabel(text: "Broken", icon: "exclamationmark.triangle.fill")) {
Expand Down
222 changes: 222 additions & 0 deletions lara/views/tweaks/cacheclean/BundleResolver.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
//
// BundleResolver.swift
// lara
//

import Foundation
import UIKit

// MARK: - Model

struct ResolvedApp {
let dataUUID: String
let bundleID: String
let bundlePath: String
let name: String
let icon: UIImage?
}

// MARK: - Resolver

final class BundleResolver {

private let fm = FileManager.default

private let bundleRoot = "/var/containers/Bundle/Application"
private let dataRoot = "/var/mobile/Containers/Data/Application"

// MARK: Public

func resolveAll() -> [ResolvedApp] {

let bundleMap = buildBundleMap()

guard let dataContainers = try? fm.contentsOfDirectory(atPath: dataRoot) else {
return []
}

var results: [ResolvedApp] = []

for dataUUID in dataContainers {

let dataPath = dataRoot + "/" + dataUUID
let metaPath = dataPath + "/.com.apple.mobile_container_manager.metadata.plist"

// MARK: STEP 1 - metadata
var bundleID =
NSDictionary(contentsOfFile: metaPath)?["MCMMetadataIdentifier"] as? String

// MARK: STEP 2 - fallback scan inside container
if bundleID == nil {
bundleID = findBundleIDInDataContainer(dataPath)
}

// ❗ DO NOT DROP APP
let finalBundleID = bundleID ?? "unknown.\(dataUUID)"

// MARK: STEP 3 - resolve bundle path
let resolvedBundlePath =
bundleID != nil
? (bundleMap[finalBundleID] ?? findBundlePathFallback(bundleID: finalBundleID))
: nil

let finalBundlePath = resolvedBundlePath ?? ""

// MARK: STEP 4 - name resolution (NEVER FAIL)
let finalName = readSafeName(
bundlePath: finalBundlePath.isEmpty ? dataPath : finalBundlePath,
fallback: dataUUID
)

// MARK: STEP 5 - icon resolution (NEVER FAIL)
let finalIcon =
finalBundlePath.isEmpty
? UIImage(systemName: "app")
: readIcon(finalBundlePath)

results.append(
ResolvedApp(
dataUUID: dataUUID,
bundleID: finalBundleID,
bundlePath: finalBundlePath,
name: finalName,
icon: finalIcon
)
)
}

return results
}

// MARK: Bundle Map

private func buildBundleMap() -> [String: String] {

var map: [String: String] = [:]

guard let roots = try? fm.contentsOfDirectory(atPath: bundleRoot) else {
return map
}

for root in roots {

let rootPath = bundleRoot + "/" + root

guard let items = try? fm.contentsOfDirectory(atPath: rootPath) else {
continue
}

for item in items where item.hasSuffix(".app") {

let appPath = rootPath + "/" + item

// PRIMARY
if let meta = NSDictionary(contentsOfFile: appPath + "/.com.apple.mobile_container_manager.metadata.plist"),
let bundleID = meta["MCMMetadataIdentifier"] as? String {
map[bundleID] = appPath
continue
}

// FALLBACK
if let info = NSDictionary(contentsOfFile: appPath + "/Info.plist"),
let bundleID = info["CFBundleIdentifier"] as? String {
map[bundleID] = appPath
}
}
}

return map
}

// MARK: Data container scan

private func findBundleIDInDataContainer(_ dataPath: String) -> String? {

guard let items = try? fm.contentsOfDirectory(atPath: dataPath) else {
return nil
}

for item in items where item.hasSuffix(".app") {

let infoPath = dataPath + "/" + item + "/Info.plist"

if let info = NSDictionary(contentsOfFile: infoPath),
let bundleID = info["CFBundleIdentifier"] as? String {
return bundleID
}
}

return nil
}

// MARK: Bundle fallback

private func findBundlePathFallback(bundleID: String) -> String? {

guard let roots = try? fm.contentsOfDirectory(atPath: bundleRoot) else {
return nil
}

for root in roots {

let rootPath = bundleRoot + "/" + root

guard let items = try? fm.contentsOfDirectory(atPath: rootPath) else {
continue
}

for item in items where item.hasSuffix(".app") {

let appPath = rootPath + "/" + item

if let info = NSDictionary(contentsOfFile: appPath + "/Info.plist"),
let id = info["CFBundleIdentifier"] as? String,
id == bundleID {
return appPath
}
}
}

return nil
}

// MARK: SAFE NAME (never empty)

private func readSafeName(bundlePath: String, fallback: String) -> String {

let infoPath = bundlePath + "/Info.plist"

guard let info = NSDictionary(contentsOfFile: infoPath) else {
return fallback
}

return info["CFBundleDisplayName"] as? String ??
info["CFBundleName"] as? String ??
fallback
}

// MARK: Icon

private func readIcon(_ bundlePath: String) -> UIImage? {

let infoPath = bundlePath + "/Info.plist"

guard let info = NSDictionary(contentsOfFile: infoPath) else {
return UIImage(systemName: "app")
}

if let icons = info["CFBundleIcons"] as? [String: Any],
let primary = icons["CFBundlePrimaryIcon"] as? [String: Any],
let files = primary["CFBundleIconFiles"] as? [String],
let iconName = files.last {

let path = bundlePath + "/" + iconName

return UIImage(contentsOfFile: path)
?? UIImage(contentsOfFile: path + "@2x.png")
?? UIImage(contentsOfFile: path + ".png")
}

return UIImage(systemName: "app")
}
}
Loading