Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 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,8 @@ Important Notes:
- OTA Update Disabler
- Screen Time Disabler
- App Decrypt

- Clean Cache
- Remove "This Call is being Recorded" Sound

### 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;
}
251 changes: 251 additions & 0 deletions lara/views/tweaks/RecordView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import SwiftUI
import UIKit
import UniformTypeIdentifiers

struct RecordView: View {
@ObservedObject var mgr: laramgr

@State private var disabled = false
@State private var isOverwriting = false

private let target1 = "/var/mobile/Library/CallServices/Greetings/default/StartDisclosureWithTone.m4a"
private let target2 = "/var/mobile/Library/CallServices/Greetings/default/StopDisclosure.caf"

// MARK: - Remote Download URLs
private let remote1 = URL(string:
"https://github.com/YangJiiii/Disable-Call-Recording-BookRestore-/raw/refs/heads/main/Sounds/StartDisclosureWithTone.m4a"
)!

private let remote2 = URL(string:
"https://github.com/YangJiiii/Disable-Call-Recording-BookRestore-/raw/refs/heads/main/Sounds/StopDisclosure.caf"
)!

var body: some View {
List {

Section(header: HeaderLabel(text: "Status", icon: "info.circle")) {
HStack {
Text("Status")
Spacer()

Text(disabled ? "Disabled" : "Enabled")
.foregroundColor(disabled ? .red : .green)
.monospaced()
}
}

Section(header: HeaderLabel(text: "Actions", icon: "hammer")) {

Button("Disable") {
disableRecordNotify()
}
.disabled(disabled || isOverwriting)

Button("Enable") {
enableRecordNotify()
}
.disabled(isOverwriting)
}

// MARK: - NEW DOWNLOAD SECTION
Section(header: HeaderLabel(text: "Download", icon: "arrow.down.circle")) {

Button("Download Sounds") {
downloadSounds()
}
.disabled(isOverwriting)
}
}
.navigationTitle("Call Record Notification")
.onAppear {
downloadIfNeeded()
check()
}
}

// MARK: - Documents Paths

private var documents: URL {
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
}

private var local1: URL {
documents.appendingPathComponent("StartDisclosurewithTone.m4a")
}

private var local2: URL {
documents.appendingPathComponent("StopDisclosure.caf")
}

// MARK: - Status Check

private func check() {
guard
let attrs1 = try? FileManager.default.attributesOfItem(atPath: target1),
let attrs2 = try? FileManager.default.attributesOfItem(atPath: target2),
let size1 = attrs1[.size] as? NSNumber,
let size2 = attrs2[.size] as? NSNumber
else {
disabled = false
return
}

disabled = size1.intValue < 2048 || size2.intValue < 2048
}

// MARK: - DOWNLOAD SYSTEM

private func downloadIfNeeded() {
let fm = FileManager.default

if !fm.fileExists(atPath: local1.path) {
download(remote1, to: local1)
}

if !fm.fileExists(atPath: local2.path) {
download(remote2, to: local2)
}
}

private func downloadSounds() {
isOverwriting = true

let group = DispatchGroup()

group.enter()
download(remote1, to: local1) { group.leave() }

group.enter()
download(remote2, to: local2) { group.leave() }

group.notify(queue: .main) {
self.isOverwriting = false
self.mgr.logmsg("Sounds downloaded")
self.check()
}
}

private func download(_ url: URL, to dest: URL, completion: (() -> Void)? = nil) {
URLSession.shared.downloadTask(with: url) { tempURL, _, error in

defer { completion?() }

guard let tempURL = tempURL, error == nil else {
DispatchQueue.main.async {
self.mgr.logmsg("Download failed: \(url.lastPathComponent)")
}
return
}

do {
let fm = FileManager.default

if fm.fileExists(atPath: dest.path) {
try fm.removeItem(at: dest)
}

try fm.moveItem(at: tempURL, to: dest)

DispatchQueue.main.async {
self.mgr.logmsg("Downloaded: \(dest.lastPathComponent)")
}

} catch {
DispatchQueue.main.async {
self.mgr.logmsg("File error: \(error.localizedDescription)")
}
}
}.resume()
}

// MARK: - Backup Creation

private func createBackupsIfNeeded() {
let fm = FileManager.default

let backupFolder = documents.appendingPathComponent("Backup")

let backup1 = backupFolder.appendingPathComponent("StartDisclosurewithTone.m4a")
let backup2 = backupFolder.appendingPathComponent("StopDisclosure.caf")

if !fm.fileExists(atPath: backupFolder.path) {
try? fm.createDirectory(at: backupFolder, withIntermediateDirectories: true)
}

if !fm.fileExists(atPath: backup1.path) {
try? fm.copyItem(at: URL(fileURLWithPath: target1), to: backup1)
}

if !fm.fileExists(atPath: backup2.path) {
try? fm.copyItem(at: URL(fileURLWithPath: target2), to: backup2)
}
}

// MARK: - Overwrite

@discardableResult
private func overwrite(target: String, source: String) -> Bool {
let ok = mgr.vfsoverwritefromlocalpath(target: target, source: source)

mgr.logmsg(ok ? "overwrite ok: \(target)" : "overwrite failed: \(target)")
return ok
}

// MARK: - Disable

private func disableRecordNotify() {
isOverwriting = true

DispatchQueue.global(qos: .userInitiated).async {

self.createBackupsIfNeeded()

let ok1 = self.overwrite(target: self.target1, source: self.local1.path)
let ok2 = self.overwrite(target: self.target2, source: self.local2.path)

DispatchQueue.main.async {
self.isOverwriting = false
self.check()

if !(ok1 && ok2) {
self.mgr.logmsg("Failed disabling notification")
}
}
}
}

// MARK: - Enable

private func enableRecordNotify() {
let fm = FileManager.default

let backupFolder = documents.appendingPathComponent("Backup")
let backup1 = backupFolder.appendingPathComponent("StartDisclosurewithTone.m4a")
let backup2 = backupFolder.appendingPathComponent("StopDisclosure.caf")

guard
fm.fileExists(atPath: backup1.path),
fm.fileExists(atPath: backup2.path)
else {
mgr.logmsg("Backups not found")
return
}

isOverwriting = true

DispatchQueue.global(qos: .userInitiated).async {

let ok1 = self.overwrite(target: self.target1, source: backup1.path)
let ok2 = self.overwrite(target: self.target2, source: backup2.path)

DispatchQueue.main.async {
self.isOverwriting = false
self.check()

if !(ok1 && ok2) {
self.mgr.logmsg("Failed restoring notification")
}
}
}
}
}
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
2 changes: 2 additions & 0 deletions lara/views/tweaks/TweaksView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ 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())
NavigationLink("Call Record Notification", destination: RecordView(mgr: mgr))
}

Section(header: HeaderLabel(text: "Broken", icon: "exclamationmark.triangle.fill")) {
Expand Down
Loading