├── .DS_Store ├── source ├── .DS_Store ├── 1111.png ├── 2222.png ├── 3333.png └── 4444.png ├── tools ├── .DS_Store └── verifyAlgorithm │ ├── .DS_Store │ ├── checkDemo │ ├── ida_fun.png │ ├── check_com.png │ ├── test_check.png │ ├── check_pintout.png │ ├── trace_result.png │ ├── test.py │ └── wtpytracer.py ├── README.md ├── .gitignore ├── main.mm └── lldbTrace.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/.DS_Store -------------------------------------------------------------------------------- /source/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/source/.DS_Store -------------------------------------------------------------------------------- /source/1111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/source/1111.png -------------------------------------------------------------------------------- /source/2222.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/source/2222.png -------------------------------------------------------------------------------- /source/3333.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/source/3333.png -------------------------------------------------------------------------------- /source/4444.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/source/4444.png -------------------------------------------------------------------------------- /tools/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/tools/.DS_Store -------------------------------------------------------------------------------- /tools/verifyAlgorithm/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/tools/verifyAlgorithm/.DS_Store -------------------------------------------------------------------------------- /tools/verifyAlgorithm/checkDemo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/tools/verifyAlgorithm/checkDemo -------------------------------------------------------------------------------- /tools/verifyAlgorithm/ida_fun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/tools/verifyAlgorithm/ida_fun.png -------------------------------------------------------------------------------- /tools/verifyAlgorithm/check_com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/tools/verifyAlgorithm/check_com.png -------------------------------------------------------------------------------- /tools/verifyAlgorithm/test_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/tools/verifyAlgorithm/test_check.png -------------------------------------------------------------------------------- /tools/verifyAlgorithm/check_pintout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/tools/verifyAlgorithm/check_pintout.png -------------------------------------------------------------------------------- /tools/verifyAlgorithm/trace_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyss/lldb-trace/HEAD/tools/verifyAlgorithm/trace_result.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lldbTrace 2 | 3 | ##### How to use it? 4 | 5 | > 1.*Break at an address where you want to begin tracing.* 6 | > 7 | > ![](https://github.com/yangyss/lldb-trace/blob/script/source/1111.png) 8 | > 9 | > 2, *Import lldb python script.* 10 | > 11 | > ![](https://github.com/yangyss/lldb-trace/blob/script/source/2222.png) 12 | > 13 | > 3,*Use 'trace' command,and set end tracing addresses.Multi-address split by ";".* 14 | > 15 | > ![](https://github.com/yangyss/lldb-trace/blob/script/source/3333.png) 16 | > 17 | > 4,*Result like ...* 18 | > 19 | > ![](https://github.com/yangyss/lldb-trace/blob/script/source/4444.png) 20 | 21 | 22 | 23 | > *参考:https://github.com/gm281/lldb-trace* 24 | 25 | -------------------------------------------------------------------------------- /tools/verifyAlgorithm/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- encoding: utf-8 -*- 3 | #@File : test.py 4 | #@Time : 2021/07/29 15:15:38 5 | #@Author : wt 6 | 7 | from wtpytracer import * 8 | 9 | #################### 10 | ## command : 11 | ## python3 test.py ~/Desktop/1627533881instrace.log 12 | 13 | ## 定义需要检测的 变量 : flag + '_' + 地址 + '_' + 寄存器 14 | Check_0x10000393c_w8 = 'Check_0x10000393c_w8' 15 | 16 | 17 | ### 翻译的测试代码 18 | def f(x): 19 | ret = 0 20 | for index in range(x): 21 | ret = ret + index 22 | check_value(ret,Check_0x10000393c_w8) # check ret 和 0x10000393c 的 w8 的寄存器值 23 | return ret + x 24 | 25 | 26 | if __name__ == '__main__': 27 | import sys 28 | args_list = sys.argv 29 | if len(args_list) != 2 : 30 | exit() 31 | file_name = args_list[1] 32 | 33 | try: 34 | set_trace_data(Check_0x10000393c_w8) 35 | parser_trace_log_file(file_name) 36 | enable(CheckFunctionTracer()) 37 | f(5) 38 | finally: 39 | disable() 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /main.mm: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // checkDemo 4 | // 5 | // Created by wt on 2021/4/21. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | #import 12 | #include 13 | #import 14 | #import 15 | #import "WTAes.hpp" 16 | 17 | int test(int a,int b,int c){ 18 | int tmp = 2 * c; 19 | return a + b + tmp; 20 | } 21 | 22 | int test_fun(){ 23 | NSString * a = @"{\"b1\":\"\",\"b2\":1,\"b3\":\"AAAAAAAAAAAAAMnu601KCPF0Mj3cObiE77iT8YWCbhK1vSgWHJ3uNlYTdmODBjMGMyZGMn-JGVHeeVP_WmIdd2TFi6Si0TpSJ8_Q\",\"b4\":\"\",\"b5\":1,\"b6\":{\"c1\":\"com.meituan.imeituan\",\"c2\":\"56226DD0E7DEB85C417DD793041E5CC9\",\"c3\":\"11.7.202\",\"c4\":117202,\"c5\":-2}}"; 24 | NSLog(@"%ld",[a length]); 25 | unsigned char arr[] = { 26 | 0xc2,0x55,0xe9,0x74,0xb0,0xd6,0x39,0xb2, 27 | 0xf3,0x0e,0x85,0x98,0x6b,0xd0,0xb8,0xc9, 28 | 0x35,0x50,0x56,0xe0,0xef,0xe7,0x1d,0x2c, 29 | 0x5a,0x0e,0x76,0x76,0xd8,0x6f,0xda,0xee, 30 | 0xf5,0xfe,0x78,0x0f,0x08,0x3d,0x47,0xe2, 31 | 0x51,0xf3,0xc1,0x75,0xf5,0xf1,0x40,0x10, 32 | 0x74,0xd6,0x62,0x5e,0xe7,0x51,0xce,0xd7, 33 | 0x8b,0x4d,0x66,0x95,0x34,0x33,0xda,0x3b, 34 | 0x0f,0xe7,0x55,0x27,0x5b,0xe8,0x11,0x2c, 35 | 0xcd,0xc5,0xfa,0x76,0x97,0x8c,0x4c,0xcc, 36 | 0x33,0x1e,0xe5,0xf2,0x5e,0xba,0xca,0xae, 37 | 0x6c,0x32,0x21,0x18,0x1e,0x5e,0x32,0x69, 38 | 0x00,0x3c,0xfa,0x14,0xea,0x62,0xed,0x81, 39 | 0x59,0xad,0x70,0x7b,0x56,0xa7,0x1d,0x40, 40 | 0x44,0x23,0x69,0x3e,0xda,0x14,0xb8,0x42, 41 | 0x67,0x9f,0xc7,0x07,0xe4,0x92,0xd3,0xff, 42 | 0x5b,0x6d,0x0d,0xd6,0x3c,0x0d,0xcb,0x33, 43 | 0x95,0x4f,0x8c,0xbe,0xd1,0xbf,0x87,0x8e, 44 | 0x24,0x03,0x8b,0xc4,0xfa,0xfd,0x25,0x7d, 45 | 0xe9,0x40,0xda,0xe8,0xc0,0xf4,0xd5,0x12, 46 | 0x6f,0xf0,0x3d,0x3e,0xca,0x96,0x63,0x72, 47 | 0x9d,0x2c,0x72,0xbb,0xef,0x73,0xac,0xaa, 48 | 0xfd,0xd1,0x4c,0x2d,0x38,0x9c,0xd2,0x19, 49 | 0x54,0x43,0x1b,0xd5,0x9d,0xa5,0x15,0x7d, 50 | 0xf2,0x27,0x7a,0x1d,0xee,0x91,0xfc,0xf2, 51 | 0xca,0x9b,0xee,0x14,0x5c,0xe5,0x6d,0x5c, 52 | 0x31,0xe6,0x47,0x45,0xf2,0x68,0xb8,0x32, 53 | 0x85,0x08,0x68,0x4e,0x57,0x80,0x82,0xc9, 54 | 0x8f,0xe2,0x7c,0xff,0x79,0xd6,0xc7,0xba, 55 | 0x68,0xf7,0x9a,0x13,0xbf,0x99,0x01,0xe8, 56 | 0x98,0x7a,0xd6,0xab,0xb8,0xae,0x0c,0x3f, 57 | 0xe7,0xb0}; 58 | 59 | NSData * data = [[NSData alloc] initWithBytes:arr length:0xfd]; 60 | NSData *base64Data = [data base64EncodedDataWithOptions:0]; 61 | 62 | NSString *base64 = [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding]; 63 | NSLog(@"%@",base64); 64 | 65 | int value = test(2, 3, 5); 66 | NSString * str = [NSString stringWithFormat:@"%d",value]; 67 | [str stringByAppendingString:@"abc"]; 68 | 69 | // @"wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsA=="; 70 | // @"wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsCgAMA=="; 71 | 72 | // wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsA== 73 | 74 | // struct stat a; 75 | // const char * path = '/Users/wt/pro'; 76 | // stat(path, &a); 77 | // int abc = sizeof(a); 78 | // 79 | // CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; 80 | // NSLog(@"%f",[[NSDate date]timeIntervalSince1970]); 81 | // 82 | // 83 | // [NSKeyedUnarchiver unarchiveObjectWithData:nil]; 84 | // 85 | // CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding|kCCOptionECBMode,) 86 | return 0; 87 | } 88 | 89 | void test_aes(){ 90 | AES aes; 91 | byte enc[16]; 92 | byte buf[16]="this is a test"; 93 | byte ret[16]; 94 | aes.encrypt(buf,enc); 95 | aes.decrypt(enc,ret); 96 | printf("%s",ret); 97 | } 98 | 99 | 100 | void test_folly() 101 | { 102 | 103 | } 104 | 105 | void b(void) 106 | { 107 | usleep(200 * 1000); 108 | } 109 | 110 | void a(void) 111 | { 112 | for(int i=0; i<3; i++) 113 | { 114 | b(); 115 | } 116 | NSString * sour = @"abc"; 117 | NSString * str = [[NSString alloc] initWithString:sour]; 118 | printf("Cycle\n"); 119 | NSLog(@"%@",str); 120 | } 121 | 122 | void c(int i); 123 | void d(int i) 124 | { 125 | c(i-1); 126 | } 127 | 128 | void c(int i) 129 | { 130 | if (i > 0) { 131 | d(i); 132 | } 133 | } 134 | 135 | void breakpoint(void) 136 | { 137 | a(); 138 | c(1); 139 | } 140 | 141 | int test() 142 | { 143 | while(true) { 144 | breakpoint(); 145 | } 146 | return 0; 147 | } 148 | 149 | 150 | int main(int argc, const char * argv[]) { 151 | sleep(1); 152 | test(); 153 | // test_fun(); 154 | // test_aes(); 155 | return 0; 156 | } 157 | -------------------------------------------------------------------------------- /tools/verifyAlgorithm/wtpytracer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- encoding: utf-8 -*- 3 | #@File : wtpytracer.py 4 | #@Time : 2021/07/27 18:17:18 5 | #@Author : wt 6 | 7 | import re 8 | import sys 9 | import inspect 10 | from collections import OrderedDict 11 | 12 | class TracebackFancy: 13 | 14 | def __init__(self, traceback): 15 | self.t = traceback 16 | 17 | def getFrame(self): 18 | return FrameFancy(self.t.tb_frame) 19 | 20 | def getLineNumber(self): 21 | return self.t.tb_lineno if self.t is not None else None 22 | 23 | def getNext(self): 24 | return TracebackFancy(self.t.tb_next) 25 | 26 | def __str__(self): 27 | if self.t is None: 28 | return "" 29 | str_self = "%s @ %s" % ( 30 | self.getFrame().getName(), self.getLineNumber()) 31 | return str_self + "\n" + self.getNext().__str__() 32 | 33 | 34 | class ExceptionFancy: 35 | 36 | def __init__(self, frame): 37 | self.etraceback = frame.f_exc_traceback 38 | self.etype = frame.exc_type 39 | self.evalue = frame.f_exc_value 40 | 41 | def __init__(self, tb, ty, va): 42 | self.etraceback = tb 43 | self.etype = ty 44 | self.evalue = va 45 | 46 | def getTraceback(self): 47 | return TracebackFancy(self.etraceback) 48 | 49 | def __nonzero__(self): 50 | return self.etraceback is not None or self.etype is not None or self.evalue is not None 51 | 52 | def getType(self): 53 | return str(self.etype) 54 | 55 | def getValue(self): 56 | return self.evalue 57 | 58 | 59 | class CodeFancy: 60 | 61 | def __init__(self, code): 62 | self.c = code 63 | 64 | def getArgCount(self): 65 | return self.c.co_argcount if self.c is not None else 0 66 | 67 | def getFilename(self): 68 | return self.c.co_filename if self.c is not None else "" 69 | 70 | def getVariables(self): 71 | return self.c.co_varnames if self.c is not None else [] 72 | 73 | def getName(self): 74 | return self.c.co_name if self.c is not None else "" 75 | 76 | def getFileName(self): 77 | return self.c.co_filename if self.c is not None else "" 78 | 79 | 80 | class ArgsFancy: 81 | 82 | def __init__(self, frame, arginfo): 83 | self.f = frame 84 | self.a = arginfo 85 | 86 | def __str__(self): 87 | args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs() 88 | ret = "" 89 | count = 0 90 | size = len(args) 91 | for arg in args: 92 | ret = ret + ("%s = %s" % (arg, args[arg])) 93 | count = count + 1 94 | if count < size: 95 | ret = ret + ", " 96 | if varargs: 97 | if size > 0: 98 | ret = ret + " " 99 | ret = ret + "varargs are " + str(varargs) 100 | if kwargs: 101 | if size > 0: 102 | ret = ret + " " 103 | ret = ret + "kwargs are " + str(kwargs) 104 | return ret 105 | 106 | def getNumArgs(wantVarargs=False, wantKWArgs=False): 107 | args, varargs, keywords, values = self.a 108 | size = len(args) 109 | if varargs and wantVarargs: 110 | size = size + len(self.getVarArgs()) 111 | if keywords and wantKWArgs: 112 | size = size + len(self.getKWArgs()) 113 | return size 114 | 115 | def getArgs(self): 116 | args, _, _, values = self.a 117 | argWValues = OrderedDict() 118 | for arg in args: 119 | argWValues[arg] = values[arg] 120 | return argWValues 121 | 122 | def getVarArgs(self): 123 | _, vargs, _, _ = self.a 124 | if vargs: 125 | return self.f.f_locals[vargs] 126 | return () 127 | 128 | def getKWArgs(self): 129 | _, _, kwargs, _ = self.a 130 | if kwargs: 131 | return self.f.f_locals[kwargs] 132 | return {} 133 | 134 | class FrameFancy: 135 | 136 | def __init__(self, frame): 137 | self.f = frame 138 | 139 | def getCaller(self): 140 | return FrameFancy(self.f.f_back) 141 | 142 | def getLineNumber(self): 143 | return self.f.f_lineno if self.f is not None else 0 144 | 145 | def getCodeInformation(self): 146 | return CodeFancy(self.f.f_code) if self.f is not None else None 147 | 148 | def getExceptionInfo(self): 149 | return ExceptionFancy(self.f) if self.f is not None else None 150 | 151 | def getName(self): 152 | return self.getCodeInformation().getName() if self.f is not None else "" 153 | 154 | def getFileName(self): 155 | return self.getCodeInformation().getFileName() if self.f is not None else "" 156 | 157 | def getLocals(self): 158 | return self.f.f_locals if self.f is not None else {} 159 | 160 | def getArgumentInfo(self): 161 | return ArgsFancy( 162 | self.f, inspect.getargvalues( 163 | self.f)) if self.f is not None else None 164 | 165 | class TracerClass: 166 | 167 | def callEvent(self, frame): 168 | pass 169 | 170 | def lineEvent(self, frame): 171 | pass 172 | 173 | def returnEvent(self, frame, retval): 174 | pass 175 | 176 | def exceptionEvent(self, frame, exception, value, traceback): 177 | pass 178 | 179 | def cCallEvent(self, frame, cfunct): 180 | pass 181 | 182 | def cReturnEvent(self, frame, cfunct): 183 | pass 184 | 185 | def cExceptionEvent(self, frame, cfunct): 186 | pass 187 | 188 | tracer_impl = TracerClass() 189 | data_dic = {} 190 | old_trace_func = None 191 | 192 | def parser_flag(flag): 193 | import re 194 | aa = re.split(r'_',flag) 195 | if len(aa) != 3 : 196 | return None,None 197 | return aa[1],aa[2] 198 | 199 | class CheckFunctionTracer(): 200 | def callEvent(self, frame): 201 | if 'check_value' == frame.getName(): 202 | flag = frame.getArgumentInfo().getArgs()['check_flag'] 203 | value = frame.getArgumentInfo().getArgs()['value'] 204 | addr,register = parser_flag(flag) 205 | if addr in data_dic and register in data_dic[addr]: 206 | run_index = data_dic[addr][register]['run_index'] 207 | data_len = len(data_dic[addr][register]['data']) 208 | if run_index >= data_len: 209 | print('*** err : at address : {} . run_index : {} out of rang'.format(addr,run_index)) 210 | return 211 | if value == data_dic[addr][register]['data']['{}'.format(run_index + 1)] : 212 | print('check : {} at {} times,match.'.format(addr,run_index + 1)) 213 | data_dic[addr][register]['run_index'] = run_index + 1 214 | 215 | # print("->>LoggingTracer : call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())) 216 | 217 | 218 | 219 | # @ check_flag 为 携带了地址,和寄存器名称 220 | # @ value 为当前需要 check 的值 221 | # 在 sys.settracer设置的回调中,只接管此函数 222 | def check_value(value,check_flag): 223 | pass 224 | 225 | 226 | def set_trace_data(check_flag): 227 | global data_dic 228 | addr,register = parser_flag(check_flag) 229 | if not addr or not register : 230 | print('err : check_flag is wrong.') 231 | return 232 | 233 | if addr in data_dic: 234 | data_dic[addr][register] = { 235 | 'data':{}, 236 | 'run_index':0 237 | } 238 | else: 239 | addr_dic = { 240 | register:{ 241 | 'data':{}, 242 | 'run_index':0 243 | } 244 | } 245 | data_dic[addr] = addr_dic 246 | 247 | 248 | def add_data_in_data_dic(addr,register,value): 249 | global data_dic 250 | cur_reg_dic = data_dic[addr][register] 251 | data_len = len(cur_reg_dic['data']) 252 | data_dic[addr][register]['data']['{}'.format(data_len + 1)] = value 253 | 254 | def parser_trace_log_file(fileName): 255 | global data_dic 256 | file = open(fileName) 257 | while True: 258 | lines = file.readlines(100000) 259 | if not lines: 260 | break 261 | for line in lines: 262 | matchObj = re.match(r'\s*(\S+)\s+',line,re.M|re.I) 263 | if matchObj: 264 | addr = str(matchObj.group()).replace(' ','') 265 | if addr in data_dic: 266 | reg = data_dic[addr] 267 | for register in data_dic[addr].keys(): 268 | register_out = re.findall(register +r' : (\S+)',line) 269 | if register_out: 270 | register_value = int(register_out[0],16) 271 | add_data_in_data_dic(addr,register,register_value) 272 | 273 | file.close() 274 | # {'1234':{'1':0,"2":1}} # flag : {...} address:{'x0':{data:{},run_index:0},'x1':{data:{},run_index:0}} 275 | 276 | 277 | def the_tracer_check_data(frame, event, args = None): 278 | global data_dic 279 | global tracer_impl 280 | 281 | code = frame.f_code 282 | 283 | func_name = code.co_name 284 | 285 | line_no = frame.f_lineno 286 | if tracer_impl is None: 287 | print('@@@ tracer_impl : None.') 288 | return None 289 | 290 | if event == 'call': 291 | tracer_impl.callEvent(FrameFancy(frame)) 292 | 293 | return the_tracer_check_data 294 | 295 | 296 | 297 | def enable(tracer_implementation=None): 298 | global tracer_impl,old_trace_func 299 | if tracer_implementation: 300 | tracer_impl = tracer_implementation # 传递 工厂实力的对象 301 | old_trace_func = sys.gettrace() 302 | sys.settrace(the_tracer_check_data) # 注册回调到系统中 303 | 304 | 305 | def check_run_ok(): 306 | global data_dic 307 | for addr,addr_dic in data_dic.items(): 308 | for _,reg_dic in addr_dic.items(): 309 | if reg_dic['run_index'] == len(reg_dic['data']): 310 | print('->>> at {} check value is perfect.'.format(addr)) 311 | else: 312 | print('*** err : at {} check {} times.'.format(addr,reg_dic['run_index'])) 313 | 314 | def disable(): 315 | check_run_ok() 316 | global old_trace_func 317 | sys.settrace(old_trace_func) 318 | 319 | -------------------------------------------------------------------------------- /lldbTrace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- encoding: utf-8 -*- 3 | #@File : lldb-trace.py 4 | #@Time : 2021/06/25 22:16:01 5 | #@Author : wt 6 | 7 | import re 8 | import lldb 9 | import shlex 10 | import optparse 11 | import threading 12 | import ctypes 13 | import os 14 | 15 | 16 | 17 | log_default_path = '~/Desktop/' # 默认路径 , 18 | 19 | options = None 20 | d_log_file = None # fileName : Redirect debug log in d_log_file 21 | d_log_file_name = None 22 | t_log_file = None # fileName : Redirect trace log in t_log_file 23 | t_log_file_name = None 24 | t_only_self_module = None 25 | t_parser_msgsend_parameters = None 26 | ASLR = None 27 | num_for_print_progress = 500 # 进度条 28 | 29 | def log_d(msg): # debug log 30 | global d_log_file,options 31 | if options.log_type == 'debug': 32 | d_log_file.write(msg) 33 | d_log_file.write('\n') 34 | 35 | def log_t(msg): # trace log 36 | global t_log_file 37 | t_log_file.write(msg) 38 | t_log_file.write('\n') 39 | 40 | def log_c(msg): # console log 41 | global options 42 | if options.print_tracing_progress: 43 | print(msg) 44 | 45 | def log_flush(): 46 | global d_log_file,t_log_file 47 | if d_log_file is not None: 48 | d_log_file.flush() 49 | if t_log_file is not None: 50 | t_log_file.flush() 51 | 52 | def dlog(msg): 53 | print("xxxxxxxxx-> {}".format(msg)) 54 | 55 | # 调试类型 56 | TRACE_TYPE_Instrument = 0, 57 | TRACE_TYPE_Function = 1, 58 | # 设备架构 59 | DEVICE_BSD32 = 'BSD32' 60 | DEVICE_BSD64 = 'BSD64' 61 | DEVICE_Arm64 = 'Arm64' 62 | DEVICE_x8664 = 'x86-64' 63 | DEVICE_x8632 = 'x86-32' 64 | # 调试中需要处理的 汇编指令信息 65 | CONST_INS_call = 'call', 66 | CONST_INS_jmp = 'jmp', 67 | CONST_INS_condition_jmp = 'condition_jmp', 68 | CONST_INS_syscall = 'syscall', 69 | CONST_INS_end = 'func_end_mnemonic' 70 | CONST_FUNC_NAME_ignore_list = 'ignore_func_name_list' 71 | CONST_FUNC_NAME_protect_list = 'protect_func_name_list' 72 | CONST_PRINT_obj = 'obj' 73 | CONST_PRINT_char_star = 'char_star' 74 | CONST_REGISTER_re = 're' 75 | CONST_REGISTER_default_return_register = 'default_return_register' 76 | 77 | 78 | # 断点列表里的 key 79 | CONST_BREAKPOINT_BREAKPOINE = 'breakpoint', 80 | CONST_BREAKPOINT_INDEX = 'index', # 引用计数 81 | 82 | # deal_with 的 返回值 83 | CONST_DEAL_WITH_error = 0, 84 | CONST_DEAL_WITH_continue = 1, 85 | CONST_DEAL_WITH_wait_breakpoint = 2, 86 | CONST_DEAL_WITH_break = 3, 87 | # check ins end type 88 | CONST_CHECK_ins_default = 0 89 | CONST_CHECK_ins_ret = 1 90 | CONST_CHECK_ins_end_address =2 91 | 92 | 93 | ######################################################### 94 | CONST_DEVICE_info_list = { 95 | DEVICE_BSD64 : { 96 | CONST_FUNC_NAME_ignore_list : ['printf','objc_unsafeClaimAutoreleasedReturnValue','objc_storeStrong'], 97 | CONST_FUNC_NAME_protect_list : { 98 | 'objc_msgSend' : { 99 | # if trace function,need to analyse parameters. if parser_msgsend_parameters was true, need to analyse parameters too. 100 | CONST_PRINT_obj:['po [$x0 class]'], 101 | CONST_PRINT_char_star:['x1'] 102 | } 103 | }, 104 | CONST_REGISTER_re : [r'\b[xwd][0-9]{1,2}',r'\b[xwd][0-9]{1,2},',r'sp'], # r'\b[xw][0-9]{1,2}[,]{0,1}' 105 | CONST_REGISTER_default_return_register:'x0', 106 | 107 | CONST_INS_call : ['bl'],#,'bl', 108 | CONST_INS_jmp : ['cb','b','tb'],#'b', 109 | CONST_INS_condition_jmp : ['b'], 110 | CONST_INS_syscall : ['svc'],#'svc' 111 | CONST_INS_end : ['ret'] 112 | }, 113 | DEVICE_Arm64 : {}, 114 | DEVICE_x8664 : {}, 115 | DEVICE_x8632 : {} 116 | } 117 | ######################################################### 118 | # 当前设备类型 119 | DEVICE = DEVICE_BSD64 120 | ######################################################### 121 | 122 | 123 | class WTListeningThread(threading.Thread): 124 | def __init__(self, wait_event, notify_event,listener,process): 125 | super(WTListeningThread, self).__init__() 126 | self.wait_event = wait_event 127 | self.notify_event = notify_event 128 | self.listener = listener 129 | self.process = process 130 | self.exiting = False 131 | self.wait_timeout = False 132 | 133 | def wait_timed_out(self): 134 | return self.wait_timeout 135 | 136 | def exit(self): 137 | self.exiting = True 138 | 139 | def run(self): 140 | steam :lldb.SBStream = lldb.SBStream() 141 | while True: 142 | self.wait_event.wait() 143 | self.wait_event.clear() 144 | if self.exiting: 145 | log_d('=>>>Listener thread was asked to exit, complying') 146 | self.notify_event.set() 147 | return 148 | while True: 149 | event = lldb.SBEvent() 150 | steam.Clear() 151 | log_d('=>>>Listener waiting for events') 152 | wait_result = self.listener.WaitForEvent(10, event) 153 | event.GetDescription(steam) 154 | log_d('=>>>Listener wait exited: {}, {}'.format(str(wait_result), steam.GetData())) 155 | 156 | if not wait_result: 157 | log_d('=>>>Listener thread timed out waiting for notification') 158 | self.wait_timeout = True 159 | self.notify_event.set() 160 | break 161 | processState = self.process.GetState() 162 | if processState == lldb.eStateStopped: 163 | log_d('=>>>Listener detected process state change, but it is not stopped: {}'.format(str(processState))) 164 | break 165 | log_d('=>>>Process not stopped, listening for the next event') 166 | log_d('=>>>Listener thread got event, notifying') 167 | self.notify_event.set() 168 | 169 | def get_c_char_star(address): 170 | retstr = '' 171 | curr_addr = address 172 | while True: 173 | p = ctypes.cast(curr_addr,ctypes.POINTER(ctypes.c_char)) 174 | value = p.contents.value 175 | if not (value[0] == 0) : 176 | retstr = retstr + chr(value[0]) 177 | curr_addr = curr_addr + 1 178 | else: 179 | break 180 | return retstr 181 | 182 | def handle_command(command,debugger:lldb.SBDebugger): 183 | log_d('handle_command -> command : {}'.format(command)) 184 | interpreter:lldb.SBCommandInterpreter = debugger.GetCommandInterpreter() 185 | re_obj:lldb.SBCommandReturnObject = lldb.SBCommandReturnObject() 186 | interpreter.HandleCommand(command,re_obj) 187 | result = '' 188 | log_d('handle_command -> re_obj status : {}'.format(re_obj.GetStatus())) 189 | if re_obj.GetStatus() == lldb.eReturnStatusSuccessFinishResult: 190 | result = re_obj.GetOutput() 191 | # print('|{}|'.format(result.replace('\n',''))) 192 | return result.replace('\n','') 193 | 194 | def continue_and_wait_for_breakpoint(process, thread, listening_thread, wait_event, notify_event): 195 | wait_event.set() 196 | log_d("Process in state: {}".format(str(process.GetState()))) 197 | process.Continue() 198 | log_d('Process continued, waiting for notification') 199 | notify_event.wait() 200 | notify_event.clear() 201 | log_d('Got notification, process in state: {}, sanity checks follow'.format(str(process.GetState()))) 202 | if listening_thread.wait_timed_out(): 203 | log_d('Listener thread exited unexpectedly') 204 | return False 205 | if thread.GetStopReason() != lldb.eStopReasonBreakpoint: 206 | log_d("Thread {} didn't stop due to a breakpoint".format(str(thread))) 207 | return False 208 | return True 209 | 210 | def suspend_threads_escape_select_thread(process:lldb.SBProcess,flag:bool): 211 | select_thread :lldb.SBThread = process.GetSelectedThread() 212 | if flag : 213 | for item in process: 214 | if select_thread.GetThreadID() == item.GetThreadID(): 215 | log_d('current run thread : {}'.format(item)) 216 | else: 217 | log_d('Suspend thread : {}'.format(item)) 218 | item.Suspend() 219 | else: 220 | log_d('Resume all threads.') 221 | for item in process: 222 | item.Resume() 223 | 224 | 225 | 226 | def match_registers(text): 227 | now_list = [] 228 | fileters = CONST_DEVICE_info_list[DEVICE][CONST_REGISTER_re] 229 | for item in fileters: 230 | find_result = re.finditer(item,text) 231 | match : str = '' 232 | for match in find_result: 233 | tmpStr = '{}'.format(match.group()) 234 | if tmpStr.find(',') >= 0 : 235 | if not(tmpStr[:-1] in now_list) : 236 | now_list.append(tmpStr[:-1]) 237 | else: 238 | if not(tmpStr in now_list): 239 | now_list.append(tmpStr) 240 | return now_list 241 | 242 | class WTInstruction(): 243 | def __init__(self, target, thread, frame,debugger,traceType=TRACE_TYPE_Instrument,traceMsgSend=False,endAddress=None): 244 | self.target:lldb.SBTarget = target 245 | self.thread:lldb.SBThread = thread 246 | self.frame:lldb.SBFrame = frame 247 | self.debugger:lldb.SBDebugger = debugger 248 | 249 | self.trace_type = traceType # Trace 类型 250 | 251 | self.next_instruction:lldb.SBInstruction = None # 下一条 instruction 252 | self.current_instruction:lldb.SBInstruction = None # 当前 instruction 253 | self.last_instruction:lldb.SBInstruction = None # 上一条 instruction 254 | 255 | self.begin_trace_address = None # 开始 Trace 地址 256 | self.end_trace_address = [] 257 | 258 | for item in re.split(';',endAddress): 259 | self.end_trace_address.append(int(item,16)) # 结束 Trace 地址 260 | 261 | # 包含 breakpoint : 以及 引用计数 used_num : 262 | self.breakpoint_list = {} # 所有断点 的 list 263 | self.current_instruction_list = {} # 当前 symbol 下的 所有的 instruction 列表 264 | self.current_instruction_end_address_list = [] # 当前 symbol 下的 所有的 end_address 列表 265 | self.call_return_instruction_list = {} # tracing 中,所有函数返回的地址 列表 266 | 267 | self.current_module_name:str = None # 当前模块 268 | 269 | self.append_msg = '' # 附加消息 270 | 271 | self.print_index = 0 272 | self.print_text = ' ' 273 | 274 | def increase_print_index(self): 275 | log_d('@@@@ increase print index. {} : {}'.format(self.print_index,self.print_index + 1)) 276 | self.print_index = self.print_index + 1 277 | 278 | 279 | def check_in_call_return_instruction_list(self): 280 | pc = self.get_current_pc() 281 | if pc in self.call_return_instruction_list: 282 | log_d('@@@@ {} in call_return_instruction_list'.format(hex(pc))) 283 | return True 284 | log_d('@@@@ {} not in call_return_instruction_list'.format(hex(pc))) 285 | return False 286 | 287 | def decrease_print_index(self): 288 | log_d('@@@@ decrease print index. {} : {}'.format(self.print_index,self.print_index - 1)) 289 | self.print_index = self.print_index - 1 290 | 291 | def check_str_in_arr(self,cur_str:str,cur_arr): 292 | for item in cur_arr: 293 | if cur_str.startswith(item): 294 | return True 295 | return False 296 | 297 | def init_env(self): 298 | 299 | frame :lldb.SBFrame = self.thread.GetSelectedFrame() 300 | symbol:lldb.SBSymbol = frame.GetSymbol() 301 | 302 | if self.current_module_name is None: 303 | self.current_module_name:str = '{}'.format(self.frame.GetModule()) 304 | log_d('current module name : {}'.format(self.current_module_name)) 305 | 306 | 307 | instructionlist : lldb.SBInstructionList = symbol.GetInstructions(self.target) 308 | # 清空 current_instruction_list 和 current_instruction_end_address_list 309 | if self.current_instruction_list: 310 | self.current_instruction_list = {} 311 | self.current_instruction_end_address_list = [] 312 | 313 | # endaddress 加入到 end tracing 地址列表中 314 | cur_end_address = symbol.GetEndAddress().GetLoadAddress(self.target) - 4 315 | self.end_trace_address.append(cur_end_address) 316 | 317 | # 把 返回指令的 地址 加入到 end tracing 地址列表中 318 | instruction :lldb.SBInstruction = None 319 | for instruction in instructionlist: 320 | address :lldb.SBAddress = instruction.GetAddress() 321 | cur_mnemonic:str = instruction.GetMnemonic(self.target) 322 | load_address = address.GetLoadAddress(self.target) 323 | if self.check_str_in_arr(cur_mnemonic,CONST_DEVICE_info_list[DEVICE][CONST_INS_end]): 324 | if not load_address in self.end_trace_address: 325 | self.end_trace_address.append(load_address) 326 | 327 | 328 | # 获得当前 pc 329 | def get_current_pc(self): 330 | now_frame :lldb.SBFrame = self.thread.GetSelectedFrame() 331 | if now_frame: 332 | return now_frame.GetPC() 333 | return None 334 | 335 | # 判断当前 pc 是否在 list 中 336 | # 不在的话,更新所有 list 337 | def checkPCInList_transferCurrentSymbolInstrucionsToList(self,address): 338 | # current_instruction_list 为空,或者 cur_pc(有效) 不在 current_instruction_list 里 339 | if not self.current_instruction_list or (address and (not (address in self.current_instruction_list))) : 340 | frame :lldb.SBFrame = self.thread.GetSelectedFrame() 341 | symbol:lldb.SBSymbol = frame.GetSymbol() 342 | ################## 给 current_instruction_end_address_list 赋值 343 | # 获得 当前 symbol 下的 endAddress 344 | cur_end_address = symbol.GetEndAddress().GetLoadAddress(self.target) - 4 345 | log_d('cur symbol end addr : {}'.format(hex(cur_end_address))) 346 | self.current_instruction_end_address_list = [] 347 | # 把 结束地址,加入到 current_instruction_end_address_list 中 348 | self.current_instruction_end_address_list.append(cur_end_address) 349 | 350 | # 给 current_instruction_list 赋值 351 | # 获得 当前 symbol 下的 instructionlist 352 | instructionlist : lldb.SBInstructionList = symbol.GetInstructions(self.target) 353 | 354 | # 清空 current_instruction_list 355 | if self.current_instruction_list: 356 | self.current_instruction_list = {} 357 | self.current_instruction_end_address_list = {} 358 | 359 | instruction :lldb.SBInstruction = None 360 | # 处理 所有的 instruction, 361 | for instruction in instructionlist: 362 | address :lldb.SBAddress = instruction.GetAddress() 363 | cur_mnemonic:str = instruction.GetMnemonic(self.target) 364 | load_address = address.GetLoadAddress(self.target) 365 | self.current_instruction_list[load_address] = instruction 366 | 367 | return False 368 | return True 369 | 370 | def updata_instruction_instructionList(self): 371 | cur_pc = self.get_current_pc() 372 | self.checkPCInList_transferCurrentSymbolInstrucionsToList(cur_pc) 373 | 374 | if cur_pc in self.current_instruction_list: 375 | self.current_instruction = self.current_instruction_list[cur_pc] 376 | else: 377 | self.current_instruction = None 378 | 379 | 380 | def clean_env(self): 381 | for item in self.breakpoint_list.values(): 382 | breakpoint :lldb.SBBreakpoint = item[CONST_BREAKPOINT_BREAKPOINE] 383 | self.target.BreakpointDelete(breakpoint.GetID()) 384 | self.breakpoint_list = {} 385 | 386 | 387 | def deal_with(self): 388 | return self.deal_with_ins() 389 | 390 | def updata_last_instruction(self): 391 | self.last_instruction = self.current_instruction 392 | 393 | def get_current_symbol_name(self): 394 | frame:lldb.SBFrame = self.thread.GetSelectedFrame() 395 | sym:lldb.SBSymbol = frame.GetSymbol() 396 | return sym.GetName() 397 | 398 | def get_next_instruction(self): 399 | pc = self.get_current_pc() 400 | size = self.current_instruction.GetByteSize() 401 | next_pc = pc + size 402 | self.checkPCInList_transferCurrentSymbolInstrucionsToList(next_pc) 403 | if next_pc in self.current_instruction_list: 404 | self.next_instruction = self.current_instruction_list[next_pc] 405 | else: 406 | self.next_instruction = None 407 | 408 | def print_tracing_progress(self,count): 409 | # 当前trace的总行数 内存地址:文件地址: <函数名> 410 | global ASLR 411 | mem_addr = 0 412 | file_addr = 0 413 | if self.current_instruction: 414 | mem_addr = self.current_instruction.GetAddress().GetLoadAddress(self.target) 415 | if not (mem_addr == 0) : 416 | file_addr = mem_addr - ASLR 417 | out_str = '{: <10} {} : {} <{}>'.format(count,hex(mem_addr),hex(file_addr),self.get_current_symbol_name()) 418 | log_c(out_str) 419 | 420 | def log_current_instruction(self,cur_pc): 421 | cur_mnemonic:str = self.current_instruction.GetMnemonic(self.target) 422 | cur_operands:str = self.current_instruction.GetOperands(self.target) 423 | aligns = self.print_text * self.print_index 424 | if self.last_instruction: 425 | last_mnemonic:str = self.last_instruction.GetMnemonic(self.target) 426 | if self.check_str_in_arr(last_mnemonic,CONST_DEVICE_info_list[DEVICE][CONST_INS_call]) : 427 | frame:lldb.SBFrame = self.thread.GetSelectedFrame() 428 | return_register = CONST_DEVICE_info_list[DEVICE][CONST_REGISTER_default_return_register] 429 | value:lldb.SBValue = frame.FindRegister(return_register) 430 | data_str = '{: <3} : {} '.format(return_register,value.GetValue()) 431 | log_t('{}{: <15}{: <6}{: <30}// {} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,data_str,self.append_msg)) 432 | self.append_msg = '' 433 | return 434 | last_operands:str = self.last_instruction.GetOperands(self.target) 435 | register_arr = match_registers(last_operands) 436 | data_str = '' 437 | for now_reg in register_arr: 438 | frame:lldb.SBFrame = self.thread.GetSelectedFrame() 439 | value:lldb.SBValue = frame.FindRegister(now_reg) 440 | data_str = '{}{: <3} : {} '.format(data_str,now_reg,value.GetValue()) 441 | 442 | log_t('{}{: <15}{: <6}{: <30}// {} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,data_str,self.append_msg)) 443 | self.append_msg = '' 444 | return 445 | log_t('{}{: <15}{: <6}{: <30} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,self.append_msg)) 446 | self.append_msg = '' 447 | 448 | def parser_ins_symbol_name(self,last_symbole_name:str,cur_symbol_name : str): 449 | 450 | if not cur_symbol_name or not last_symbole_name: 451 | log_d('err : cur_symbol_name or last_symbole_name is None') 452 | return True 453 | 454 | if cur_symbol_name in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_ignore_list]: 455 | # 忽略的 符号名 456 | log_d('cur_symbol_name in ignore_function_names') 457 | return True 458 | 459 | if cur_symbol_name in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_protect_list]: 460 | # # 设置 附加信息 461 | 462 | # # log_t('{}<< current frame name >> : {}'.format(aligens,cur_symbol_name)) 463 | # frame :lldb.SBFrame = self.thread.GetSelectedFrame() 464 | 465 | # for pro_key,pro_value in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_protect_list].items(): 466 | 467 | # if pro_key == cur_symbol_name: 468 | 469 | # objs = pro_value[CONST_PRINT_obj] 470 | # char_stars = pro_value[CONST_PRINT_char_star] 471 | 472 | # for char_star_item in char_stars: 473 | # func_name_register:lldb.SBValue = frame.FindRegister(char_star_item) 474 | # addr = int(func_name_register.GetValue(),16) 475 | # self.append_msg = ' : {}{: <3} ==> {} '.format(self.append_msg,char_star_item,get_c_char_star(addr)) 476 | 477 | # for obj_item in objs: 478 | # item_value = handle_command(obj_item,self.debugger) 479 | # self.append_msg = '{}{: <3} ==> {} '.format(self.append_msg,obj_item,item_value) 480 | 481 | # break 482 | 483 | # log_d('cur_symbol_name in protect_function_names') 484 | # return True 485 | pass 486 | 487 | return False 488 | 489 | def add_next_breakpoint(self): 490 | if self.next_instruction: 491 | next_pc = self.next_instruction.GetAddress().GetLoadAddress(self.target) 492 | if next_pc in self.breakpoint_list: 493 | breakpoint = self.breakpoint_list[next_pc][CONST_BREAKPOINT_BREAKPOINE] 494 | log_d('->>> increase index on breakpoint : {}'.format(str(breakpoint))) 495 | self.breakpoint_list[next_pc][CONST_BREAKPOINT_INDEX] = self.breakpoint_list[next_pc][CONST_BREAKPOINT_INDEX] + 1 496 | else: 497 | breakpoint :lldb.SBBreakpoint = self.target.BreakpointCreateByAddress(next_pc) 498 | breakpoint.SetThreadID(self.thread.GetThreadID()) 499 | item = {} 500 | item[CONST_BREAKPOINT_BREAKPOINE] = breakpoint 501 | item[CONST_BREAKPOINT_INDEX] = 1 502 | self.breakpoint_list[next_pc] = item 503 | log_d('->>> add address : {} breakpoint : {}'.format(hex(next_pc),str(breakpoint))) 504 | 505 | def add_call_return_addr(self): 506 | if self.next_instruction: 507 | next_pc = self.next_instruction.GetAddress().GetLoadAddress(self.target) 508 | log_d('add {} index in call_return_instruction_list.'.format(hex(next_pc))) 509 | if next_pc in self.call_return_instruction_list: 510 | self.call_return_instruction_list[next_pc] = self.call_return_instruction_list[next_pc] + 1 511 | else: 512 | self.call_return_instruction_list[next_pc] = 1 513 | 514 | def sub_call_return_addr(self): 515 | pc = self.get_current_pc() 516 | if pc in self.call_return_instruction_list: 517 | log_d('@@@@ delete call return addr : {} out of call_return_instruction_list.'.format(hex(pc))) 518 | if self.call_return_instruction_list[pc] > 1: 519 | tmp = self.call_return_instruction_list[pc] 520 | self.call_return_instruction_list[pc] = tmp - 1 521 | else: 522 | self.call_return_instruction_list.pop(pc) 523 | 524 | 525 | def check_need_delete_breakpoint_in_current_call_return_list_and_decrease_index(self,cur_pc): 526 | if cur_pc in self.call_return_instruction_list: 527 | index = self.call_return_instruction_list[cur_pc] 528 | if index > 0 : 529 | self.call_return_instruction_list[cur_pc] = index - 1 530 | return True 531 | else: 532 | self.call_return_instruction_list.pop(cur_pc) 533 | return False 534 | 535 | def delete_current_breakpoint(self): 536 | if self.current_instruction: 537 | curr_pc = self.current_instruction.GetAddress().GetLoadAddress(self.target) 538 | if not curr_pc in self.breakpoint_list: 539 | log_d('->>> {} not in breakpoint_list'.format(hex(curr_pc))) 540 | return 541 | item = self.breakpoint_list[curr_pc] 542 | if not item : 543 | log_d('->>> curr address : {} not in breakpoint_list'.format(hex(curr_pc))) 544 | return 545 | index = item[CONST_BREAKPOINT_INDEX] 546 | if index > 1 : 547 | log_d('->>> increase index on breakpoint : {}'.format(str(item[CONST_BREAKPOINT_BREAKPOINE]))) 548 | self.breakpoint_list[curr_pc][CONST_BREAKPOINT_INDEX] = index - 1 549 | elif index == 1: 550 | delete_breakpoint :lldb.SBBreakpoint = item[CONST_BREAKPOINT_BREAKPOINE] 551 | if not self.check_need_delete_breakpoint_in_current_call_return_list_and_decrease_index(curr_pc): 552 | self.target.BreakpointDelete(delete_breakpoint.GetID()) 553 | log_d('**** delet breakpoint at : {}'.format(hex(self.get_current_pc()))) 554 | self.breakpoint_list.pop(curr_pc) 555 | else: 556 | log_c('->>> {} : breakpoint delete error'.format(hex(curr_pc))) 557 | log_d('->>> {} : breakpoint delete error'.format(hex(curr_pc))) 558 | 559 | def check_currentIns_is_endIns(self): 560 | if self.current_instruction: 561 | size = self.current_instruction.GetByteSize() 562 | pc = self.get_current_pc() 563 | nextpc = pc + size 564 | if nextpc in self.current_instruction_end_address_list: 565 | log_d('addr : {} in current_instruction_end_address_list'.format(hex(nextpc))) 566 | return True,CONST_CHECK_ins_end_address 567 | 568 | mnemonic:str = self.current_instruction.GetMnemonic(self.target) 569 | for ins_end_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_end]: 570 | if mnemonic.startswith(ins_end_item): 571 | log_d('addr : {} is CONST_INS_end'.format(hex(pc))) 572 | return True,CONST_CHECK_ins_ret 573 | log_d('addr : {} is default ins.'.format(hex(pc))) 574 | return False,CONST_CHECK_ins_default 575 | else: 576 | log_d('warning : current ins is None.') 577 | log_c('warning : current ins is None.') 578 | return False,CONST_CHECK_ins_default 579 | 580 | def check_ins_call(self,mnemonic:str,cur_symbol:lldb.SBSymbol): 581 | for call_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_call]: 582 | if not mnemonic.startswith(call_item): 583 | continue 584 | pc = self.get_current_pc() 585 | self.get_next_instruction() # 获得下一条指令 586 | if not self.next_instruction is None: 587 | self.add_next_breakpoint() 588 | self.add_call_return_addr() 589 | 590 | last_symbol_name = self.get_current_symbol_name() 591 | self.delete_current_breakpoint()# 删除当前断点 592 | self.thread.StepInstruction(False) # 单步进入 593 | sym_name = self.get_current_symbol_name() 594 | 595 | if self.parser_ins_symbol_name(last_symbol_name,sym_name) : # 解析 symbol_name 596 | self.append_msg = sym_name + self.append_msg 597 | self.log_current_instruction(pc) 598 | self.increase_print_index() 599 | log_d('####### return : check_ins_call. ignore fun or protect fun. value : CONST_DEAL_WITH_wait_breakpoint') 600 | return True,CONST_DEAL_WITH_wait_breakpoint 601 | 602 | self.log_current_instruction(pc) # 打印信息 603 | if not(sym_name == last_symbol_name) : 604 | if sym_name and (not (sym_name == '')): 605 | log_t('{}{} : '.format(self.print_text * self.print_index,sym_name)) 606 | 607 | # 忽略的,保护的,需要 CONST_DEAL_WITH_wait_breakpoint 608 | self.increase_print_index() 609 | 610 | log_d('####### return : check_ins_call. value : CONST_DEAL_WITH_continue') 611 | return True,CONST_DEAL_WITH_continue 612 | 613 | return False,None 614 | 615 | def check_ins_jmp(self,mnemonic:str,cur_symbol:lldb.SBSymbol): 616 | for jmp_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_jmp]: 617 | if not mnemonic.startswith(jmp_item): 618 | continue 619 | 620 | pc = self.get_current_pc() 621 | self.get_next_instruction() # 获得下一条指令 622 | if not self.next_instruction is None: 623 | self.add_next_breakpoint() 624 | 625 | last_symbol_name = self.get_current_symbol_name() 626 | self.delete_current_breakpoint() 627 | self.thread.StepInstruction(False) 628 | 629 | sym_name = self.get_current_symbol_name() 630 | 631 | if sym_name and self.parser_ins_symbol_name(last_symbol_name,sym_name): 632 | print('type : {} symName : {}'.format(type(sym_name),sym_name)) 633 | if self.append_msg == None: 634 | self.append_msg = '' 635 | self.append_msg = sym_name + self.append_msg 636 | self.log_current_instruction(pc) 637 | log_d('####### return : check_ins_jmp. ignore fun or protect fun. value : CONST_DEAL_WITH_wait_breakpoint') 638 | return True,CONST_DEAL_WITH_wait_breakpoint 639 | 640 | self.log_current_instruction(pc) # 打印信息 641 | 642 | log_d('####### return : check_ins_jmp. same module. value : CONST_DEAL_WITH_continue') 643 | return True,CONST_DEAL_WITH_continue 644 | 645 | return False,None 646 | 647 | def check_ins_syscall(self,mnemonic:str,cur_symbol:lldb.SBSymbol): 648 | for syscall_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_syscall]: 649 | if not mnemonic.startswith(syscall_item): 650 | continue 651 | 652 | 653 | self.get_next_instruction() # 获得下一条指令 654 | if not self.next_instruction is None: 655 | self.add_next_breakpoint() 656 | 657 | self.delete_current_breakpoint() 658 | 659 | self.log_current_instruction(self.get_current_pc()) # 打印信息 660 | log_d('####### return : check_ins_syscall. value : CONST_DEAL_WITH_wait_breakpoint') 661 | return True,CONST_DEAL_WITH_wait_breakpoint 662 | 663 | return False,None 664 | 665 | def check_ins_other(self,cur_symbol:lldb.SBSymbol): 666 | self.get_next_instruction() # 获得下一条指令 667 | if not self.next_instruction is None: 668 | self.add_next_breakpoint() 669 | 670 | self.delete_current_breakpoint() 671 | self.log_current_instruction(self.get_current_pc()) # 打印信息 672 | 673 | def check_out_tracing(self): 674 | # 递归函数的处理 。。。。。。。 675 | 676 | pc = self.get_current_pc() 677 | if pc in self.end_trace_address: 678 | self.delete_current_breakpoint() 679 | self.log_current_instruction(pc) 680 | log_d('end trace addr list : {}'.format(self.end_trace_address)) 681 | log_d('cur pc : {}'.format(pc)) 682 | return True 683 | return False 684 | 685 | def check_end_fun(self): 686 | # 当前在结束地址 687 | flag,ret = self.check_currentIns_is_endIns() 688 | if flag : 689 | if ret == CONST_CHECK_ins_ret: 690 | pc = self.get_current_pc() 691 | self.delete_current_breakpoint() 692 | self.log_current_instruction(pc) 693 | log_d('@@@@ check_end_fun : address : {} is ret ins.'.format(hex(pc))) 694 | return True,CONST_DEAL_WITH_wait_breakpoint 695 | elif ret == CONST_CHECK_ins_end_address: 696 | last_pc = self.get_current_pc() 697 | self.thread.StepInstruction(False) 698 | self.delete_current_breakpoint() 699 | # 判断当前pc 是否在 instructionList中 700 | pc = self.get_current_pc() 701 | if pc in self.current_instruction_list: 702 | self.log_current_instruction(last_pc) 703 | log_d('@@@@ check_end_fun : address : {} is call end address,and in current_instruction_list.'.format(hex(last_pc))) 704 | return True,CONST_DEAL_WITH_continue 705 | else: 706 | # 可以 decrease print index 707 | self.log_current_instruction(last_pc) 708 | log_d('@@@@ check_end_fun : address : {} is call end address,and not in current_instruction_list.'.format(hex(last_pc))) 709 | return True,CONST_DEAL_WITH_wait_breakpoint 710 | else: 711 | pass 712 | log_d('@@@@ check_end_fun : address : {} is not call end address or ret ins.'.format(hex(self.get_current_pc()))) 713 | return False,None 714 | 715 | def check_symbol_valid(self): 716 | now_frame :lldb.SBFrame = self.thread.GetSelectedFrame() 717 | if now_frame: 718 | sym:lldb.SBSymbol = now_frame.GetSymbol() 719 | if not sym.IsValid(): 720 | log_d('####### return : check_symbol_valid not valid. value : CONST_DEAL_WITH_wait_breakpoint') 721 | return False,CONST_DEAL_WITH_wait_breakpoint 722 | log_d('@@@@ check_symbol_valid : valid.') 723 | return True,None 724 | 725 | def check_in_module(self): 726 | frame :lldb.SBFrame = self.thread.GetSelectedFrame() 727 | now_module_name = '{}'.format(frame.GetModule()) 728 | log_d('@@@@ current module name : {}'.format(now_module_name)) 729 | if now_module_name == self.current_module_name : 730 | return True,None 731 | log_d('####### return : check_in_module. is not current module. value : CONST_DEAL_WITH_wait_breakpoint') 732 | return False,CONST_DEAL_WITH_wait_breakpoint 733 | 734 | 735 | def deal_with_ins(self): 736 | 737 | if self.check_in_call_return_instruction_list(): 738 | self.decrease_print_index() 739 | self.sub_call_return_addr() 740 | 741 | # 结束tracing 742 | if self.check_out_tracing(): 743 | log_d('####### return : check_out_tracing value : CONST_DEAL_WITH_break') 744 | return CONST_DEAL_WITH_break 745 | 746 | # 函数结束的判断 747 | flag,ret = self.check_end_fun() 748 | if flag: 749 | log_d('####### return : check_end_fun') 750 | return ret 751 | 752 | # frame.GetFunction 和 frame.GetSymbol 是否有效 753 | flag,ret = self.check_symbol_valid() 754 | if not flag : 755 | return ret 756 | 757 | global t_only_self_module 758 | if t_only_self_module : 759 | flag,ret = self.check_in_module() 760 | if not flag: 761 | return ret 762 | 763 | instruction:lldb.SBInstruction = self.current_instruction 764 | mnemonic = None 765 | if instruction : 766 | mnemonic:str = instruction.GetMnemonic(self.target) 767 | else: 768 | log_d('warning : instruction is None') 769 | log_c('warning : instruction is None') 770 | 771 | cur_frame:lldb.SBFrame = self.thread.GetFrameAtIndex(0) 772 | cur_symbol:lldb.SBSymbol = cur_frame.GetSymbol() 773 | flag,value = self.check_ins_call(mnemonic,cur_symbol) # call 指令 操作 774 | if flag: 775 | log_d('check_ins_call') 776 | return value 777 | 778 | flag,value = self.check_ins_jmp(mnemonic,cur_symbol) # jmp 指令 操作 779 | if flag: 780 | log_d('check_ins_jmp') 781 | return value 782 | 783 | flag,value = self.check_ins_syscall(mnemonic,cur_symbol) # syscall 指令 操作 784 | if flag : 785 | log_d('check_ins_syscall') 786 | return value 787 | 788 | self.check_ins_other(cur_symbol) # 其他指令的操作 789 | log_d('####### return : check_ins_other. value : CONST_DEAL_WITH_wait_breakpoint') 790 | return CONST_DEAL_WITH_wait_breakpoint 791 | 792 | 793 | 794 | 795 | 796 | 797 | class WTFunction(): 798 | def __init__(self, *args): 799 | pass 800 | def deal_with_fun(self): 801 | pass 802 | 803 | 804 | class TraceOptionParser(optparse.OptionParser): 805 | def __init__(self, result): 806 | optparse.OptionParser.__init__(self) 807 | self.result = result 808 | self.exited = False 809 | 810 | def get_prog_name(self): 811 | return "trace" 812 | 813 | def exit(self, status=0, msg=None): 814 | if msg is not None: 815 | # print >>self.result, msg 816 | print(msg,file=self.result) 817 | self.exited = True 818 | 819 | def parse_options(command, result): 820 | global options 821 | command_tokens = shlex.split(command) 822 | parser = TraceOptionParser(result) 823 | parser.add_option("-e","--end-address",action="store",metavar="END_ADDRESS",dest="end_address",help="End addresses of trace,using to stop trace thread.More address,use ';' to split.") 824 | parser.add_option("-o","--only-tracing-self-module",action="store_true",dest="only_tracing_self_module",default=True,help="Only tracing in current module.Default is True") 825 | parser.add_option("-m","--mode-type",action="store",metavar="",dest="mode_type",default="instruction",help='Tracing mode,contains function and instruction.Default is instruction mode.') 826 | parser.add_option("-l","--log-type",action="store",metavar="",dest="log_type",default='trace',help="Set log type for this tracing. With trace type redirect trace output file. With debug type redirect trace and debug output files.Default is trace type.") 827 | parser.add_option("-P","--parser-msgsend-parameters",action="store_true",dest="parser_msgsend_parameters",default=False,help="Parser objc_msgsend function's parameters.Default is False") 828 | parser.add_option("-p","--print-tracing-progress",action="store_true",dest="print_tracing_progress",default=True,help="Print tracing progress in console.Default is True") 829 | parser.add_option("-s","--suspend-threads-except-current-thread",action="store_true",dest="suspend_threads",default=True,help="Suspend threads except current thread,to clean env.Default is True") 830 | (options, _) = parser.parse_args(command_tokens) 831 | 832 | return parser.exited 833 | 834 | def check_parser_command(): 835 | global options 836 | global t_only_self_module,t_parser_msgsend_parameters 837 | global t_log_file,t_log_file_name,d_log_file,d_log_file_name 838 | 839 | if options.end_address is None : 840 | print('err : plz input an address where you want to end tracing.') 841 | return False 842 | 843 | log_type_arr = ['trace','debug'] 844 | if not options.log_type in log_type_arr : 845 | print('err : plz input -l --log-type value, use "trace" or "debug".') 846 | return False 847 | 848 | mode_type_arr = ['function','instruction'] 849 | if not options.mode_type in mode_type_arr: 850 | print('err : plz input -m --mode-type value, use "function" or "instruction".') 851 | return False 852 | 853 | if options.log_type == 'trace': 854 | print(type(t_log_file_name)) 855 | print(t_log_file_name) 856 | t_log_file = open(t_log_file_name,'w') 857 | 858 | if options.log_type == 'debug': 859 | t_log_file = open(t_log_file_name,'w') 860 | d_log_file = open(d_log_file_name,'w') 861 | 862 | t_only_self_module = options.only_tracing_self_module 863 | t_parser_msgsend_parameters = options.parser_msgsend_parameters 864 | return True 865 | 866 | def ini_log_file(mode_name:str): 867 | import time 868 | global log_default_path,t_log_file_name,d_log_file_name 869 | timeName = int(time.time()) 870 | if mode_name == 'instruction': 871 | if log_default_path.endswith('/'): 872 | t_log_file_name = "{}{}{}".format(log_default_path,timeName,'instrace.log') 873 | d_log_file_name = "{}{}{}".format(log_default_path,timeName,'insdebug.log') 874 | log_c('trace log file : {}'.format(t_log_file_name)) 875 | log_c('debug log file : {}'.format(d_log_file_name)) 876 | else: 877 | t_log_file_name = "{}/{}{}".format(log_default_path,timeName,'instrace.log') 878 | d_log_file_name = "{}/{}{}".format(log_default_path,timeName,'insdebug.log') 879 | log_c('trace log file : {}'.format(t_log_file_name)) 880 | log_c('debug log file : {}'.format(d_log_file_name)) 881 | 882 | elif mode_name == 'function': 883 | 884 | if log_default_path.endswith('/'): 885 | t_log_file_name = "{}{}{}".format(log_default_path,timeName,'funtrace.log') 886 | d_log_file_name = "{}{}{}".format(log_default_path,timeName,'fundebug.log') 887 | log_c('trace log file : {}'.format(t_log_file_name)) 888 | log_c('debug log file : {}'.format(d_log_file_name)) 889 | else: 890 | t_log_file_name = "{}/{}{}".format(log_default_path,timeName,'funtrace.log') 891 | d_log_file_name = "{}/{}{}".format(log_default_path,timeName,'fundebug.log') 892 | log_c('trace log file : {}'.format(t_log_file_name)) 893 | log_c('debug log file : {}'.format(d_log_file_name)) 894 | else: 895 | print('err : trace mode err.') 896 | 897 | 898 | def test(debugger:lldb.SBDebugger): 899 | return False 900 | # import sys 901 | # import os 902 | # print(sys.argv[0]) 903 | # print(__file__) 904 | # current_path = os.path.abspath(__file__) 905 | # print(current_path) 906 | # father_path = os.path.abspath(os.path.dirname(current_path) + os.path.sep + ".") 907 | # print(father_path) 908 | # global options 909 | # endAddress = options.end_address 910 | # a = re.split(';',endAddress) 911 | # for item in a: 912 | # print(type(int(item,16))) 913 | # print(int(item,16)) 914 | # print(item) 915 | # print(a) 916 | # target: lldb.SBTarget = debugger.GetSelectedTarget() 917 | # process: lldb.SBProcess = target.GetProcess() 918 | # thread: lldb.SBThread = process.GetSelectedThread() 919 | # frame: lldb.SBFrame = thread.GetSelectedFrame() 920 | # symbol :lldb.SBSymbol = frame.GetSymbol() 921 | 922 | # print(frame.GetModule()) 923 | # print('frame : {}'.format(frame)) 924 | # print('symbol.Instructions : ') 925 | # print(symbol.GetInstructions(target)) 926 | # print('symbol : {}'.format(symbol)) 927 | # print('symbol.Name : "{}"'.format(symbol.GetName())) 928 | # print('thread : {}'.format(thread)) 929 | # print('thread name : {}'.format(thread.GetName())) 930 | # ins:lldb.SBInstruction = None 931 | # stream:lldb.SBStream = lldb.SBStream() 932 | # for ins in symbol.GetInstructions(target): 933 | # # print(ins.GetData(target)) 934 | # ins.GetDescription(stream) 935 | # addr :lldb.SBAddress = ins.GetAddress() 936 | # module : lldb.SBModule = addr.GetModule() 937 | # print('module : {}'.format(module)) 938 | # sym : lldb.SBSymbol = None 939 | # for sym in module: 940 | # print('sym name : {}'.format(sym.GetName())) 941 | 942 | # break 943 | # print('symbol valid : {}'.format(symbol.IsValid())) 944 | # print('symbol DisplayName : {}'.format(symbol.GetDisplayName())) 945 | # print('symbol MangledName : {}'.format(symbol.GetMangledName())) 946 | 947 | 948 | return True 949 | 950 | def trace(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict): 951 | ''' 952 | Traces execution of the symbol in the currently selected frame. 953 | trace -h/--help, for full help 954 | ''' 955 | global options 956 | if parse_options(command, result): 957 | return 958 | 959 | #################################################### 960 | ########################测 试######################## 961 | #################################################### 962 | if test(debugger): 963 | return 964 | #################################################### 965 | 966 | ini_log_file(options.mode_type) 967 | 968 | if not check_parser_command(): 969 | return 970 | 971 | 972 | wait_event = threading.Event() 973 | wait_event.clear() 974 | notify_event = threading.Event() 975 | notify_event.clear() 976 | 977 | target: lldb.SBTarget = debugger.GetSelectedTarget() 978 | broadcaster: lldb.SBBroadcaster = target.GetBroadcaster() 979 | log_d("Target: {}".format(str(target))) 980 | process: lldb.SBProcess = target.GetProcess() 981 | log_d("Process: {}".format(str(process))) 982 | log_d("Broadcaster: {}".format(str(broadcaster))) 983 | if options.suspend_threads : 984 | suspend_threads_escape_select_thread(process,True) 985 | 986 | listener = lldb.SBListener("trace breakpoint listener") 987 | rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged) 988 | my_thread = WTListeningThread(wait_event, notify_event,listener, process) 989 | my_thread.start() 990 | 991 | thread: lldb.SBThread = process.GetSelectedThread() 992 | log_d("Thread: {}".format(str(thread))) 993 | 994 | frame: lldb.SBFrame = thread.GetSelectedFrame() 995 | 996 | module: lldb.SBModule = frame.GetModule() 997 | if frame.GetFrameID() == 0xFFFFFFFF: 998 | log_d("Invalid frame, has your process started?") 999 | return 1000 | 1001 | insObj = WTInstruction(target,thread,frame,debugger,TRACE_TYPE_Instrument,endAddress=options.end_address) 1002 | ## 初始化 环境 1003 | insObj.init_env() 1004 | global num_for_print_progress 1005 | insCount = 0 1006 | test_index = 0 1007 | while True: 1008 | log_d('index : {}'.format(test_index)) 1009 | # 打印进度 1010 | if options.print_tracing_progress : 1011 | if insCount % num_for_print_progress == 0 and insCount > 0: 1012 | insObj.print_tracing_progress(insCount) 1013 | insCount = insCount + 1 1014 | 1015 | # 更新当前 instruction / instructionList 1016 | log_d("////////////////////////////////loop begin////////////////////////////////") 1017 | insObj.updata_instruction_instructionList() # 更新所有的 指令 ,更新当前 指令 1018 | 1019 | # ins : 设置断点,进行有必要的 单步 调试 1020 | # fun : 设置断点 1021 | ret = insObj.deal_with() # 处理 指令 1022 | 1023 | # 保存指令 1024 | insObj.updata_last_instruction() 1025 | 1026 | log_d("=================== Stopped at: ====================") 1027 | log_d("Frame: {}, symbol: {}, pc: {pc:#x}".format(str(frame), str(frame.GetSymbol()), pc=frame.GetPC())) 1028 | # 判断结果 1029 | if ret == CONST_DEAL_WITH_error: 1030 | log_c('err : deal with error.') 1031 | log_d('err : deal with error.') 1032 | insObj.clean_env() 1033 | break 1034 | 1035 | if ret == CONST_DEAL_WITH_continue: 1036 | continue 1037 | 1038 | if ret == CONST_DEAL_WITH_break : 1039 | break 1040 | continue_and_wait_for_breakpoint(process,thread,my_thread,wait_event,notify_event) 1041 | 1042 | 1043 | 1044 | if options.suspend_threads : 1045 | suspend_threads_escape_select_thread(process,False) 1046 | my_thread.exit() 1047 | wait_event.set() 1048 | my_thread.join() 1049 | broadcaster.RemoveListener(listener) 1050 | log_d('Listener thread exited completing') 1051 | log_flush() 1052 | 1053 | 1054 | ############################################################################################################################################################ 1055 | #######################################################################traceblock########################################################################### 1056 | ############################################################################################################################################################ 1057 | 1058 | class WTBlock(): 1059 | def __init__(self, target, thread, frame,debugger,endAddress=None): 1060 | self.target:lldb.SBTarget = target 1061 | self.thread:lldb.SBThread = thread 1062 | self.frame:lldb.SBFrame = frame 1063 | self.debugger:lldb.SBDebugger = debugger 1064 | 1065 | self.current_instruction_list = {} 1066 | self.end_trace_address = [] 1067 | self.block_list = {} # 存贮所有的 block 1068 | 1069 | # 1070 | # { 1071 | # addr : { # 这里是断点地址 1072 | # 'index' : 0 # 这里是断点信息 1073 | # 'breakpoint' : None # 这里是 lldb.SBBreakpoint 1074 | # } 1075 | # } 1076 | self.breakpoint_list = {} # 断点列表 1077 | 1078 | self.loop_flag = False 1079 | self.append_msg = '' 1080 | 1081 | # log 1082 | self.last_block_msg = '' 1083 | self.last_isnts_msg = '' 1084 | self.last_reg_msg = '' 1085 | 1086 | ## 1087 | self.test_test_index = 0 1088 | 1089 | for item in re.split(';',endAddress): 1090 | self.end_trace_address.append(int(item,16)) # 结束 Trace 地址 1091 | 1092 | def initEnv(self): 1093 | cur_pc = self.get_current_pc() 1094 | self.block_add_block_to_block_list(cur_pc) 1095 | for item in self.end_trace_address : 1096 | self.block_add_breakpoint(item) # 给结束地址下断点 1097 | 1098 | def block_set_loop_flag(self,flag_value): 1099 | self.loop_flag = flag_value 1100 | 1101 | def block_add_append_msg(self,msg): 1102 | self.append_msg = '{}[{}]'.format(self.append_msg,msg) 1103 | 1104 | 1105 | def block_clear_append_msg(self): 1106 | self.append_msg = '' 1107 | 1108 | def block_delete_breakpoint(self,inst_addr): 1109 | if inst_addr in self.breakpoint_list : 1110 | index_value = self.breakpoint_list[inst_addr]['index'] 1111 | delete_breakpoint:lldb.SBBreakpoint = self.breakpoint_list[inst_addr]['breakpoint'] 1112 | if index_value > 1 : 1113 | self.breakpoint_list[inst_addr]['index'] = index_value -1 1114 | elif index_value == 1: 1115 | log_d('delete breakpoint at : {}'.format(hex(inst_addr))) 1116 | self.target.BreakpointDelete(delete_breakpoint.GetID()) 1117 | self.breakpoint_list[inst_addr]['index'] = 0 1118 | self.breakpoint_list.pop(inst_addr) 1119 | else: 1120 | log_d('err : delete breakpoint with wrong index . < index : {} >'.format(index_value)) 1121 | 1122 | def block_add_breakpoint(self,inst_addr): 1123 | if inst_addr in self.breakpoint_list: 1124 | # index_value = self.breakpoint_list[inst_addr]['index'] 1125 | # if index_value > 0 : 1126 | # print('increase breakpoint index at : {}'.format(hex(inst_addr))) 1127 | # self.breakpoint_list[inst_addr]['index'] = index_value + 1 1128 | # else: 1129 | # print('err : add breakpoint with wrong index. < index : {} >'.format(index_value)) 1130 | log_d('breakpoint at {} had been exist.'.format(hex(inst_addr))) 1131 | else: 1132 | item = {} 1133 | breakpoint :lldb.SBBreakpoint = self.target.BreakpointCreateByAddress(inst_addr) 1134 | breakpoint.SetThreadID(self.thread.GetThreadID()) 1135 | item['index'] = 1 1136 | item['breakpoint'] = breakpoint 1137 | self.breakpoint_list[inst_addr] = item 1138 | log_d('add breakpoint at : {}'.format(hex(inst_addr))) 1139 | def block_add_block_to_block_list(self,block_id): 1140 | if not (block_id in self.block_list) : 1141 | log_d('>>>>>> add block : {} >>> value : None.'.format(hex(block_id))) 1142 | self.block_list[block_id] = None 1143 | 1144 | # 获得当前 pc 1145 | def get_current_pc(self): 1146 | now_frame :lldb.SBFrame = self.thread.GetSelectedFrame() 1147 | if now_frame: 1148 | return now_frame.GetPC() 1149 | return None 1150 | # 1151 | def block_update_current_ins(self): 1152 | frame : lldb.SBFrame = self.thread.GetSelectedFrame() 1153 | # symbol:lldb.SBSymbol = frame.GetSymbol() 1154 | # # 给 current_instruction_list 赋值 1155 | # # 获得 当前 symbol 下的 instructionlist 1156 | # insts : lldb.SBInstructionList = symbol.GetInstructions(self.target) 1157 | 1158 | cur_pc = self.get_current_pc() 1159 | 1160 | if not (cur_pc in self.current_instruction_list) : 1161 | # 清空一哈 1162 | self.current_instruction_list = {} 1163 | # 更新 self.current_instruction_list 1164 | 1165 | target: lldb.SBTarget = self.debugger.GetSelectedTarget() 1166 | process: lldb.SBProcess = target.GetProcess() 1167 | thread: lldb.SBThread = process.GetSelectedThread() 1168 | frame: lldb.SBFrame = thread.GetSelectedFrame() 1169 | symbol :lldb.SBSymbol = frame.GetSymbol() 1170 | insts :lldb.SBInstructionList = symbol.GetInstructions(target) 1171 | # func : lldb.SBFunction = frame.GetFunction() 1172 | # insts : lldb.SBInstructionList = func.GetInstructions(self.target) 1173 | for inst in insts : 1174 | instAddr :lldb.SBAddress = inst.GetAddress() 1175 | addr = instAddr.GetLoadAddress(self.target) 1176 | if not (addr in self.current_instruction_list) : 1177 | self.current_instruction_list[addr] = inst 1178 | 1179 | return cur_pc 1180 | 1181 | 1182 | # 判断当前 ins 是否在 trace 的结束列表中 1183 | def block_check_current_ins_in_end_tracing_address_list(self,curIns): 1184 | if curIns in self.end_trace_address : 1185 | return True 1186 | return False 1187 | 1188 | def block_update_block_data(self,block_id,block_dic): 1189 | if block_id in self.block_list: 1190 | block_data = self.block_list[block_id] 1191 | if not block_data : 1192 | self.block_list[block_id] = block_dic 1193 | else : 1194 | log_d('>> block : {} had been update'.format(hex(block_id))) 1195 | else: 1196 | log_d('err : block id dont input to block list.') 1197 | 1198 | def block_update_current_block(self): 1199 | # 需要在 bl 以及 jmp 目标地址,和条件jmp的下一条指令处下断点,以及 增加对应的 block 到 blockList 中 1200 | cur_pc = self.get_current_pc() 1201 | # print(self.current_instruction_list) 1202 | inst :lldb.SBInstruction = self.current_instruction_list[cur_pc] 1203 | 1204 | if (cur_pc in self.block_list) and ( self.block_list[cur_pc]) : 1205 | self.block_set_loop_flag(True) 1206 | self.block_delete_breakpoint(cur_pc) 1207 | return self.block_list[cur_pc] 1208 | 1209 | use_inst = inst 1210 | block_ins_list = {} 1211 | need_break = False 1212 | log_d('update block : {} insts :'.format(hex(cur_pc))) 1213 | while True : 1214 | mnemonic: str = use_inst.GetMnemonic(self.target) 1215 | inst_addr = use_inst.GetAddress().GetLoadAddress(self.target) 1216 | next_addr = inst_addr + use_inst.GetByteSize() 1217 | operands = use_inst.GetOperands(self.target) 1218 | 1219 | flag = False 1220 | for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_call] : 1221 | if mnemonic.startswith(item) : 1222 | flag = True 1223 | break 1224 | 1225 | if flag : 1226 | self.block_add_breakpoint(inst_addr) 1227 | block_ins_list[inst_addr] = use_inst # 代码加入到 block_ins_list 1228 | if next_addr in self.current_instruction_list : 1229 | use_inst = self.current_instruction_list[next_addr] # 更新 use_inst 1230 | else : 1231 | break 1232 | continue 1233 | 1234 | flag = False 1235 | for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_jmp]: 1236 | if item == mnemonic : 1237 | flag = True 1238 | need_break = True 1239 | break 1240 | 1241 | if flag : 1242 | self.block_add_block_to_block_list(int(operands,16)) # 添加block 到 block_list 中 1243 | self.block_add_breakpoint(int(operands,16))# 在 int(operands,16) 处下断点 1244 | 1245 | if not need_break : 1246 | flag = False 1247 | for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_condition_jmp] : 1248 | if mnemonic.startswith(item): 1249 | flag = True 1250 | need_break = True 1251 | break 1252 | if flag : 1253 | if int(operands,16) > inst_addr : 1254 | self.block_add_block_to_block_list(int(operands,16)) 1255 | self.block_add_breakpoint(int(operands,16)) # 在 operands 下断点 1256 | 1257 | self.block_add_block_to_block_list(next_addr) 1258 | self.block_add_breakpoint(next_addr) # 在 next_addr 下断点 1259 | 1260 | 1261 | block_ins_list[inst_addr] = use_inst # 代码加入到 block_ins_list 1262 | if need_break : 1263 | break 1264 | 1265 | if next_addr in self.current_instruction_list : 1266 | use_inst = self.current_instruction_list[next_addr] # 更新 use_inst 1267 | else : 1268 | break 1269 | # self.block_list[cur_pc] = block_ins_list 1270 | # print('block : {} \n{}:'.format(hex(cur_pc),self.block_list[cur_pc])) 1271 | return block_ins_list 1272 | 1273 | 1274 | def block_at_bl(self,curIns): 1275 | ins:lldb.SBInstruction = self.current_instruction_list[curIns] 1276 | mnem:str = ins.GetMnemonic(self.target) 1277 | for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_call]: 1278 | if mnem.startswith(item) : 1279 | return True 1280 | return False 1281 | 1282 | def block_at_header(self,curIns): 1283 | if curIns in self.block_list : 1284 | return True 1285 | return False 1286 | 1287 | ############################## 1288 | def block_step_into(self): 1289 | self.thread.StepInstruction(False) 1290 | 1291 | def block_get_data_about_function_and_symbol(self,curIns): 1292 | target: lldb.SBTarget = self.debugger.GetSelectedTarget() 1293 | process: lldb.SBProcess = target.GetProcess() 1294 | thread: lldb.SBThread = process.GetSelectedThread() 1295 | frame: lldb.SBFrame = thread.GetSelectedFrame() 1296 | symbol :lldb.SBSymbol = frame.GetSymbol() 1297 | func : lldb.SBFunction = frame.GetFunction() 1298 | # insts:lldb.SBInstructionList = func.GetInstructions(target) 1299 | # inst:lldb.SBInstruction = None 1300 | # block_delete_breakpoint 1301 | self.block_delete_breakpoint(curIns) 1302 | 1303 | if func.IsValid(): 1304 | return True,symbol.GetName() 1305 | 1306 | return False,symbol.GetName() 1307 | 1308 | 1309 | def block_get_reg_msg(self): 1310 | reg_msg = '' 1311 | target: lldb.SBTarget = self.debugger.GetSelectedTarget() 1312 | process: lldb.SBProcess = target.GetProcess() 1313 | thread: lldb.SBThread = process.GetSelectedThread() 1314 | frame: lldb.SBFrame = thread.GetSelectedFrame() 1315 | 1316 | registerSet :lldb.SBValueList = frame.GetRegisters() 1317 | regs:lldb.SBValue = registerSet.GetValueAtIndex(0) 1318 | for reg in regs : 1319 | if reg_msg == "" : 1320 | reg_msg = '{}:{}'.format(reg.name,reg.value) 1321 | else: 1322 | reg_msg = '{}|{}:{}'.format(reg_msg,reg.name,reg.value) 1323 | 1324 | if reg.name == 'pc' : 1325 | break 1326 | 1327 | return reg_msg 1328 | 1329 | def block_get_current_insts_msg(self,block_id): 1330 | global ASLR 1331 | target: lldb.SBTarget = self.debugger.GetSelectedTarget() 1332 | isnts_msg = '' 1333 | if not self.loop_flag : 1334 | # isnts_msg = '0x12345 mov x0,1' 1335 | if block_id in self.block_list: 1336 | cur_block = self.block_list[block_id] 1337 | inst:lldb.SBInstruction = None 1338 | if cur_block : 1339 | for key,inst in cur_block.items(): 1340 | inst_msg = '{: <5} {}'.format(inst.GetMnemonic(target),inst.GetOperands(target)) 1341 | if isnts_msg == "" : 1342 | isnts_msg = '{: <10} {}'.format(hex(key - ASLR),inst_msg) 1343 | else: 1344 | isnts_msg = '{}\n\t{: <10} {}'.format(isnts_msg,hex(key - ASLR),inst_msg) 1345 | 1346 | return isnts_msg 1347 | 1348 | ################################ 1349 | # log 输出 格式 1350 | # block_id : 1351 | # { 1352 | # addr : inst 1353 | # ... 1354 | # }<函数名|函数名|..>[x0:value|x1:value|....] 1355 | # block_id : 1356 | # {}<函数名|函数名|..>[x0:value|x1:value|....] 1357 | # 1358 | # out_msg = "%s\n{\n\t%s\n}<%s>[%s]" % ('block id : 0x1233333','0x12345 mov x0,1','malloc|strlen','x0:0x1234|x1:0x222222') 1359 | def block_log_msg(self,block_id): 1360 | global ASLR 1361 | self.test_test_index = self.test_test_index + 1 1362 | 1363 | block_msg = "{} =>> block id : {}".format(self.test_test_index,hex(block_id-ASLR)) 1364 | isnts_msg = self.block_get_current_insts_msg(block_id) 1365 | reg_msg = self.block_get_reg_msg() 1366 | 1367 | if not (self.last_block_msg == '' and self.last_isnts_msg == '' and self.last_reg_msg == '') : 1368 | out_msg = "%s\n{\n\t%s\n}<%s>[%s]" % (self.last_block_msg,self.last_isnts_msg,self.append_msg,self.last_reg_msg) 1369 | log_t(out_msg) 1370 | 1371 | self.last_block_msg = block_msg 1372 | self.last_isnts_msg = isnts_msg 1373 | self.last_reg_msg = reg_msg 1374 | 1375 | # 清空 append_msg 1376 | self.append_msg = '' 1377 | 1378 | def block_log_end_msg(self): 1379 | if not (self.last_block_msg == '' and self.last_isnts_msg == '' and self.last_reg_msg == '') : 1380 | out_msg = "%s\n{\n\t%s\n}<%s>[%s]" % (self.last_block_msg,self.last_isnts_msg,self.append_msg,self.last_reg_msg) 1381 | log_t(out_msg) 1382 | 1383 | self.last_block_msg = '' 1384 | self.last_isnts_msg = '' 1385 | self.last_reg_msg = '' 1386 | 1387 | self.append_msg = '' 1388 | 1389 | 1390 | def block_get_symbol_name(self): 1391 | target: lldb.SBTarget = self.debugger.GetSelectedTarget() 1392 | process: lldb.SBProcess = target.GetProcess() 1393 | thread: lldb.SBThread = process.GetSelectedThread() 1394 | frame: lldb.SBFrame = thread.GetSelectedFrame() 1395 | symbol :lldb.SBSymbol = frame.GetSymbol() 1396 | return symbol.GetName() 1397 | 1398 | 1399 | def block_print_tracing_progress(self,count): 1400 | # 当前trace的总行数 内存地址:文件地址: <函数名> 1401 | global ASLR 1402 | file_addr = 0 1403 | cur_pc = self.get_current_pc() 1404 | if cur_pc == 0 : 1405 | log_c('{: <10} err .'.format(count)) 1406 | else: 1407 | file_addr = cur_pc - ASLR 1408 | if cur_pc in self.current_instruction_list: 1409 | out_str = '{: <10} {} : {} <{}>'.format(count,hex(cur_pc),hex(file_addr),self.block_get_symbol_name()) 1410 | log_c(out_str) 1411 | else: 1412 | out_str = '{: <10} {}'.format(count,hex(cur_pc)) 1413 | log_c(out_str) 1414 | 1415 | def block_get_block_id(self,block): 1416 | retaddr = 0 1417 | for addr in block.keys(): 1418 | if retaddr == 0 : 1419 | retaddr = addr 1420 | else: 1421 | if retaddr > addr : 1422 | retaddr = addr 1423 | 1424 | return retaddr 1425 | 1426 | 1427 | def block_print(self): 1428 | print('---> block_list <---') 1429 | for item in self.block_list: 1430 | print(hex(item)) 1431 | 1432 | print('---> breakpoint_list <---') 1433 | for item in self.breakpoint_list : 1434 | print(hex(item)) 1435 | 1436 | print('--------------------------') 1437 | 1438 | 1439 | 1440 | 1441 | def block_parser_options(command, result): 1442 | global options 1443 | command_tokens = shlex.split(command) 1444 | parser = TraceOptionParser(result) 1445 | parser.add_option("-e","--end-address",action="store",metavar="END_ADDRESS",dest="end_address",help="End addresses of trace,using to stop trace thread.More address,use ';' to split.") 1446 | parser.add_option("-l","--log-type",action="store",metavar="",dest="log_type",default='trace',help="Set log type for this tracing. With trace type redirect trace output file. With debug type redirect trace and debug output files.Default is trace type.") 1447 | parser.add_option("-p","--print-tracing-progress",action="store_true",dest="print_tracing_progress",default=True,help="Print tracing progress in console.Default is True") 1448 | parser.add_option("-s","--suspend-threads-except-current-thread",action="store_true",dest="suspend_threads",default=True,help="Suspend threads except current thread,to clean env.Default is True") 1449 | 1450 | (options, _) = parser.parse_args(command_tokens) 1451 | 1452 | return parser.exited 1453 | 1454 | 1455 | def block_ini_log_file(): 1456 | import time 1457 | global log_default_path,t_log_file_name,d_log_file_name 1458 | timeName = int(time.time()) 1459 | 1460 | if log_default_path.endswith('/'): 1461 | t_log_file_name = "{}{}{}".format(log_default_path,timeName,'blocktrace.log') 1462 | d_log_file_name = "{}{}{}".format(log_default_path,timeName,'blockdebug.log') 1463 | log_c('trace log file : {}'.format(t_log_file_name)) 1464 | log_c('debug log file : {}'.format(d_log_file_name)) 1465 | else: 1466 | t_log_file_name = "{}/{}{}".format(log_default_path,timeName,'blocktrace.log') 1467 | d_log_file_name = "{}/{}{}".format(log_default_path,timeName,'blockdebug.log') 1468 | log_c('trace log file : {}'.format(t_log_file_name)) 1469 | log_c('debug log file : {}'.format(d_log_file_name)) 1470 | 1471 | 1472 | 1473 | def block_check_parser_command(): 1474 | global options 1475 | global t_log_file,t_log_file_name,d_log_file,d_log_file_name 1476 | 1477 | if options.end_address is None : 1478 | print('err : plz input an address where you want to end tracing.') 1479 | return False 1480 | 1481 | log_type_arr = ['trace','debug'] 1482 | if not options.log_type in log_type_arr : 1483 | print('err : plz input -l --log-type value, use "trace" or "debug".') 1484 | return False 1485 | 1486 | if options.log_type == 'trace': 1487 | print(type(t_log_file_name)) 1488 | print(t_log_file_name) 1489 | t_log_file = open(t_log_file_name,'w') 1490 | 1491 | if options.log_type == 'debug': 1492 | t_log_file = open(t_log_file_name,'w') 1493 | d_log_file = open(d_log_file_name,'w') 1494 | 1495 | return True 1496 | 1497 | 1498 | def test_block(debugger:lldb.SBDebugger): 1499 | 1500 | return False 1501 | 1502 | target: lldb.SBTarget = debugger.GetSelectedTarget() 1503 | process: lldb.SBProcess = target.GetProcess() 1504 | thread: lldb.SBThread = process.GetSelectedThread() 1505 | frame: lldb.SBFrame = thread.GetSelectedFrame() 1506 | symbol :lldb.SBSymbol = frame.GetSymbol() 1507 | func : lldb.SBFunction = frame.GetFunction() 1508 | 1509 | # out_msg = "%s\n{\n\t%s\n}<%s>[%s]" % ('block id : 0x1233333','0x12345 mov x0,1','malloc|strlen','x0:0x1234|x1:0x222222') 1510 | 1511 | # print(out_msg) 1512 | # registerSet :lldb.SBValueList = frame.GetRegisters() 1513 | # regs:lldb.SBValue = registerSet.GetValueAtIndex(0) 1514 | # print('num is : {}'.format(regs.GetNumChildren())) 1515 | # for reg in regs : 1516 | # print('{} : {}'.format(reg.name,reg.value)) 1517 | # if reg.name == 'pc' : 1518 | # break 1519 | # print(symbol.GetInstructions(target)) 1520 | 1521 | # # symbol 可执行文件里有,链接库里有 1522 | # # func 可执行文件里有,但是 链接库里 没有 1523 | # if func.IsValid() : 1524 | # # insts:lldb.SBInstructionList = func.GetInstructions(target) 1525 | # # inst:lldb.SBInstruction = None 1526 | # # print('isnts : ') 1527 | # # print(insts) 1528 | # print('func : {}'.format(func)) 1529 | # print('func name : {}'.format(func.GetName())) 1530 | # # print('symbol : {}'.format(symbol)) 1531 | # # print('symbol DisplayName : {}'.format(symbol.GetDisplayName())) 1532 | # # print('symbol MangledName : {}'.format(symbol.GetMangledName())) 1533 | # print('symbol name : {}'.format(symbol.GetName())) 1534 | 1535 | 1536 | # for inst in insts : 1537 | # print('|{}|-----|{}|'.format(inst.GetMnemonic(target),inst.GetOperands(target))) 1538 | # pass 1539 | cur_block_ins_list = None # 直接更新 1540 | blockObj = WTBlock(target,thread,frame,debugger) 1541 | blockObj.initEnv() 1542 | cur_ins = blockObj.block_update_current_ins() 1543 | print('cur ins : {}'.format(hex(cur_ins))) 1544 | if not cur_block_ins_list : 1545 | cur_block_ins_list = blockObj.block_update_current_block() 1546 | 1547 | # if not (cur_ins in cur_block_ins_list) : 1548 | # cur_block_ins_list = blockObj.block_update_current_block() 1549 | 1550 | print('--> block_ins_list <---') 1551 | item : lldb.SBInstruction = None 1552 | for _,item in cur_block_ins_list.items() : 1553 | print('{} {} {}'.format(hex(item.GetAddress().GetLoadAddress(target)),item.GetMnemonic(target),item.GetOperands(target))) 1554 | 1555 | 1556 | blockObj.block_print() 1557 | 1558 | def trace_block(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict): 1559 | global options 1560 | if block_parser_options(command, result): 1561 | return 1562 | 1563 | #################################################### 1564 | ########################测 试######################## 1565 | #################################################### 1566 | if test_block(debugger): 1567 | return 1568 | #################################################### 1569 | 1570 | block_ini_log_file() 1571 | 1572 | 1573 | if not block_check_parser_command(): 1574 | return 1575 | 1576 | wait_event = threading.Event() 1577 | wait_event.clear() 1578 | notify_event = threading.Event() 1579 | notify_event.clear() 1580 | 1581 | target: lldb.SBTarget = debugger.GetSelectedTarget() 1582 | broadcaster: lldb.SBBroadcaster = target.GetBroadcaster() 1583 | print("Target: {}".format(str(target))) 1584 | process: lldb.SBProcess = target.GetProcess() 1585 | print("Process: {}".format(str(process))) 1586 | print("Broadcaster: {}".format(str(broadcaster))) 1587 | if options.suspend_threads : 1588 | suspend_threads_escape_select_thread(process,True) 1589 | 1590 | listener = lldb.SBListener("trace breakpoint listener") 1591 | rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged) 1592 | my_thread = WTListeningThread(wait_event, notify_event,listener, process) 1593 | my_thread.start() 1594 | 1595 | thread: lldb.SBThread = process.GetSelectedThread() 1596 | print("Thread: {}".format(str(thread))) 1597 | 1598 | frame: lldb.SBFrame = thread.GetSelectedFrame() 1599 | 1600 | module: lldb.SBModule = frame.GetModule() 1601 | if frame.GetFrameID() == 0xFFFFFFFF: 1602 | print("Invalid frame, has your process started?") 1603 | return 1604 | 1605 | blockObj = WTBlock(target,thread,frame,debugger,endAddress=options.end_address) 1606 | blockObj.initEnv() 1607 | 1608 | cur_block = None # 直接更新 1609 | blockCount = 0 1610 | while True : 1611 | # 打印进度 1612 | if options.print_tracing_progress : 1613 | if blockCount % num_for_print_progress == 0 and blockCount > 0: 1614 | blockObj.block_print_tracing_progress(blockCount) 1615 | blockCount = blockCount + 1 1616 | log_d("=================== Stopped at: ====================") 1617 | log_d("Frame: {}, symbol: {}, pc: {pc:#x}".format(str(frame), str(frame.GetSymbol()), pc=frame.GetPC())) 1618 | cur_ins = blockObj.block_update_current_ins() 1619 | 1620 | if blockObj.block_check_current_ins_in_end_tracing_address_list(cur_ins): 1621 | print('end tracing....... at : {}'.format(hex(cur_ins))) 1622 | blockObj.block_log_end_msg() 1623 | log_d('end tracing....... at : {}'.format(hex(cur_ins))) 1624 | # blockObj.block_print() 1625 | break 1626 | 1627 | if (not cur_block ) or not (cur_ins in cur_block): 1628 | cur_block = blockObj.block_update_current_block() # 需要在 bl 以及 jmp 目标地址,和条件jmp的下一条指令处下断点,以及 增加对应的 block 到 blockList 中 1629 | blockObj.block_update_block_data(cur_ins,cur_block) 1630 | 1631 | 1632 | at_bl_flag = blockObj.block_at_bl(cur_ins) 1633 | at_header_flag = blockObj.block_at_header(cur_ins) 1634 | 1635 | if at_bl_flag and at_header_flag : 1636 | # 当前指令 是 bl 而且是 block 头 1637 | # 输出 信息 1638 | blockObj.block_log_msg(cur_ins) 1639 | blockObj.block_set_loop_flag(False) 1640 | # 单步进入,然后获得 symble name 和 function name 1641 | blockObj.block_step_into() 1642 | _,symbol_name = blockObj.block_get_data_about_function_and_symbol(cur_ins) 1643 | blockObj.block_add_append_msg('') # blockObj.block_add_append_msg(msg) # 把信息 加入 到 1644 | 1645 | elif at_bl_flag and (not at_header_flag): 1646 | # 当前指令 仅仅是 bl 1647 | # 单步进入,然后获得 symble name 和 function name 1648 | blockObj.block_step_into() 1649 | _,symbol_name = blockObj.block_get_data_about_function_and_symbol(cur_ins) 1650 | blockObj.block_add_append_msg(symbol_name) # blockObj.block_add_append_msg(msg) # 把信息 加入 到 1651 | 1652 | elif at_header_flag and (not at_bl_flag): 1653 | # 当前指令 仅仅是 block 头,在进来的时候,已经搞定 1654 | # 输出 信息 1655 | blockObj.block_log_msg(cur_ins) 1656 | blockObj.block_set_loop_flag(False) 1657 | else: 1658 | log_d('err : ins out of control.') 1659 | print('err : ins out of control.') 1660 | break 1661 | 1662 | # 10分钟 刷新一次缓存,把缓存 写入到 block list 文件中 xxxxx_block_list.txt 1663 | # 清空 blockObj.block_list 1664 | 1665 | continue_and_wait_for_breakpoint(process,thread,my_thread,wait_event,notify_event) 1666 | 1667 | if options.suspend_threads : 1668 | suspend_threads_escape_select_thread(process,False) 1669 | my_thread.exit() 1670 | wait_event.set() 1671 | my_thread.join() 1672 | broadcaster.RemoveListener(listener) 1673 | print('Listener thread exited completing') 1674 | log_flush() 1675 | 1676 | 1677 | 1678 | def init_ASLR(debugger:lldb.SBDebugger): 1679 | global ASLR 1680 | interpreter:lldb.SBCommandInterpreter = debugger.GetCommandInterpreter() 1681 | returnObject = lldb.SBCommandReturnObject() 1682 | interpreter.HandleCommand('image list -o', returnObject) 1683 | output = returnObject.GetOutput() 1684 | match = re.match(r'.+(0x[0-9a-fA-F]+)', output) 1685 | if match: 1686 | ASLRHexStr:str = match.group(1) 1687 | ASLR = int(ASLRHexStr,16) 1688 | print('ALSR : {}'.format(ASLRHexStr)) 1689 | return ASLRHexStr 1690 | else: 1691 | ASLR = '' 1692 | print('err : ALSR is None') 1693 | return None 1694 | 1695 | def setDefaultPath(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict): 1696 | global log_default_path 1697 | log_default_path = command 1698 | # 还需要判断这个 路径存在否 1699 | print(command) 1700 | 1701 | def defaultPath(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict): 1702 | global log_default_path 1703 | print(log_default_path) 1704 | 1705 | def __lldb_init_module(debugger:lldb.SBDebugger, internal_dict): 1706 | global log_default_path 1707 | init_ASLR(debugger) 1708 | log_default_path = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + ".") 1709 | debugger.HandleCommand('command script add -f lldbTrace.trace trace') 1710 | debugger.HandleCommand('command script add -f lldbTrace.setDefaultPath setlogpath') 1711 | debugger.HandleCommand('command script add -f lldbTrace.defaultPath logpath') 1712 | print('WT::The "trace" python command has been installed and is ready for use.') 1713 | 1714 | 1715 | 1716 | print('WT::Default path =>>>> {}'.format(log_default_path)) 1717 | print(' use : logpath command to look up logfile default path.') 1718 | print(' use : setlogpath command to reset logfile default path.') 1719 | 1720 | debugger.HandleCommand('command script add -f lldbTrace.trace_block trace_b') 1721 | print('WT::The "trace_b" python command has been installed and is ready for use.') 1722 | 1723 | 1724 | --------------------------------------------------------------------------------