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调试倒是很方便,不过查看变量时,也是各种不舒服。

原创粉丝点击