gdb是用于调试C程序的一种工具,一般包含在gcc工具链中,
常用于调试用gcc -g编译的可执行文件。
1. 断点命令列表
gdb支持断点命令列表,即在断点发生时执行一连串命令。
如果断点命令列表中包含cont(continue的缩写),
则其行为很像OllyDbg的日志断点。
不过,gdb断点命令列表是针对带源码的程序调试,
而OllyDbg则是汇编级的。
例如,如果我用-g开关编译lua(Windows下用MinGW,Linux下用gcc)
把CC=gcc
改为CC= gcc -g
并且注释掉#$(RANLIB) $@
然后用gdb尝试对llex.c文件的llex静态函数进行断点并输出其参数ls的地址。
可以先写一个gdb脚本(保存为gdbinit.txt):
# # 编译lua时修改Makefile使用-g开关 # CC= gcc -g # 并且注释掉#$(RANLIB) $@ # # 测试平台: # 1. GNU gdb 6.3 for MinGW # 2. GNU gdb (GDB) 7.1-ubuntu # # 启动命令行: # gdb --command=gdbinit.txt --quiet ./lua # # see # http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_node/gdb_34.html # Breakpoint command lists b llex.c:llex commands silent printf "ls is %p\n", ls cont end # see # gdb-6.3\gdb\windows-nat.c # Linux下需要注释掉 set debugevents off set debugexceptions off # set args -e "print('hello, world')" run -e "print('hello, world')" quit
这里指定了一个命令列表,然后用
-e "print('hello, world')"
参数执行lua脚本。
其中,如果用Ubuntu的gdb,则删除以下两句
set debugevents off set debugexceptions off
然后执行
--command用于指定前面提到的那个gdbinit脚本
则输出如下信息:
Breakpoint 1 at 0x40a794: file llex.c, line 333.
ls is 0022FB50
ls is 0022FB50
ls is 0022FB50
ls is 0022FB50
ls is 0022FB50
hello, world
Program exited normally.
可以看到lua在解析执行
时,执行了5次llex,每次的ls指针都是相同的。
这里还可以使用更复杂的表达式,然后用gdb自带的printf输出到控制台上。
20120411补注:
网上有许多写得很复杂的gdb脚本,例如这个:
https://github.com/mkottman/lua-gdb-helper
可以参考,不过我自己没有测试过。
----------------------
2. 基于二进制地址的断点设置(仅适用于mingw带源码编译的调试版exe)
如果用mingw编译的exe,可以用nm命令查找符号所在地址。
用这种方法,不需要指定函数所在的文件名。
$ nm ./lua.exe | grep llex
0040a780 t _llex
然后在gdb中设置这个地址
(gdb) b *0x40a780
Breakpoint 1 at 0x40a780: file llex.c, line 332.
3. 用gcc工具链查找函数(包括系统API)引用(仅适用于mingw带源码编译的调试版exe)
如果要查找所有调用llex的地址,可以使用objdump进行反编译
$ objdump -d ./lua.exe | grep call | grep llex
40b14b: e8 30 f6 ff ff call 40a780 <_llex>
40b179: e8 02 f6 ff ff call 40a780 <_llex>
可以看到调用llex函数的地方有两个:0x40b14b和0x40b179。
还可以用addr2line转换为可读的函数名。
$ objdump -d ./lua.exe | grep call | grep llex | addr2line -f -e ./lua.exe
luaX_next
D:/java/home/Administrator/testgprof/lua-5.1.4/src/llex.c:453
luaX_lookahead
D:/java/home/Administrator/testgprof/lua-5.1.4/src/llex.c:459
可以看到引用llex的函数是luaX_next和luaX_lookahead。
利用上面查找到的地址,
用b *0x40b14b和b *0x40b179在gdb中添加断点。
用这种方法可以实现类似API断点的效果
(例如把断点设置在所有使用fprintf的地方)
$ objdump -d ./lua.exe | grep call | grep fprintf
4013de: e8 6d 1a 02 00 call 422e50 <_fprintf>
4013fb: e8 50 1a 02 00 call 422e50 <_fprintf>
40208d: e8 be 0d 02 00 call 422e50 <_fprintf>
405bad: e8 9e d2 01 00 call 422e50 <_fprintf>
414ed2: e8 79 df 00 00 call 422e50 <_fprintf>
41e6d6: e8 cd 49 00 00 call 4230a8 <_vfprintf>
4. 用OllyDbg确定API引用的地址
确定API引用的地址,有助于用断点使程序尽可能停在执行该API之前。
以OllyDbg 1.10为例,要调试的exe为testbp.exe
1) 如果OllyDbg的标题栏显示此时CPU窗口显示的是exe所在的模块
标题应该是:
OllyDbg - testbp.exe -[CPU - module testbp]
如果标题是:
OllyDbg - testbp.exe -[CPU - module kernel32]
需要切换回exe所在模块:
CPU->右键->View->View->Module testbp
2) 查找导入API函数的引用位置
CPU->右键->Search for->Name (Label) in current module (Ctrl+N)
弹出Names in testbp列表一般很长,可以粘贴出来查找。
如果对
KERNEL32.OutputDebugStringA
感兴趣,那么
选中->右键->Find references to import
则弹出一个引用列表,显示该API在反编译后被引用的所有地址
(如果API的地址不是动态获取的)。
3) 查看某个地址附近的指令
有时用工具知道大概要关心的地址,可以在
CPU->右键->Go to->Expression
输入地址(可忽略0x前缀)跳转到相应位置。
CPU->右键->Go to->Previous procedure
跳转到当前地址之前最近的过程入口点(相当于函数入口,一般标有$)。
4) 列出交叉引用表(call <...>)
CPU->右键->Search for->All intermodular calls
和1, 2的做法差不多,也可用于下API断点或日志断点。
5. 用IDA Pro确定API引用的地址
View->Open subviews->Imports
(或View->Open subviews->Names,列出所有模块的符号,
或View->Open subviews->Functions,列出所有方法)
选中感兴趣的API如fprintf(或Search->Search...查找字符串)
双击跳到IDA View A视图
然后用鼠标把光标移到
.idata:0042A390 ; int fprintf(FILE *File, const char *Format, ...)
的fprintf
右键->Jump to xref to operand... X
打开交叉引用列表,列出所有引用fprintf函数的相对地址。
如果要查看绝对地址,需要双击跳转。
6. 无源码的内存查看(类似OllyDbg的log breakpoint)
用gcc编译的可执行文件(包括exe)可以用命令列表实现日志断点(立刻恢复的断点)。
但是,即便无源码,也可以通过直接读取内存,或通过寄存器的指针值读取内存。
例如,
用OllyDbg依附mysqld后步进调试,(不能打开Handle窗口,OllyDbg会崩溃)
发现mysqld在执行到0x0045da00地址时ebx指向一个字符串,
是网络接收到的命令(不带末尾的分号),可以用如下gdb命令查看此时的字符串值
(gdb) attach 7820
(gdb) b *0x0045da00
(gdb) c
(gdb) i r
(gdb) p $ebx
(gdb) x/s $ebx
(gdb) printf "%s\n", $ebx
每当mysqld接收到字符串时,执行到0x0045da00处会被gdb中断,
然后可以通过x/s $ebx或printf "%s\n", $ebx输出接收到的字符串。
x表示读内存,ebx作为寄存器,必须带$前缀,s表示数据类型为字符串。
用这种方法结合命令列表可实时输出mysqld通过recv调用获取的字符串内容。
7. 产生core核心转储文件,分析堆栈回溯和其它运行时信息(主要用于linux)(对于win32的mingw,见第8项)
(1) 用ulimit和kill生成core文件
这种方法会中止进程,但可以查看较详细的堆栈回溯信息。
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 20
file size (blocks, -f) unlimited
pending signals (-i) 16382
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) unlimited
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
$ ulimit -c unlimited
$ ./lua
(注意,ulimit只对当前会话有效)
$ ps -a | grep lua
19950 pts/0 00:00:00 lua
$ kill -6 19950
(kill -6是Aborted,kill -11是Segmentation fault)
$ ls | grep core
core
$ gdb ./lua ./core
(gdb) bt
(2) 强制生成core文件
这种方法不中止进程,但堆栈回溯信息不详。
$ ps -a | grep lua
19678 pts/0 00:00:00 lua
$ gcore 19678
0x00ef9422 in __kernel_vsyscall ()
Saved corefile core.19678
$ gdb ./lua ./core.19678
(20140126补充:)
8.win32 mingw gdb的attach调试(相当于linux的core转储,用于判断程序卡在哪个位置),
(1)用-g3 -O0参数编译程序。
(2)如果程序会崩溃的话,直接用gdb启动程序(run命令)即可,不需要用attach命令,gdb会自动暂停,用bt命令可看到后退回溯(backtrace)。
(3)否则,可以尝试用attach(相当于上面的core转储)
首先,不用gdb直接启动程序,然后通过任务管理器查询到进程号(通常是4位整数),然后在合适的时候手动执行attach:
(gdb) attach <进程号>
然后列举线程
(gdb) info threads
切换线程(t=thread命令)
(gdb) thread <线程编号>
打印后退回溯(bt=backtrace命令)
(gdb) bt
通常主线程在thread 1上,但有可能会看不到bt,如果是这样需要暂停多次(退出后在合适的时候重新执行attach命令)。
如果仍无法看到bt,可以考虑用breakpoint方法(这个更需要技巧确定断在什么位置)
(gdb) b <文件名>:<行号>
删除breakpoint。
(gdb) info break
(gdb) remove <断点序号>
(TODO)
------------------------
参考资料:
1. Debugging Mozilla with gdb
https://developer.mozilla.org/en/Debugging_Mozilla_on_Linux_FAQ
4. eglog
5. Digital Travesia
http://hp.vector.co.jp/authors/VA028184/
6. GDB 多线程调试
http://www.yuanma.org/data/2009/0407/article_3605.htm
http://www.linuxforum.net/forum/gshowflat.php?Cat=&Board=program&Number=692404&page=0&view=collapsed
http://www.ibm.com/developerworks/cn/java/j-memoryanalyzer/
7. DLL劫持技术(内存补丁技术) (转)
http://hi.baidu.com/woaiwlaopo/blog/item/699f2a3fb0485ee954e7238d.html
8. gdb的一些命令
http://blog.sinzy.net/ifyr/entry/22198
9. Windows API Hooking Tutorial
http://ruffnex.oc.to/kenji/text/api_hook/
10. Visual Novel tools
(其它,游戏提取,与上述内容无关。。。)
11. Welcome to m-akita's Home Page
http://m-akita.sakura.ne.jp/index.php
12. asmodean's reverse engineering page - news and updates
13. VN Translation
http://tlwiki.tsukuru.info/index.php?title=Tools
14. notazsite
http://anime.geocities.jp/notazsite1/soft/index.html
Irregular child .. ?
http://hp.vector.co.jp/authors/VA018359/index2.html
(20130715)
15. 混沌の部屋
http://www.geocities.jp/hoku_hoshi/index2.html
(20150528)
16. 【教材】用OllyDbg找出Agth提取GAL文本的特殊码(详细新人版)
http://867258173.diandian.com/post/2014-02-12/40060970396
相关推荐
【linux学习笔记-1】使用GDB调试简单的用户程序 【linux学习笔记-2】父子进程共享文件描述符 【linux学习笔记-3】文件操作(stat,chmod,umask) 【linux学习笔记-4】进程扇和进程链 【linux学习笔记-5】编写自己的ls...
根据提供的文件内容,以下是对Go语言学习笔记的详细知识点阐述。 Go语言是Google开发的一种静态类型、编译型、并发型,并具有垃圾回收功能的编程语言。它由Robert Griesemer、Rob Pike和Ken Thompson于2007年9月...
【linux学习笔记-1】使用GDB调试简单的用户程序.doc 【linux学习笔记-2】父子进程共享文件描述符.doc 【linux学习笔记-3】文件操作(stat,chmod,umask).doc 【linux学习笔记-4】进程扇和进程链.doc 【linux学习笔记-...
Go语言,又称Golang,是一种静态类型的编程语言,由Google开发,于2007年首次对外公布,并在2009年进行了...通过本学习笔记的内容,我们可以对Go语言有一个全面而系统的认识,为深入学习和应用Go语言打下坚实的基础。
### gdb调试器命令学习总结 #### 一、简介 GDB (GNU Debugger) 是Linux下的一款强大而灵活的调试工具,适用于C/C++程序的调试。通过GDB,开发人员可以轻松地设置断点、单步执行代码、监控变量值等,从而帮助他们...
在学习笔记的附录部分,编者还添加了对Go工具集的介绍,比如条件编译、跨平台编译、调试工具GDB的使用,以及Go测试相关知识,包括单元测试、数据竞争测试、基准测试和代码覆盖率测试。 总的来说,Go语言学习笔记...
本文档主要记录了 Linux 操作系统的学习笔记,涵盖了 Basic 的编程、VI 编辑器的使用、GCC 编译器的应用、GDB 调试工具的使用等方面的知识点。 一、编程基础 * 了解 C 语言的基本语法,例如变量声明、数据类型、...
这份"C++学习笔记"涵盖了C++的基础到高级概念,旨在帮助初学者和有一定经验的程序员深入理解并掌握C++。 在C++的学习过程中,以下几个关键知识点是不可或缺的: 1. **基础语法**:C++起源于C语言,因此它保留了...
Go 学习笔记, 第 4 版 4.4 Struct 47 第 5 章 ⽅法 53 5.1 ⽅法定义 53 5.2 匿名字段 54 5.3 ⽅法集 56 5.4 表达式 56 第 6 章 接⼝ 60 6.1 接⼝定义 60 6.2 执⾏机制 62 6.3 接⼝转换 63 6.4 接⼝技巧 65 第 7 章 ...
学习笔记可能涵盖了如何开发自定义插件、编写脚本,以及使用调试工具如GDB进行问题排查。 8. **安全与隐私保护**: 如何通过OpenWrt设置安全策略,包括加密无线网络、限制非法访问、防止DDoS攻击等。 9. **故障...
《新手C++学习笔记》是一份专为编程初学者打造的资源,旨在帮助那些刚刚踏入C++编程领域的“菜鸟”快速成长。这份笔记包含了前辈们的实践经验总结,具有很高的学习价值。文档以.doc格式存储,方便读者使用常见的文字...
Go 语言编程 + Go 学习笔记, 第 部分 语 第 1 章 类型 1.1 变量 1.2 常量 1.3 基本类型 1.4 引 类型 1.5 类型转换 1.6 字符串 1.7 指针 1.8 定义类型 第 2 章 表达式 2.1 保留字 2.2 运算符 2.3 初始化 2.4 控制流 ...
《雨痕golang学习笔记第四版 加上书签版》是针对Go语言学习者的参考资料,作者雨痕在书中详细记录了从2012年开始学习Go语言至今的经验与成果。本书内容全面,涵盖了Go语言的基础知识、数据结构、函数特性、并发编程...
Go+学习笔记中还介绍了各种工具的使用,如命令行工具、GDB调试、条件编译、跨平台编译、程序测试和开发工具等,这些都是提升开发效率和程序质量的重要工具。 进阶部分则包含了Go语言运行时的深入探讨、内存分配和...
这篇学习笔记将带你走进ARM汇编的世界,理解其基本概念,掌握指令集,并学会如何在实际应用中运用。 一、ARM架构概述 ARM(Advanced RISC Machines)架构是一种广泛应用于移动设备、嵌入式系统和个人电脑的精简指令...
【Java学习笔记】 Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems开发,现在由甲骨文公司维护。它的设计目标是提供平台无关性,这意味着Java编写的代码可以在任何支持Java虚拟机(JVM)的设备上运行...
我自己做了一些C++学习笔记,包括cmake、gdb、“剑指优惠”、“努力的C++”、“C++入门”、“现代C++语言核心特性的详细说明”,以及一些个人总结。我希望它们对初学者有帮助
### GCC 学习笔记知识点详解 #### 一、GCC简介与版本检查 - **GCC**(GNU Compiler Collection)是一款开源的编译器集合,广泛应用于Linux等类Unix系统上,支持多种编程语言如C、C++等。 - **版本检查**: - 要...
根据提供的文件信息,本文主要讨论Go语言的学习笔记内容,涵盖了Go语言的基础知识到一些高级特性的介绍。以下是具体的知识点分析: 1. **基础语法**: - **变量定义与初始化**:Go语言使用关键字`var`来定义变量,...