LLDB查詢對象存儲區(qū)域

LLDB查詢對象存儲區(qū)域(mach-o 棧區(qū) 堆區(qū))

#import "LGCatAddress.h"
// 1. C++插件
// 2. 模版
// 3. lldb + 基本上所有mach-o,執(zhí)行其他代碼信息
// cat address 0x00010000010
// 命令傳遞的參數
namespace LG {
using lldb::eReturnStatusFailed;
using lldb::eReturnStatusSuccessFinishResult;
using lldb::SBCommandInterpreter;
using lldb::SBCommandReturnObject;
using lldb::SBDebugger;
using lldb::SBError;
using lldb::SBExpressionOptions;
using lldb::SBFrame;
using lldb::SBStream;
using lldb::SBSymbol;
using lldb::SBTarget;
using lldb::SBThread;
using lldb::SBValue;
using lldb::SBAddress;
using lldb::SBSection;
using lldb::SBModule;
std::tuple<bool, const char *> tryMachOAddress(SBAddress addr, SBTarget target) {
    // section
    SBSection section = addr.GetSection();
    if (!section.IsValid()) {
        return std::make_tuple(false, nullptr);
    }
    NSMutableString *sectionName = [NSString stringWithUTF8String:section.GetName()].mutableCopy;
    SBSection tmpS = section;
    while (tmpS.GetParent().IsValid()) {
        tmpS = tmpS.GetParent();
        sectionName = [NSMutableString stringWithFormat:@"%s.%@", tmpS.GetName(), sectionName];
    }
    SBModule module = addr.GetModule();
    if (module.IsValid()) {
        sectionName = [NSMutableString stringWithFormat:@"%s.%@", addr.GetModule().GetFileSpec().GetFilename(), sectionName];
    }
    uint64_t addrOffset = addr.GetLoadAddress(target) - section.GetLoadAddress(target);
    [sectionName appendFormat:@" +%llx", addrOffset];
    SBSymbol symbol = addr.GetSymbol();
    NSMutableString *returnDescription = [NSMutableString stringWithFormat:@"%llx", addr.GetOffset()];
    if (symbol.IsValid()) {
        [returnDescription appendFormat:@"%s", symbol.GetName()];
        SBAddress startAddr =  symbol.GetStartAddress();

        uint64_t addrOffset = addr.GetLoadAddress(target) - startAddr.GetLoadAddress(target);
        [returnDescription appendFormat:@" <+%llu> ", addrOffset];

        if (symbol.GetMangledName()) {
            [returnDescription appendFormat:@", (%s)", symbol.GetMangledName()];
        }
        [returnDescription appendFormat:@", External: %@ ", symbol.IsSynthetic() ? @"YES" : @"NO"];
    }
    
    [returnDescription appendFormat:@"%@", sectionName];
    return std::make_tuple(true, returnDescription.UTF8String);
}
std::tuple<bool, const char *>  tryStackAddress(SBAddress addr, SBTarget target) {
        // frame -> thread
        SBThread thread = target.GetProcess().GetSelectedThread();
        uint32_t num_frames = thread.GetNumFrames();
        SBStream stream;
        for (UInt32 i = 0; i < num_frames; i++) {
            const uint64_t address = addr.GetLoadAddress(target);
            SBFrame frame = thread.GetFrameAtIndex(i);
            const uint64_t fp = frame.GetFP();
            const uint64_t sp = frame.GetSP();
            if (address >= sp && address <= fp) {
                stream.Printf("stack address (SP: 0x%llx FP: 0x%llx) %s", sp, fp, frame.GetFunctionName());
                return std::make_tuple(true, [NSString stringWithUTF8String:stream.GetData()].UTF8String);
            }
        }
        return std::make_tuple(false, nullptr);
    }
// 插件執(zhí)行的環(huán)境
// 執(zhí)行插件所在的調試環(huán)境

// lldb -》 運行在一個進程上
// exec -〉 運行在一個進程上 lldb -》debugserver
// lldb -> 加載這個插件的-》調代碼-〉cat address
// 2個環(huán)境 -》 porcess -〉 2堆
// 開發(fā)porcess
//hmap
// 執(zhí)行插件-》調試環(huán)境-〉執(zhí)行相關的判斷代碼
// 自定義協議 + 客戶端 服務端 大廠用 人力物力成本大 引擎
// 動態(tài)庫 + 蘋果點頭
    std::tuple<bool, const char *> tryHeapAddress(SBAddress addr, SBTarget target) {
        SBStream stream = SBStream();
        stream.Printf("import Foundation\n");
        stream.Printf("let address: UnsafeRawPointer? = UnsafeRawPointer(bitPattern: %llu)\n", addr.GetLoadAddress(target));
        stream.Printf(R"___(
                      var returnString: String?
                      if let address = address, let ptr = malloc_zone_from_ptr(address) {
                            returnString = String(format: "%%p heap pointer, (0x%%x bytes), zone: %%p", Int(bitPattern: address), malloc_good_size(malloc_size(address)), Int(bitPattern: ptr))
                      }

                      guard let string = returnString else {
                          return ""
                      }
                      return string
          )___");
//        stream.Printf("uintptr_t ptr_t = %llu;", addr.GetLoadAddress(target));
//        stream.Printf("void *ptr = (void *)ptr_t;");
//        stream.Printf(R"___(
//              @import CoreFoundation;
//              char name[80];
//                if ((void*)malloc_zone_from_ptr(ptr)) {
//                      size_t a = (size_t)malloc_good_size((size_t)malloc_size(ptr));
//                      void *p = (void*)malloc_zone_from_ptr(ptr);
//                    sprintf(name, "%%p heap pointer, (0x%%zx bytes), zone: %%p", ptr, a, p);
//                } else {
//                      memset(name,'\0',sizeof(name));
//                }
//                bool isReturn = strcmp(name,"") == 0;
//        )___");
//        stream.Printf("isReturn ? nil : name;");
        lldb::SBExpressionOptions eval_options;
//        eval_options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus);
        eval_options.SetLanguage(lldb::eLanguageTypeSwift);
        eval_options.SetAutoApplyFixIts(false);
        eval_options.SetGenerateDebugInfo(false);
        // 執(zhí)行它支持的語言的代碼
        // lldb調試環(huán)境
        SBValue value = target.EvaluateExpression(stream.GetData(), eval_options);
        SBStream returnStream;
        if (value.GetError().Success()) {
            value.GetDescription(returnStream);
            return std::make_tuple(true, [NSString stringWithUTF8String:returnStream.GetData()].UTF8String);
        } else {
            value.GetError().GetDescription(returnStream);
        }
        
        return std::make_tuple(false, nullptr);
    }
    
    bool CatAddressCommand::DoExecute(lldb::SBDebugger debugger, char **command,
                                      lldb::SBCommandReturnObject & result) {
        SBTarget target = debugger.GetSelectedTarget();
        SBThread thread = target.GetProcess().GetSelectedThread();
        if (!thread.IsValid()) {
            result.SetError("Expects an address");
            //false:命令處理失敗
            return false;
        }
        // 0x -> 地址 -》SBAddress
        // 0x10000
        NSString *cmd = [NSString stringWithCString:*command encoding:NSUTF8StringEncoding];
        if ( !cmd || cmd.length < 1) {
            result.SetError("Expects an address");
            return false;
        }
        long address = 0;
        char* end = nullptr;
        if ([cmd.lowercaseString hasPrefix:@"0x"]) {
            address = strtol(*command, &end, 16);
        } else {
            address = strtol(*command, &end, 10);
        }
        bool foundAddress = false;
        const char *returnDescription = nullptr ;
        SBAddress addr = target.ResolveLoadAddress(address);
        // mach-o 所在的Section   addr.GetSection()

        // 1. 掃描Mach-o
        if (addr.GetSection().IsValid()) {
            std::tuple<bool, const char *> tuple = tryMachOAddress(addr, target);
            foundAddress = std::get<0>(tuple);
            returnDescription = std::get<1>(tuple);
        }
        // 2. 掃描stack
        if (returnDescription == nullptr) {
            std::tuple<bool, const char  *> tuple = tryStackAddress(addr, target);
            foundAddress = std::get<0>(tuple);
            returnDescription = std::get<1>(tuple);
        }
        // 3. 掃描堆
        if (returnDescription == nullptr) {
            std::tuple<bool, const char  *> tuple = tryHeapAddress(addr, target);
            foundAddress = std::get<0>(tuple);
            returnDescription = std::get<1>(tuple);
        }
        SBStream stream = SBStream();
        if (foundAddress) {
            stream.Printf("address:%s, %s", *command, returnDescription);
            result.AppendMessage(stream.GetData());
            //true:命令處理成功
            return true;
        } else {
            stream.Printf("Couldn't find address, reverting to \"image lookup -a %s\"", *command);
            result.AppendMessage(stream.GetData());
            return false;
        }
        
    }
}

// 一個療程
// 蘋果的驗證機制 -》 SIP -〉自編譯的lldb.dylib
// SIP -〉還是不行 -》簽名的事

// 繼承SBCommandPluginInterface
// 動態(tài)庫插件的mach-o掃描符號 lldb::PluginInitialize
// SBDebugger: 當前的調試器
// 干什么?自定義的命令掛載上
namespace lldb {
    bool PluginInitialize(SBDebugger debugger) {
        // SBCommandInterpreter :
        lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
        // p
        // po 單個關鍵字的命令
        
        // br set 多個關鍵字的命令
        // cat address <地址> :地址所在的空間:mach-o、堆上、棧上
        // help cat
        // help cat address
        lldb::SBCommand cmd = interpreter.AddMultiwordCommand("cat", NULL);
        cmd.AddCommand("address", new LG::CatAddressCommand(@"Cat ??!"), "cat address ---- ??");
        return true;
    }
}

測試用例

#import <XCTest/XCTest.h>
#import "LGCatAddress.h"

@interface LGCatAddressTests : XCTestCase
{
    lldb::SBDebugger _debugger;
    lldb::SBTarget _target;
    lldb::SBProcess _process;
    lldb::SBCommandInterpreter _interp;
}
@end

@implementation LGCatAddressTests

- (void)setUp {
    // 初始化SBDebugger -》加載一個可執(zhí)行文件-〉驗證我們的插件
    lldb::SBDebugger::Initialize();
    _debugger = lldb::SBDebugger::Create();
    _debugger.SetAsync(false);
    
    // 1. 初始化target
    _target = _debugger.CreateTargetWithFileAndArch("/Users/xiaokai/Desktop/邏輯IOS/iOS\ 高級強化班/第十四節(jié)課、單元測試與UI測試/上課代碼/02-插件判斷地址在堆區(qū)/LGCatAddress/TestExec/a.out", "x86_64");
    _target.BreakpointCreateByLocation("test.c", 17);
    _interp = _debugger.GetCommandInterpreter();
}


- (void)testExample {
    _process = _target.LaunchSimple(nil, nil, "/Users/xiaokai/Desktop/邏輯IOS/iOS\ 高級強化班/第十四節(jié)課、單元測試與UI測試/上課代碼/02-插件判斷地址在堆區(qū)/LGCatAddress/TestExec");
    lldb::SBCommandReturnObject result;

//    _interp.HandleCommand("r", result);
    XCTAssertTrue(_process.GetNumThreads() > 0);
    lldb::SBThread thread = _process.GetThreadAtIndex(0);
    const char * name = thread.GetFrameAtIndex(0).GetFunctionName();
    // 測試代碼
    // 手動的命令解釋器+CatAddressCommand
//    LG::CatAddressCommand lgCmd(@"zhin笨");
//    lldb::SBCommand cmd = _interp.AddMultiwordCommand("cat", NULL);
//    cmd.AddCommand("address", &lgCmd, "cat address");
    // 調用我的cat address
    _interp.HandleCommand("plugin load /Users/ws/Library/Developer/Xcode/DerivedData/LGCatAddress-gwqawrzsvandhqawsrpvhsxvjifb/Build/Products/Debug/libLGCatAddress.dylib", result);
    NSLog(@"%s", result.GetOutput());
    _interp.HandleCommand("cat address 0x10000", result);
    NSLog(@"%s", result.GetOutput());
    
    
    lldb::SBStream stream;
    // cat address (po m)地址
    _interp.HandleCommand("po m", result);
    stream.Printf("cat address %s", result.GetOutput());
    _interp.HandleCommand(stream.GetData(), result);
    NSLog(@"%s", result.GetOutput());

    // cat address (po b)地址
    _interp.HandleCommand("po b", result);
    lldb::SBStream bstream;
    bstream.Printf("cat address %s", result.GetOutput());
    _interp.HandleCommand(bstream.GetData(), result);
    NSLog(@"%s", result.GetOutput());
    
    // cat address (po p)地址 --malloc
    _interp.HandleCommand("po p", result);
    lldb::SBStream pstream;
    pstream.Printf("cat address %s", result.GetOutput());
    _interp.HandleCommand(pstream.GetData(), result);
    NSLog(@"%s", result.GetOutput());

}


@end
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1 你好,Mach-O Mach-O是在任何蘋果操作系統(tǒng)上運行的編譯程序所使用的文件格式。格式知識對于調試和逆向工...
    收納箱閱讀 633評論 0 0
  • 本文主要介紹為什么結構體是值類型,類是引用類型。 值類型 前提:需要了解內存五大區(qū),內存五大區(qū)可以參考這篇文章iO...
    源本平凡閱讀 455評論 0 1
  • 通過閱讀這篇文章,我們將了解APP啟動過程中都做了哪些事情。文章分為三部分,第一部分是原理講解,第二部分是優(yōu)化方案...
    CNWH閱讀 999評論 0 5
  • Swift值類型&引用類型 前言 值類型和引用類型是Swift中兩種數據存儲方式,簡單來說值類型就是直接存儲的值,...
    just東東閱讀 2,691評論 3 3
  • 落寒z閱讀 1,072評論 0 6

友情鏈接更多精彩內容