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变为ecx
► 0x600b69 <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 0x7fffffffcb69
↓
0x7fffffffcb69 xor byte ptr [rsi], 0x13
0x7fffffffcb6c inc rsi
0x7fffffffcb6f loop 0x7fffffffcb69
↓
0x7fffffffcb69 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 (可以看到函数的全部伪代码)