[逆向][writeup]0ctf2015 r0ops

这道逆向题相对其分值来说,实在是太难了,想要逆向这个程序,需要足够的耐心,而且还需要有一定的数学知识。

这是一个64位的ELF程序。首先用IDA进行分析,开始部分的逻辑是比较简单的:

1 void *__usercall [email protected]<rax>(__int64 [email protected]<rbp>)
2 {
3   *(_DWORD *)(a1 - 4) = accept(3, 0LL, 0LL);
4   recv(*(_DWORD *)(a1 - 4), &qword_E0B10C0, 0x1000uLL, 0);
5   close(*(_DWORD *)(a1 - 4));
6   qmemcpy(&unk_E0AF0A0, &unk_E0B00A0, 0x1000uLL);
7   return &unk_E0AF8A0;
8 }

程序打开了一个套接字(描述符为3),然后监听这个套接字,在接收到消息后,会进行拷贝操作,然后返回。

最关键的就是返回操作。动态调试发现函数返回时,ret指令会取出栈上地址并跳转到该地址处执行一系列指令,结束后会再次返回到栈上,重复下一次过程。大概如下:

.text:000000000DEAD1F4 jmp     short loc_DEAD1F8
.text:000000000DEAD1F8 pop     rcx
.text:000000000DEAD1F9 retn
.text:000000000DEAD271 jmp     short loc_DEAD275
.text:000000000DEAD275 pop     r9
.text:000000000DEAD277 retn

换句话说,整个stack就是由一系列的ROP gadgets构成的ROPChain。在进行动态调试时,发现gadgets中含有大量的垃圾指令,比如无效的赋值,重复的拷贝等等,从而增大了我们理解程序的难度。

栈上的内容我们是可以获得的,想到可以写一个脚本,结合代码段与栈上的内容来还原这个ROPChain,但是后来发现gadgets中有不少rsp操作和条件跳转操作,这些操作的结果取决于动态执行的内容,用脚本来进行静态还原相当于写一个解释器了,难度可想而知,最终放弃。

耐着性子一步步跟踪gadget的执行,去掉无效的干扰指令,记录下有效指令,及相关内存、寄存器的值,如下:

  1 .text:000000000DEAD1F8 pop     rcx                ;0x0000000000000008
  2 .text:000000000DEAD275 pop     r9                ;0x1337DEADBEEF0095
  3 .text:000000000DEAD127 mov     rax, [rdi]        ;rax = 8bytes user input
  4 .text:000000000DEAD208 mov     [rsi], rax        ;[rsi] = 8bytes user input
  5 .text:000000000DEAD26B mov     r8, [rsi]        ;ri = 8bytes user input
  6 .text:000000000DEAD107 add     rdi, 8            ;rdi points to next 8 bytes user input
  7 .text:000000000DEAD27E mov     [rsi], r9        ;[rsi] = 0x1337DEADBEEF0095
  8 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x1337DEADBEEF0095
  9 .text:000000000DEAD1F0 pop     rbx                ;rbx = 0x000000000000CAFE
 10 .text:000000000DEAD145 imul    rax, rbx            ;rax = 0x1337DEADBEEF0095 * 0x000000000000CAFE
 11 .text:000000000DEAD208 mov     [rsi], rax
 12 .text:000000000DEAD288 mov     r9, [rsi]        ;r9 = 0x1337DEADBEEF0095 * 0x000000000000CAFE
 13 .text:000000000DEAD1F0 pop     rbx                ;rbx = 0x000000000000BEEF
 14 .text:000000000DEAD131 add     rax, rbx            ;rax = 0x1337DEADBEEF0095 * 0x000000000000CAFE + 0x000000000000BEEF
 15 .text:000000000DEAD208 mov     [rsi], rax
 16 .text:000000000DEAD288 mov     r9, [rsi]        ;r9 = 0x1337DEADBEEF0095 * 0x000000000000CAFE + 0x000000000000BEEF
 17 .text:000000000DEAD2CC pop     r12                ;r12 = 0x0000000000000001
 18 .text:000000000DEAD292 pop     r10                ;r10 = 0x0000000000003419 = 13337
 19 .text:000000000DEAD1E8 pop     rax                ;rax = 0x0000000000000000
 20 .text:000000000DEAD1F0 pop     rbx                ;rbx = 0x0000000000000000
 21 .text:000000000DEAD200 pop     rdx                ;rdx = 0x00000000000001D8
 22 .text:000000000DEAD19F cmp     rax, rbx            ;
 23 .text:000000000DEAD1A2 jnz     short locret_DEAD1A7    ;not jmp
 24 .text:000000000DEAD1A4 add     rsp, rdx            ;rsp = 0x000000000E0AFBD0
 25 .text:000000000DEAD29B mov     [rsi], r10
 26 .text:000000000DEAD212 mov     rax, [rsi]        ;rax =  0x0000000000003419
 27 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000
 28 .text:000000000DEAD200 pop     rdx                ;0xFFFFFFFFFFFFFDE0
 29 .text:000000000DEAD1AE cmp     rax, rbx            ;
 30 .text:000000000DEAD1B1 jz      short locret_DEAD1B6
 31 .text:000000000DEAD1B3 add     rsp, rdx            ;rsp = 0x000000000E0AF9F8
 32 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = r10 = 0x0000000000003419
 33 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
 34 .text:000000000DEAD177 and     rax, rbx            ;rax = rax & rbx = 0x0000000000000001
 35 .text:000000000DEAD208 mov     [rsi], rax        ;[rsi] = 0x0000000000000001
 36 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000001
 37 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
 38 .text:000000000DEAD200 pop     rdx                ;0x0000000000000068
 39 .text:000000000DEAD1AE cmp     rax, rbx            ;
 40 .text:000000000DEAD1B1 jz      short locret_DEAD1B6    ;jmped
 41 .text:000000000DEAD1B6 retn
 42 .text:000000000DEAD2D5 mov     [rsi], r12        ;[rsi] = 0x0000000000000001
 43 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000001
 44 .text:000000000DEAD261 mov     [rsi], r8        ;[rsi] = input8
 45 text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8
 46 .text:000000000DEAD145 imul    rax, rbx            ;rax = 0x0000000000000001 * input8
 47 .text:000000000DEAD208 mov     [rsi], rax        ;rax = input8
 48 .text:000000000DEAD2DF mov     r12, [rsi]        ;r12 = input8        r12用于保存幂的值
 49 .text:000000000DEAD261 mov     [rsi], r8        ;[rsi] = input8
 50 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = input8
 51 .text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8
 52 .text:000000000DEAD145 imul    rax, rbx            ;rax = input8*input*
 53 .text:000000000DEAD208 mov     [rsi], rax
 54 .text:000000000DEAD26B mov     r8, [rsi]        ;r8 = input8*input8
 55 .text:000000000DEAD29B mov     [rsi], r10        ;*rsi = 0x0000000000003419
 56 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000003419
 57 .text:000000000DEAD195 shr     rax, 1            ;rax = 0x0000000000001A0C
 58 .text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000001A0C
 59 .text:000000000DEAD2A5 mov     r10, [rsi]        ;r10 = 0x0000000000001A0C
 60 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000
 61 .text:000000000DEAD200 pop     rdx                ;0xFFFFFFFFFFFFFDE0
 62 .text:000000000DEAD1AE cmp     rax, rbx
 63 .text:000000000DEAD1B1 jz      short locret_DEAD1B6                            ;if r10/2 > 0
 64 .text:000000000DEAD1B3 add     rsp, rdx            ;0x000000000E0AF9F8
 65 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
 66 .text:000000000DEAD177 and     rax, rbx            ;rax = 0x0000000000000000
 67 .text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000000000
 68 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
 69 .text:000000000DEAD200 pop     rdx                ;0x0000000000000068
 70 .text:000000000DEAD1AE cmp     rax, rbx
 71 .text:000000000DEAD1B1 jz      short locret_DEAD1B6    ;not jmp
 72 .text:000000000DEAD1B3 add     rsp, rdx            ;rsp = 0x000000000E0AFB20
 73 .text:000000000DEAD261 mov     [rsi], r8        ;*rsi = input8*input8
 74 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = input8*input8
 75 .text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8*input8
 76 .text:000000000DEAD145 imul    rax, rbx            ;rax = input8*input8*input8*input8
 77 .text:000000000DEAD208 mov     [rsi], rax        ;*rsi = input8*input8*input8*input8
 78 .text:000000000DEAD26B mov     r8, [rsi]        ;r8 = input8*input8*input8*input8
 79 .text:000000000DEAD29B mov     [rsi], r10        ;*rsi = 0x0000000000001A0C
 80 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000001A0C
 81 .text:000000000DEAD195 shr     rax, 1            ;0x0000000000000D06
 82 .text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000000D06
 83 .text:000000000DEAD2A5 mov     r10, [rsi]        ;r10  = 0x0000000000000D06
 84 .text:000000000DEAD1F0 pop     rbx                ;rbx = 0x0000000000000000
 85 .text:000000000DEAD200 pop     rdx                ;rdx = 0x0000000000000068
 86 .text:000000000DEAD1AE cmp     rax, rbx
 87 .text:000000000DEAD1B1 jz      short locret_DEAD1B6;not jmp
 88 .text:000000000DEAD1B3 add     rsp, rdx            ;0x000000000E0AF9F8
 89 .text:000000000DEAD212 mov     rax, [rsi]        ;
 90 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
 91 .text:000000000DEAD177 and     rax, rbx            ;0x0000000000000000
 92 .text:000000000DEAD208 mov     [rsi], rax        ;*rsi=0x0000000000000000
 93 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = r11 = 0x0000000000000000
 94 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
 95 .text:000000000DEAD200 pop     rdx                ;0x0000000000000068
 96 .text:000000000DEAD1AE cmp     rax, rbx
 97 .text:000000000DEAD1B1 jz      short locret_DEAD1B6 ; not jmp
 98 .text:000000000DEAD1B3 add     rsp, rdx            ;0x000000000E0AFB20
 99 .text:000000000DEAD261 mov     [rsi], r8        ;*rsi = input8*input8*input8*input8
100 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = input8*input8*input8*input8
101 .text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8*input8*input8*input8
102 .text:000000000DEAD145 imul    rax, rbx            ;rax = input8*input8*input8*input8*input8*input8*input8*input8
103 .text:000000000DEAD208 mov     [rsi], rax
104 .text:000000000DEAD26B mov     r8, [rsi]        ;r8 = input8*input8*input8*input8*input8*input8*input8*input8
105 .text:000000000DEAD29B mov     [rsi], r10        ;0x0000000000000D06
106 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000D06
107 .text:000000000DEAD195 shr     rax, 1            ;rax = 0x0000000000000683
108 .text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000000683
109 .text:000000000DEAD2A5 mov     r10, [rsi]        ;r10 = 0x0000000000000683
110 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000683
111 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000
112 .text:000000000DEAD200 pop     rdx                ;0xFFFFFFFFFFFFFDE0
113 .text:000000000DEAD1AE cmp     rax, rbx
114 .text:000000000DEAD1B1 jz      short locret_DEAD1B6                        ;if r10/2 > 0
115 .text:000000000DEAD1B3 add     rsp, rdx            ;0x000000000E0AF9F8
116 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000683
117 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
118 .text:000000000DEAD177 and     rax, rbx            ;rax = 0x0000000000000001
119 .text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000000001
120 .text:000000000DEAD212 mov     rax, [rsi]
121 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
122 .text:000000000DEAD200 pop     rdx                ;0x0000000000000068
123 .text:000000000DEAD1AE cmp     rax, rbx
124 .text:000000000DEAD1B1 jz      short locret_DEAD1B6;jmped
125 .text:000000000DEAD1B6 retn
126 .text:000000000DEAD2D5 mov     [rsi], r12        ;*rsi = input8
127 .text:000000000DEAD212 mov     rax, [rsi]        ;rax = input8
128 .text:000000000DEAD261 mov     [rsi], r8        ;*rsi = input8*input8*input8*input8*input8*input8*input8*input8
129 .text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8*input8*input8*input8*input8*input8*input8*input8
130 .text:000000000DEAD145 imul    rax, rbx            ;rax = input(9)
131 .text:000000000DEAD208 mov     [rsi], rax
132 .text:000000000DEAD2DF mov     r12, [rsi]        ;r12 = r12 * r8 = input(9)
133 .text:000000000DEAD261 mov     [rsi], r8        ;*rsi = input(8)
134 .text:000000000DEAD212 mov     rax, [rsi]
135 .text:000000000DEAD226 mov     rbx, [rsi]
136 .text:000000000DEAD145 imul    rax, rbx
137 .text:000000000DEAD208 mov     [rsi], rax
138 .text:000000000DEAD26B mov     r8, [rsi]
139 .text:000000000DEAD29B mov     [rsi], r10
140 .text:000000000DEAD212 mov     rax, [rsi]
141 .text:000000000DEAD195 shr     rax, 1
142 .text:000000000DEAD208 mov     [rsi], rax
143 .text:000000000DEAD2A5 mov     r10, [rsi]
144 .text:000000000DEAD29B mov     [rsi], r10
145 .text:000000000DEAD212 mov     rax, [rsi]
146 .text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000
147 ……

程序似乎没有结束的尽头,而且我们能够明显的感觉程序执行进入了一个循环。通过这些已经执行的代码,我们来大概分析一下程序的执行逻辑,并用伪码进行表示。如下:

;rcx = 8,应该是一个8次的循环
.text:000000000DEAD1F8 pop     rcx                ;0x0000000000000008

;r8 = input[rcx], r9 = 0x1337DEADBEEF0095
.text:000000000DEAD275 pop     r9                ;0x1337DEADBEEF0095
.text:000000000DEAD127 mov     rax, [rdi]        ;rax = 8bytes user input
.text:000000000DEAD208 mov     [rsi], rax        ;[rsi] = 8bytes user input
.text:000000000DEAD26B mov     r8, [rsi]        ;ri = 8bytes user input
.text:000000000DEAD107 add     rdi, 8            ;rdi points to next 8 bytes user input

;r9 = r9 * 0x000000000000CAFE + 0x000000000000BEEF
.text:000000000DEAD27E mov     [rsi], r9        ;[rsi] = 0x1337DEADBEEF0095
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x1337DEADBEEF0095
.text:000000000DEAD1F0 pop     rbx                ;rbx = 0x000000000000CAFE
.text:000000000DEAD145 imul    rax, rbx            ;rax = 0x1337DEADBEEF0095 * 0x000000000000CAFE
.text:000000000DEAD208 mov     [rsi], rax
.text:000000000DEAD288 mov     r9, [rsi]        ;r9 = 0x1337DEADBEEF0095 * 0x000000000000CAFE
.text:000000000DEAD1F0 pop     rbx                ;rbx = 0x000000000000BEEF
.text:000000000DEAD131 add     rax, rbx            ;rax = 0x1337DEADBEEF0095 * 0x000000000000CAFE + 0x000000000000BEEF
.text:000000000DEAD208 mov     [rsi], rax
.text:000000000DEAD288 mov     r9, [rsi]        ;r9 = 0x1337DEADBEEF0095 * 0x000000000000CAFE + 0x000000000000BEEF

;r12 = 1, r10 = 13337
.text:000000000DEAD2CC pop     r12                ;r12 = 0x0000000000000001
.text:000000000DEAD292 pop     r10                ;r10 = 0x0000000000003419 = 13337

.text:000000000DEAD1E8 pop     rax                ;rax = 0x0000000000000000
.text:000000000DEAD1F0 pop     rbx                ;rbx = 0x0000000000000000
.text:000000000DEAD200 pop     rdx                ;rdx = 0x00000000000001D8
.text:000000000DEAD19F cmp     rax, rbx            ;
.text:000000000DEAD1A2 jnz     short locret_DEAD1A7    ;not jmp
.text:000000000DEAD1A4 add     rsp, rdx            ;rsp = 0x000000000E0AFBD0
.text:000000000DEAD29B mov     [rsi], r10
.text:000000000DEAD212 mov     rax, [rsi]        ;rax =  0x0000000000003419
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000
.text:000000000DEAD200 pop     rdx                ;0xFFFFFFFFFFFFFDE0
.text:000000000DEAD1AE cmp     rax, rbx            ;
.text:000000000DEAD1B1 jz      short locret_DEAD1B6
.text:000000000DEAD1B3 add     rsp, rdx            ;rsp = 0x000000000E0AF9F8

if (r10 & 0x01 == 0x01)
{
    r12 = r12 * r8;
    r8 = r8 * r8;
}

.text:000000000DEAD212 mov     rax, [rsi]        ;rax = r10 = 0x0000000000003419
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
.text:000000000DEAD177 and     rax, rbx            ;rax = rax & rbx = 0x0000000000000001
.text:000000000DEAD208 mov     [rsi], rax        ;[rsi] = 0x0000000000000001
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000001
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
.text:000000000DEAD200 pop     rdx                ;0x0000000000000068
.text:000000000DEAD1AE cmp     rax, rbx            ;
.text:000000000DEAD1B1 jz      short locret_DEAD1B6    ;jmped
.text:000000000DEAD1B6 retn
.text:000000000DEAD2D5 mov     [rsi], r12        ;[rsi] = 0x0000000000000001
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000001
.text:000000000DEAD261 mov     [rsi], r8        ;[rsi] = input8
text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8
.text:000000000DEAD145 imul    rax, rbx            ;rax = 0x0000000000000001 * input8
.text:000000000DEAD208 mov     [rsi], rax        ;rax = input8
.text:000000000DEAD2DF mov     r12, [rsi]        ;r12 = input8        r12用于保存幂的值
.text:000000000DEAD261 mov     [rsi], r8        ;[rsi] = input8
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = input8
.text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8
.text:000000000DEAD145 imul    rax, rbx            ;rax = input8*input*
.text:000000000DEAD208 mov     [rsi], rax
.text:000000000DEAD26B mov     r8, [rsi]        ;r8 = input8*input8

r10 = r10 / 2;

.text:000000000DEAD29B mov     [rsi], r10        ;*rsi = 0x0000000000003419
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000003419
.text:000000000DEAD195 shr     rax, 1            ;rax = 0x0000000000001A0C
.text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000001A0C
.text:000000000DEAD2A5 mov     r10, [rsi]        ;r10 = 0x0000000000001A0C

if (r10 != 0)
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000
.text:000000000DEAD200 pop     rdx                ;0xFFFFFFFFFFFFFDE0
.text:000000000DEAD1AE cmp     rax, rbx
.text:000000000DEAD1B1 jz      short locret_DEAD1B6                            ;if r10/2 > 0

.text:000000000DEAD1B3 add     rsp, rdx            ;0x000000000E0AF9F8
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001

if (r10 & 0x01 == 0)
{
    r8 = r8 * r8;
}

.text:000000000DEAD177 and     rax, rbx            ;rax = 0x0000000000000000
.text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000000000
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
.text:000000000DEAD200 pop     rdx                ;0x0000000000000068
.text:000000000DEAD1AE cmp     rax, rbx
.text:000000000DEAD1B1 jz      short locret_DEAD1B6    ;not jmp
.text:000000000DEAD1B3 add     rsp, rdx            ;rsp = 0x000000000E0AFB20
.text:000000000DEAD261 mov     [rsi], r8        ;*rsi = input8*input8
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = input8*input8
.text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8*input8
.text:000000000DEAD145 imul    rax, rbx            ;rax = input8*input8*input8*input8
.text:000000000DEAD208 mov     [rsi], rax        ;*rsi = input8*input8*input8*input8
.text:000000000DEAD26B mov     r8, [rsi]        ;r8 = input8*input8*input8*input8

r10 = r10 /2;

.text:000000000DEAD29B mov     [rsi], r10        ;*rsi = 0x0000000000001A0C
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000001A0C
.text:000000000DEAD195 shr     rax, 1            ;0x0000000000000D06
.text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000000D06
.text:000000000DEAD2A5 mov     r10, [rsi]        ;r10  = 0x0000000000000D06

if (r10 > 0)

.text:000000000DEAD1F0 pop     rbx                ;rbx = 0x0000000000000000
.text:000000000DEAD200 pop     rdx                ;rdx = 0x0000000000000068
.text:000000000DEAD1AE cmp     rax, rbx
.text:000000000DEAD1B1 jz      short locret_DEAD1B6;not jmp
.text:000000000DEAD1B3 add     rsp, rdx            ;0x000000000E0AF9F8

if (r10 & 0x01 == 0)
{
    r8 = r8*r8;
}
.text:000000000DEAD212 mov     rax, [rsi]        ;
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
.text:000000000DEAD177 and     rax, rbx            ;0x0000000000000000
.text:000000000DEAD208 mov     [rsi], rax        ;*rsi=0x0000000000000000
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = r11 = 0x0000000000000000
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
.text:000000000DEAD200 pop     rdx                ;0x0000000000000068
.text:000000000DEAD1AE cmp     rax, rbx
.text:000000000DEAD1B1 jz      short locret_DEAD1B6 ; not jmp
.text:000000000DEAD1B3 add     rsp, rdx            ;0x000000000E0AFB20
.text:000000000DEAD261 mov     [rsi], r8        ;*rsi = input8*input8*input8*input8
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = input8*input8*input8*input8
.text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8*input8*input8*input8
.text:000000000DEAD145 imul    rax, rbx            ;rax = input8*input8*input8*input8*input8*input8*input8*input8
.text:000000000DEAD208 mov     [rsi], rax
.text:000000000DEAD26B mov     r8, [rsi]        ;r8 = input8*input8*input8*input8*input8*input8*input8*input8

r10 = r10 / 2
.text:000000000DEAD29B mov     [rsi], r10        ;0x0000000000000D06
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000D06
.text:000000000DEAD195 shr     rax, 1            ;rax = 0x0000000000000683
.text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000000683
.text:000000000DEAD2A5 mov     r10, [rsi]        ;r10 = 0x0000000000000683

if (r10 > 0)

.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000683
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000
.text:000000000DEAD200 pop     rdx                ;0xFFFFFFFFFFFFFDE0
.text:000000000DEAD1AE cmp     rax, rbx
.text:000000000DEAD1B1 jz      short locret_DEAD1B6                        ;if r10/2 > 0

if (r10 & 0x01 == 1)
{
    r12 = r12 * r8;
    r8 = r8 * r8;
}

.text:000000000DEAD1B3 add     rsp, rdx            ;0x000000000E0AF9F8
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0x0000000000000683
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
.text:000000000DEAD177 and     rax, rbx            ;rax = 0x0000000000000001
.text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0x0000000000000001
.text:000000000DEAD212 mov     rax, [rsi]
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000001
.text:000000000DEAD200 pop     rdx                ;0x0000000000000068
.text:000000000DEAD1AE cmp     rax, rbx
.text:000000000DEAD1B1 jz      short locret_DEAD1B6;jmped
.text:000000000DEAD1B6 retn
.text:000000000DEAD2D5 mov     [rsi], r12        ;*rsi = input8
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = input8
.text:000000000DEAD261 mov     [rsi], r8        ;*rsi = input8*input8*input8*input8*input8*input8*input8*input8
.text:000000000DEAD226 mov     rbx, [rsi]        ;rbx = input8*input8*input8*input8*input8*input8*input8*input8
.text:000000000DEAD145 imul    rax, rbx            ;rax = input(9)
.text:000000000DEAD208 mov     [rsi], rax
.text:000000000DEAD2DF mov     r12, [rsi]        ;r12 = r12 * r8 = input(9)
.text:000000000DEAD261 mov     [rsi], r8        ;*rsi = input(8)
.text:000000000DEAD212 mov     rax, [rsi]
.text:000000000DEAD226 mov     rbx, [rsi]
.text:000000000DEAD145 imul    rax, rbx
.text:000000000DEAD208 mov     [rsi], rax
.text:000000000DEAD26B mov     r8, [rsi]

r10 = r10 / 2;

.text:000000000DEAD29B mov     [rsi], r10
.text:000000000DEAD212 mov     rax, [rsi]
.text:000000000DEAD195 shr     rax, 1
.text:000000000DEAD208 mov     [rsi], rax
.text:000000000DEAD2A5 mov     r10, [rsi]
.text:000000000DEAD29B mov     [rsi], r10
.text:000000000DEAD212 mov     rax, [rsi]
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000

将我们写的伪码汇总一下,大概如下:

r9 = 0x1337DEADBEEF0095;

r9 = 0x000000000000CAFE + 0x000000000000BEEF

r12 = 1, r10 = 13337

if (r10 & 0x01 == 0x01)
{
    r12 = r12 * r8;
    r8 = r8 * r8;
}

r10 = r10 / 2;

if (r10 != 0)

if (r10 & 0x01 == 0)
{
    r8 = r8 * r8;
}

r10 = r10 /2;

if (r10 != 0)

if (r10 & 0x01 == 0)
{
    r8 = r8*r8;
}

r10 = r10 / 2

if (r10 ! 0)

if (r10 & 0x01 == 1)
{
    r12 = r12 * r8;
    r8 = r8 * r8;
}

r10 = r10 / 2;

从上述伪码大概可以看,开始的时候,程序进行了初始化的赋值操作,然后会对r10 & 0x01进行判断,如果该值不为0,会执行“r12 = r12 * r8; r8 = r8 * r8;”,如果该值为0,执行“r8 = r8 * r8;”,然后r10右移一位,重复这个过程,直到r10为0为止。

那么用C语言表示这段代码的逻辑,如下:

r9 = 0x1337DEADBEEF0095;

r12 = 1
r9 = r9 * 0x000000000000CAFE + 0x000000000000BEEF;
for (r10 = 13337; r10 != 0; r10 = r10/2)
{
    if (r10 & 0x01)
    {
            r12 = r12 * r8
    }

    r8 = r8 * r8;
}

上述处理都是r10不为0的时候。那么当r10为0的时候,处理逻辑是怎样的呢?由于r10的初始值为13337,经过13次右移1位后,r10将为0,我们在移位处设置断点:

重新运行程序进行调试,前13次断在该位置时,我们直接按”F9”,在第14次断在该位置时,我们按”F8”进行单步跟踪,此时有效执行的gadgets及分析如下:

if (r10 == 0 )
.text:000000000DEAD208 mov     [rsi], rax        ;*rsi = 0
.text:000000000DEAD2A5 mov     r10, [rsi]        ;r10 = 0
.text:000000000DEAD212 mov     rax, [rsi]        ;rax = 0
.text:000000000DEAD1F0 pop     rbx                ;0x0000000000000000
.text:000000000DEAD200 pop     rdx                ;0xFFFFFFFFFFFFFDE0
.text:000000000DEAD1AE cmp     rax, rbx            ;
.text:000000000DEAD1B1 jz      short locret_DEAD1B6

if (r12 != r9)
{
    handlemsg ()
}

.text:000000000DEAD2D5 mov     [rsi], r12
.text:000000000DEAD212 mov     rax, [rsi]
.text:000000000DEAD27E mov     [rsi], r9
.text:000000000DEAD226 mov     rbx, [rsi]
.text:000000000DEAD200 pop     rdx
.text:000000000DEAD1AE cmp     rax, rbx
.text:000000000DEAD1B1 jz      short locret_DEAD1B6
.text:000000000DEAD200 pop     rdx                        ;0xFFFFFFFFFFFFFC38
.text:000000000DEAD1DF loop    loc_DEAD1DB

这段用伪码来表示的执行逻辑为:

if (r10 == 0)
{
    if (r12 != r9)
    {
        handlemsg ()
    }
}

即在上述for循环结束时,判断r12是否等于r9,如果不相等,则继续监听socket,重复整个过程。

至此,用c语言还原的完整代码为:

r9 = 0x1337DEADBEEF0095;

r12 = 1
r9 = r9 * 0x000000000000CAFE + 0x000000000000BEEF;
for (r10 = 13337; r10 != 0; r10 = r10/2)
{
    if (r10 & 0x01)
    {
            r12 = r12 * r8
    }

    r8 = r8 * r8;
}

if (r9 != r12)
{
    handlemsg()
}

那么还有一个分支我们没有走到,即r9如果等于r12,程序会执行什么操作?还记得之前POP RCX后,RCX==8吗?我们猜想此时会进入外层的这个循环。动态调试一下来验证我们的想法。重复上述过程,在第14次断在.text:000000000DEAD195 shr     rax, 1时,采用单步调试,在执行到下面的判断时,我们可以修改寄存器的值来满足这个判断,进而执行r9==r12后的逻辑:

.text:000000000DEAD1AE cmp     rax, rbx
.text:000000000DEAD1B1 jz      short locret_DEAD1B6

在执行到这个位置后,寄存器内容如下:

此时rax为0,rbx为0x2724090C0798E4C5,我们修改rax寄存器的值为0x2724090C0798E4C5,这样就满足了r9==r12,修改后,我们跟踪gadgets的执行,有效指令如下:

text:000000000DEAD1FC jmp     short loc_DEAD200
.text:000000000DEAD200 pop     rdx
.text:000000000DEAD1DF loop    loc_DEAD1DB
.text:000000000DEAD1DB add     rsp, rdx
.text:000000000DEAD127 mov     rax, [rdi]
.text:000000000DEAD208 mov     [rsi], rax
.text:000000000DEAD26B mov     r8, [rsi]

此时,rcx变为7,rdi指向用户输入的下一个8字节,开始了一个新的循环过程。

在8个外循环执行后,程序将打印出flag。

综合上述分析,我们可以用C语言表示该程序的执行逻辑了:

#include <stdio.h>
#include <stdlib.h>

long long r8[8] = {???, ???, ???, ???, ???, ???, ???, ???};

int main ()
{
    r9 = 0x1337DEADBEEF0095;

    for (rcx = 0; rcx < 8; rcx ++)
    {
        r9 = r9 * 0x000000000000CAFE + 0x000000000000BEEF;
        r12 = 1;

        for (r10 = 13337; r10 > 0; r10 = r10 / 2)
        {
            if (r10 & 0x01)
                r12 = r12 * r8[rcx];

            r8[rcx] = r8[rcx] * r8[rcx];
        }

        if (r12 != r9)
        {
            handlemsg();
        }
    }

    printflag ();
}

R9的初始值为0x1337DEADBEEF0095,每次循环后会变化,我们可以计算出每次循环后R9的值分别为:

long long r9[8] = {
    0x2724090c0798e4c5,
    0x44e477ee2e372c65,
    0xa150eec963c67d25,
    0xeab7d48b9db01ba5,
    0xf01b0cf36a8c5ea5,
    0x930eeb9679f4d8a5,
    0xaeb27b8833e1e4a5,
    0x2a900a13b88bcca5
};

从我们分析的结果来看,R12为用户输入数据的N次幂,N是多少呢?仿照这个程序我们写一段C代码来计算一下:

int getpower ()
{
    long long magic = 0x0000000000003419;
    int twopower = 1;
    int r8power = 0;

    for (; magic > 0; magic = magic >> 1)
    {
        if (magic & 0x01)
        {
            r8power += twopower;
        }

        twopower = twopower*2;
    }

    return r8power;
}

可以知道幂的次数是13337,也就是程序监听的端口。于是问题转化为,给定Y,求X,使得X满足如下条件:

X^13337 = Y

实际上,由于X是一个64位整数,在计算其幂时,很可能会溢出,所以实际问题应该是给定Y,求X,使得X满足如下条件:

X^13337 %2^64 = Y

这就是个数学问题了,本人数学功底太差,不知道怎么去求解。但是看网上有人用欧拉定理来求解,有人用广义费马小定理来求解,膜拜这些数学大牛们。

网上还看到有大牛们用python的pack函数来求解,得到了flag,没想明白是怎么做到的,代码如下:

import sys,struct

def f(x):
    return struct.pack(‘Q‘, x)

p = ‘‘
p += f(0xd5b028b6c97155a5)
p += f(0x51a2c3e8e288fa45)
p += f(0x561720a3f926b105)
p += f(0xa325ec548e4e0385)
p += f(0x5369761ad6ccde85)
p += f(0x9475802813002885)
p += f(0xcadd6a0bdc679485)
p += f(0x7d67b37124bcbc85)

sys.stdout.write(p)

将上述脚本的输出传递给r0ops即可打印flag:

[email protected]:/home/ctf/0ctf2015/r0ops# python roops.py | nc localhost 13337

[email protected]:/home/ctf/0ctf2015/r0ops# ./r0ops
YOU WIN!

FLAG IS: 0ctf{c97155a5e288fa45f926b1058e4e0385d6ccde8513002885dc67948524bcbc85}
时间: 2024-07-28 20:06:07

[逆向][writeup]0ctf2015 r0ops的相关文章

简单的Elf逆向Writeup

ElfCrackMe1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,t

[逆向][Writeup]EIS2016 chkflag - .NET程序逆向

这是一道比较简单的逆向题,难点之处在于chkflag.exe是.NET编译生成的,如果用IDA进行逆向难度很大,因此本题主要考察.NET逆向工具的使用.题目中使用的二进制文件可以从我的github上下载:https://github.com/gsharpsh00ter/reverse 0x01 工具准备 在对.NET程序进行反编译时,常用的一个工具为.NET Reflector,但是目前该工具是收费的.本例中我们使用另一款开源的.NET反编译工具dnSpy.dnSpy是一款开源的基于ILSpy发

IDF实验室-简单的ELF逆向 writeup

题目:http://ctf.idf.cn/index.php?g=game&m=article&a=index&id=39 下载得到ElfCrackMe1文件,直接用IDA打开. 最早想到的是 function一路F5下去.可以看到关键的main函数 int __cdecl main(int argc, const char **argv, const char **envp) { int v3; // [email protected] const char **v4; // [

ISCC 2016 逆向部分 writeup

ISCC2016 逆向部分 by GoldsNow 做了这套题目感觉涨了不少的姿势..渣渣就只能够用渣渣的方法 题目下载 Help me 描述:I've got a difficult task and I can't solve it. I need your help! 思路:爆破 ELF64位的程序,直接在IDA中打开,可以看出来思路应该是比较清晰 先点进去main函数来进行分析. for ( i = 0; i <= 15; ++i ) { if ( !(v11 & 1) ) ++v5

DDCTF2019逆向分析前俩题WriteUP

DDCTF2019 笔者做了前俩道题.冷不丁过去一个月了.现在在此做一下WriteUp:题目链接: 1:题目1 2:题目2 reverse1:writeup: 1.程序打开后如下所示 2.查壳结果为UPX的壳. 3.UPXSHELL脱壳之后用GHIDRA打开后如下 这就程序大致的流程.我们的关键点在于确定其算法. 4.动态调试. 当我输入aaa时,程序内变成了=== 当我输入bbbb时,程序内部变成了<<<< 经计算 我们输入的值在程序逆向思维出来是9E-该数即可. 5.解密 成功

ctf.360.cn第二届,逆向部分writeup——第四题

题目:见附件 这题开始有些小复杂了. 运行程序,可以看见界面如下 注意看"隐藏信息完毕!"字符串的位置 直接搜索push 40405c,找到代码位置401a48. 网上翻找到代码块的入口地址4017a0.很显然这是一个非常长的函数,使用IDA进行静态分析.   v2 = CreateFileA(*((LPCSTR *)v1 + 24), 0x80000000u, 1u, 0, 3u, 0x80u, 0);   if ( v2 == (HANDLE)-1 )   {     result

ctf.360.cn第二届,逆向部分writeup——第五题

题目:见附件 这是最后一题,难度加倍. 看题目意思,应该是模拟一个下载者,从网上下载一个shellcode然后执行.要求修复这个shellcode然后获得key. OD载入MFC_ASM.exe,F9出现程序界面. 由于平时写C程序访问网络都直接用socket,找了一下竟然没有发现socket调用,看了导入表,发现原来使用wininet.dll提供的http封装. (这里不知道有没有更好的方法能让OD跟踪到button按钮的用户代码调用,还请大牛不吝赐教) 直接按button,出现错误: 此时的

ctf.360.cn第二届,逆向部分writeup——第二题

题目:见附件 这题目被提示的运行两次坑了. OD载入,设置命令行参数pass.db. F8到VirtualAlloc函数,发现size参数为0,导致函数调用失败. 根据pass.db长度,设置size=0x10,F8继续. 发现CreateFileA的FileName参数依然是pass.db,修改成pas1.db. F9正常运行,得到pas1.db文件. 实际上,这里pas1.db的内容已经是答案了,受到提示影响"patch掉bug后运行两次",所以得到pas2.db后,怎么提交都不对

ctf.360.cn第二届,逆向部分writeup——第三题

题目:见附件 这题目是最快搞定的,提示很明确 exe直接运行出错,OD打开后,发现入口点就是一个jmp F8,跟踪到jmp后的地址,发现了程序运行出错的原因. 实际上这个题目就是模拟病毒感染exe,修改文件入口指令,插入恶意代码的行为. 修补实际上就是找到真实的入口函数头的代码,将前面的jmp等指令nop掉.(修改OEP也行)