Closed izmcm closed 1 year ago
Also, I learned to use Theos to try to test this code. I followed this writeup: https://www.mbo42.com/2018/04/01/hooking-swift-methods/
Tweak.x
%hook OtherClass
static void (*orig_OtherClass_hookThisFunctionToTestMSHook)(void) = NULL;
BOOL hook_OtherClass_hookThisFunctionToTestMSHook() {
orig_OtherClass_hookThisFunctionToTestMSHook();
NSLog(@"Hooked random function");
return YES;
}
%end
%ctor {
%init(OtherClass = objc_getClass("HookDetectionPoC.OtherClass"));
MSHookFunction(MSFindSymbol(NULL, "_$s16HookDetectionPoC10OtherClassC028hookThisFunctionToTestMSHookB0SbyF"),
(void*)hook_OtherClass_hookThisFunctionToTestMSHook,
(void**)&orig_OtherClass_hookThisFunctionToTestMSHook);
}
This code works as expected and hookThisFunctionToTestMSHookDetection
now is returning true
, but MSHookChecker keeps returning false
hey, @izmcm
The OtherClass. hookThisFunctionToTestMSHookDetection
function’s type is @convention(method) (@guaranteed OtherClass) -> Bool
. (you can get by using the command line swiftc -emit-sil OtherClass.swift
). In this case, you don't get the really function address by using getSwiftFunctionAddr2
. maybe you can get the function address by swift v-table
I'am not familiar with how Frida works, but I guess it's inlineHook
instead of objcHook
. so amIRuntimeHooked
doesn't work
Hi @TannerJin, hope you're well :)
You are right about Frida, it should not be detected using amIRuntimeHooked
but using amIReverseEngineered
According my tests, RuntimeHookChecker is capable to detect the replacement of an objective-c function by a Tweak with Theos. If we don't need to have an objc func, doesn't make sense use this class, right?
Now, about MSHookChecker, I still have some doubts:
The example function someFunction
that appears in the README only seems to work if the function is not inside a class as usual, right? I tested putting someFunction
inside OtherClass
and the type changed to @convention (method) (Int, @guaranteed OtherClass) -> Bool
. Whereas I can't just put this new type as FunctionType
as this will result in two errors
'guaranteed' only allowed in SIL modules
Convention 'method' not supported
So, should I use the virtual method table (v-table) to get function's address? I have no idea how it works 🙁, do you have some example? The only example I found on the internet about getting the address of a function in swift was a response from you on Stackoverflow haha
Hi again @TannerJin! I saw that in the stackoverflow edits there was an example code for vtable, so my code was like this
ViewController.swift
{...}
@IBAction func callMSHook(_ sender: Any) {
let funcAddr = getSwiftFunctionAddressFromVtable(OtherClass.self, methodIndex: 1)!
let amIMSHooked = IOSSecuritySuite.amIMSHooked(funcAddr)
self.textView.text = "MSHook detector = \(amIMSHooked)\nMSHook func = \(otherClass.hookThisFunctionToTestMSHookDetection())"
}
func getSwiftFunctionAddressFromVtable(_ objc_class: AnyClass,
methodIndex offset: Int) -> UnsafeMutablePointer<UnsafeMutableRawPointer>? {
let classPointer = Unmanaged.passUnretained(objc_class as AnyObject).toOpaque()
guard let outCount = malloc(MemoryLayout<UInt32>.size)?.assumingMemoryBound(to: UInt32.self) else { return nil }
defer {
free(outCount)
}
let _ = class_copyIvarList(objc_class, outCount)
let cachePointer = classPointer.advanced(by: 0x50 + 32*Int(outCount.pointee))
return cachePointer.advanced(by: offset*MemoryLayout<UnsafeMutableRawPointer>.size).assumingMemoryBound(to: UnsafeMutableRawPointer.self)
}
{...}
OtherClass.swift
class OtherClass {
init() { } // vtable 0
// vtable 1
func hookThisFunctionToTestMSHookDetection() -> Bool {
print("hookThisFunctionToTestMSHookDetection")
return false
}
// vtable 2
@objc dynamic func hookThisFunctionToTestRuntimeHookDetection() -> Bool {
print("hookThisFunctionToTestRuntimeHookDetection")
return false
}
}
I noticed that the address really changes Address from function's type -> 0x00000001008dacd0 Address from vtable -> 0x000000010091ab18
Unfortunately the behavior is the same :( hookThisFunctionToTestMSHookDetection
is returning true
, but MSHookChecker
keeps returning false
.
P.S.: If it help, I noticed the MSHookFunctionChecker
always return nil in translateInstruction
func in both cases
hi, @izmcm This is just a demo of my previous Swift learning,it's not very accurate. you can use v-table to get the function address by referring to https://github.com/johnno1962/SwiftTrace#how-it-works
Hey @TannerJin, I used the three methods of getting the function address to group all the results together for readability. My code looks like this
@IBAction func callMSHook(_ sender: Any) {
let funcHook = otherClass.hookThisFunctionToTestMSHookDetection()
print("hookThisFunctionToTestMSHookDetection should return false and is returning \(funcHook)")
let funcAddrVtable = getSwiftFunctionAddressFromVtable(OtherClass.self, methodIndex: 1)!
let amIMSHookedVtable = IOSSecuritySuite.amIMSHooked(funcAddrVtable)
print("Address from manual vtable: \(funcAddrVtable)")
print("amIMSHooked with address from manual vtable: \(amIMSHookedVtable)")
let funcAddrType = getSwiftFunctionAddr(OtherClass.hookThisFunctionToTestMSHookDetection)
let amIMSHookedType = IOSSecuritySuite.amIMSHooked(funcAddrType)
print("Address from FunctionType method: \(funcAddrType)")
print("amIMSHooked with address from FunctionType method \(amIMSHookedType)")
SwiftTrace.forEachVTableEntry(ofClass: OtherClass.self, callback: { symname, slotIndex, vtableSlot, stop in
print("Address from SwiftTrace vtable at index \(slotIndex): \(vtableSlot)")
let amIMSHookedSwiftTrace = IOSSecuritySuite.amIMSHooked(vtableSlot)
print("amIMSHooked with address from SwiftTrace vtable at index \(slotIndex): \(amIMSHookedSwiftTrace)")
})
}
The result obtained in the console is below. As we can see, the first line shows that the function must return false
, but it returns true
. The second and third lines show the address captured by the stackoverflow function using vtable and the result of calling iOSSecuritySwift for that case. The fourth and fifth lines show the same thing through the method described in the README. The next six lines show the forEach
of the function implemented by SwiftTrace for each of the methods described in OtherClass
. It is worth noting that the address obtained by SwiftTrace is the same one obtained by the stackoverflow function. Unfortunately, in neither case amIMSHooked returns true
hookThisFunctionToTestMSHookDetection should return false and is returning true
Address from manual vtable: 0x0000000100a1eac0
amIMSHooked with address from manual vtable: false
Address from FunctionType method: 0x00000001009dfb9c
amIMSHooked with address from FunctionType method false
Address from SwiftTrace vtable at index 1: 0x0000000100a1eab8
amIMSHooked with address from SwiftTrace vtable at index 1: false
Address from SwiftTrace vtable at index 2: 0x0000000100a1eac0
amIMSHooked with address from SwiftTrace vtable at index 2: false
Address from SwiftTrace vtable at index 3: 0x0000000100a1eac8
amIMSHooked with address from SwiftTrace vtable at index 3: false
Hey @TannerJin, is there any update about this? 😄
@izmcm were you able to prevent Frida from dynamically injecting in your app ? I've tried ISS but came to the same conclusions as you, it can't prevent it. Did you use any other tool to achieve this?
@KeiroMidori I noticed that ISS Reverse Engineering module can detect if Frida is installed on device, but I couldn't detect more than that. I couldn't use ISS to detect hook with Frida or with Theos
Hi there, this is possibly a dumb question but I'm new with iOS security and I'm having some doubts about using the library.
I created a dumb app to test some knowledge and imported the iOSSecuritySuite library via Swift Package Manager. In my test app, I created a class with two functions as shown below (I'm trying to understand the difference between RuntimeHookChecker and MSHookChecker)
So, on my ViewController, I has two buttons that call
I installed this app in my jailbroken iPhone and used Frida to change the return of OtherClass' functions with the script bellow
This was able to modify the result of the functions and now they are returning
true
instead offalse
. Unfortunately, the hook detections not working and are returningfalse
always.Someone can help me to test the hook detection?