调试环境搭建

设备

KALI

Android 10

NDK clang(编译器)

NDK配置

ndk下载:https://developer.android.google.cn/ndk/downloads/

ndk clang环境变量

1

# ndk clang 配置

2

PATH="/root/Desktop/desktop_soft/ndk/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin:${PATH}"

3

export PATH

4

alias clang="/root/Desktop/desktop_soft/ndk/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang"

5

alias clang2="/usr/bin/clang"

ARM32可执行文件

ndk交叉编译

https://developer.android.com/ndk/guides/other_build_systems

1

- 预处理

2

3

> -E Only run the preprocessor

4

> clang -target armv7a-linux-androideabi21 -E kingsun.c -o kingsun.i

5

6

- 汇编

7

8

> -S Only run preprocess and compilation steps

9

> clang -target armv7a-linux-androideabi21 -S kingsun.i -o kingsun.s

10

11

- 编译

12

13

> -c Only run preprocess, compile, and assemble steps

14

> clang -target armv7a-linux-androideabi21 -c kingsun.s -o kingsun.o

15

16

- 链接

17

18

>clang -target armv7a-linux-androideabi21 kingsun.o -o kingsun

tool.sh

1

clang -target armv7a-linux-androideabi21 -E kingsun.c -o kingsun.i

2

clang -target armv7a-linux-androideabi21 -S kingsun.i -o kingsun.s

3

clang -target armv7a-linux-androideabi21 -c kingsun.s -o kingsun.o

4

clang -target armv7a-linux-androideabi21 kingsun.o -o kingsun

运行tool.sh,生成对应的文件

GDB安装

安装GDB

apt install gdb-multiarch

下载安装GEF

https://github.com/hugsy/gef

bash -c "$(curl -fsSL http://gef.blah.cat/sh)"

导入GDBSERVER

找到对应的gdbserver版本,push到手机中

1

adb push gdbserver /data/local/tmp

2

chmod 777 gdbserver

导入可执行文件kingsun

1

adb push kingsun /data/local/tmp/kingsun

2

adb shell chmod +x /data/local/tmp/kingsun

3

adb shell /data/local/tmp/kingsun

GDBSERVER启动可执行文件kingsun

gdbserver :prot process

./gdbserver :11111 kingsun 

ADB端口转发

adb forward tcp:11111 tcp:11111 

GDB CLIENT

gdb-multiarch

gef-remote host:port

gef-remote localhost:11111 

GDB调试

b下断点

b main 

c继续

地址断点

b *0xaaaab418

disassemble main

hexdump byte 0xaaaab418

kingsun.s汇编解释

1

    .text

2

    .syntax unified

3

    .file    "kingsun.c"

4

    .globl    main @ -- Begin function main

5

    .p2align    2

6

    .type    main,%function

7

    .code    32 @ @main

8

main:

9

    .fnstart

10

@ %bb.0:

11

    push    {r11, lr}    // PUSH 从右至左将寄存器数据依次压入栈中

12

    mov    r11, sp            // MOV 赋值指令 r11 = sp, 将SP寄存器的值放入R11寄存器中

13

    sub    sp, sp, #8        // SUB 减法指令 sp = sp - 8

14

    movw    r0, #0        // MOVW 赋值指令 只影响16位(2字节) r0 = 0

15

    str    r0, [sp, #4]    // STR 数据存储指令 将R0寄存器的值放入 SP + 4的位置

16

    ldr    r0, .LCPI0_0    // LDR 数据取出指令 将

17

.LPC0_0:

18

    add    r0, pc, r0        // ADD 加法指令 r0 = pc + r0

19

    bl    printf            // BL 函数调用

20

    movw    r0, #0

21

    mov    sp, r11

22

    pop    {r11, pc}        // POP 将栈中的数据取出依次从左至右赋值给寄存器

23

    .p2align    2

24

@ %bb.1:

25

.LCPI0_0:

26

    .long    .L.str-(.LPC0_0+8)

27

.Lfunc_end0:

28

    .size    main, .Lfunc_end0-main

29

    .cantunwind

30

    .fnend

31

@ -- End function

32

    .type    .L.str,%object @ @.str

33

    .section    .rodata.str1.1,"aMS",%progbits,1

34

.L.str:

35

    .asciz    "Hello, World!n"

36

    .size    .L.str, 12

37

38

    .ident    "Android (7714059, based on r416183c1) clang version 12.0.8 (https://android.googlesource.com/toolchain/llvm-project c935d99d7cf2016289302412d708641d52d2f7ee)"

39

    .section    ".note.GNU-stack","",%progbits

gdb基本使用命令

参考:linux下gdb调试方法与技巧整理

运行命令

run:简记为 r ,其作用是运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步的命令。

continue (简写c ):继续执行,到下一个断点处(或运行结束)

next:(简写 n),单步跟踪程序,当遇到函数调用时,也不进入此函数体;此命令同 step 的主要区别是,step 遇到用户自定义的函数,将步进到函数中去运行,而 next 则直接调用函数,不会进入到函数体内。

step (简写s):单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的

until:当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。

until+行号: 运行至某行,不仅仅用来跳出循环

finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。

call 函数(参数):调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)

quit:简记为 q ,退出gdb

设置断点

break n (简写b n):在第n行处设置断点

(可以带上代码路径和代码名称: b OAGUPDATE.cpp:578)

b fn1 if a>b:条件断点设置

break func(break缩写为b):在函数func()的入口处设置断点,如:break cb_button

delete 断点号n:删除第n个断点

disable 断点号n:暂停第n个断点

enable 断点号n:开启第n个断点

clear 行号n:清除第n行的断点

info b (info breakpoints) :显示当前程序的断点设置情况

delete breakpoints:清除所有断点:

查看源码

list :简记为 l ,其作用就是列出程序的源代码,默认每次显示10行。

list 行号:将显示当前文件以“行号”为中心的前后10行代码,如:list 12

list 函数名:将显示“函数名”所在函数的源代码,如:list main

list :不带参数,将接着上一次 list 命令的,输出下边的内容。

打印表达式

print 表达式:简记为 p ,其中“表达式”可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,那么“表达式”可以是任何C语言的有效表达式,包括数字,变量甚至是函数调用。

print a:将显示整数 a 的值

print ++a:将把 a 中的值加1,并显示出来

print name:将显示字符串 name 的值

print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数

print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数

display 表达式:在单步运行时将非常有用,使用display命令设置一个表达式后,它将在每次单步进行指令后,紧接着输出被设置的表达式及值。如: display a

watch 表达式:设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如: watch a

whatis :查询变量或函数

info function: 查询函数

扩展info locals: 显示当前堆栈页的所有变量

查看运行信息

where/bt :当前运行的堆栈列表;

bt backtrace 显示当前调用堆栈

up/down 改变堆栈显示的深度

set args 参数:指定运行时的参数

show args:查看设置好的参数

info program: 来查看程序的是否在运行,进程号,被暂停的原因。

分割窗口

layout:用于分割窗口,可以一边查看代码,一边测试:

layout src:显示源代码窗口

layout asm:显示反汇编窗口

layout regs:显示源代码/反汇编和CPU寄存器窗口

layout split:显示源代码和反汇编窗口

Ctrl + L:刷新窗口

cgdb强大工具

cgdb主要功能是在调试时进行代码的同步显示,这无疑增加了调试的方便性,提高了调试效率。界面类似vi,符合unix/linux下开发人员习惯;如果熟悉gdb和vi,几乎可以立即使用cgdb。