标题: GDB条件断点中进行字符串比较 创建: 2018-06-22 16:43 更新: 2023-06-02 14:02 链接: https://scz.617.cn/unix/201806221643.txt 假设被调试进程空间有strcmp()可用,可以直接在断点条件中使用它。 b *addr if ((int)strcmp((char*)sth,"magic"))==0 或 b *addr cond $bpnum ((int)strcmp((char*)sth,"magic"))==0 这是比较保守的写法,加了两处强制类型转换,某些时候并不需要。 如果被调试进程空间没有strcmp()可用,或者正在进行远程调试(GDB Server),前述 方案不可行。此外,前述办法有微妙的陷阱,在目标进程空间调用strcmp()会破坏上 下文,并不推荐。 新版GDB有一些基于Python的内置函数可用于这种条件断点: b *addr if $_streq((char*)sth,"magic") 可以使用正则表达式: b *addr if $_regex((char*)$r0,"^{\"id\":") 其他示例: b *addr if $_strlen((char*)$r0)==40 && $_memeq((char*)$r0,(char*)0x1F076514,40) 参看: -------------------------------------------------------------------------- (gdb) help function _memeq $_memeq - compare bytes of memory Usage: $_memeq(a, b, len) Returns: True if len bytes at a and b compare equally. (gdb) help function _regex $_regex - check if a string matches a regular expression Usage: $_regex(string, regex) Returns: True if string str (in the current language) matches the regular expression regex. (gdb) help function _streq $_streq - check string equality Usage: $_streq(a, b) Returns: True if a and b are identical strings in the current language. Example (amd64-linux): catch syscall open cond $bpnum $_streq((char*) $rdi, "foo") (gdb) help function _strlen $_strlen - compute string length Usage: $_strlen(a) Returns: Length of string a, assumed to be a string in the current language. -------------------------------------------------------------------------- 这批内置函数可能因内存访问违例而导致GDB断下来,比如: b *0x1F0482BC if $_strlen((char*)$r0)==40 Python Exception Cannot access memory at address 0x1f085224: Error in testing breakpoint condition: Error occurred in Python convenience function: Cannot access memory at address 0x1f085224 0x1f085224: 此时可以尝试"set unwindonsignal on",让GDB继续。不过这样干,会错失一些命中。 -------------------------------------------------------------------------- (gdb) help set unwindonsignal Set unwinding of stack if a signal is received while in a call dummy. The unwindonsignal lets the user determine what gdb should do if a signal is received while in a function called from gdb (call dummy). If set, gdb unwinds the stack and restore the context to what as it was before the call. The default is to stop in the frame where the signal was received. off(default) GDB remains in the frame where the signal was received. on GDB has restored the context to what it was before the call. -------------------------------------------------------------------------- Q: 意外发现$_regex()的逻辑不是grep的逻辑 (gdb) p $_regex("scz", "sc") $1 = 1 (gdb) p $_regex("scz", "cz") $2 = 0 A: scz 2023-06-02 (gdb) help function _regex $_regex - check if a string matches a regular expression. Usage: $_regex (STRING, REGEX) Returns: True if string STRING (in the current language) matches the regular expression REGEX. https://sourceware.org/gdb/onlinedocs/gdb/Convenience-Funs.html 若正则匹配成功,$_regex返回1,否则返回0。上文说正则表达式用Python支持的语 法,这得看$_regex()的具体实现才能解释现象。 (gdb) python import sys;print(sys.path) ['/usr/share/gdb/python', ...] $ dpkg -L gdb | grep function /usr/share/gdb/python/gdb/function /usr/share/gdb/python/gdb/function/__init__.py /usr/share/gdb/python/gdb/function/as_string.py /usr/share/gdb/python/gdb/function/caller_is.py /usr/share/gdb/python/gdb/function/strfns.py $ grep -RI "\$_regex" /usr/share/gdb/python /usr/share/gdb/python/gdb/function/strfns.py:"""$_memeq, $_strlen, $_streq, $_regex""" /usr/share/gdb/python/gdb/function/strfns.py: """$_regex - check if a string matches a regular expression. /usr/share/gdb/python/gdb/function/strfns.py: Usage: $_regex (STRING, REGEX) https://ftp.gnu.org/gnu/gdb/ https://github.com/bminor/binutils-gdb/blob/master/gdb/python/lib/gdb/function/strfns.py strfns.py中有$_regex()具体实现 -------------------------------------------------------------------------- class _RegEx(gdb.Function): """$_regex - check if a string matches a regular expression. Usage: $_regex (STRING, REGEX) Returns: True if string STRING (in the current language) matches the regular expression REGEX.""" def __init__(self): super(_RegEx, self).__init__("_regex") def invoke(self, string, regex): s = string.string() r = re.compile(regex.string()) return bool(r.match(s)) _RegEx() -------------------------------------------------------------------------- 从中看出,$_regex()用了re.match(),后者的官方说明是 -------------------------------------------------------------------------- re.match(pattern, string, flags=0) If zero or more characters at the beginning of string match the regular expression pattern, return a corresponding match object. Return None if the string does not match the pattern. Note that even in MULTILINE mode, re.match() will only match at the beginning of the string and not at the beginning of each line. If you want to locate a match anywhere in string, use search() instead (see also search() vs. match()). -------------------------------------------------------------------------- re.match()从字符串首部开始正则匹配,常规grep不是这样。为了用re.match()检查 字符串尾部,必须让正则表达式能匹配字符串首部。 -------------------------------------------------------------------------- >>> import re >>> print(re.match("sc", "scz")) >>> print(re.match("cz", "scz")) None >>> print(re.match(".*cz", "scz")) -------------------------------------------------------------------------- 回到gdb的$_regex(),同样遵循re.match()的逻辑 (gdb) p $_regex("scz", ".*cz") $3 = 1