Flare-on5 Challenge6 magic -Writeup
0x00 序
- Auth: vvv_347
- Date: 09/14/2018
- From: Flare-on5
0x01 破
signed __int64 __fastcall main(__int64 a1, char **a2, char **a3) { unsigned __int64 v3; // rax unsigned __int64 len; // rax __int64 *v6; // [rsp+0h] [rbp-1E0h] unsigned int seed; // [rsp+1Ch] [rbp-1C4h] unsigned int i; // [rsp+20h] [rbp-1C0h] unsigned int j; // [rsp+20h] [rbp-1C0h] unsigned int k; // [rsp+24h] [rbp-1BCh] char input_s[128]; // [rsp+40h] [rbp-1A0h] char a3a; // [rsp+C0h] [rbp-120h] char arr_1[72]; // [rsp+140h] [rbp-A0h] char v14; // [rsp+188h] [rbp-58h] unsigned __int64 v15; // [rsp+1C8h] [rbp-18h] v15 = __readfsqword(0x28u); seed = 0; memset(input_s, 0, sizeof(input_s)); memset(&a3a, 0, 0x80uLL); *arr_1 = 0x45123A7920755C24LL; *&arr_1[8] = 0x17263719711D201ELL; *&arr_1[16] = 0x4A7C67303E100367LL; *&arr_1[24] = 0x11621308555E1B11LL; *&arr_1[32] = 0x122C17445A7C6C68LL; *&arr_1[40] = 0x576D0C6324095979LL; *&arr_1[48] = 0x265D0F6A0C27651FLL; *&arr_1[56] = 0xA375C1433594643LL; *&arr_1[64] = 0x2C16022663LL; memset(&v14, 0, 0x38uLL); for ( i = 0; i < strlen("Run, Forrest, run!!"); i += 4 ) seed ^= *&aRunForrestRun[i]; srand(seed); if ( sub_402D47() ) { v3 = strlen(a2[1]); func_proc1(a2[1], v3, &a3a); func_proc2(*a2); puts("Generated first permutation!"); exit(0); } puts("Welcome to the ever changing magic mushroom!"); printf("%d trials lie ahead of you!\n", 666LL, a2); for ( j = 0; j < 666; ++j ) { printf("Challenge %d/%d. Enter key: ", j + 1, 666LL); if ( !fgets(input_s, 128, unk_617630) ) return 0xFFFFFFFFLL; len = strlen(input_s); func_proc1(input_s, len, &a3a); for ( k = 0; k < strlen(input_s); ++k ) arr_1[k] ^= input_s[k]; func_proc2(*v6); } printf("Congrats! Here is your price:\n%s\n", arr_1); return 0LL; }
main生成個固定seed,之後進入sub_402D47做check,run時發現不會進入branch,先忽略。
接著讀輸入Key,進入func_proc1,完成後與加密flag做xor,最後進入func_proc2。
一共做666次Chanllenges,全部正確即可拿到flag。
Proc_1:
__int64 __fastcall func_proc1(char *input_s, unsigned __int64 len, char *a3) { __int64 result; // rax char *dst; // [rsp+8h] [rbp-28h] unsigned int i; // [rsp+2Ch] [rbp-4h] dst = a3; for ( i = 0; ; ++i ) // loop 34 { result = i; if ( i >= 33uLL ) break; if ( (func_list[i].len_p1 + func_list[i].len_p2) > len )// check1 func_exit(); func_xor(func_list[i].xor_func, func_list[i].xor_size, func_list[i].xor_data_pos);// ptr dec_smc if ( !(func_list[i].xor_func)(&input_s[func_list[i].len_p1], func_list[i].len_p2, func_list[i].x_data) )// check2 guess:smc { func_xor(func_list[i].xor_func, func_list[i].xor_size, func_list[i].xor_data_pos); func_exit(); } func_xor(func_list[i].xor_func, func_list[i].xor_size, func_list[i].xor_data_pos);// smc enc_smc memcpy(&dst[func_list[i].dst_pos], &input_s[func_list[i].len_p1], func_list[i].len_p2);// update dst } return result; }
可以明顯看出是個解smc,呼叫,再復原smc的過程。
設計到有個0x120大小的資料結構:
xor_func: 被smc的函式地址 xor_size: 函式大小 len_p1: Start_addr,被Check的key的起始地址 len_p2: len,被Check的key的範圍 xor_data_pos:用於解smc的資料 x_data: 呼叫被解smc函式時所需要的引數
一共Check33個函式,意味著就33個這樣的結構體。
我們可以手動跑一下得到解smc的函式。
使用指令碼:
from struct import * fp= open("magic", "rb+") def dec_smc_core(func_addr, size, xor_addr, fp): fp.seek(0,0) file = fp.read() res = '' for i in range(size): res += chr(ord(file[func_addr+i]) ^ ord(file[xor_addr+i])) fp.seek(func_addr, 0) fp.write(res) def dec_smc(fp): fp.seek(0x5100,0) f = fp.read() func_pos = '' for i in range(33): print "dp0", i xor_func, xor_size, len_p1, len_p2, dst_pos, xor_data_pos = unpack("<q4iq", f[i*0x120:i*0x120+32]) func_pos += hex(xor_func)+'\n' xor_func -= 0x400000 xor_data_pos -= 0x600000 dec_smc_core(xor_func, xor_size, xor_data_pos, fp) open("smc_func_.txt", "w").write(func_pos) print "done" dec_smc(fp)
可以拿到復原後的33個函式。
不難發現,這33個函式分為了7個種類:
- 斐波那契數列
- crc32
- base64
- 陣列變換+xor_swap+xor
- 字元異或
- 字元相等
- 字元偏移
於是,我們可以手動解一下(1/666)的Key:
from struct import * import binascii import base64 import string Offst_xor_func = 0x00 Offst_func_size = 0x08 Offst_s_start_addr = 0x0c Offst_s_len = 0x10 Offst_dst_pos = 0x14 Offst_xor_data_pos = 0x18 Offst_x_data = 0x20 fib_list = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 1293530146158671551, 13493690561280548289, 14787220707439219840, 9834167195010216513, 6174643828739884737, 16008811023750101250, 3736710778780434371, 1298777728820984005, 5035488507601418376, 6334266236422402381, 11369754744023820757, 17704020980446223138, 10627031650760492279, 9884308557497163801, 2064596134548104464, 11948904692045268265, 14013500826593372729, 7515661444929089378, 3082418197812910491, 10598079642741999869, 13680497840554910360, 5831833409587358613, 1065587176432717357, 6897420586020075970, 7963007762452793327, 14860428348472869297, 4376692037216111008, 790376311979428689, 5167068349195539697, 5957444661174968386, 11124513010370508083, 17081957671545476469, 9759726608206432936, 8394940206042357789, 18154666814248790725, 8102862946581596898, 7810785687120836007] orig_bs_table = [0x2A, 0x39, 0x5F, 0x64, 0xC2, 0xA7, 0x46, 0x23, 0x53, 0x6B, 0x74, 0x47, 0x28, 0x4D, 0x70, 0x42, 0x49, 0x25, 0x52, 0x6A, 0x62, 0x38, 0x40, 0x4A, 0x69, 0x45, 0x44, 0x59, 0x2D, 0x31, 0x24, 0x50, 0x67, 0x79, 0x54, 0x21, 0x4C, 0x76, 0x71, 0x66, 0x2B, 0x63, 0x68, 0x6D, 0x51, 0x57, 0x4F, 0x30, 0x65, 0x4E, 0x5A, 0x34, 0x75, 0x6E, 0x33, 0x6C, 0x37, 0x48, 0x26, 0x32, 0x77, 0x61, 0x7A, 0x4B] for i in range(len(orig_bs_table)): orig_bs_table[i] = chr(orig_bs_table[i]) def dump_data_core(filename, data_addr, base_addr, size): fp= open(filename, "rb") offset = data_addr - base_addr fp.seek(offset,0) f = fp.read() type_format = '<' #default if size == 1: type_format += 'B' elif size == 2: type_format += 'H' elif size == 4: type_format += 'I' elif size == 8: type_format += 'Q' else: print "[warn]" type_format += 'x' target_data, = unpack(type_format, f[:size]) return target_data def dump_data_specific(filename, start_addr, base_addr, order, species, size, count): arr_data = [] for i in range(count): data_addr = start_addr + 0x120*order + species + i*size arr_data.append(hex(dump_data_core(filename, data_addr, base_addr, size))) return arr_data def explode_fib_num(dst): for i in range(len(fib_list)): if(dst == fib_list[i]): return i-1 return "Error" def spec_fib(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count): res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count) print 'order:'+str(order)+' '+str(res_arr) for i in range(len(res_arr)): if(res_arr[i][-1] == 'L'): c = chr(explode_fib_num(int(res_arr[i][:-1] ,16))) key_1[key_pos+i] = c else: c = chr(explode_fib_num(int(res_arr[i],16))) key_1[key_pos+i] = c return key_1 def explode_crc32_c1(dst): if dst == 0x0: return ord('X') for i in range(31, 127): if(dst == binascii.crc32(chr(i)) &0xffffffff): return chr(i) return 'E1ROR' def explode_crc32_c2(dst): if dst == 0x0: return ord('X') for x0 in range(31, 127): for x1 in range(31, 127): s = chr(x0) + chr(x1) if(binascii.crc32(s) &0xffffffff) == dst: return s return 'E2ROR' def explode_crc32_c3(dst): if dst == 0x0: return ord('X') for x0 in range(31, 127): for x1 in range(31, 127): for x2 in range(31, 127): s = chr(x0) + chr(x1) + chr(x2) if(binascii.crc32(s) &0xffffffff) == dst: return s return 'E3ROR' def spec_crc32(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count): res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, 1) #dst_value must is 1*dword print 'order:'+str(order)+' '+str(res_arr) if count == 1: p = res_arr[0] if res_arr[0][-1] == 'L': p = res_arr[0][:-1] dec = explode_crc32_c1(int(p,16)) elif count == 2: p = res_arr[0] if res_arr[0][-1] == 'L': p = res_arr[0][:-1] dec = explode_crc32_c2(int(p,16)) elif count == 3: p = res_arr[0] if res_arr[0][-1] == 'L': p = res_arr[0][:-1] dec = explode_crc32_c3(int(p,16)) else: print "Can not reach explode num" return "Fail" for i in range(count): key_1[key_pos+i] = dec[i] return key_1 def xor_swap(count): arr_mess = [0xDC, 0x48, 0x8F, 0x56, 0xBC, 0x36, 0xB0, 0x64, 0x40, 0x27, 0xE6, 0x2C, 0xD2, 0x3F, 0xC2, 0x34, 0x5D, 0x52, 0xEE, 0xCD, 0xAA, 0xCA, 0x81, 0x8D, 0x71, 0x23, 0x28, 0xD7, 0x96, 0x4E, 0x7F, 0x6B, 0xA1, 0x3E, 0xA3, 0x12, 0x91, 0x26, 0xE4, 0x03, 0x60, 0x8C, 0x01, 0x44, 0x79, 0xE3, 0x84, 0x35, 0xB8, 0x4A, 0xC1, 0x55, 0x1A, 0x9D, 0x11, 0xE7, 0x92, 0xA4, 0xD4, 0x68, 0x37, 0x85, 0x62, 0x66, 0xFC, 0xBF, 0xD8, 0x98, 0x9A, 0x8E, 0x32, 0x20, 0x16, 0x38, 0x57, 0x0E, 0x18, 0x5B, 0xF4, 0x17, 0x1E, 0xA0, 0xDD, 0x53, 0x5F, 0x06, 0xF8, 0xF6, 0xE1, 0x0C, 0x02, 0x74, 0xF3, 0xC0, 0xC3, 0xF0, 0x3C, 0x94, 0x10, 0xDB, 0x04, 0xF9, 0x08, 0xD6, 0x1F, 0xBE, 0xEF, 0x95, 0xE5, 0x50, 0xB6, 0xAB, 0x5A, 0x19, 0xAD, 0x24, 0x99, 0x43, 0xCB, 0xA5, 0xEB, 0x39, 0xCC, 0x67, 0xB9, 0xC5, 0xC9, 0xA6, 0x6A, 0x90, 0x7A, 0x0F, 0xD9, 0x3B, 0x1C, 0xE8, 0xA8, 0x7E, 0xC4, 0x72, 0x8B, 0x63, 0x1B, 0x59, 0x07, 0x49, 0xAE, 0x05, 0xA9, 0xEC, 0x00, 0xC6, 0x31, 0x14, 0x69, 0xBA, 0x82, 0x1D, 0x65, 0x46, 0x70, 0x29, 0xAF, 0xC8, 0xDE, 0xD0, 0xFD, 0x77, 0x73, 0x2B, 0x6D, 0xDF, 0x6C, 0xFE, 0x30, 0x2F, 0xF1, 0x78, 0x21, 0x7C, 0x4D, 0xCE, 0x13, 0xB5, 0x97, 0x2A, 0x9E, 0xFF, 0xEA, 0xCF, 0x25, 0xBD, 0xAC, 0x4C, 0x0D, 0x80, 0xE9, 0xB2, 0x4B, 0xFA, 0x54, 0x41, 0x89, 0x3A, 0x51, 0xF7, 0x00, 0x8A, 0x2D, 0xDA, 0x33, 0xF2, 0x22, 0x9B, 0xD5, 0xA2, 0x45, 0x6E, 0x4F, 0xD3, 0x76, 0x3D, 0x86, 0x2E, 0xBB, 0x7B, 0x0A, 0x42, 0xB1, 0x5E, 0xED, 0x9C, 0xE0, 0x88, 0x7D, 0x15, 0x93, 0xD1, 0x83, 0x6F, 0xFB, 0xB4, 0x9F, 0x47, 0x09, 0xA7, 0x87, 0xF5, 0x61, 0xE2, 0xC7, 0xB3, 0x75, 0x0B, 0x58, 0x5C] add = 0 res = [] for i_ in range(count): i_ += 1 add = (add +arr_mess[i_]) & 0xff arr_mess[i_] ^= arr_mess[add] arr_mess[add] ^= arr_mess[i_] arr_mess[i_] ^= arr_mess[add] pos = (arr_mess[i_] + arr_mess[add])&0xff res.append(arr_mess[pos]) return res def spec_xor_swap(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count): res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count) print 'order:'+str(order)+' '+str(res_arr) dst = xor_swap(count) for i in range(len(res_arr)): if(res_arr[i][-1] == 'L'): key_1[key_pos+i] = chr(dst[i] ^ int(res_arr[i][:-1] ,16)) else: key_1[key_pos+i] = chr(dst[i] ^ int(res_arr[i],16)) return key_1 def dec_base64(dst, read_size): for i in range(read_size): if(dst[i] == '\x00'): dst[i] = '=' dst = ''.join(dst) this_table = ''.join(orig_bs_table) orig_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' transtab = string.maketrans(this_table, orig_table) dec_1 = dst.translate(transtab).decode('base64') return dec_1 def spec_base64(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count): if(count % 3 !=0): read_size = (count/3+1)*4 else: read_size = (count/3)*4 res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, read_size) print 'order:'+str(order)+' '+str(res_arr) dst = [] for i in range(len(res_arr)): dst.append(chr(int(res_arr[i], 16))) dec_1 = dec_base64(dst, read_size) for i in range(len(dec_1)): key_1[key_pos+i] = dec_1[i] return key_1 def dec_value_shift(dst, count): for i in range(count): dst[i] = chr(dst[i]-13) return dst def spec_value_shift(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count): res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count) print 'order:'+str(order)+' '+str(res_arr) dst = [] for i in range(len(res_arr)): dst.append((int(res_arr[i], 16))) dec_1 = dec_value_shift(dst, count) for i in range(count): key_1[key_pos+i] = dec_1[i] return key_1 def dec_value_equal(dst, count): for i in range(count): dst[i] = chr(dst[i]) return dst def spec_value_equal(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count): res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count) print 'order:'+str(order)+' '+str(res_arr) dst = [] for i in range(len(res_arr)): dst.append((int(res_arr[i], 16))) dec_1 = dec_value_equal(dst, count) for i in range(count): key_1[key_pos+i] = dec_1[i] return key_1 def dec_value_xor(dst, count): for i in range(count): dst[i] = chr(dst[i] ^ 0x2A) return dst def spec_value_xor(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count): res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count) print 'order:'+str(order)+' '+str(res_arr) dst = [] for i in range(len(res_arr)): dst.append((int(res_arr[i], 16))) dec_1 = dec_value_xor(dst, count) for i in range(count): key_1[key_pos+i] = dec_1[i] return key_1 key_1 = ['x'] * 69 key_1 = spec_fib(key_1, 2, "magic", 0x605100, 0x600000, 0, Offst_x_data, 8, 3) key_1 = spec_fib(key_1, 0x2c, "magic", 0x605100, 0x600000, 1, Offst_x_data, 8, 2) key_1 = spec_crc32(key_1, 0x10, "magic", 0x605100, 0x600000, 2, Offst_x_data, 4, 1) key_1 = spec_xor_swap(key_1, 0x7, "magic", 0x605100, 0x600000, 3, Offst_x_data, 1, 3) key_1 = spec_base64(key_1, 0x3f, "magic", 0x605100, 0x600000, 4, Offst_x_data, 1, 1) key_1 = spec_fib(key_1, 0x39, "magic", 0x605100, 0x600000, 5, Offst_x_data, 8, 3) key_1 = spec_fib(key_1, 0x30, "magic", 0x605100, 0x600000, 6, Offst_x_data, 8, 2) key_1 = spec_value_shift(key_1, 0x1e, "magic", 0x605100, 0x600000, 7, Offst_x_data, 1, 3) key_1 = spec_value_equal(key_1, 0x0a, "magic", 0x605100, 0x600000, 8, Offst_x_data, 1, 1) key_1 = spec_value_equal(key_1, 0x3c, "magic", 0x605100, 0x600000, 9, Offst_x_data, 1, 3) key_1 = spec_value_shift(key_1, 0x0d, "magic", 0x605100, 0x600000, 10, Offst_x_data, 1, 1) key_1 = spec_fib(key_1, 0x2b, "magic", 0x605100, 0x600000, 11, Offst_x_data, 8, 1) key_1 = spec_value_shift(key_1, 0x38, "magic", 0x605100, 0x600000, 12, Offst_x_data, 1, 1) key_1 = spec_value_xor(key_1, 0x12, "magic", 0x605100, 0x600000, 13, Offst_x_data, 1, 2) key_1 = spec_value_equal(key_1, 0x11, "magic", 0x605100, 0x600000, 14, Offst_x_data, 1, 1) key_1 = spec_crc32(key_1, 0x42, "magic", 0x605100, 0x600000, 15, Offst_x_data, 4, 3) key_1 = spec_value_equal(key_1, 0x28, "magic", 0x605100, 0x600000, 16, Offst_x_data, 1, 3) key_1 = spec_value_xor(key_1, 0x2e, "magic", 0x605100, 0x600000, 17, Offst_x_data, 1, 2) key_1 = spec_value_shift(key_1, 0x0, "magic", 0x605100, 0x600000, 18, Offst_x_data, 1, 2) key_1 = spec_xor_swap(key_1, 0xB, "magic", 0x605100, 0x600000, 19, Offst_x_data, 1, 2) key_1 = spec_value_xor(key_1, 0x26, "magic", 0x605100, 0x600000, 20, Offst_x_data, 1, 2) key_1 = spec_value_xor(key_1, 0x14, "magic", 0x605100, 0x600000, 21, Offst_x_data, 1, 2) key_1 = spec_base64(key_1, 0x32, "magic", 0x605100, 0x600000, 22, Offst_x_data, 1, 3) key_1 = spec_value_shift(key_1, 0x24, "magic", 0x605100, 0x600000, 23, Offst_x_data, 1, 2) key_1 = spec_value_equal(key_1, 0x1c, "magic", 0x605100, 0x600000, 24, Offst_x_data, 1, 2) key_1 = spec_value_equal(key_1, 0x2f, "magic", 0x605100, 0x600000, 25, Offst_x_data, 1, 1) key_1 = spec_value_xor(key_1, 0x05, "magic", 0x605100, 0x600000, 26, Offst_x_data, 1, 2) key_1 = spec_value_xor(key_1, 0x35, "magic", 0x605100, 0x600000, 27, Offst_x_data, 1, 3) key_1 = spec_fib(key_1, 0x40, "magic", 0x605100, 0x600000, 28, Offst_x_data, 8, 2) key_1 = spec_value_xor(key_1, 0x16, "magic", 0x605100, 0x600000, 29, Offst_x_data, 1, 3) key_1 = spec_fib(key_1, 0x0e, "magic", 0x605100, 0x600000, 30, Offst_x_data, 8, 2) key_1 = spec_value_shift(key_1, 0x19, "magic", 0x605100, 0x600000, 31, Offst_x_data, 1, 3) key_1 = spec_value_xor(key_1, 0x21, "magic", 0x605100, 0x600000, 32, Offst_x_data, 1, 3) print ''.join(key_1) #inds isng llg w. e HthitheoftheAh,urnolik inefe yo blrhot in owace
這樣,Proc1分析完成。
那麼現在就有這樣的問題:
1/666的check與n/666的Check的不同。
猜測:
- 函式smc後地址不變,僅是呼叫順序改變
- 函式smc後地址改變,但函式型別不變
- 函式smc後地址改變,型別改變
難度依次遞增。
Proc2:
黑箱測試:Proc2的作用是重寫33個資料結構,並且會在進下一輪Proc1之前,將改動寫回檔案當中。
當完成(1/666)的Proc1,我們就拿到了Proc2的bin,再用指令碼還原,可以發現:
函式雖然smc的地址改變了,但函式型別不變,都在這7種。
那麼我們就必要硬逆Proc2的演算法了。
0x02 急
讓我們梳理下執行邏輯:
- 生成seed為proc_2更新做準備
- 輸入key 共666輪
- Proc_1 Check
- 解密flag 共666輪
- Proc_2 更新檔案(本地寫)
- loop到2, 直到666輪完成,輸出解密flag
那麼我們可以在proc_2更新之前,複製出來一份。這一份的我們可以用來手動解smc從而得到33個函式,而不影響正常的proc_2過程。
就算得到了33個函式,那如何實現自動化生成key呢?根據Proc_2的結果我們知道33個函式均在7種型別內,這樣就可以通過某一地址上的值兩兩不同去識別。比如:
- func_fib: 48 85 C0 75
- func_crc32: 0F B6 00 0F
- func_base64: 6A 62 38 40
- func_xor_swap: 48 B8 61 20
- fubc_value_xor: 48 01 D0 8B
- func_value_equal: 48 01 C2 8B
- func_value_shift: 8B 55 FC 48
以上是以0x30為起點的4位元組值,可以注意到0x32地址上值兩兩不同,即可用於識別函式。
這樣,Crack思路就很清晰了:
- 手動解smc,識別33個函式屬於的種類
- 根據種類,執行對應的解密演算法
- 使用pwntools完成recv和send的自動化。
完整的Crack指令碼:
from pwn import * from struct import * import binascii import base64 import string import shutil import os context.log_level = 'debug' context.terminal = ['gnome-terminal','-x','bash','-c'] Offst_xor_func = 0x00 Offst_func_size = 0x08 Offst__start_addr = 0x0c Offst_s_len = 0x10 Offst_dst_pos = 0x14 Offst_xor_data_pos = 0x18 Offst_x_data = 0x20 fib_list = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 1293530146158671551, 13493690561280548289, 14787220707439219840, 9834167195010216513, 6174643828739884737, 16008811023750101250, 3736710778780434371, 1298777728820984005, 5035488507601418376, 6334266236422402381, 11369754744023820757, 17704020980446223138, 10627031650760492279, 9884308557497163801, 2064596134548104464, 11948904692045268265, 14013500826593372729, 7515661444929089378, 3082418197812910491, 10598079642741999869, 13680497840554910360, 5831833409587358613, 1065587176432717357, 6897420586020075970, 7963007762452793327, 14860428348472869297, 4376692037216111008, 790376311979428689, 5167068349195539697, 5957444661174968386, 11124513010370508083, 17081957671545476469, 9759726608206432936, 8394940206042357789, 18154666814248790725, 8102862946581596898, 7810785687120836007] orig_bs_table = [0x2A, 0x39, 0x5F, 0x64, 0xC2, 0xA7, 0x46, 0x23, 0x53, 0x6B, 0x74, 0x47, 0x28, 0x4D, 0x70, 0x42, 0x49, 0x25, 0x52, 0x6A, 0x62, 0x38, 0x40, 0x4A, 0x69, 0x45, 0x44, 0x59, 0x2D, 0x31, 0x24, 0x50, 0x67, 0x79, 0x54, 0x21, 0x4C, 0x76, 0x71, 0x66, 0x2B, 0x63, 0x68, 0x6D, 0x51, 0x57, 0x4F, 0x30, 0x65, 0x4E, 0x5A, 0x34, 0x75, 0x6E, 0x33, 0x6C, 0x37, 0x48, 0x26, 0x32, 0x77, 0x61, 0x7A, 0x4B] for i in range(len(orig_bs_table)): orig_bs_table[i] = chr(orig_bs_table[i]) def dump_data_core(filename, data_addr, base_addr, size): fp= open(filename, "rb") offset = data_addr - base_addr fp.seek(offset,0) f = fp.read() type_format = '<' #default if size == 1: type_format += 'B' elif size == 2: type_format += 'H' elif size == 4: type_format += 'I' elif size == 8: type_format += 'Q' else: print "[warn]" type_format += 'x' target_data, = pack(type_format, f[:size]) return target_data def dump_data_specific(filename, start_addr, base_addr, order, size, read_size): addr_addr = start_addr + 0x120*order + Offst_s_start_addr arr_addr = dump_data_core(filename, addr_addr, base_addr, 4) len_addr = start_addr + 0x120*order + Offst_s_len arr_len = dump_data_core(filename, len_addr, base_addr, 4) arr_data = [] count = arr_len if read_size != 0: count = read_size for i in range(count): data_addr = start_addr + 0x120*order + Offst_x_data + i*size arr_data.append(hex(dump_data_core(filename, data_addr, base_addr, size))) return arr_addr, arr_len, arr_data def explode_fib_num(dst): for i in range(len(fib_list)): if(dst == fib_list[i]): return i-1 return "Error" def spec_fib(key_1, filename, start_addr, base_addr, order): key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 8, 0) print 'order:'+str(order)+' '+str(res_arr) for i in range(len(res_arr)): if(res_arr[i][-1] == 'L'): c = chr(explode_fib_num(int(res_arr[i][:-1] ,16))) key_1[key_pos+i] = c else: c = chr(explode_fib_num(int(res_arr[i],16))) key_1[key_pos+i] = c return key_1 def xplode_crc32_c1(dst): if dst == 0x0: return ord('X') for i in range(31, 127): if(dst == binascii.crc32(chr(i)) &0xffffffff): return chr(i) return 'E1ROR' def explode_crc32_c2(dst): if dst == 0x0: return ord('X') for x0 in range(31, 127): for x1 in range(31, 127): s = chr(x0) + chr(x1) if(binascii.crc32(s) &0xffffffff) == dst: return s return 'E2ROR' def explode_crc32_c3(dst): if dst == 0x0: return ord('X') for x0 in range(31, 127): for x1 in range(31, 127): for x2 in range(31, 127): s = chr(x0) + chr(x1) + chr(x2) if(binascii.crc32(s) &0xffffffff) == dst: return s return 'E3ROR' def spec_crc32(key_1, filename, start_addr, base_addr, order): key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 4, 0) print 'order:'+str(order)+' '+str(res_arr) if count == 1: p = res_arr[0] if res_arr[0][-1] == 'L': p = res_arr[0][:-1] dec = explode_crc32_c1(int(p,16)) elif count == 2: p = res_arr[0] if res_arr[0][-1] == 'L': p = res_arr[0][:-1] dec = explode_crc32_c2(int(p,16)) elif count == 3: p = res_arr[0] if res_arr[0][-1] == 'L': p = res_arr[0][:-1] dec = explode_crc32_c3(int(p,16)) else: print "Can not reach explode num" return "Fail" for i in range(count): key_1[key_pos+i] = dec[i] return key_1 def xor_swap(count): arr_mess = [0xDC, 0x48, 0x8F, 0x56, 0xBC, 0x36, 0xB0, 0x64, 0x40, 0x27, 0xE6, 0x2C, 0xD2, 0x3F, 0xC2, 0x34, 0x5D, 0x52, 0xEE, 0xCD, 0xAA, 0xCA, 0x81, 0x8D, 0x71, 0x23, 0x28, 0xD7, 0x96, 0x4E, 0x7F, 0x6B, 0xA1, 0x3E, 0xA3, 0x12, 0x91, 0x26, 0xE4, 0x03, 0x60, 0x8C, 0x01, 0x44, 0x79, 0xE3, 0x84, 0x35, 0xB8, 0x4A, 0xC1, 0x55, 0x1A, 0x9D, 0x11, 0xE7, 0x92, 0xA4, 0xD4, 0x68, 0x37, 0x85, 0x62, 0x66, 0xFC, 0xBF, 0xD8, 0x98, 0x9A, 0x8E, 0x32, 0x20, 0x16, 0x38, 0x57, 0x0E, 0x18, 0x5B, 0xF4, 0x17, 0x1E, 0xA0, 0xDD, 0x53, 0x5F, 0x06, 0xF8, 0xF6, 0xE1, 0x0C, 0x02, 0x74, 0xF3, 0xC0, 0xC3, 0xF0, 0x3C, 0x94, 0x10, 0xDB, 0x04, 0xF9, 0x08, 0xD6, 0x1F, 0xBE, 0xEF, 0x95, 0xE5, 0x50, 0xB6, 0xAB, 0x5A, 0x19, 0xAD, 0x24, 0x99, 0x43, 0xCB, 0xA5, 0xEB, 0x39, 0xCC, 0x67, 0xB9, 0xC5, 0xC9, 0xA6, 0x6A, 0x90, 0x7A, 0x0F, 0xD9, 0x3B, 0x1C, 0xE8, 0xA8, 0x7E, 0xC4, 0x72, 0x8B, 0x63, 0x1B, 0x59, 0x07, 0x49, 0xAE, 0x05, 0xA9, 0xEC, 0x00, 0xC6, 0x31, 0x14, 0x69, 0xBA, 0x82, 0x1D, 0x65, 0x46, 0x70, 0x29, 0xAF, 0xC8, 0xDE, 0xD0, 0xFD, 0x77, 0x73, 0x2B, 0x6D, 0xDF, 0x6C, 0xFE, 0x30, 0x2F, 0xF1, 0x78, 0x21, 0x7C, 0x12, 0xCE, 0x13, 0xB5, 0x97, 0x2A, 0x9E, 0xFF, 0xEA, 0xCF, 0x25, 0xBD, 0xAC, 0x4C, 0x0D, 0x80, 0xE9, 0xB2, 0x4B, 0xFA, 0x54, 0x41, 0x89, 0x3A, 0x51, 0xF7, 0x00, 0x8A, 0x2D, 0xDA, 0x33, 0xF2, 0x22, 0x9B, 0xD5, 0xA2, 0x45, 0x6E, 0x4F, 0xD3, 0x76, 0x3D, 0x86, 0x2E, 0xBB, 0x7B, 0x0A, 0x42, 0xB1, 0x5E, 0xED, 0x9C, 0xE0, 0x88, 0x7D, 0x15, 0x93, 0xD1, 0x83, 0x6F, 0xFB, 0xB4, 0x9F, 0x47, 0x09, 0xA7, 0x87, 0xF5, 0x61, 0xE2, 0xC7, 0xB3, 0x75, 0x0B, 0x58, 0x5C] add = 0 res = [] for i_ in range(count): i_ += 1 add = (add +arr_mess[i_]) & 0xff arr_mess[i_] ^= arr_mess[add] arr_mess[add] ^= arr_mess[i_] arr_mess[i_] ^= arr_mess[add] pos = (arr_mess[i_] + arr_mess[add])&0xff res.append(arr_mess[pos]) return res def spec_xor_swap(key_1, filename, start_addr, base_addr, order): key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0) print 'order:'+str(order)+' '+str(res_arr) dst = xor_swap(count) for i in range(len(res_arr)): if(res_arr[i][-1] == 'L'): key_1[key_pos+i] = chr(dst[i] ^ int(res_arr[i][:-1] ,16)) else: key_1[key_pos+i] = chr(dst[i] ^ int(res_arr[i],16)) return key_1 def dec_base64(dst, read_size): for i in range(read_size): if(dst[i] == '\x00'): dst[i] = '=' dst = ''.join(dst) this_table = ''.join(orig_bs_table) orig_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' transtab = string.maketrans(this_table, orig_table) dec_1 = dst.translate(transtab).decode('base64') return dec_1 def spec_base64(key_1, filename, start_addr, base_addr, order): key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0) if(count % 3 !=0): read_size = (count/3+1)*4 else: read_size = (count/3)*4 key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, read_size) print 'order:'+str(order)+' '+str(res_arr) dst = [] for i in range(len(res_arr)): dst.append(chr(int(res_arr[i], 16))) dec_1 = dec_base64(dst, read_size) for i in range(len(dec_1)): key_1[key_pos+i] = dec_1[i] return key_1 def dec_value_shift(dst, count): for i in range(count): dst[i] = chr(dst[i]-13) return dst def spec_value_shift(key_1, filename, start_addr, base_addr, order): key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0) print 'order:'+str(order)+' '+str(res_arr) dst = [] for i in range(len(res_arr)): dst.append((int(res_arr[i], 16))) dec_1 = dec_value_shift(dst, count) for i in range(count): key_1[key_pos+i] = dec_1[i] return key_1 def dec_value_equal(dst, count): for i in range(count): dst[i] = chr(dst[i]) return dst def spec_value_equal(key_1, filename, start_addr, base_addr, order): key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0) print 'order:'+str(order)+' '+str(res_arr) dst = [] for i in range(len(res_arr)): dst.append((int(res_arr[i], 16))) dec_1 = dec_value_equal(dst, count) for i in range(count): key_1[key_pos+i] = dec_1[i] return key_1 def dec_value_xor(dst, count): for i in range(count): dst[i] = chr(dst[i] ^ 0x2A) return dst def spec_value_xor(key_1, filename, start_addr, base_addr, order): key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0) prnt 'order:'+str(order)+' '+str(res_arr) dst = [] for i in range(len(res_arr)): dst.append((int(res_arr[i], 16))) dec_1 = dec_value_xor(dst, count) for i in range(count): key_1[key_pos+i] = dec_1[i] return key_1 func_spec = [spec_fib, spec_crc32, spec_base64, spec_xor_swap, spec_value_xor, spec_value_equal, spec_value_shift] #0 1 2 3 4 5 6 def deal_file(): if(os.path.exists("magic_dsmc")): os.remove("magic_dsmc") shutil.copy("magic", "magic_dsmc") fp_r = open("magic", "rb") fp_w = open("magic_dsmc", "rb+") return fp_r, fp_w def dec_smc_core(func_addr, size, xor_addr, fp_o, fp_w): fp_o.seek(0,0) f_r = fp_o.read() res = '' for i in range(size): res += chr(ord(f_r[func_addr+i]) ^ ord(f_r[xor_addr+i])) fp_w.seek(func_addr, 0) fp_w.write(res) def dec_smc(fp_r, fp_w): fp_r.seek(0x5100, 0) f_r = fp_r.read() func_pos = [] for i in range(33): xor_func, xor_size, len_p1, len_p2, dst_pos, xor_data_pos = pack("<q4iq", f_r[i*0x120:i*0x120+32]) xor_func -= 0x400000 xor_data_pos -= 0x600000 dec_smc_core(xor_func, xor_size, xor_data_pos, fp_r, fp_w) func_pos.append(xor_func) return func_pos def verify_func(func_pos, fp_w): fp_w.seek(0,0) f_w = fp_w.read() func_list = [] for i in range(33): sig_addr = func_pos[i] + 0x56 sig_value, = pack("<H", f_w[sig_addr:sig_addr+1]) print i, hex(sig_value) if sig_value == 0xC0: func_list.append(0) # fib elif sig_value == 0x00: func_list.append(1) # crc32 elif sig_value == 0x38: func_list.append(2) # base64 elif sig_value == 0x61: func_list.append(3) # xor_swap elif sig_value == 0xD0: func_list.append(4) # value_xor elif sig_value == 0xC2: func_list.append(5) # value_equal elif sig_value == 0xFC: func_list.append(6) # value_shift else: print "Critcal Error!!!" return -1 return func_list def get_func_list(): fp_r, fp_w = deal_file() func_pos = dec_smc(fp_r, fp_w) func_list = verify_func(func_pos, fp_w) return func_list def ch_run(func_list): key_1 = ['x'] * 69 for i in range(len(func_list)): ptr_f = func_spec[func_list[i]] key_1 = ptr_f(key_1, "magic", 0x605100, 0x600000, i) return ''.join(key_1) def deal_key(i): print "#-------Ch%d--------#"%i func_list = get_func_list() key_d = ch_run(func_list) return key_d def Crack(): sh = process('./magic',shell=True) bin = ELF('./magic') sleep(0) for i in range(666): sh.recvuntil('Enter key:') inut_key = deal_key(i) sh.sendline(input_key) sh.recvuntil('Congrats! Here is your price:') Crack()
0x03 終
最後,因為Flare-on5直到Oct.5才結束,所以以上的指令碼都被我輕微的改動了一下。
本人僅僅提供一點點思路,還請各位Cracker斧正。
更新了附件, password: infected
原文作者: 蒼V嵐
原文連結:https://bbs.pediy.com/thread-246838.htm
轉載請註明:轉自看雪論壇
看雪閱讀推薦:
1、[原創]微軟輕量級系統監控工具sysmon原理與實現完全分析(上篇)
2、[原創]【很有時間系列】講講怎麼列舉MmMapViewInSystemSpace分配的記憶體
3、[原創]死磕python位元組碼-手工還原python原始碼
5、[原創] 《軟體除錯》分頁機制windbg例子分析(各種填坑)
相關文章
- SSCTF Writeup2020-08-19
- BCTF Writeup2020-08-19
- JCTF Writeup2020-08-19
- Magic2024-10-10
- HCTF writeup(web)2020-08-19Web
- wargame narnia writeup2020-08-19GAM
- 太湖杯writeup2020-11-22
- 0ctf writeup2020-08-19
- 360hackgame writeup2020-08-19GAM
- Wargama-leviathan Writeup2020-08-19GAM
- CoolShell解密遊戲的WriteUp2020-08-19解密遊戲
- guestbook(hackme web部分writeup)2020-10-31Web
- 三道MISC的writeup2022-12-08
- Magic Firewall 簡介2021-03-03
- xss挑戰賽writeup2020-08-19
- web_ping的writeup2018-08-19Web
- CTFSHOW-WEB入門 writeup2020-09-29Web
- use-magic-grid:magic-grid 庫的官方 React 埠2024-09-21React
- Alictf2014 Writeup2020-08-19TF2
- cmseasy&內網滲透 Writeup2021-08-19內網
- 2016hctf writeup2017-03-04
- F. Magic Will Save the World2024-07-10
- 榮耀Magic未來手機正式釋出 榮耀Magic真機圖賞2016-12-20
- Hack.lu 2014 Writeup2020-08-19
- 31C3 CTF web關writeup2020-08-19Web
- CTF-safer-than-rot13-writeup2021-07-20
- CTF——WriteUp(2020招新)2020-11-04
- Misc_BUUCTF_WriteUp | 面具下的flag2024-10-30
- Web_Bugku_WriteUp | 變數12024-03-17Web變數
- Red Giant Magic Bullet Suite2022-09-14UI
- Python 的 Magic Methods 指南2016-01-11Python
- 輕量級UI元件 Magic2014-10-18UI元件
- 安裝 Magic Linux(轉)2007-08-16Linux
- 榮耀Magic未來手機釋出會圖文回顧 榮耀Magic怎麼樣2016-12-20
- 無聲杯 xss 挑戰賽 writeup2020-08-19
- 技術分享 | "錦行杯"比賽 Writeup2021-02-02
- 網鼎杯-writeup-第二場-babyRSA2018-08-24
- xctf攻防世界—Web新手練習區 writeup2020-12-22Web