在找资料的时候看到了这个playground,那就做一下?‣
BASIC
if(ObjC.available) {
console.log("ObjC.available: true");
const VulnerableVault = ObjC.classes.VulnerableVault;
// -[VulnerableVault setSecretInt:]
const VulnerableVault_setSecretInVault = VulnerableVault["- setSecretInt:"]
const VulnerableVault_setSecretInVault_old = VulnerableVault_setSecretInVault.implementation;
VulnerableVault_setSecretInVault.implementation = ObjC.implement(VulnerableVault_setSecretInVault, (self,sel,any) => {
console.warn(`----------\nI: -[VulnerableVault setSecretInVault:] (${any})`);
let retval = VulnerableVault_setSecretInVault_old(self,sel,any);
console.warn(`O: -[VulnerableVault setSecretInVault:] (${retval})\n----------`);
return retval;
});
// -[VulnerableVault setSecretNumber:]
const VulnerableVault_setSecretNumber = VulnerableVault["- setSecretNumber:"]
const VulnerableVault_setSecretNumber_old = VulnerableVault_setSecretNumber.implementation;
VulnerableVault_setSecretNumber.implementation = ObjC.implement(VulnerableVault_setSecretNumber, (self,sel,any) => {
console.warn(`----------\nI: -[VulnerableVault setSecretNumber:] (${new ObjC.Object(any)})`);
let retval = VulnerableVault_setSecretNumber_old(self,sel,any);
console.warn(`O: -[VulnerableVault setSecretNumber:] (${retval})\n----------`);
return retval;
});
// -[VulnerableVault setSecretString:]
const VulnerableVault_setSecretString = VulnerableVault["- setSecretString:"]
const VulnerableVault_setSecretString_old = VulnerableVault_setSecretString.implementation;
VulnerableVault_setSecretString.implementation = ObjC.implement(VulnerableVault_setSecretString, (self,sel,any) => {
console.warn(`----------\nI: -[VulnerableVault setSecretString:] (${new ObjC.Object(any)})`);
let retval = VulnerableVault_setSecretString_old(self,sel,any);
console.warn(`O: -[VulnerableVault setSecretString:] (${retval})\n----------`);
return retval;
});
// -[VulnerableVault winIfTrue:]
const VulnerableVault_winIfTrue = VulnerableVault["- winIfTrue:"]
const VulnerableVault_winIfTrue_old = VulnerableVault_winIfTrue.implementation;
VulnerableVault_winIfTrue.implementation = ObjC.implement(VulnerableVault_winIfTrue, (self,sel,any) => {
console.warn(`----------\nI: -[VulnerableVault winIfTrue:] (${any}) -> (1)`);
let retval = VulnerableVault_winIfTrue_old(self,sel,1);
console.warn(`O: -[VulnerableVault winIfTrue:] (${retval})\n----------`);
return retval;
});
// -[VulnerableVault getSecretString:]
const VulnerableVault_getSecretString = VulnerableVault["- getSecretString"]
const VulnerableVault_getSecretString_old = VulnerableVault_getSecretString.implementation;
VulnerableVault_getSecretString.implementation = ObjC.implement(VulnerableVault_getSecretString, (self,sel) => {
console.warn(`----------\nI: -[VulnerableVault getSecretString:]`);
let retval = VulnerableVault_getSecretString_old(self,sel);
console.warn(`O: -[VulnerableVault getSecretString:] (${new ObjC.Object(retval).toString()})\n----------`);
return retval;
});
// -[VulnerableVault hasWon]
const VulnerableVault_hasWon = VulnerableVault["- hasWon"]
const VulnerableVault_hasWon_old = VulnerableVault_hasWon.implementation;
VulnerableVault_hasWon.implementation = ObjC.implement(VulnerableVault_hasWon, (self,sel) => {
console.warn(`----------\nI: -[VulnerableVault hasWon]`);
let retval = VulnerableVault_hasWon_old(self,sel);
console.warn(`O: -[VulnerableVault hasWon:] (${retval}) -> (1)\n----------`);
return 1;
});
// -[VulnerableVault getSecretKey:]
const VulnerableVault_getSecretKey = VulnerableVault["- getSecretKey"]
const VulnerableVault_getSecretKey_old = VulnerableVault_getSecretKey.implementation;
VulnerableVault_getSecretKey.implementation = ObjC.implement(VulnerableVault_getSecretKey, (self,sel) => {
console.warn(`----------\nI: -[VulnerableVault getSecretKey:]`);
let retval = VulnerableVault_getSecretKey_old(self,sel); // is a byte
let retval_str = ObjC.classes.NSString.alloc()["- initWithData:encoding:"](retval, 4);
console.warn(`O: -[VulnerableVault getSecretKey:] bytes(${retval_str})\n----------`);
return retval;
});
// -[VulnerableVault getself]
const VulnerableVault_getself = VulnerableVault["- getself"]
const VulnerableVault_getself_old = VulnerableVault_getself.implementation;
VulnerableVault_getself.implementation = ObjC.implement(VulnerableVault_getself, (self,sel) => {
console.warn(`----------\nI: -[VulnerableVault getself:]`);
let retval = VulnerableVault_getself_old(self,sel);
console.warn(`O: -[VulnerableVault getself:] (${retval})\n----------`);
// call self.winIfFrida_and27042_
let vault = new ObjC.Object(retval)
// vault.winIfFrida_and_27042_("Frida",27042);
vault["- winIfFrida:and27042:"]("Frida",27042);
// new ObjC.Object(retval)["- win"]();
return retval;
});
// -[VulnerableVault doNothing]
const VulnerableVault_doNothing = VulnerableVault["- doNothing"]
const VulnerableVault_doNothing_old = VulnerableVault_doNothing.implementation;
VulnerableVault_doNothing.implementation = ObjC.implement(VulnerableVault_doNothing, (self,sel) => {
console.warn(`----------\nI: -[VulnerableVault doNothing:]`);
let retval = VulnerableVault_doNothing_old(self,sel);
let HiddenVault = ObjC.classes.HiddenVault;
let hiddenVault = ObjC.chooseSync(HiddenVault)[0];
// hiddenVault["- win"]();
hiddenVault["- super_secret_function"]();
console.warn(`O: -[VulnerableVault doNothing:] (${retval})\n----------`);
return retval;
});
// -[VulnerableVault generateNumbers]
const VulnerableVault_generateNumbers = VulnerableVault["- generateNumbers"]
const VulnerableVault_generateNumbers_old = VulnerableVault_generateNumbers.implementation;
VulnerableVault_generateNumbers.implementation = ObjC.implement(VulnerableVault_generateNumbers, (self,sel) => {
console.warn(`----------\nI: -[VulnerableVault generateNumbers:]`);
let retval = VulnerableVault_generateNumbers_old(self,sel);
let retval_obj = new ObjC.Object(retval)
for(let i = 0; i < retval_obj["- count"](); i++) {
let number = retval_obj["- objectAtIndex:"](i)
if(number > 42) {
retval_obj["- setObject:atIndex:"](42,i);
}
}
console.warn(`O: -[VulnerableVault generateNumbers:] (${retval})\n----------`);
return retval;
});
console.log("Hooked");
} Advanced
if(ObjC.available) {
// -[VulnerableVault lose]
const VulnerableVault = ObjC.classes.VulnerableVault;
const VulnerableVault_lose = VulnerableVault["- lose"]
const VulnerableVault_lose_old = VulnerableVault_lose.implementation;
VulnerableVault_lose.implementation = ObjC.implement(VulnerableVault_lose, (self,sel) => {
console.warn(`----------\nI: -[VulnerableVault lose:]`);
// let retval = VulnerableVault_lose_old(self,sel);
let self_obj = new ObjC.Object(self);
let retval = self_obj["- win"]();
console.warn(`O: -[VulnerableVault lose:] (${retval})\n----------`);
return retval;
});
// another way to do it
// Interceptor.replace(VulnerableVault_lose_old, new NativeCallback(args => {
// console.warn(`----------\nI: -[VulnerableVault lose:]`);
// let self_obj = new ObjC.Object(args[0]);
// let retval = self_obj["- win"]();
// console.warn(`O: -[VulnerableVault lose:] (${retval})\n----------`);
// return retval;
// }, 'void', ['pointer', 'pointer']))
// 这里几个Native都爆炸了,应该写不了,或者是在ida里看然后走hex地址patch。
} Interact with UI
function convertDict(dict){
let keys = dict.allKeys();
let ob = {};
for (let index = 0; index < keys.count(); index++) {
let k = keys.objectAtIndex_(index);
let v = dict.objectForKey_(k);
if (["svce", "pdmn" ,"mdat", "cdat", "agrp"].includes(k.toString())) {
v = new ObjC.Object(v).toString()
}
if(k == "acct" || k == "v_Data"){
let data = new ObjC.Object(v)
v = data.bytes().readUtf8String(data.length());
}
ob[k] = v;
}
return ob;
}
if(ObjC.available) {
function getConstant(name){
var pptr = Module.getGlobalExportByName(name);
// return ObjC.Object(readPointer(pptr));
return new ObjC.Object(pptr);
}
const UIAlertController = ObjC.classes.UIAlertController;
const UIAlertAction = ObjC.classes.UIAlertAction;
const UIApplication = ObjC.classes.UIApplication;
console.log("ObjC.available: true");
// -[VulnerableVault doNothing]
const VulnerableVault = ObjC.classes.VulnerableVault;
const VulnerableVault_doNothing = VulnerableVault["- doNothing"]
const VulnerableVault_doNothing_old = VulnerableVault_doNothing.implementation;
VulnerableVault_doNothing.implementation = ObjC.implement(VulnerableVault_doNothing, (self,sel) => {
console.warn(`----------\nI: -[VulnerableVault doNothing:]`);
let retval = VulnerableVault_doNothing_old(self,sel);
console.warn(`O: -[VulnerableVault doNothing:] (${retval})\n----------`);
const handler = new ObjC.Block({
retType: "void",
argTypes: ["object"],
implementation: () => {}
})
ObjC.schedule(ObjC.mainQueue, () => {
let alert = UIAlertController.alertControllerWithTitle_message_preferredStyle_("Alert", "Called by Frida", 1);
let defaultAction = UIAlertAction.actionWithTitle_style_handler_("OK", 1, handler);
alert.addAction_(defaultAction);
UIApplication.sharedApplication().keyWindow().rootViewController().presentViewController_animated_completion_(alert, true, NULL);
})
return retval;
});
console.log("Hooked")
} Keychain
// -[VulnerableVault saveKey]
(() => {
console.log("Hook SecItemAdd")
let Security = Process.enumerateModules().find(m => m.name === "Security");
let SecItemAdd = Security.findExportByName("SecItemAdd");
Interceptor.attach(SecItemAdd, {
onEnter: function(args) {
console.log(JSON.stringify(convertDict(ObjC.Object(args[0])), null, 2))
}
})
})();
// dump keychain
(() => {
console.log("Dump keychain")
let Security = Process.enumerateModules().find(m => m.name === "Security");
let getConstWrapper = (module, name) => ObjC.Object(ptr(module.findExportByName(name)).readPointer())
let kCFBooleanTrue = getConstWrapper(Security, "kCFBooleanTrue");
let kSecReturnAttributes = getConstWrapper(Security, "kSecReturnAttributes");
let kSecMatchLimitAll = getConstWrapper(Security, "kSecMatchLimitAll");
let kSecMatchLimit = getConstWrapper(Security, "kSecMatchLimit");
let kSecClassGenericPassword = getConstWrapper(Security, "kSecClassGenericPassword");
let kSecClassInternetPassword = getConstWrapper(Security, "kSecClassInternetPassword");
let kSecClassCertificate = getConstWrapper(Security, "kSecClassCertificate");
let kSecClassKey = getConstWrapper(Security, "kSecClassKey");
let kSecClassIdentity = getConstWrapper(Security, "kSecClassIdentity");
let kSecClass = getConstWrapper(Security, "kSecClass");
let NSMutableDictionary = ObjC.classes.NSMutableDictionary;
let query = NSMutableDictionary.alloc().init();
let SecItemCopyMatching = new NativeFunction(Security.findExportByName("SecItemCopyMatching"), "int", ["pointer", "pointer"]);
[kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey, kSecClassIdentity].forEach(secItemClass => {
query.setObject_forKey_(kCFBooleanTrue, kSecReturnAttributes);
query.setObject_forKey_(kSecMatchLimitAll, kSecMatchLimit);
query.setObject_forKey_(kSecClassGenericPassword, kSecClass);
var result = Memory.alloc(8);
result.writePointer(ptr("0"));
SecItemCopyMatching(query.handle, result);
var pt = result.readPointer();
if (!pt.isNull()) {
console.log(ObjC.Object(pt).toString());
}
});
});
Biometry
if(ObjC.available) {
const pendingBlocks = new Set();
var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
Interceptor.attach(hook.implementation, {
onEnter: function(args) {
console.log("Hooking Touch Id..")
console.log(args[4])
var block = new ObjC.Block(args[4]);
pendingBlocks.add(block); // Keep it alive
const appCallback = block.implementation;
block.implementation = function (error, value) {
const result = appCallback(1, null);
pendingBlocks.delete(block);
return result;
};
},
});
console.log("Hooked")
} 这个没有entitlement也许大概是用不了?
NSUserDefaults
if(ObjC.available) {
const pendingBlocks = new Set();
const NSUserDefaults = ObjC.classes.NSUserDefaults;
// setObject:forKey:
const NSUserDefaults_setObject_forKey = NSUserDefaults["- setObject:forKey:"]
const NSUserDefaults_setObject_forKey_old = NSUserDefaults_setObject_forKey.implementation;
NSUserDefaults_setObject_forKey.implementation = ObjC.implement(NSUserDefaults_setObject_forKey, (self,sel,any,any2) => {
console.warn(`----------\nI: -[NSUserDefaults setObject:forKey:] (${new ObjC.Object(any)}) (${new ObjC.Object(any2)})`);
let retval = NSUserDefaults_setObject_forKey_old(self,sel,any,any2);
console.warn(`O: -[NSUserDefaults setObject:forKey:] (${retval})\n----------`);
if(new ObjC.Object(any2).toString() == "bio") {
console.log("bio")
console.log(new ObjC.Object(any).toString())
}
return retval;
});
// standardUserDefaults
const NSUserDefaults_standardUserDefaults = NSUserDefaults["+ standardUserDefaults"] // class method, will not require any instance.
console.log(NSUserDefaults["+ standardUserDefaults"]().dictionaryRepresentation().toString())
console.log("Hooked")
} Detect Frida/Jailbreak
27042,改端口就好了。看源码发现是这样:
所以就是尝试bind,如果没bind上说明被占用了,那么solution就是把bind给干掉(一般场景还是不能这么干的,会有问题)
同样hook掉_dyld_get_image_name
这个是一样的,把_dyld_get_image_name换成安全状态下的。