题目来源:qsnctf/reverse/flower_tea
直接下载: link
此题目中有一处明显的调用IsDebuggerPresent()的反调试:
.text:00000001400022AA call cs:__imp_IsDebuggerPresent
另外一处隐藏在一个乍一看很像printf的函数(1400021E0)中。如果没有patch掉暗处的,那么很容易认为140001050处的函数就是加密、比较函数,并且此函数非常像是真正的加密函数,但是根据这个函数解出来的是假的flag。
因此,关键在于隐藏在1400021E0函数中的反调试。
.text:00000001400021E0 sub rsp, 158h
.text:00000001400021E7 mov rax, cs:__security_cookie
.text:00000001400021EE xor rax, rsp
.text:00000001400021F1 mov [rsp+158h+var_8], rax
.text:00000001400021F9 mov [rsp+158h+var_110], rcx
.text:00000001400021FE lea rax, [rsp+158h+var_110+4]
.text:0000000140002203 mov [rsp+158h+var_120], rax
.text:0000000140002208 mov rax, [rsp+158h+var_120]
.text:000000014000220D mov [rsp+158h+var_130], rax
.text:0000000140002212 mov rcx, [rsp+158h+var_110]
.text:0000000140002217 call modify_bytesin1050_to_12A0
; modify_bytesin1050_to_12A0函数会改变140001050处的汇编代码,
; 会改成跳转到1400012A0,这才是真正的加密函数
.text:00000001400020C0 modify_bytesin1050_to_12A0 proc near ; CODE XREF: sub_1400021E0+37↓p
.text:00000001400020C0 ; DATA XREF: .pdata:0000000140008030↓o
.text:00000001400020C0
.text:00000001400020C0 var_38 = qword ptr -38h
.text:00000001400020C0 var_30 = qword ptr -30h
.text:00000001400020C0 Block = qword ptr -28h
.text:00000001400020C0 var_20 = qword ptr -20h
.text:00000001400020C0 var_18 = qword ptr -18h
.text:00000001400020C0 lpflOldProtect = dword ptr -0Ch
.text:00000001400020C0 var_8 = qword ptr -8
.text:00000001400020C0
.text:00000001400020C0 sub rsp, 58h
.text:00000001400020C4 mov rax, cs:__security_cookie
.text:00000001400020CB xor rax, rsp
.text:00000001400020CE mov [rsp+58h+var_8], rax
.text:00000001400020D3 mov [rsp+58h+var_20], rcx ; rcx = a_welcometoDRKCTF
.text:00000001400020D8 xor ecx, ecx
.text:00000001400020DA call gs__60__debugger_detect
; gs__60__debugger_detect函数内部:
;.text:00000001400020A2 mov rax, gs:[rax] ; gs:[60] debugger here!
;.text:00000001400020A6 movsx eax, byte ptr [rax+2]
.text:00000001400020DF cmp eax, 0
.text:00000001400020E2 jz loc_1400020F7 ; must jz
.text:00000001400020E8 mov rax, [rsp+58h+var_20]
.text:00000001400020ED mov [rsp+58h+var_18], rax
.text:00000001400020F2 jmp loc_1400021B0
.text:00000001400020F7 ; ---------------------------------------------------------------------------
.text:00000001400020F7
.text:00000001400020F7 loc_1400020F7: ; CODE XREF: modify_bytesin1050_to_12A0+22↑j
.text:00000001400020F7 call sub_140001010
; 1010函数中,先malloc(0x10)的堆,
; 前8个字节是0x0000000140001050
; 后8个字节是0x00000001400012A0
; 返回值为堆的地址
.text:00000001400020FC mov [rsp+58h+Block], rax ; rax = addr_malloc(0x10)
.text:0000000140002101 call sub_140002410
; 2410函数:取得kernel32.dll中VirtualProtect函数的地址并返回
.text:0000000140002106 mov [rsp+58h+var_30], rax
.text:000000014000210B mov rax, [rsp+58h+var_30] ;var_30:&VirtualProtect()
.text:0000000140002110 mov rax, [rax]
.text:0000000140002113 mov rcx, [rsp+58h+Block] ;block = addr_malloc(0x10)
.text:0000000140002118 mov rcx, [rcx] ;rcx = 0x140001050
.text:000000014000211B mov edx, 20h ; ' '
.text:0000000140002120 mov r8d, 40h ; '@' ;PAGE_EXECUTE_READWRITE
.text:0000000140002126 lea r9, [rsp+58h+lpflOldProtect]
.text:000000014000212B call rax ; VirtualProctect
.text:000000014000212D cmp eax, 0
.text:0000000140002130 jz loc_14000219B
.text:0000000140002136 mov rax, [rsp+58h+Block]
.text:000000014000213B mov rax, [rax] ; rax = addr_1050
.text:000000014000213E mov byte ptr [rax], 48h ; 'H' ; 改写!
.text:0000000140002141 mov rax, [rsp+58h+Block]
.text:0000000140002146 mov rax, [rax]
.text:0000000140002149 mov byte ptr [rax+1], 0B8h ; 改写!
.text:000000014000214D mov rax, [rsp+58h+Block]
.text:0000000140002152 mov rcx, [rax+8]
.text:0000000140002156 mov rax, [rsp+58h+Block]
.text:000000014000215B mov rax, [rax]
.text:000000014000215E mov [rax+2], rcx ; 改写!
.text:0000000140002162 mov rax, [rsp+58h+Block]
.text:0000000140002167 mov rax, [rax]
.text:000000014000216A mov byte ptr [rax+0Ah], 50h ; 'P' ; 改写!
.text:000000014000216E mov rax, [rsp+58h+Block]
.text:0000000140002173 mov rax, [rax]
.text:0000000140002176 mov byte ptr [rax+0Bh], 0C3h ; 改写!
.text:000000014000217A mov rax, [rsp+58h+var_30]
.text:000000014000217F mov rax, [rax]
.text:0000000140002182 mov r8d, [rsp+58h+lpflOldProtect]
.text:0000000140002187 mov rcx, [rsp+58h+Block]
.text:000000014000218C mov rcx, [rcx]
.text:000000014000218F mov edx, 20h ; ' '
.text:0000000140002194 lea r9, [rsp+58h+lpflOldProtect]
.text:0000000140002199 call rax ;再次调用VirtualProtect函数,恢复
.text:000000014000219B
.text:000000014000219B loc_14000219B: ; CODE XREF: modify_bytesin1050_to_12A0+70↑j
.text:000000014000219B mov rcx, [rsp+58h+Block] ; Block
.text:00000001400021A0 call cs:__imp_free
之后就是分析12A0函数。
浙公网安备 33010602011771号