过段时间可能要逆向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 0x4006f6
Dump 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 args
argc = 1
argv = 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 10

int 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 \
    -g

BIN = test_gdb_no_source_debug

INC = -I. 

LIBS = -lstdc++ \
    -pthread 

LIBPATH = /usr/local/lib

SUBDIR = $(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_output

clean:
    clear
    @echo make clean
    rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)
    ls -l

all:$(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 all

only_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 main
Line 14 of "main.cpp" starts at address 0x4006f6 <main(int, char**)> and ends at 0x400705 <main(int, char**)+15>.

从main函数开始反汇编,看看应该在哪个地址下断点

(gdb) disassemble 0x4006f6
Dump 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 args
argc = 1
argv = 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调试器的使用资料

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

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐