您好,登錄后才能下訂單哦!
這篇文章的內(nèi)容主要圍繞DDCTF2019兩個(gè)逆向分別是什么進(jìn)行講述,文章內(nèi)容清晰易懂,條理清晰,非常適合新手學(xué)習(xí),值得大家去閱讀。感興趣的朋友可以跟隨小編一起閱讀吧。希望大家通過(guò)這篇文章有所收獲!
01Confused
首先參考鏈接 https://www.52pojie.cn/forum.php?mod=viewthread&tid=860237&page=1
首先分析到這個(gè)sub_1000011D0是關(guān)鍵函數(shù)是沒(méi)有什么問(wèn)題的,直接shift+f12定位DDCTF的字符串就到了這一部分邏輯
if ( (unsigned int)sub_1000011D0(*((__int64 *)&v14 + 1)) == 1 ) objc_msgSend(v17, "onSuccess"); else objc_msgSend(v17, "onFailed");
跟進(jìn)去以后發(fā)現(xiàn)
__int64 __fastcall sub_1000011D0(__int64 a1) { char v2; // [rsp+20h] [rbp-C0h] __int64 v3; // [rsp+D8h] [rbp-8h] v3 = a1; memset(&v2, 0, 0xB8uLL); sub_100001F60(&v2, a1); return (unsigned int)sub_100001F00(&v2); }
這個(gè)函數(shù)首先分配了一個(gè)0xb8大小的空間,然后填充為0x00,然后把這個(gè)空間傳入了一個(gè)sub_100001F60函數(shù) 跟進(jìn)去
_int64 __fastcall sub_100001F60(__int64 a1, __int64 a2) { *(_DWORD *)a1 = 0; *(_DWORD *)(a1 + 4) = 0; *(_DWORD *)(a1 + 8) = 0; *(_DWORD *)(a1 + 12) = 0; *(_DWORD *)(a1 + 16) = 0; *(_DWORD *)(a1 + 176) = 0; *(_BYTE *)(a1 + 32) = 0xF0u; *(_QWORD *)(a1 + 40) = sub_100001D70; *(_BYTE *)(a1 + 48) = 0xF1u; *(_QWORD *)(a1 + 56) = sub_100001A60; *(_BYTE *)(a1 + 64) = 0xF2u; *(_QWORD *)(a1 + 72) = sub_100001AA0; *(_BYTE *)(a1 + 80) = 0xF4u; *(_QWORD *)(a1 + 88) = sub_100001CB0; *(_BYTE *)(a1 + 96) = 0xF5u; *(_QWORD *)(a1 + 104) = sub_100001CF0; *(_BYTE *)(a1 + 112) = 0xF3u; *(_QWORD *)(a1 + 120) = sub_100001B70; *(_BYTE *)(a1 + 128) = 0xF6u; *(_QWORD *)(a1 + 136) = sub_100001B10; *(_BYTE *)(a1 + 144) = 0xF7u; *(_QWORD *)(a1 + 152) = sub_100001D30; *(_BYTE *)(a1 + 160) = 0xF8u; *(_QWORD *)(a1 + 168) = sub_100001C60; qword_100003F58 = malloc(0x400uLL); return __memcpy_chk((char *)qword_100003F58 + 48, a2, 18LL, -1LL); }
首先先按H把-16這些改成 unsigned_int8類型,看著方便。 這里對(duì)照前面那個(gè)文章里的看,就是在對(duì)vm_cpu結(jié)構(gòu)體進(jìn)行初始化,前6個(gè)四字節(jié)的顯然是寄存器,后幾個(gè)是綁定虛擬機(jī)字節(jié)碼和字節(jié)碼對(duì)應(yīng)的函數(shù) 這里可以切換到structures窗口按insert創(chuàng)建一個(gè)結(jié)構(gòu)體,這樣來(lái)更清晰的看代碼 首先要對(duì)下面初始化的結(jié)構(gòu)體和opcode對(duì)應(yīng)的每個(gè)函數(shù)簡(jiǎn)要分析 第一個(gè)0xF0虛擬機(jī)指令對(duì)應(yīng)的函數(shù)
_int64 __fastcall sub_100001D70(__int64 a1) { __int64 result; // rax signed int *v2; // [rsp+Ch] [rbp-18h] v2 = (signed int *)(*(_QWORD *)(a1 + 24) + 2LL); switch ( *(unsigned __int8 *)(*(_QWORD *)(a1 + 24) + 1LL) ) { case 0x10u: *(_DWORD *)a1 = *v2; break; case 0x11u: *(_DWORD *)(a1 + 4) = *v2; break; case 0x12u: *(_DWORD *)(a1 + 8) = *v2; break; case 0x13u: *(_DWORD *)(a1 + 12) = *v2; break; case 0x14u: *(_DWORD *)a1 = *((char *)qword_100003F58 + *v2); break; default: break; } result = a1; *(_QWORD *)(a1 + 24) += 6LL; return result; }
首先可以看到每個(gè)函數(shù)中一開始都在引用 (_QWORD*)(a1+24),于是猜測(cè)這是指令指針寄存器,在structure窗口中先創(chuàng)建結(jié)構(gòu)體給這個(gè)偏移處的qword*取個(gè)名字叫myeip
可以看到v2是虛擬機(jī)指令指針寄存器指向的地方后面第二個(gè)字節(jié)的內(nèi)容,然后有一個(gè)switch結(jié)構(gòu),是在判斷虛擬機(jī)指令后面第一個(gè)字節(jié)指定的是哪個(gè)虛擬機(jī)寄存器,然后將v2賦值到寄存器里,如果是0x14的話就把 *((char*)qword_100003F58+*v2)賦值給第一個(gè)寄存器,顯然這qword100003F58相當(dāng)于虛擬機(jī)的棧,然后函數(shù)負(fù)責(zé)移動(dòng)指令指針寄存器,這個(gè)函數(shù)對(duì)應(yīng)的虛擬機(jī)指令占六個(gè)字節(jié),所以在最后有 *(_QWORD*)(a1+24)+=6LL;,所以這個(gè)函數(shù)的功能就是把一個(gè)立即數(shù)傳入虛擬機(jī)的一個(gè)寄存器中,給他取個(gè)名字叫movreg_imm,方便后面查看
然后第二個(gè)0xF1對(duì)應(yīng)的函數(shù)
__int64 __fastcall sub_100001A60(__int64 a1) { __int64 result; // rax result = (unsigned int)(*(_DWORD *)(a1 + 4) ^ *(_DWORD *)a1); *(_DWORD *)a1 = result; ++*(_QWORD *)(a1 + 24); return result; }
可以看到他把前兩個(gè)寄存器里的值進(jìn)行異或然后又把結(jié)果放到了第一個(gè)寄存器中,同樣的這個(gè)虛擬機(jī)指令占一個(gè)字節(jié),此函數(shù)負(fù)責(zé)將指令指針寄存器加1字節(jié)
0xF2對(duì)應(yīng)的函數(shù)和0xF6對(duì)應(yīng)的函數(shù)要結(jié)合來(lái)看
_int64 __fastcall sub_100001AA0(__int64 a1) { __int64 result; // rax *(_DWORD *)(a1 + 16) = *(_DWORD *)a1 == *((char *)qword_100003F58 + *(unsigned __int8 *)(*(_QWORD *)(a1 + 24) + 1LL)); result = a1; *(_QWORD *)(a1 + 24) += 2LL; return result; } __int64 __fastcall sub_100001B10(__int64 a1) { __int64 result; // rax if ( *(_DWORD *)(a1 + 16) ) *(_DWORD *)(a1 + 16) = 0; else *(_QWORD *)(a1 + 24) += *(unsigned __int8 *)(*(_QWORD *)(a1 + 24) + 1LL); result = a1; *(_QWORD *)(a1 + 24) += 2LL; return result; }
可以看到0xF2中他把
*(_DWORD*)a1==*((char*)qword_100003F58+*(unsigned__int8*)(*(_QWORD*)(a1+24)+1LL));這個(gè)表達(dá)式的結(jié)果放到了 *(_DWORD*)(a1+16)里,0xF6中他有根據(jù) *(_DWORD*)(a1+16)移動(dòng)eip指令指針寄存器,這就很明顯了,這個(gè)寄存器的功能就是標(biāo)志寄存器,存放對(duì)比的結(jié)果,然后后面一個(gè)函數(shù)就是條件跳轉(zhuǎn)指令了
然后0xF4
_int64 __fastcall sub_100001CB0(__int64 a1) { __int64 result; // rax result = (unsigned int)(*(_DWORD *)(a1 + 4) + *(_DWORD *)a1); *(_DWORD *)a1 = result; ++*(_QWORD *)(a1 + 24); return result; }
很明顯的看出這個(gè)實(shí)在做加法運(yùn)算,把前兩個(gè)寄存器的值加起來(lái)放到第一個(gè)寄存器里,取個(gè)名字叫addregimm
然后0xF5
_int64 __fastcall sub_100001CF0(__int64 a1) { __int64 result; // rax result = (unsigned int)(*(_DWORD *)a1 - *(_DWORD *)(a1 + 4)); *(_DWORD *)a1 = result; ++*(_QWORD *)(a1 + 24); return result; }
與上面的函數(shù)類似,這個(gè)是減法,取個(gè)名字叫subregimm
跟進(jìn)0xF3對(duì)應(yīng)的函數(shù)發(fā)現(xiàn)只有一個(gè)花括號(hào),于是取名為nop
然后0xF7
__int64 __fastcall sub_100001D30(__int64 a1) { __int64 result; // rax result = *(unsigned int *)(*(_QWORD *)(a1 + 24) + 1LL); *(_DWORD *)(a1 + 176) = result; *(_QWORD *)(a1 + 24) += 5LL; return result; }
可以看到他把操作數(shù)放進(jìn)了 (_DWORD*)(a1+176)處,先不管他是在干啥,先看0xF8
__int64 __fastcall sub_100001C60(__int64 a1) { __int64 result; // rax result = sub_100001B80((unsigned int)(char)*(_DWORD *)a1, 2LL); *(_DWORD *)a1 = (char)result; ++*(_QWORD *)(a1 + 24); return result; } __int64 __fastcall sub_100001B80(char a1, int a2) { bool v3; // [rsp+7h] [rbp-11h] bool v4; // [rsp+Fh] [rbp-9h] char v5; // [rsp+17h] [rbp-1h] v4 = 0; if ( a1 >= 65 ) v4 = a1 <= 90; if ( v4 ) { v5 = (a2 + a1 - 65) % 26 + 65; } else { v3 = 0; if ( a1 >= 97 ) v3 = a1 <= 122; if ( v3 ) v5 = (a2 + a1 - 97) % 26 + 97; else v5 = a1; } return (unsigned int)v5; }
可以看到他調(diào)用了下級(jí)函數(shù)sub100001B80,顯然這個(gè)sub100001B80函數(shù)是在對(duì)(unsigned int)(char)*(_DWORD *)a1進(jìn)行移位為2的凱撒加密,首先他通過(guò)ascii碼的范圍判斷是大寫還是小寫,以確保大小寫字母都能夠通用,然后對(duì)其進(jìn)行凱撒移位
分析完了這幾個(gè)函數(shù)和幾個(gè)寄存器以后,可以把結(jié)構(gòu)體補(bǔ)充完整了 如下 前四個(gè)就是通用用途寄存器,第五個(gè)就是標(biāo)志寄存器,第六個(gè)是指令指針寄存器,其余的函數(shù)的功能就如其名稱所示
_int64 __fastcall sub_100001F60(vm_cpu *a1, __int64 a2) { a1->vm_r1 = 0; a1->vm_r2 = 0; a1->vm_r3 = 0; a1->vm_r4 = 0; a1->flag = 0; a1->myeip = 0; LOBYTE(a1->opcode_f0) = 0xF0u; a1->mov_reg_imm = (__int64)mov_reg_imm; LOBYTE(a1->opcode_f1) = 0xF1u; a1->xor_r1_r2 = (__int64)xor_r1_r2; LOBYTE(a1->opcode_f2) = 0xF2u; a1->cmp_r1_imm = (__int64)cmp_r1_imm; LOBYTE(a1->opcode_f4) = 0xF4u; a1->add_r1_r2 = (__int64)add_r1_r2; LOBYTE(a1->opcode_f5) = 0xF5u; a1->dec_r1_r2 = (__int64)sub_r1_r2; LOBYTE(a1->opcode_f3) = 0xF3u; a1->nop = (__int64)nop; LOBYTE(a1->opcode_f6) = 0xF6u; a1->jz_imm = (__int64)jz_imm; LOBYTE(a1->opcode_f7) = 0xF7u; a1->mov_buff_imm = (__int64)mov_buff_imm; LOBYTE(a1->opcode_f8) = 0xF8u; a1->shift_r1_2 = (__int64)shift_r1_2; qword_100003F58 = malloc(0x400uLL); return __memcpy_chk((char *)qword_100003F58 + 48, a2, 18LL, -1LL); }
現(xiàn)在返回去查看sub_100001F00函數(shù)里調(diào)用的第二個(gè)函數(shù)
__int64 __fastcall sub_100001F00(vm_cpu *a1) { a1->myeip = (__int64)&loc_100001980 + 4; while ( *(unsigned __int8 *)a1->myeip != 0xF3 ) sub_100001E50(a1); free(qword_100003F58); return a1->vm_r6; }
可以看到此函數(shù)初始化了myeip指令指針寄存器將其指向 (__int64)&loc_100001980+4的地方 現(xiàn)在vm_cpu結(jié)構(gòu)體搞清楚了,就可以照著結(jié)構(gòu)體翻譯 (__int64)&loc_100001980+4處的虛擬機(jī)opcode了 這里既然我們已經(jīng)了解了這些opcode的功能,其實(shí)并不需要費(fèi)力去提取出代碼執(zhí)行或者寫腳本一句一句翻譯了 他就是把一個(gè)立即數(shù)裝入r1中,然后判斷大小寫,對(duì)其進(jìn)行凱撒移位,我們直接在idapython里寫一句腳本便出來(lái)了
"".join([chr(0x41+(int(i[-2:],16)+2-0x41)%26) if int(i[-2:],16)<0x61 else chr(0x61+(int(i[-2:],16)+2-0x61)%26) for i in re.findall("f010..",get_bytes(0x100001984,3000).encode("hex"))])
當(dāng)然也可以寫個(gè)腳本把整個(gè)虛擬機(jī)字節(jié)碼全部翻譯出來(lái),鑒于比賽時(shí)的時(shí)間限制,如今比賽已停止,可以看一下 首先可以用get_bytes(0x100001984,3000,0).encode("hex")把虛擬機(jī)字節(jié)碼給提取出來(lái),也可以用lazyida插件 然后解析代碼如下
import re
loc_100001980="f01066000000f8f230f6c1f01063000000f8f231f6b6f0106a000000f8f232f6abf0106a000000f8f233f6a0f0106d000000f8f234f695f01057000000f8f235f68af0106d000000f8f236f67ff01073000000f8f237f674f01045000000f8f238f669f0106d000000f8f239f65ef01072000000f8f23af653f01052000000f8f23bf648f01066000000f8f23cf63df01063000000f8f23df632f01044000000f8f23ef627f0106a000000f8f23ff61cf01079000000f8f240f611f01065000000f8f241f606f701000000f3f700000000f35dc30f1f840000000000554889e548897df8488b7df88b078945f4488b7df88b47048945f08b45f43345f0488b7df88907488b7df8488b4f184883c10148894f185dc30f1f8000000000554889e548897df8488b7df88b078945f4488b7df8488b7f180fb64701488b3d942400004863c84801cf48897de88b45f4488b4de80fbe1139d00f8510000000488b45f8c7401001000000e90b000000488b45f8c7401000000000488b45f8488b48184883c102488948185dc30f1f00554889e548897df8488b7df8488b7f188a47018845f7488b7df8837f10000f851b0000000fb645f7488b4df8488b51184863f04801f248895118e90b000000488b45f8c7401000000000488b45f8488b48184883c102488948185dc30f1f4000554889e548897df85dc3660f1f440000554889e54088f88845fe8975f831c088c10fbe45fe83f841884df70f8c0d0000000fbe45fe83f85a0f9ec1884df78a45f7a8010f8505000000e929000000b81a0000000fbe4dfe83e941034df88945f089c8998b4df0f7f983c2414088d6408875ffe965000000e90000000031c088c10fbe45fe83f861884def0f8c0d0000000fbe45fe83f87a0f9ec1884def8a45efa8010f8505000000e929000000b81a0000000fbe4dfe83e961034df88945e889c8998b4de8f7f983c2614088d6408875ffe9060000008a45fe8845ff0fbe45ff5dc366666666662e0f1f840000000000554889e54883ec10be0200000048897df8488b7df88b0788c1884df70fbe7df7e8fbfeffff0fbef0488b55f88932488b55f84c8b42184983c0014c8942184883c4105dc36666662e0f1f840000000000554889e548897df8488b7df88b078945f4488b7df88b47048945f08b45f40345f0488b7df88907488b7df8488b4f184883c10148894f185dc30f1f8000000000554889e548897df8488b7df88b078945f4488b7df88b47048945f08b45f42b45f0488b7df88907488b7df8488b4f184883c10148894f185dc30f1f8000000000554889e548897df8488b7df8488b7f184883c70148897df0488b7df08b07488b7df88987b0000000488b7df8488b4f184883c10548894f185dc3660f1f440000554889e548897df8488b7df8488b7f1848ffc748897df0488b7df8488b7f184883c70248897de8488b7df00fb60783c0f089c783e80448897de08945dc0f8773000000488d057e000000488b4de0486314884801c2ffe2488b45e88b08488b45f88908e94e000000488b45e88b08488b45f8894804e93c000000488b45e88b08488b45f8894808e92a000000488b45e88b08488b45f889480ce918000000488b0543210000488b4de84863090fbe1408488b45f88910488b45f8488b48184883c106488948185dc38fffffffa0ffffffb2ffffffc4ffffffd6ffffff0f1f4000554889e54883ec2048897df8c745f400000000c745f00000000031c088c1837df400884def0f850a000000837df0090f9cc08845ef8a45efa8010f8505000000e963000000488b45f8488b40180fb608488b45f84883c020486355f048c1e2044801d00fb63039f10f852c000000c745f401000000488b45f84883c02048634df048c1e1044801c8488b4008488b4df84889cfffd0e9090000008b45f083c0018945f0e972ffffff4883c4205dc36690554889e54883ec10488d0571faffff4883c00448897df8488b7df848894718488b45f8488b40180fb60881f9f30000000f840e000000488b7df8e811ffffffe9dbffffff488b3d0d200000e880020000488b7df88b87b00000004883c4105dc3554889e54157415641554154534883ec18b80004000089c1488d15e1fcffff4c8d05aafdffff4c8d0d83fbffff4c8d15dcfbffff4c8d1d55fdffff488d1d0efdffff4c8d35f7faffff4c8d3db0faffff4c8d25b9fdffff48897dd0488975c8488b75d0c70600000000488b75d0c7460400000000488b75d0c7460800000000488b75d0c7460c00000000488b75d0c7461000000000488b75d0c786b000000000000000488b75d0c64620f0488b75d04c896628488b75d0c64630f1488b75d04c897e38488b75d0c64640f2488b75d04c897648488b75d0c64650f4488b75d048895e58488b75d0c64660f5488b75d04c895e68488b75d0c64670f3488b75d04c895678488b75d0c68680000000f6488b75d04c898e88000000488b75d0c68690000000f7488b75d04c898698000000488b75d0c686a0000000f8488b75d0488996a80000004889cfe82901000041bd120000004489ea48c7c1ffffffff488905941e0000488b058d1e00004883c030488b75c84889c7e8ef000000488945c04883c4185b415c415d415e415f5dc39090554889e54883ec20488d45e848897df8488975f048c745e8000000004889c74889d6e8ef00000031c989ce488d45e84889c7e8df0000004883c4205dc30f1f00554889e54883ec20488d45e848897df8488975f048c745e8000000004889c74889d6e8af00000031c989ce488d45e84889c7e89f00000041b001410fbec04883c4205dc36666662e0f1f840000000000554889e54883ec20488d45e848897df8488975f048c745e8000000004889c74889d6e85f00000031c989ce488d45e84889c7e84f0000004883c4205dc3ffff255c0e0000ff255e0e0000ff25600e0000ff25620e0000ff25640e0000ff25660e0000ff25680e0000ff256a0e0000ff256c0e0000ff256e0e0000ff25700e0000ff25720e0000ff25740e0000ff25760e0000ff25780e00004c8d1de90d00004153ff25d90d0000906819000000e9e6ffffff6862000000e9dcffffff6885000000e9d2ffffff689d000000e9c8ffffff68ba000000e9beffffff68d4000000e9b4ffffff68f2000000e9aaffffff681c010000e9a0ffffff6835010000e996ffffff684c010000e98cffffff6826000000e982ffffff683a000000e978ffffff6846000000e96effffff6854000000e964ffffff6800000000e95affffff766965774469644c6f616400736574526570726573656e7465644f626a6563743a0070776400737472696e6756616c7565006861735072656669783a006c656e67746800737562737472696e6746726f6d496e6465783a006973457175616c546f537472696e673a00737562737472696e675769746852616e67653a0055544638537472696e67006f6e4661696c6564006f6e5375636365737300616c6c6f6300696e697400736574416c6572745374796c653a00616464427574746f6e576974685469746c653a007365744d657373616765546578743a00736574496e666f726d6174697665546578743a007368617265644170706c69636174696f6e006b657957696e646f7700626567696e53686565744d6f64616c466f7257696e646f773a636f6d706c6574696f6e48616e646c65723a00636865636b436f64653a002e6378785f6465737472756374007365745077643a005f707764006973457175616c3a00636c6173730073656c6600706572666f726d53656c6563746f723a00706572666f726d53656c6563746f723a776974684f626a6563743a00706572666f726d53656c6563746f723a776974684f626a6563743a776974684f626a6563743a00697350726f78790069734b696e644f66436c6173733a0069734d656d6265724f66436c6173733a00636f6e666f726d73546f50726f746f636f6c3a00726573706f6e6473546f53656c6563746f723a0072657461696e0072656c65617365006175746f72656c656173650072657461696e436f756e74007a6f6e650068617368007375706572636c617373006465736372697074696f6e0064656275674465736372697074696f6e006170706c69636174696f6e53686f756c6454"
loc_100001980=re.findall("..",loc_100001980)
#print(loc_100001980)
a=0
code=[]
c=[
["f0",6,lambda x:str("mov r"+x[1]+",0x"+x[2])],
["f1",1,lambda x:str("xor r10,r11")],
["f2",2,lambda x:str("cmp r10,byte ptr ss:[0x"+x[1]+"]")],
["f3",1,lambda x:"nop"],
["f4",1,lambda x:str("add r10,r11")],
["f5",1,lambda x:str("sub r10,r11")],
["f6",2,lambda x:str("jz "+x[1])],
["f7",5,lambda x:str("mov buf,imm")],
["f8",1,lambda x:str("caesar encode r10,2")]
]
while 1:
for i in c:
if(loc_100001980[a] in i):
print(i[2](loc_100001980[a:a+i[1]]))
#print(loc_100001980[a:a+i[1]])
a+=i[1]
break
運(yùn)行后效果如下,極大的增強(qiáng)了可讀性
mov r10,0x66
caesar encode r10,2
cmp r10,byte ptr ss:[0x30]
jz c1
mov r10,0x63
caesar encode r10,2
cmp r10,byte ptr ss:[0x31]
jz b6
mov r10,0x6a
caesar encode r10,2
cmp r10,byte ptr ss:[0x32]
jz ab
mov r10,0x6a
caesar encode r10,2
cmp r10,byte ptr ss:[0x33]
jz a0
mov r10,0x6d
caesar encode r10,2
cmp r10,byte ptr ss:[0x34]
jz 95
mov r10,0x57
caesar encode r10,2
cmp r10,byte ptr ss:[0x35]
jz 8a
mov r10,0x6d
caesar encode r10,2
cmp r10,byte ptr ss:[0x36]
jz 7f
mov r10,0x73
caesar encode r10,2
cmp r10,byte ptr ss:[0x37]
jz 74
mov r10,0x45
caesar encode r10,2
cmp r10,byte ptr ss:[0x38]
jz 69
mov r10,0x6d
caesar encode r10,2
cmp r10,byte ptr ss:[0x39]
jz 5e
mov r10,0x72
caesar encode r10,2
cmp r10,byte ptr ss:[0x3a]
jz 53
mov r10,0x52
caesar encode r10,2
cmp r10,byte ptr ss:[0x3b]
jz 48
mov r10,0x66
caesar encode r10,2
cmp r10,byte ptr ss:[0x3c]
jz 3d
mov r10,0x63
caesar encode r10,2
cmp r10,byte ptr ss:[0x3d]
jz 32
mov r10,0x44
caesar encode r10,2
cmp r10,byte ptr ss:[0x3e]
jz 27
mov r10,0x6a
caesar encode r10,2
cmp r10,byte ptr ss:[0x3f]
jz 1c
mov r10,0x79
caesar encode r10,2
cmp r10,byte ptr ss:[0x40]
jz 11
mov r10,0x65
caesar encode r10,2
cmp r10,byte ptr ss:[0x41]
jz 06
mov buff,imm
nop
mov buff,imm
nop
像這種偽代碼不能運(yùn)行,所以說(shuō)實(shí)際比賽中還是分析好了像前一個(gè)方法一樣,不一句一句翻譯,直接寫腳本解題比較快
02Obfuscating macros
ubuntu64 + gdbserver + ida64調(diào)試環(huán)境
首先main函數(shù)里關(guān)鍵的函數(shù)只有兩個(gè),一個(gè)sub4069D6一個(gè)sub4013E6,先跟進(jìn)第一個(gè)函數(shù),在所有傳入我們輸入的變量的地方下斷點(diǎn) 然后配置好遠(yuǎn)程gdb調(diào)試器,f9運(yùn)行起來(lái),隨手輸入ABCD,ida中觸發(fā)斷點(diǎn),首先先觀察寄存器的值,在堆棧中找到我們輸入的字符串
然后一路f9觀察對(duì)我們輸入的字符串做了什么
f9幾次后會(huì)發(fā)現(xiàn)他把我們輸入的ABCD轉(zhuǎn)換成了0xABCD
繼而我們推測(cè)下一個(gè)函數(shù)會(huì)對(duì)0xABCD進(jìn)一步處理或者與一些值進(jìn)行比較,于是刪除所有其他的斷點(diǎn),在0xABCD處下內(nèi)存讀寫斷點(diǎn),然后f9運(yùn)行,就觸發(fā)了硬件斷點(diǎn)
第一次 test al,al是檢測(cè)輸入是否為空,再按f9觸發(fā)第二次斷點(diǎn),會(huì)發(fā)現(xiàn)如下代碼
text:0000000000405FA3 loc_405FA3:
.text:0000000000405FA3 mov rax, [rbp+var_220]
.text:0000000000405FAA lea rdx, [rax+1]
.text:0000000000405FAE mov [rbp+var_220], rdx
.text:0000000000405FB5 movzx edx, byte ptr [rax]
.text:0000000000405FB8 mov rax, [rbp+var_210]
.text:0000000000405FBF movzx eax, byte ptr [rax]
.text:0000000000405FC2 mov ecx, eax
.text:0000000000405FC4 mov eax, edx
.text:0000000000405FC6 sub ecx, eax
.text:0000000000405FC8 mov eax, ecx
.text:0000000000405FCA mov edx, eax
.text:0000000000405FCC mov rax, [rbp+var_210]
.text:0000000000405FD3 mov [rax], dl
.text:0000000000405FD5 mov rax, [rbp+var_280]
.text:0000000000405FDC test rax, rax
.text:0000000000405FDF jnz short loc_
f8到0000000000405FC6處會(huì)發(fā)現(xiàn)他拿我們的0xAB與一個(gè)0x79進(jìn)行了對(duì)比,這樣的話我們只需要在sub這里下一個(gè)斷點(diǎn),一路f9就好了 他一開始沒(méi)有驗(yàn)證長(zhǎng)度,直接進(jìn)行了對(duì)比,只要對(duì)比到不同就退出,因?yàn)槲覀冚斎肓薃BCD,觀察到他對(duì)比一次就會(huì)退出了 這樣我們就可以每次多輸入兩個(gè)字符,并且這兩個(gè)字符只能是0到9和A到F,然后取出新的對(duì)比的字符再多輸入兩個(gè)字符直到他不在對(duì)比就得到flag了
這道題目還是說(shuō),如果沒(méi)有先調(diào)試得到的知識(shí)背景,用pintool解題也會(huì)卡殼的,因?yàn)榻?jīng)過(guò)我們的分析,發(fā)現(xiàn)第一個(gè)函數(shù)把字符串ABCD轉(zhuǎn)換成了0xABCD,這里四個(gè)字節(jié)變成了兩個(gè)字節(jié),如果用pintool解題需要兩個(gè)字符兩個(gè)字符得組合得測(cè)試,這個(gè)題目不是純正的ollvm混淆的,大體的思路就是污點(diǎn)追蹤,把所有的涉及到用戶輸入的地方都下斷點(diǎn),還有就是內(nèi)存斷點(diǎn)的使用,在必要時(shí)刻是很有用的。
感謝你的閱讀,相信你對(duì)“DDCTF2019兩個(gè)逆向分別是什么”這一問(wèn)題有一定的了解,快去動(dòng)手實(shí)踐吧,如果想了解更多相關(guān)知識(shí)點(diǎn),可以關(guān)注億速云網(wǎng)站!小編會(huì)繼續(xù)為大家?guī)?lái)更好的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。