Evr_Q
0x00 寫在前面
這題一開始是準備TLS+SMC+反調試的,發現放在第一題有些不太合適,就把SMC的調用部分刪掉了。
(其實留下了彩蛋,smc的實現我沒有刪XD)
設計思路:
用TLS檢測工具進程和調試器,進入主函數后先檢測用戶名,通過后檢測StartCode(即flag),最后輸入’Y’確認CM。
部分細節:
- Win10的TLS在vs17上有點小Bug,只能在Debug模式下跑起來,于是沒有選擇Release版本,如果給大家帶來困擾這里十分抱歉。
- 用戶名注冊存在多解,原因是我把進位值舍去了(輸入’I’也能通過username驗證哦)
- StartCode部分先驗證長度為35
Step1: 全體 xor 0x76
Step2: [7:14]每個字節先異或0xAD, 再將0b10101010位與0b01010101位互換
Step3: [14:21]每個字節先異或0xBE, 再將0b11001100位與0b00110011位互換
Step4: [21:28]每個字節先異或0xAD, 再將0b11110000位于0b00001111位互換- Step2~4加密前先調用ntdll!NtQueryInformationProcess, 各檢查1種標志(7, 30,31)
- 比較簡單的做法直接用ida看了,cuz沒有造成任何靜態反編譯的難度
0x01 Wp

import random
import os
import hashlib
enc_flag = [30, 21, 2, 16, 13, 72, 72, 111, 221, 221, 72, 100, 99, 215, 46, 44, 254, 106, 109, 42, 242, 111, 154, 77, 139, 75, 30, 30, 14, 14, 14, 14, 14, 14, 11]
dec_flag = [0] * len(enc_flag)
#/////////////////////////////////////////////////
def dec0_f(dec_t, enc_t, num):
for i in range(num):
dec_t[i] = chr(enc_t[i] ^ 0x76)
return dec_t
#/////////////////////////////////////////////////
def dec1_f(dec_t, enc_t, num):
for i in range(num):
v1 = (enc_t[i] & 0x55) << 1
v2 = (enc_t[i] >> 1) & 0x55
enc_t[i] = v1 | v2
dec_t[i] = enc_t[i] ^ 0xAD
return dec_t
#/////////////////////////////////////////////////
def dec2_f(dec_t, enc_t, num):
for i in range(num):
v1 = (enc_t[i] & 0x33) << 2
v2 = (enc_t[i] >> 2) & 0x33
enc_t[i] = v1 | v2
dec_t[i] = enc_t[i] ^ 0xBE
return dec_t
#/////////////////////////////////////////////////
def dec3_f(dec_t, enc_t, num):
for i in range(num):
v1 = (enc_t[i] & 0xF) << 4
v2 = (enc_t[i] >> 4) & 0xF
enc_t[i] = v1 | v2
dec_t[i] = enc_t[i] ^ 0xEF
return dec_t
#/////////////////////////////////////////////////
def dec_f(dec_flag, enc_flag):
for i in range(len(enc_flag)):
dec_flag[i] = enc_flag[i]
dec_flag[21:28] = dec3_f(dec_flag[21:28], enc_flag[21:28], 7)
dec_flag[14:21] = dec2_f(dec_flag[14:21], enc_flag[14:21], 7)
dec_flag[7:14] = dec1_f(dec_flag[7:14], enc_flag[7:14], 7)
dec_flag = dec0_f(dec_flag, dec_flag, 35)
#/////////////////////////////////////////////////
dec_f(dec_flag, enc_flag)
print ''.join(dec_flag)
flag:
hctf{>>D55_CH0CK3R_B0o0M!-xxxxxxxx}
ez_crackme
考察對簡單解釋器的逆向能力。
加密解密過程
box=[]
for i in range(32):
x=(x+51)%32
box.append(x)
先用如上方式初始化一個box。
用這個box將輸入的明文進行亂序。
head = (out[0]&0xe0)>>5
for i in range(31):
out[i] = ((out[i]&0x1f)<<3)+((out[i+1]&0xe0)>>5)
out[31] = ((out[31]&0x1f)<<3) + head
然后用如上方式,將亂序后的結果進行整體循環左移3位。
key = 'deadbeef'.decode('hex')
for i in range(32):
out2.append(out[i]^((ord(key[i%4])+i)&0xff))
然后利用key和下標i對左移后的結果做異或即可。
完整python加密解密腳本:
key = 'deadbeef'.decode('hex')
def encrypt(flag):
out=[]
out2=[]
x=0#gen box
box=[]
for i in range(32):
x=(x+51)%32
box.append(x)
for i in range(32):
out.append(ord(flag[box[i]]))
head = (out[0]&0xe0)>>5
for i in range(31):
out[i] = ((out[i]&0x1f)<<3)+((out[i+1]&0xe0)>>5)
out[31] = ((out[31]&0x1f)<<3) + head
for i in range(32):
out2.append(out[i]^((ord(key[i%4])+i)&0xff))
return out2
def decrypt(enc_list):
out=[]
out2=[0]*32
x=0#gen box
box=[]
for i in range(32):
x=(x+51)%32
box.append(x)
for i in range(32):
out.append(enc_list[i]^(ord(key[i%4])+i))
tail = out[31]&0x7
for i in reversed(range(1,32)):
out[i] = ((out[i]&0xf8)>>3)+((out[i-1]&0x7)<<5)
out[0] = ((out[0]&0xf8)>>3)+(tail<<5)
for i in range(32):
out2[box[i]] = out[i]
return ''.join(map(chr,out2))
#### 解釋器分析
//register
#define _eax 0
#define _ebx 1
#define _ebx2 2
#define _ecx 3
#define _edx 4
#define _esp 5
#define _lf 6
#define _neq 7
#define _t_intp 8
#define _t_chp 9
#define _t_int 10
#define _flag 11
#define _enc 12
#define _key 13
//opcode
#define _mov (0<<1)
#define _mov32 (1<<1)
#define _lea_ch (2<<1)
#define _lea_int (3<<1)
#define _ldr_int (4<<1)
#define _ldr_ch (5<<1)
#define _add (6<<1)
#define _add_pint (7<<1)
#define _add_pch (8<<1)
#define _my_xor (9<<1)
#define _mod (10<<1)
#define _my_or (11<<1)
#define _my_and (12<<1)
#define _push (13<<1)
#define _pop (14<<1)
#define _shr (15<<1)
#define _shl (16<<1)
#define _ror (17<<1)
#define _cmpl (18<<1)
#define _cmpeq (19<<1)
#define loop (20<<1)
#define code_end (21<<1)
//type
#define rn 0
#define rr 1
定義了一些寄存器以及變量,解釋器指令,以及指令后面的變量種類。一個完整的指令由高7位的類型和低1位的變量類型組成。
rr表示op reg,reg,rn表示op reg,num。
用宏寫的解釋代碼
char code[] = {
_lea_ch | rr,_ebx, _flag,
_my_xor | rr,_ecx, _ecx,
_my_xor | rr,_eax,_eax,
_my_xor | rr,_edx,_edx,
loop,
_add | rn,_eax, 51,
_mod | rn,_eax, 32,
_lea_ch | rr,_t_chp, _ebx,
_add_pch | rr,_t_chp,_eax,
_ldr_ch | rr,_t_int,_t_chp,
_mov | rr,_edx,_t_int,
_push | rr,_esp,_edx,
_add | rn,_ecx, 1,
_cmpl | rn, _ecx, 32,
loop,
_my_xor | rr,_eax,_eax,
_lea_int | rr,_t_intp,_esp,
_add_pint | rn,_t_intp, -32,
_lea_int | rr,_ebx2,_t_intp,
_ldr_int | rr,_t_int, _ebx2,
_mov | rr,_eax,_t_int,
_my_and | rn,_eax, 0xe0,
_shr | rn,_eax, 5,
_mov | rr,_edx,_eax,
_my_xor | rr,_ecx, _ecx,
loop,
_ldr_int | rr,_t_int, _ebx2,
_mov | rr,_eax,_t_int,
_my_and | rn,_eax, 0x1f,
_shl | rn,_eax, 3,
_push | rr,_esp,_eax,
_lea_int | rr,_t_intp,_esp,
_add_pint | rn,_t_intp, -32,
_lea_int | rr,_ebx2,_t_intp,
_ldr_int | rr,_t_int, _ebx2,
_mov | rr,_eax,_t_int,
_my_and | rn,_eax, 0xe0,
_shr | rn,_eax, 5,
_pop | rr,_esp,_t_int,
_add | rr,_t_int,_eax,
_push | rr,_esp,_t_int,
_add | rn,_ecx, 1,
_cmpl | rn, _ecx, 31,
loop,
_ldr_int | rr,_t_int, _ebx2,
_mov | rr,_eax,_t_int,
_my_and | rn,_eax, 0x1f,
_shl | rn,_eax, 3,
_add | rr,_eax,_edx,
_push | rr,_esp,_eax,
_my_xor | rr,_ecx, _ecx,
_mov32 | rr,_edx, _key,
loop,
_lea_int | rr,_t_intp,_esp,
_add_pint | rn,_t_intp, -32,
_lea_int | rr,_ebx2,_t_intp,
_ldr_int | rr,_t_int, _ebx2,
_mov | rr,_eax,_t_int,
_push | rr,_esp,_eax,
_mov | rr,_eax,_edx,
_add | rr,_eax, _ecx,
_pop | rr,_esp,_t_int,
_my_xor | rr,_t_int,_eax,
_push | rr,_esp,_t_int,
_ror | rn,_edx, 8,
_add | rn,_ecx, 1,
_cmpl | rn, _ecx, 32,
loop,
_my_xor | rr,_ecx, _ecx,
_my_xor | rr,_edx,_edx,
_lea_ch | rr,_ebx,_enc,
loop,
_lea_ch | rr,_t_chp, _ebx,
_add_pch | rr,_t_chp, _ecx,
_ldr_ch | rr,_t_int,_t_chp,
_mov | rr,_eax,_t_int,
_push | rr,_esp,_eax,
_lea_int | rr,_t_intp,_esp,
_add_pint | rn,_t_intp, -33,
_ldr_int | rr,_t_int,_t_intp,
_pop | rr,_esp,_eax,
_push | rr,_esp,_eax,
_cmpeq | rr,_eax,_t_int,
_my_or | rr,_edx, _neq,
_add | rn,_ecx, 1,
_cmpl | rn, _ecx, 32,
loop,
code_end
};
其中loop的實現是用記錄ip的方式來實現的。
完整的程序代碼見github。
2017HCTF-Writeup