KJCracks / Clutch

Fast iOS executable dumper
3.69k stars 647 forks source link

Clutch 3? #203

Closed Tatsh closed 6 years ago

Tatsh commented 6 years ago

@ttwj @iT0ny @NinjaLikesCheez and anyone else interested.

I would like some input on using 99% (or 100%) Swift for a complete rewrite of Clutch (version 3?). This would require installing the Swift libraries one way or another on the device. On Cydia there is already a package for this. Over the last 2 years Swift has stabilised at version 4 so we do not have to worry so much about extreme syntax changes.

Once the unsafe parts of the API (kernel and dyld) are wrapped in Swift it should be smooth sailing. This should ease the process for contributors, and yes it is possible to build such a thing without using Xcode (swiftc with flags). This actually could tie-in to using CMake as part #201.

MiniZip would stay as is, unless there is a good (and small Swift alternative). The project would not switch to using dependencies, and still package such things in unless we really want to switch to Carthage or CocoaPods, or Apple's package manager.

Some of the things we need are already made, like the Swift Darwin module which gets imported with import Foundation. This provides a lot of those common C functions we use.

Unsafe Swift Using Legacy C APIs with Swift (a bit dated)

Tatsh commented 6 years ago

Most internal libraries used by Clutch are now available with the Darwin.Mach module. This is ASLRDisabler ported to Swift:

import Foundation
import Darwin.Mach
import MachO.fat

public let VM_REGION_SUBMAP_INFO_COUNT_64 = mach_msg_type_number_t(
    MemoryLayout<vm_region_submap_info_data_64_t>.size / MemoryLayout<Int>.size)

class ASLRDisabler {
    static func slideForPID(pid: Int32, error: inout NSError?) -> mach_vm_address_t {
        var targetTask: vm_map_t = 0
        var kr: kern_return_t = 0
        var ret: mach_vm_address_t = 0

        kr = task_for_pid(mach_task_self_, pid, &targetTask)
        if kr != KERN_SUCCESS {
            let info = [
                NSLocalizedDescriptionKey: "Can't execute task_for_pid! Do you have the right permissions/entitlements?",
            ]
            error = NSError(domain: NSMachErrorDomain, code: Int(kr), userInfo: info)
            return 0
        }

        var iter: vm_address_t = 0
        var found = false
        var n = Int32(0)

        while !found {
            var mh: mach_header = mach_header()
            var addr: vm_address_t = iter
            var lsize: vm_size_t = 0
            var depth: UInt32 = 0
            var bytesRead: vm_size_t = 0
            let info: vm_region_recurse_info_t = vm_region_recurse_info_t.init(mutating: &n)
            var count: mach_msg_type_number_t = VM_REGION_SUBMAP_INFO_COUNT_64

            if vm_region_recurse_64(targetTask, &addr, &lsize, &depth, info, &count) != 0 {
                break
            }

            kr = withUnsafeMutablePointer(to: &mh) { p -> kern_return_t in
                let vma = vm_address_t(bitPattern: p)
                return vm_read_overwrite(targetTask, addr, vm_size_t(MemoryLayout<mach_header>.size), vma, &bytesRead)
            }

            if kr == KERN_SUCCESS && bytesRead == MemoryLayout<mach_header>.size {
                // only one image with MH_EXECUTE filetype
                if (mh.magic == MH_MAGIC || mh.magic == MH_MAGIC_64) && mh.filetype == MH_EXECUTE {
                    found = true
                    ret = mach_vm_address_t(addr)
                }
            }
            iter = addr + lsize
        }

        if !found {
            let info = [
                NSLocalizedDescriptionKey: "ASLR disabler failed!",
            ]
            error = NSError(domain: NSMachErrorDomain, code: -1, userInfo: info)
        }

        return ret
    }
}
NinjaLikesCheez commented 6 years ago

I do plan on responding to this - I've just been away the last week or two (family visiting)

Tatsh commented 6 years ago

We'll stick where we are now that we have done the refactoring I wanted to do.