def inspect(debugger, command, exe_ctx, result, internal_dict): """ Syntax: inspect Examples: (lldb) inspect Summary: Inspect UIView. The "infoView" is based on https://github.com/QMUI/LookinServer This command is implemented in HMInspectView.py """ HMInspectViewController.register() command_script = f''' Class objClass = (Class)objc_lookUpClass("{HMInspectViewController.gClassName}"); if ((BOOL)[(Class)objClass respondsToSelector:@selector(start)]) {{ (void)[objClass performSelector:@selector(start)]; }} ''' HM.evaluateExpressionValue(command_script) HM.processContinue()
def sandbox(debugger, command, exe_ctx, result, internal_dict): """ Syntax: sandbox Examples: (lldb) sandbox This command is implemented in HMSandbox.py """ HMSandboxViewController.register() command_script = f''' UIViewController *vc = (UIViewController *)[[NSClassFromString(@"{HMSandboxViewController.gClassName}") alloc] init]; UINavigationController *nv = [[UINavigationController alloc] initWithRootViewController:vc]; ((void (*)(id, SEL, long)) objc_msgSend)((id)nv, @selector(setModalPresentationStyle:), 0); // UIModalPresentationFullScreen UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController; if ([rootVC presentedViewController]) {{ [[rootVC presentedViewController] presentViewController:nv animated:YES completion:nil]; }} else {{ [rootVC presentViewController:nv animated:YES completion:nil]; }} ''' HM.evaluateExpressionValue(command_script) HM.processContinue()
def showFPS(debugger, command, exe_ctx, result, internal_dict): """ Syntax: showfps Examples: (lldb) showfps Notice: showfps is deprecated. Use showhud instead. This command is implemented in HMFPSLabel.py """ HM.DPrint("showfps is deprecated. Use showhud instead.") FPSClassName = "HMFPSLabel" if HM.existClass(FPSClassName): HM.DPrint("HMFPSLabel is already on display") return # Register class FPSLabelClassValue = HM.allocateClass(FPSClassName, "UILabel") HM.addIvar(FPSLabelClassValue.GetValue(), "_link", "CADisplayLink *") HM.addIvar(FPSLabelClassValue.GetValue(), "_count", "int") HM.addIvar(FPSLabelClassValue.GetValue(), "_lastTime", "double") HM.registerClass(FPSLabelClassValue.GetValue()) addToKeyWindowIMPValue = makeAddToKeyWindowIMP() if not HM.judgeSBValueHasValue(addToKeyWindowIMPValue): return HM.addClassMethod(FPSClassName, "addToKeyWindow", addToKeyWindowIMPValue.GetValue(), "@@:") tickIMPValue = makeTickIMP() if not HM.judgeSBValueHasValue(tickIMPValue): return HM.addInstanceMethod(FPSClassName, "tick:", tickIMPValue.GetValue(), "v@:@") # Show fps command addToKeyWindowCommand = ''' Class fps = NSClassFromString(@"HMFPSLabel"); (UILabel *)[fps performSelector:@selector(addToKeyWindow)]; ''' HM.evaluateExpressionValue(addToKeyWindowCommand) HM.DPrint("showfps Done!") HM.processContinue()
def request(debugger, command, exe_ctx, result, internal_dict): """ Syntax: request Examples: (lldb) request Notice: Except WKWebView This command is implemented in HMNetwork.py """ global gProtocolName if HM.existClass(gProtocolName): return registerProtocol() swizzlingProtocolClasses() HM.processContinue()
def push(debugger, command, exe_ctx, result, internal_dict): """ Syntax: push <className> push [--instance] <instance> Options: --instance/-i; Push the UIViewController instance. Examples: (lldb) push PersonalViewController (lldb) push -i [[PersonalViewController alloc] init] (lldb) expression -l objc -O -- [PersonalViewController new] <PersonalViewController: 0x7fed30c5a070> (lldb) push -i 0x7fed30c5a070 Notice: "push MyViewController" needs to execute "[[MyViewController alloc] init]" first. If the initializer of the class requires parameters, or the class needs to pass parameters after initialization, this command may cause errors. This command is implemented in HMPushViewController.py """ # HM.DPrint(type(command)) # <class 'str'> # HM.DPrint(type(exe_ctx)) # <class 'lldb.SBExecutionContext'> # HM.DPrint(type(result)) # <class 'lldb.SBCommandReturnObject'> # HM.DPrint(type(internal_dict)) # <class 'dict'> command_args = shlex.split(command) parser = generate_option_parser() try: # options: optparse.Values # args: list (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return if len(args) == 0: HM.DPrint("Error input, plase enter 'help push' for more infomation") return HM.DPrint("Waiting...") navigationVC = getNavigationVC() if navigationVC is None: HM.DPrint("Cannot find a UINavigationController") return state = False if options.instance: instanceExpr: str = "" for string in args: instanceExpr += string + " " instanceExpr = instanceExpr.rstrip() VCObject = HM.evaluateExpressionValue(instanceExpr).GetValue() else: makeVCExpression = f"(UIViewController *)[[NSClassFromString(@\"{args[0]}\") alloc] init]" VCObject = HM.evaluateExpressionValue(makeVCExpression).GetValue() # address if verifyObjIsKindOfClass(VCObject, "UIViewController"): pushExpression = f"(void)[{navigationVC} pushViewController:(id){VCObject} animated:YES]" debugger.HandleCommand('expression -l objc -O -- ' + pushExpression) state = True elif not options.instance: classPrefixes = HM.getClassPrefixes()[0] for prefix in classPrefixes: # for Swift file className = f"{prefix}.{args[0]}" if not HM.existClass(className): continue makeVCExpression = f"(UIViewController *)[[NSClassFromString(@\"{className}\") alloc] init]" VCObject = HM.evaluateExpressionValue(makeVCExpression).GetValue() # address if verifyObjIsKindOfClass(VCObject, "UIViewController"): pushExpression = f"(void)[{navigationVC} pushViewController:(id){VCObject} animated:YES]" debugger.HandleCommand('expression -l objc -O -- ' + pushExpression) state = True break HM.DPrint("push succeed" if state else "push failed") if state: HM.processContinue()
def selectedInspectViewBreakPointHandler(frame, bp_loc, internal_dict) -> bool: HMInspectViewController.register() HM.processContinue() return True
def selectedAPPInfoBreakPointHandler(frame, bp_loc, internal_dict) -> bool: HMDebugInfoViewController.register() HM.processContinue() return True
def tapSelfBreakPointHandler(frame, bp_loc, internal_dict) -> bool: HMDebugMainViewController.register() HM.processContinue() return True
def showDebugHUD(debugger, command, exe_ctx, result, internal_dict): """ Syntax: showhud Examples: (lldb) showhud Summary: Show debug HUD. 1.Memory footprint. 2.CPU utilization. 3.FPS in main thread. The UI style is based on https://github.com/meitu/MTHawkeye This command is implemented in HMDebugHUD.py """ global gClassName if isDisplayingHUD(): HM.DPrint(f"{gClassName} is already on display") HM.processContinue() return elif HM.existClass(gClassName): showHUDFunc() HM.processContinue() return # Register class HMProgressHUD.show(f"Register {gClassName}...") HM.DPrint(f"Register {gClassName}...") classValue = HM.allocateClass(gClassName, "UIView") HM.addIvar(classValue.GetValue(), "_link", "CADisplayLink *") HM.addIvar(classValue.GetValue(), "_count", "int") # count in 1 second HM.addIvar(classValue.GetValue(), "_lastTime", "double") HM.addIvar(classValue.GetValue(), "_memoryLab", "UILabel *") HM.addIvar(classValue.GetValue(), "_cpuUtilizationLab", "UILabel *") HM.addIvar(classValue.GetValue(), "_fpsLab", "UILabel *") HM.registerClass(classValue.GetValue()) # Add methods HM.DPrint(f"Add methods to {gClassName}...") addToKeyWindowIMPValue = makeAddToKeyWindowIMP() if not HM.judgeSBValueHasValue(addToKeyWindowIMPValue): HMProgressHUD.hide() return HM.addClassMethod(gClassName, "addToKeyWindow", addToKeyWindowIMPValue.GetValue(), "@@:") tapSelfIMPValue = makeTapSelfIMP() if not HM.judgeSBValueHasValue(tapSelfIMPValue): HMProgressHUD.hide() return HM.addInstanceMethod(gClassName, "tapSelf", tapSelfIMPValue.GetValue(), "v@:") # Add methods(update) if not addUpdateMethods(): HMProgressHUD.hide() return # Add methods(move) HM.DPrint(f"Add methods to {gClassName}......") if not addMoveMethods(): HMProgressHUD.hide() return # Add breakpoint in tapSelf HM.DPrint("Add breakpoint to hook method...") HM.addOneShotBreakPointInIMP(tapSelfIMPValue, "HMDebugHUD.tapSelfBreakPointHandler", "HMDebugHUD_TapSelf_Breakpoint") HM.DPrint(f"Register {gClassName} done!") # Show HUD command showHUDFunc() HMProgressHUD.hide() HM.processContinue()