linux程序无源码调试的方法
来源:互联网 发布:win7精简优化版 编辑:程序博客网 时间:2024/05/22 13:43
序
过段时间可能要逆向linux上的cm, 先将调试方法做个实验, 将菜谱备好.
远程调试有2个方法:
*GDB在linux服务器上直接调试无源码的cm,这个调试起来比较繁琐,即使没有源码,也是按照C语言代码行进行的单步。寄存器值变的太突然,不好理解。
*在windows上用IDA6.8pro远程启动(或附加)调试linux服务器上的cm。这个可以直接单步反汇编代码, 可以通过单步,理解寄存器值的变化。
因为是做实验,我采用的是直接由调试器启动cm.
demo
在本地写好,上传到服务器,编译后,用Makefile中写好的命令,将输出之外文件(main.cpp, Makefile)都删掉, 模拟cm没有源码的实际场景。
demo实现1+..+N的值打印
// @file main.cpp// @brief test gdb debug the elf that no source// if debian OS not install gdb, please run below command to install gdb// apt-get install gdb// run below command to rebuild project// make rebuild// run below command to only stay output file// make only_stay_output// ================================================================================// gdb// ================================================================================// now can use gdb to debug ./test_gdb_no_source_debug without source code// gdb ./test_gdb_no_source_debug// gdb documentation below// http://www.gnu.org/software/gdb/documentation/// 如果命令只记得一部分, 用tab key 补齐命令// view main funtion addr, because main was export on this Makefile// (gdb) info line main// Line 14 of "main.cpp" starts at address 0x4006f6 <main(int, char**)> and ends at 0x400705 <main(int, char**)+15>.// view main's dasm code// (gdb) disassemble 0x4006f6/**(gdb) disassemble 0x4006f6Dump of assembler code for function main(int, char**): 0x00000000004006f6 <+0>: push %rbp 0x00000000004006f7 <+1>: mov %rsp,%rbp 0x00000000004006fa <+4>: sub $0x20,%rsp 0x00000000004006fe <+8>: mov %edi,-0x14(%rbp) 0x0000000000400701 <+11>: mov %rsi,-0x20(%rbp) 0x0000000000400705 <+15>: movq $0x0,-0x8(%rbp) 0x000000000040070d <+23>: movl $0x0,-0xc(%rbp) 0x0000000000400714 <+30>: mov $0x0,%edi 0x0000000000400719 <+35>: callq 0x4005f0 <time@plt> 0x000000000040071e <+40>: mov %eax,%edi 0x0000000000400720 <+42>: callq 0x4005e0 <srand@plt> 0x0000000000400725 <+47>: movl $0xa,-0xc(%rbp) 0x000000000040072c <+54>: mov -0xc(%rbp),%eax 0x000000000040072f <+57>: mov %eax,%edi 0x0000000000400731 <+59>: callq 0x400768 <Add1ToN(int)> 0x0000000000400736 <+64>: mov %rax,-0x8(%rbp) 0x000000000040073a <+68>: mov -0x8(%rbp),%rdx 0x000000000040073e <+72>: mov -0xc(%rbp),%eax 0x0000000000400741 <+75>: mov %eax,%esi 0x0000000000400743 <+77>: mov $0x400824,%edi 0x0000000000400748 <+82>: mov $0x0,%eax 0x000000000040074d <+87>: callq 0x400590 <printf@plt> 0x0000000000400752 <+92>: mov $0x400837,%edi 0x0000000000400757 <+97>: callq 0x4005b0 <puts@plt> 0x000000000040075c <+102>: callq 0x4005d0 <getchar@plt> 0x0000000000400761 <+107>: mov $0x0,%eax 0x0000000000400766 <+112>: leaveq 0x0000000000400767 <+113>: retq End of assembler dump.*/// set bp on main function's first code line// (gdb) break main// set bp on addr// (gdb) break *xxxxxxxx// e.g. (gdb) break *0x00000000004006F6// view bp was set// (gdb) info breakpoints// run until break on gdb// (gdb) run// when break on gdb, view main's parameter/**(gdb) info argsargc = 1argv = 0x7fffffffebc8*/// view current dasm code// (gdb) disassemble// step one dasm code line// (gdb) next// view register// (gdb) info registers eax// (gdb) info registers// (gdb) info all-registers// set register// (gdb) set $rax = 1// (gdb) set $rax += 1// (gdb) set $rax -= 1// view stack// (gdb) x/8x $rsp// execute C code line// (gdb) next// (gdb) step 1// quit gdb// (gdb)quit// 常见的就这么多了,如果还需要,就再去找// ================================================================================// DDD// ================================================================================// add one line append to /etc/apt/sources.list// deb http://ftp.hk.debian.org/debian sid main// do below// apt-get update// do below// apt-get install ddd// 更换介质:请把标有// “Debian GNU/Linux 7.5.0 _Wheezy_ - Official amd64 DVD Binary-1 20140426-13:37// 升级的还挺多的,下次玩ddd, 这次就用gdb#include <stdlib.h>#include <stdio.h>#include <time.h>long Add1ToN(int iN);#define MY_DEBUG#define NUM_N 10int main(int argc, char* argv[]){ long lSum = 0; int iN = 0; srand((int)time(NULL));#ifdef MY_DEBUG iN = NUM_N;#else iN = rand();#endif lSum = Add1ToN(iN); printf("Add1ToN(%d) = %ld\n", iN, lSum); printf("END, press any key to quit\n"); getchar(); return 0;}long Add1ToN(int iN){ long lRc = 1; if (iN > 1) { do { lRc += iN; } while (--iN > 1); } return lRc;}
# ==============================================================================# makefile# lostspeed 2017-06-24# ==============================================================================CC = g++CFLAGS = --std=c++11 \ -Wall \ -gBIN = test_gdb_no_source_debugINC = -I. LIBS = -lstdc++ \ -pthread LIBPATH = /usr/local/libSUBDIR = $(shell ls -d */)ROOTSRC = $(wildcard *.cpp)ROOTOBJ = $(ROOTSRC:.cpp=.o)SUBSRC = $(shell find $(SUBDIR) -name '*.cpp')SUBOBJ = $(SUBSRC:.cpp=.o)help: clear @echo make help @echo command list: @echo make clean @echo make all @echo make rebuild @echo make only_stay_outputclean: clear @echo make clean rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ) ls -lall:$(BIN) @echo make all ls -l$(BIN) : $(ROOTOBJ) $(SUBOBJ) $(CC) $(CFLAGS) -o $@ $^ -L$(LIBPATH) $(LIBS).cpp.o: $(CC) -c $(CFLAGS) $^ -o $@ $(INC)rebuild: make clean make allonly_stay_output: rm *.o rm *.cpp rm ./Makefile ls -l
GDB
上传工程到实验目录 : main.cpp , Makefile
编译程序 :make rebuild
只保留输出文件在实验目录 : make only_stay_output
开始实验时,目录下只有输出文件./test_gdb_no_source_debug
开始用GDB无源码调试demo
先确定main函数位置,也可以用IDA静态分析要下断点的地址。
(gdb) info line mainLine 14 of "main.cpp" starts at address 0x4006f6 <main(int, char**)> and ends at 0x400705 <main(int, char**)+15>.
从main函数开始反汇编,看看应该在哪个地址下断点
(gdb) disassemble 0x4006f6Dump of assembler code for function main(int, char**): 0x00000000004006f6 <+0>: push %rbp 0x00000000004006f7 <+1>: mov %rsp,%rbp 0x00000000004006fa <+4>: sub $0x20,%rsp 0x00000000004006fe <+8>: mov %edi,-0x14(%rbp) 0x0000000000400701 <+11>: mov %rsi,-0x20(%rbp) 0x0000000000400705 <+15>: movq $0x0,-0x8(%rbp) 0x000000000040070d <+23>: movl $0x0,-0xc(%rbp) 0x0000000000400714 <+30>: mov $0x0,%edi 0x0000000000400719 <+35>: callq 0x4005f0 <time@plt> 0x000000000040071e <+40>: mov %eax,%edi 0x0000000000400720 <+42>: callq 0x4005e0 <srand@plt> 0x0000000000400725 <+47>: movl $0xa,-0xc(%rbp) 0x000000000040072c <+54>: mov -0xc(%rbp),%eax 0x000000000040072f <+57>: mov %eax,%edi 0x0000000000400731 <+59>: callq 0x400768 <Add1ToN(int)> 0x0000000000400736 <+64>: mov %rax,-0x8(%rbp) 0x000000000040073a <+68>: mov -0x8(%rbp),%rdx 0x000000000040073e <+72>: mov -0xc(%rbp),%eax 0x0000000000400741 <+75>: mov %eax,%esi 0x0000000000400743 <+77>: mov $0x400824,%edi 0x0000000000400748 <+82>: mov $0x0,%eax 0x000000000040074d <+87>: callq 0x400590 <printf@plt> 0x0000000000400752 <+92>: mov $0x400837,%edi 0x0000000000400757 <+97>: callq 0x4005b0 <puts@plt> 0x000000000040075c <+102>: callq 0x4005d0 <getchar@plt> 0x0000000000400761 <+107>: mov $0x0,%eax 0x0000000000400766 <+112>: leaveq 0x0000000000400767 <+113>: retq End of assembler dump.
GDB反汇编出来是AT&T语法,和intel反汇编语法稍有不同(e.g. src,dst位置是倒的; 立即数有$前缀;寄存器值有%前缀;不用[reg+offset],而是用offset(%reg)…), 和intel反汇编语法虽然不同,但是可以看得懂。
挑出要下断点的地址,开始下断点
// set bp on addr
// (gdb) break *xxxxxxxx
// e.g. (gdb) break *0x00000000004006F6
对地址下断点,地址有*前缀。
(gdb) break *0x00000000004006F6
查看下好的断点列表
// view bp was set
// (gdb) info breakpoints
(gdb) info breakpoints
断点下好后,就可以跑了,直到断下为止
// run until break on gdb
// (gdb) run
(gdb) run
当程序断住后,可以查看程序的信息和反汇编代码了。
查看main函数入参
(gdb) info argsargc = 1argv = 0x7fffffffebc8
查看当前的反汇编
(gdb) disassemble
查看寄存器
// view register// (gdb) info registers eax// (gdb) info registers// (gdb) info all-registers
修改寄存器
// set register// (gdb) set $rax = 1// (gdb) set $rax += 1// (gdb) set $rax -= 1
查看栈
// view stack// (gdb) x/8x $rsp
单步或步入
// execute C code line// (gdb) next// (gdb) step 1
程序调试完成,就可以退出GDB
// quit gdb// (gdb)quit
很少玩x64调试,一直用OD玩x86,当断住时,想查看寄存器,各种不舒服。
以后多玩玩。
还可以用图形前端ddd, 不过apt-get时,看到要升级很多软件,怕实际调试时,有个GDB用就不错了。就没有继续做ddd的实验。
GDB调试器的使用资料
- gnu官方资料 http://www.gnu.org/software/gdb/documentation/
- CSDN上有好心人上传了”The Art of Debugging with GDB”。
IDA
在linux服务器上运行inux_serverx64
linux_serverx64位置 =>D:\Program Files (x86)\IDA 6.8\dbgsrv\linux_serverx64
将linux_serverx64上传到服务器任意目录运行,linux_serverx64开始等IDA来连接。
运行IDA连接服务器
先用IDA将demo分析好,形成test_gdb_no_source_debug.i64
打开IDA Pro (64-bit) => go
这时服务器上的demo已经在内存里加载好了
结合静态分析找好的地址,下断点,就可以开始调试了。
在IDA中调试demo时,用的是intel语法。
用着IDA调试倒是很方便,不过查看变量时,也是各种不舒服。
- linux程序无源码调试的方法
- APK程序Dex文件无源码调试方法讨论
- ok6410-第02篇-无jlink调试程序的方法
- WinDbg 调试无源码驱动方法
- WinDbg 调试无源码驱动方法
- WinDbg 调试 无源码 驱动 方法
- Linux 程序调试方法
- 嵌入式linux调试程序的一个方法
- Linux下Qt程序的调试方法
- Linux下程序的调试方法
- linux下的程序调试方法汇总
- linux下的程序调试方法汇总
- 调试程序的方法
- 无源码调试dex
- Linux下使用GDB调试程序的方法
- Linux下,使用GDB调试程序的方法
- linux gdb运行不下去的程序调试方法
- VS2010 调试基于ARM的linux程序方法
- android Toast设置弹框大小
- 《深入理解java虚拟机》读书笔记——GC与内存分配策略
- java实现二分查找法
- JNI(java Native Interface)linux下 java调用本地c函数
- java日历类和包装类的注意点
- linux程序无源码调试的方法
- VS2013/MFC编程入门之一
- 对python字符串操作的几种方法(函数)
- SpringBoot配置属性中文释义MVC(一)
- android调用系统的安装方法出现ActivityNotFoundException的异常
- 素数与丑数
- daloRADIUS中文2017年
- 面试题5_逆序输出单链表
- Python设计模式-命令模式