Reverve_gdb动态调试

Reverve

babyRE

首先用file观察一下文件类型,得到如下结果

babyRE: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b6bce514f549db35e9fd8c008199820644059859, not stripped

用ida64打开,观察伪代码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [rsp+0h] [rbp-20h]
  int v5; // [rsp+18h] [rbp-8h]
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i <= 181; ++i )
  {
    envp = (const char **)(*((unsigned __int8 *)judge + i) ^ 0xCu);
    *((_BYTE *)judge + i) ^= 0xCu;
  }
  printf("Please input flag:", argv, envp);
  __isoc99_scanf("%20s", &s);
  v5 = strlen(&s);
  if ( v5 == 14 && (unsigned int)judge(&s) )
    puts("Right!");
  else
    puts("Wrong!");
  return 0;
}

从这里可以得到,len(flag) = 14,jugde函数在ida64中不能访问,所以就要用gdb进行调试

gdb  babyRE  #启动调试

首先,看看main函数里面的所以东西,并确定各个东西的位置

disass main          #查看main函数汇编代码
Dump of assembler code for function main:
   0x0000000000400606 <+0>: push   rbp
   0x0000000000400607 <+1>: mov    rbp,rsp
   0x000000000040060a <+4>: sub    rsp,0x20
   0x000000000040060e <+8>: mov    DWORD PTR [rbp-0x4],0x0
   0x0000000000400615 <+15>:    jmp    0x400637 <main+49>
   0x0000000000400617 <+17>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040061a <+20>:    cdqe   
   0x000000000040061c <+22>:    movzx  eax,BYTE PTR [rax+0x600b00]  #调用judge
   0x0000000000400623 <+29>:    xor    eax,0xc   #12
   0x0000000000400626 <+32>:    mov    edx,eax
   0x0000000000400628 <+34>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040062b <+37>:    cdqe   
   0x000000000040062d <+39>:    mov    BYTE PTR [rax+0x600b00],dl  
   0x0000000000400633 <+45>:    add    DWORD PTR [rbp-0x4],0x1
   0x0000000000400637 <+49>:    cmp    DWORD PTR [rbp-0x4],0xb5
   0x000000000040063e <+56>:    jle    0x400617 <main+17>
   0x0000000000400640 <+58>:    mov    edi,0x400734
   0x0000000000400645 <+63>:    mov    eax,0x0
   0x000000000040064a <+68>:    call   0x4004d0 <printf@plt>
   0x000000000040064f <+73>:    lea    rax,[rbp-0x20]
   0x0000000000400653 <+77>:    mov    rsi,rax
   0x0000000000400656 <+80>:    mov    edi,0x400747
   0x000000000040065b <+85>:    mov    eax,0x0
   0x0000000000400660 <+90>:    call   0x400500 <__isoc99_scanf@plt> #输入(要输14位满,足right 条件)
   0x0000000000400665 <+95>:    lea    rax,[rbp-0x20]
   0x0000000000400669 <+99>:    mov    rdi,rax
   0x000000000040066c <+102>:   call   0x4004c0 <strlen@plt>   #长度
   0x0000000000400671 <+107>:   mov    DWORD PTR [rbp-0x8],eax
   0x0000000000400674 <+110>:   cmp    DWORD PTR [rbp-0x8],0xe  #14
   0x0000000000400678 <+114>:   jne    0x400698 <main+146>
   0x000000000040067a <+116>:   mov    edx,0x600b00    #移入judge
   0x000000000040067f <+121>:   lea    rax,[rbp-0x20]
   0x0000000000400683 <+125>:   mov    rdi,rax
   0x0000000000400686 <+128>:   call   rdx
   0x0000000000400688 <+130>:   test   eax,eax
   0x000000000040068a <+132>:   je     0x400698 <main+146>
   0x000000000040068c <+134>:   mov    edi,0x40074c
   0x0000000000400691 <+139>:   call   0x4004b0 <puts@plt>
   0x0000000000400696 <+144>:   jmp    0x4006a2 <main+156>
   0x0000000000400698 <+146>:   mov    edi,0x400753
   0x000000000040069d <+151>:   call   0x4004b0 <puts@plt>
   0x00000000004006a2 <+156>:   mov    eax,0x0
   0x00000000004006a7 <+161>:   leave  
   0x00000000004006a8 <+162>:   ret    
End of assembler dump.

现在我们在 scanf的位置设置断点,

b *0x400660    #b  --> break 设置断点
r           # r -->run  ,直接运行到断点处

得到下面,跳转下一步

n      #n-->next  下一步操作
Please input flag:qwertyuiopasdf  #后半部分是我输入的
 ► 0x400665 <main+95>     lea    rax, [rbp - 0x20]
   0x400669 <main+99>     mov    rdi, rax
   0x40066c <main+102>    call   strlen@plt <0x4004c0>

   0x400671 <main+107>    mov    dword ptr [rbp - 8], eax
   0x400674 <main+110>    cmp    dword ptr [rbp - 8], 0xe
   0x400678 <main+114>    jne    main+146 <0x400698>

   0x40067a <main+116>    mov    edx, judge <0x600b00>  #judge
   0x40067f <main+121>    lea    rax, [rbp - 0x20]
   0x400683 <main+125>    mov    rdi, rax
   0x400686 <main+128>    call   rdx

现在要进入judge里面看看它是如何进行判断的

b *0x600b00   #在judge处设置断点
c(ontinue)    #直接跳转到下一个断点

得到judge函数的内容:

 ► 0x600b00 <judge>       push   rbp
   0x600b01 <judge+1>     mov    rbp, rsp
   0x600b04 <judge+4>     mov    qword ptr [rbp - 0x28], rdi
   0x600b08 <judge+8>     mov    byte ptr [rbp - 0x20], 0x66
   0x600b0c <judge+12>    mov    byte ptr [rbp - 0x1f], 0x6d
   0x600b10 <judge+16>    mov    byte ptr [rbp - 0x1e], 0x63
   0x600b14 <judge+20>    mov    byte ptr [rbp - 0x1d], 0x64
   0x600b18 <judge+24>    mov    byte ptr [rbp - 0x1c], 0x7f
   0x600b1c <judge+28>    mov    byte ptr [rbp - 0x1b], 0x6b
   0x600b20 <judge+32>    mov    byte ptr [rbp - 0x1a], 0x37
   0x600b24 <judge+36>    mov    byte ptr [rbp - 0x19], 0x64  #数据无法显示,我分两个复制的
   0x600b28 <judge+40>    mov    byte ptr [rbp - 0x18], 0x3b
   0x600b2c <judge+44>    mov    byte ptr [rbp - 0x17], 0x56
 ► 0x600b30 <judge+48>    mov    byte ptr [rbp - 0x16], 0x60
   0x600b34 <judge+52>    mov    byte ptr [rbp - 0x15], 0x3b
   0x600b38 <judge+56>    mov    byte ptr [rbp - 0x14], 0x6e
   0x600b3c <judge+60>    mov    byte ptr [rbp - 0x13], 0x70
   0x600b40 <judge+64>    mov    dword ptr [rbp - 4], 0
   0x600b47 <judge+71>    jmp    judge+113 <0x600b71>

里面存着个数组,我记作key,待会要用的,看看用来干嘛,继续调试:


 RAX  0x7fffffffcbc0 ◂— 'qwertyuiopasdf'
 RBX  0x0
 RCX  0x0                                  #0
 RDX  0x71                                 #q  ASCII 113,这里是十六进制
 RDI  0x7fffffffcbc0 ◂— 'qwertyuiopasdf'
 RSI  0x1                                  
 R8   0x7ffff7dd38c0 (_IO_2_1_stdin_) ◂— mov    byte ptr [rdx], ah /* 0xfbad2288 */
 R9   0x0
 R10  0x309
 R11  0x7ffff7aba620 (strlen) ◂— pxor   xmm0, xmm0
 R12  0x400510 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffccc0 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffcbb0 —▸ 0x7fffffffcbe0 —▸ 0x4006b0 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffcbb0 —▸ 0x7fffffffcbe0 —▸ 0x4006b0 (__libc_csu_init) ◂— push   r15
 RIP  0x600b69 (judge+105) ◂— xor    edx, ecx /* 0x1fc45831088ca31 */
─────────────────────[ DISASM ]──────────────────────
   0x600b59 <judge+89>     movsxd rcx, edx
   0x600b5c <judge+92>     mov    rdx, qword ptr [rbp - 0x28]
   0x600b60 <judge+96>     add    rdx, rcx                 #加入rdx,rcx
   0x600b63 <judge+99>     movzx  edx, byte ptr [rdx]      #rdx变为edx
   0x600b66 <judge+102>    mov    ecx, dword ptr [rbp - 4] #rcx变为ecx0x600b69 <judge+105>    xor    edx, ecx                #将rcx与ecx异或
   0x600b6b <judge+107>    mov    byte ptr [rax], dl   
   0x600b6d <judge+109>    add    dword ptr [rbp - 4], 1
   0x600b71 <judge+113>    cmp    dword ptr [rbp - 4], 0xd
   0x600b75 <judge+117>    jle    judge+73 <0x600b49>
    ↓
   0x600b49 <judge+73>     mov    eax, dword ptr [rbp - 4]

运算过程是 rdx = rdx ^ rcx,且rsc的变化是随着数组的位数变化的由0-13

这也是对flag进行加密了

现在我们利用异或的特性,将key,也就是上面的数组,跟rcx异或一下

脚本如下:

#-*-coding:utf-8-*-   
#python3
key = [0x66,0x6d,0x63,0x64,0x7f,0x6b,0x37,0x64,0x3b,0x56,0x60,0x3b,0x6e,0x70]
flag = ""
for i in range(0,14):
  flag+=chr(key[i]^i)
print(flag)

得到flag : flag{n1c3_j0b}

correct_the_byte

按照惯例,用file看一下:

****@****-PC:~/Desktop/reverse-2/homework$ file correct_the_byte
correct_the_byte: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=4d43964329bcfe200c4cd48f640fa452b0797b02, not stripped

也是64bit的,所以还是用ida看一下,发现不能看伪代码,不能反编译

所以还是用gdb来看了,先看看main函数

pwndbg> disass main
Dump of assembler code for function main:
   0x00000000004004cc <+0>: push   rbp
   0x00000000004004cd <+1>: mov    rbp,rsp
   0x00000000004004d0 <+4>: sub    rsp,0x70
   0x00000000004004d4 <+8>: mov    DWORD PTR [rbp-0x64],edi
   0x00000000004004d7 <+11>:    mov    QWORD PTR [rbp-0x70],rsi
   0x00000000004004db <+15>:    mov    DWORD PTR [rbp-0x60],0x485e2beb
   0x00000000004004e2 <+22>:    mov    DWORD PTR [rbp-0x5c],0xc180c931
   0x00000000004004e9 <+29>:    mov    DWORD PTR [rbp-0x58],0x13368022
   0x00000000004004f0 <+36>:    mov    DWORD PTR [rbp-0x54],0xe2c6ff48
   0x00000000004004f7 <+43>:    mov    DWORD PTR [rbp-0x50],0xee8348f8
   0x00000000004004fe <+50>:    mov    DWORD PTR [rbp-0x4c],0xc0314822
   0x0000000000400505 <+57>:    mov    DWORD PTR [rbp-0x48],0x894801b0
   0x000000000040050c <+64>:    mov    DWORD PTR [rbp-0x44],0xfa8948c7
   0x0000000000400513 <+71>:    mov    DWORD PTR [rbp-0x40],0x23c28348
   0x000000000040051a <+78>:    mov    DWORD PTR [rbp-0x3c],0x3148050f
   0x0000000000400521 <+85>:    mov    DWORD PTR [rbp-0x38],0xf3cb0c0
   0x0000000000400528 <+92>:    mov    DWORD PTR [rbp-0x34],0xffd0e805
   0x000000000040052f <+99>:    mov    DWORD PTR [rbp-0x30],0x60cffff
   0x0000000000400536 <+106>:   mov    DWORD PTR [rbp-0x2c],0xf670d0b
   0x000000000040053d <+113>:   mov    DWORD PTR [rbp-0x28],0x30071e23
   0x0000000000400544 <+120>:   mov    DWORD PTR [rbp-0x24],0x3a05203f
   0x000000000040054b <+127>:   mov    DWORD PTR [rbp-0x20],0x9133d04
   0x0000000000400552 <+134>:   mov    DWORD PTR [rbp-0x1c],0x3c382f2f
   0x0000000000400559 <+141>:   mov    DWORD PTR [rbp-0x18],0x250c071b
   0x0000000000400560 <+148>:   mov    DWORD PTR [rbp-0x14],0x27227a2e
   0x0000000000400567 <+155>:   mov    DWORD PTR [rbp-0x10],0xa090210
   0x000000000040056e <+162>:   mov    BYTE PTR [rbp-0xc],0x0
   0x0000000000400572 <+166>:   lea    rax,[rbp-0x60]
   0x0000000000400576 <+170>:   mov    QWORD PTR [rbp-0x8],rax
   0x000000000040057a <+174>:   mov    rax,QWORD PTR [rbp-0x8]
   0x000000000040057e <+178>:   call   rax    #调用另一个函数
   0x0000000000400580 <+180>:   mov    eax,0x0
   0x0000000000400585 <+185>:   leave  
   0x0000000000400586 <+186>:   ret    
End of assembler dump.

看到其中的call rax,设置断点

powershell
b *0x40057e

然后r一下,单步进入函数,看到如下:

 RAX  0x7fffffffcb60 ◂— 0xc180c931485e2beb
 RBX  0x0
 RCX  0x0
 RDX  0x7fffffffccb8 —▸ 0x7fffffffcfd2 ◂— 0x5f52455454554c43 ('CLUTTER_')
 RDI  0x1
 RSI  0x7fffffffcca8 —▸ 0x7fffffffcf9b ◂— 0x65642f656d6f682f ('/home/de')
 R8   0x400620 (__libc_csu_fini) ◂— ret    
 R9   0x7ffff7de8cb0 (_dl_fini) ◂— push   rbp
 R10  0x848
 R11  0x7ffff7a5a1c0 (__libc_start_main) ◂— push   r14
 R12  0x4003c0 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffcca0 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffcbc0 —▸ 0x400590 (__libc_csu_init) ◂— mov    qword ptr [rsp - 0x28], rbp
 RSP  0x7fffffffcb40 —▸ 0x7fffffffcb92 ◂— 0x1e230f670d0b060c
 RIP  0x7fffffffcb62 ◂— 0x8022c180c931485e
──────——————————————─────────────────[ DISASM ]─────────────────————————————————————————
 ► 0x7fffffffcb62    pop    rsi
   0x7fffffffcb63    xor    rcx, rcx
   0x7fffffffcb66    add    cl, 0x22            #rcx = 0x22 ,为循环计数
   0x7fffffffcb69    xor    byte ptr [rsi], 0x13  #每次取出一个byte,也就是两位和0x13异或
   0x7fffffffcb6c    inc    rsi
   0x7fffffffcb6f    loop   0x7fffffffcb690x7fffffffcb69    xor    byte ptr [rsi], 0x13
   0x7fffffffcb6c    inc    rsi
   0x7fffffffcb6f    loop   0x7fffffffcb690x7fffffffcb69    xor    byte ptr [rsi], 0x13
   0x7fffffffcb6c    inc    rsi

由于题目所说,correct_the_byte , 意思就是让我改一下,byte,所以认为那个0x13的数有问题,不然不会输出乱码,决定用脚本跑一下

X/34xb  $rsi    #当rsi 运行到0x7fffffffcb69时执行,此指令是输出RSI后34位

得到被加密的数据:

pwndbg> X/34xb $rsi           
0x7fffffffcb92: 0x0c    0x06    0x0b    0x0d    0x67    0x0f    0x23    0x1e
0x7fffffffcb9a: 0x07    0x30    0x3f    0x20    0x05    0x3a    0x04    0x3d
0x7fffffffcba2: 0x13    0x09    0x2f    0x2f    0x38    0x3c    0x1b    0x07
0x7fffffffcbaa: 0x0c    0x25    0x2e    0x7a    0x22    0x27    0x10    0x02
0x7fffffffcbb2: 0x09    0x0a

写成脚本:

#-*-coding:utf-8-*-
key=[0x0c,0x06,0x0b,0x0d,0x67,0x0f,0x23,0x1e ,0x07,0x30,0x3f,0x20,0x05,0x3a,0x04,0x3d,0x13,0x09,0x2f ,0x2f ,0x38 ,0x3c ,0x1b ,0x07 ,0x0c ,0x25 ,0x2e ,0x7a ,0x22 ,0x27 ,0x10 ,0x02 ,0x09 ,0x0a]
for i in range(0,0x50):
  flag=""
  for j in range(0,34):
     flag+=chr(key[j]^i)
  #print(flag)
  if "FLAG"  in flag:
     print("get it")
     print(flag)
     break

得到flag:

get it
FLAG-EiTMzujOpNwYCeervQMFod0hmZHC@

gdb基础知识介绍

x $eax(寄存器)
x/nfu
n:num
f:x(16) d(10) o(8)
u:a lenth of memory unit b h w g:1 2 4 8(byte)

operation:
Start:start(If you haven't breakpoints,it will stop at main)
Run:r(Only if you have breakpoints)
Next:n(next line)
Step:s(into func)
Continue:c(run to next breakpoint directly)
disass + func_name (可以看到函数的全部伪代码)

猜你喜欢

转载自blog.csdn.net/qq_42956710/article/details/81704879
今日推荐