`

gdb学习笔记

 
阅读更多

gdb是用于调试C程序的一种工具,一般包含在gcc工具链中,

常用于调试用gcc -g编译的可执行文件。

 

1. 断点命令列表

gdb支持断点命令列表,即在断点发生时执行一连串命令。

如果断点命令列表中包含cont(continue的缩写),

则其行为很像OllyDbg的日志断点。

不过,gdb断点命令列表是针对带源码的程序调试,

而OllyDbg则是汇编级的。

 

例如,如果我用-g开关编译lua(Windows下用MinGW,Linux下用gcc)

 

 

修改Makefile,
把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

 

 

 然后执行

 

 

$ gdb --command=gdbinit.txt --quiet ./lua

 

 

--command用于指定前面提到的那个gdbinit脚本

则输出如下信息:

 

 

$ gdb --command=gdbinit.txt --quiet ./lua
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在解析执行

 

 

"print('hello, world')"

 时,执行了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

 

2. mingw 下的 stack backtrace
 
3. 使用 Strace 和 GDB 调试工具的乐趣

 

4. eglog

http://gorry.haun.org/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

http://vn.i-forge.net/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

http://asmodean.reverse.net/

 

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学习笔记

    【linux学习笔记-1】使用GDB调试简单的用户程序 【linux学习笔记-2】父子进程共享文件描述符 【linux学习笔记-3】文件操作(stat,chmod,umask) 【linux学习笔记-4】进程扇和进程链 【linux学习笔记-5】编写自己的ls...

    Go 学习笔记 高清

    根据提供的文件内容,以下是对Go语言学习笔记的详细知识点阐述。 Go语言是Google开发的一种静态类型、编译型、并发型,并具有垃圾回收功能的编程语言。它由Robert Griesemer、Rob Pike和Ken Thompson于2007年9月...

    Linux学习笔记Linux学习资料Linux教程

    【linux学习笔记-1】使用GDB调试简单的用户程序.doc 【linux学习笔记-2】父子进程共享文件描述符.doc 【linux学习笔记-3】文件操作(stat,chmod,umask).doc 【linux学习笔记-4】进程扇和进程链.doc 【linux学习笔记-...

    Go 学习笔记——雨痕

    Go语言,又称Golang,是一种静态类型的编程语言,由Google开发,于2007年首次对外公布,并在2009年进行了...通过本学习笔记的内容,我们可以对Go语言有一个全面而系统的认识,为深入学习和应用Go语言打下坚实的基础。

    gdb调试器命令学习总结笔记

    ### gdb调试器命令学习总结 #### 一、简介 GDB (GNU Debugger) 是Linux下的一款强大而灵活的调试工具,适用于C/C++程序的调试。通过GDB,开发人员可以轻松地设置断点、单步执行代码、监控变量值等,从而帮助他们...

    Go语言学习笔记

    在学习笔记的附录部分,编者还添加了对Go工具集的介绍,比如条件编译、跨平台编译、调试工具GDB的使用,以及Go测试相关知识,包括单元测试、数据竞争测试、基准测试和代码覆盖率测试。 总的来说,Go语言学习笔记...

    linux学习笔记.pdf

    本文档主要记录了 Linux 操作系统的学习笔记,涵盖了 Basic 的编程、VI 编辑器的使用、GCC 编译器的应用、GDB 调试工具的使用等方面的知识点。 一、编程基础 * 了解 C 语言的基本语法,例如变量声明、数据类型、...

    C++ 学习笔记 整理

    这份"C++学习笔记"涵盖了C++的基础到高级概念,旨在帮助初学者和有一定经验的程序员深入理解并掌握C++。 在C++的学习过程中,以下几个关键知识点是不可或缺的: 1. **基础语法**:C++起源于C语言,因此它保留了...

    Go学习笔记(第四版).zip

    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 章 ...

    openwrt深入学习笔记.zip

    学习笔记可能涵盖了如何开发自定义插件、编写脚本,以及使用调试工具如GDB进行问题排查。 8. **安全与隐私保护**: 如何通过OpenWrt设置安全策略,包括加密无线网络、限制非法访问、防止DDoS攻击等。 9. **故障...

    新手C++学习笔记(仅供菜鸟成长参考).rar

    《新手C++学习笔记》是一份专为编程初学者打造的资源,旨在帮助那些刚刚踏入C++编程领域的“菜鸟”快速成长。这份笔记包含了前辈们的实践经验总结,具有很高的学习价值。文档以.doc格式存储,方便读者使用常见的文字...

    Go 语言编程 + Go 学习笔记

    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学习笔记第四版 加上书签版

    《雨痕golang学习笔记第四版 加上书签版》是针对Go语言学习者的参考资料,作者雨痕在书中详细记录了从2012年开始学习Go语言至今的经验与成果。本书内容全面,涵盖了Go语言的基础知识、数据结构、函数特性、并发编程...

    Go+学习笔记

    Go+学习笔记中还介绍了各种工具的使用,如命令行工具、GDB调试、条件编译、跨平台编译、程序测试和开发工具等,这些都是提升开发效率和程序质量的重要工具。 进阶部分则包含了Go语言运行时的深入探讨、内存分配和...

    ARM 汇编学习笔记

    这篇学习笔记将带你走进ARM汇编的世界,理解其基本概念,掌握指令集,并学会如何在实际应用中运用。 一、ARM架构概述 ARM(Advanced RISC Machines)架构是一种广泛应用于移动设备、嵌入式系统和个人电脑的精简指令...

    java、linux、Android 学习笔记

    【Java学习笔记】 Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems开发,现在由甲骨文公司维护。它的设计目标是提供平台无关性,这意味着Java编写的代码可以在任何支持Java虚拟机(JVM)的设备上运行...

    我自己做了一些C++学习笔记,包括cmake、gdb、“剑指优惠”、“努力的

    我自己做了一些C++学习笔记,包括cmake、gdb、“剑指优惠”、“努力的C++”、“C++入门”、“现代C++语言核心特性的详细说明”,以及一些个人总结。我希望它们对初学者有帮助

    GCC 学习 笔记GCC学习笔记

    ### GCC 学习笔记知识点详解 #### 一、GCC简介与版本检查 - **GCC**(GNU Compiler Collection)是一款开源的编译器集合,广泛应用于Linux等类Unix系统上,支持多种编程语言如C、C++等。 - **版本检查**: - 要...

    Go 学习笔记第四版

    根据提供的文件信息,本文主要讨论Go语言的学习笔记内容,涵盖了Go语言的基础知识到一些高级特性的介绍。以下是具体的知识点分析: 1. **基础语法**: - **变量定义与初始化**:Go语言使用关键字`var`来定义变量,...

Global site tag (gtag.js) - Google Analytics