這題是個逆向
要輸入正確的 FLAG
.text:0000000000005666 call objects_init
.text:000000000000566B lea rsi, input
.text:0000000000005672 lea rdi, format ; "%49s"
.text:0000000000005679 mov eax, 0
.text:000000000000567E call _scanf
.text:0000000000005683 lea rdi, input ; s
.text:000000000000568A call _strlen
.text:000000000000568F cmp rax, 48
.text:0000000000005693 jz short loc_569A
.text:0000000000005695 call putNo
.text:000000000000570B label_break_loop: ; CODE XREF: main+48↑j
.text:000000000000570B mov edx, 48 ; n
.text:0000000000005710 lea rsi, flag_encrypted ; s2
.text:0000000000005717 lea rdi, input_encrypted ; s1
.text:000000000000571E call _memcmp
.text:0000000000005723 test eax, eax
.text:0000000000005725 jnz short label_fail
.text:0000000000005727 lea rsi, input
.text:000000000000572E lea rdi, aGreatHereSTheF ; "Great! Here's the flag: hitcon{%s}\n"
.text:0000000000005735 mov eax, 0
.text:000000000000573A call _printf
.text:000000000000573F jmp short label_reutrn_0
.text:0000000000005741 ; ---------------------------------------------------------------------------
.text:0000000000005741
.text:0000000000005741 label_fail: ; CODE XREF: main+C8↑j
.text:0000000000005741 call putNo
題目要輸入正確的 Flag,Flag 長度為 48,輸入的東西會經過加密後,透過 memcpy 判斷是不是跟加密的 Flag 一樣
這類型題目通常不是暴力碰撞,就是用了可逆的加密
所以先來找如何處理 input
char qword_2131A0[16];
char qword_2131B0[16];
int main() {
char input[49];
char input_encrypted[49];
scanf("%49s", &input);
if (strlen(input) != 48) {
puts("No");
} else {
int i = 0;
for (i = 0 ; i < 48; i++) { try { *(uin64_t*)qword_2131A0 = *(uin64_t*)(input + 16 * i); *(uin64_t*)(qword_2131A0 + 8) = *(uin64_t*)(input + 16 * i + 8); execute_object(0x1C); } catche(exception& ex) { if (ex->object_index != 65) {
execute_object(ex->object_index);
} else {
*(uin64_t*)(input_encrypted + 16 * i) = *(uin64_t*)(qword_2131B0);
*(uin64_t*)(input_encrypted + 16 * i + 8) = *(uin64_t*)(qword_2131B0 + 8);
}
}
}
}
}
從 main 可以看到程式用了 try-catch 以及 throw exception 來控制流程
main 流程大概是長上面那樣,有一個 for-loop 處理 input,每次複製16個bytes到 0x0000002131A0
最後呼叫 execute_object ,如果有 exception 會看他存的一個內容是不是 65,非 65 的話繼續用這個 index 找物件的函數執行,是 65 的話把 qword_2131B0 的內容複製到 input_encrypted 中,繼續下一次的 Loop, 總共執行三次後離開
@func main
.text:00000000000056A1 cmp [rbp+i], 47
.text:00000000000056A5 jg short label_break_loop
.text:00000000000056A7 mov [rbp+function_index], 1Ch
.text:00000000000056AE mov eax, [rbp-28]
.text:00000000000056B1 movsxd rdx, eax
.text:00000000000056B4 lea rax, input
.text:00000000000056BB add rax, rdx
.text:00000000000056BE mov rdx, [rax+8]
.text:00000000000056C2 mov rax, [rax]
.text:00000000000056C5 mov cs:ptr_0, rax
.text:00000000000056CC mov cs:ptr_8, rdx
.text:00000000000056D3 mov eax, [rbp+function_index]
.text:00000000000056D6 mov edi, eax
.text:00000000000056D8 call execute_object
@func execute_object
.text:00000000000055C5 mov edx, [rbp+function_index]
.text:00000000000055C8 movsxd rdx, edx
.text:00000000000055CB lea rcx, ds:0[rdx*8]
.text:00000000000055D3 lea rdx, objects ; objects pointers
.text:00000000000055DA mov rdx, [rcx+rdx]
.text:00000000000055DE mov [rax], rdx
.text:00000000000055E1 mov edx, 0
.text:00000000000055E6 lea rsi, _ZTIP4Base ; `typeinfo for'Base *
.text:00000000000055ED mov rdi, rax
.text:00000000000055F0 call ___cxa_throw
.text:00000000000055F5 ; ---------------------------------------------------------------------------
.text:00000000000055F5 cmp rdx, 1
.text:00000000000055F9 jz short loc_5603
.text:00000000000055FB mov rdi, rax ; struct _Unwind_Exception *
.text:00000000000055FE call __Unwind_Resume
.text:0000000000005603 ; ---------------------------------------------------------------------------
.text:0000000000005603 mov rdi, rax
.text:0000000000005606 call ___cxa_begin_catch
.text:000000000000560B mov [rbp+except], rax
.text:000000000000560F mov rax, [rbp+except]
.text:0000000000005613 mov rax, [rax]
.text:0000000000005616 mov rax, [rax]
.text:0000000000005619 mov rdx, [rbp+except]
.text:000000000000561D mov rdi, rdx
.text:0000000000005620 ; try {
.text:0000000000005620 call rax ; call function
在 main 中可以找到圖中 execute_object 這個 call
這邊一樣可以發現又是 try-catch throw new exception 的噁心流程
這個 calll 有一個參數 (rdi) 是第幾個物件, .text:00000000000055D3 這行會取得物件實體的位置,然後在 .text:0000000000005620 呼叫成員函數
所以從 main 開始看 .text:00000000000056A7 第一次會 execute_object(0x1c); 呼叫開始執行加密的
.bss:00000000002131E0 ; __int64 objects[]
.bss:00000000002131E0 objects dq ? ; DATA XREF: objects_init+312↑w
.bss:00000000002131E0 ; execute_object+24↑o
.bss:00000000002131E8 qword_2131E8 dq ? ; DATA XREF: objects_init+702↑w
.bss:00000000002131F0 qword_2131F0 dq ? ; DATA XREF: objects_init+B7E↑w
.bss:00000000002131F8 qword_2131F8 dq ? ; DATA XREF: objects_init+32E↑w
.bss:0000000000213200 qword_213200 dq ? ; DATA XREF: objects_init+55E↑w
.bss:0000000000213208 qword_213208 dq ? ; DATA XREF: objects_init+A2E↑w
.bss:0000000000213210 qword_213210 dq ? ; DATA XREF: objects_init+2A2↑w
.bss:0000000000213218 qword_213218 dq ? ; DATA XREF: objects_init+73A↑w
.bss:0000000000213220 qword_213220 dq ? ; DATA XREF: objects_init+2F6↑w
.bss:0000000000213228 qword_213228 dq ? ; DATA XREF: objects_init+462↑w
.bss:0000000000213230 qword_213230 dq ? ; DATA XREF: objects_init+34A↑w
.bss:0000000000213238 qword_213238 dq ? ; DATA XREF: objects_init+A4A↑w
.bss:0000000000213240 qword_213240 dq ? ; DATA XREF: objects_init+9DA↑w
.bss:0000000000213248 qword_213248 dq ? ; DATA XREF: objects_init+7C6↑w
.bss:0000000000213250 qword_213250 dq ? ; DATA XREF: objects_init+3A↑w
.bss:0000000000213258 qword_213258 dq ? ; DATA XREF: objects_init+C0A↑w
.bss:0000000000213260 qword_213260 dq ? ; DATA XREF: objects_init+152↑w
.bss:0000000000213268 qword_213268 dq ? ; DATA XREF: objects_init+D22↑w
.bss:0000000000213270 qword_213270 dq ? ; DATA XREF: objects_init+AA↑w
.bss:0000000000213278 qword_213278 dq ? ; DATA XREF: objects_init+5CE↑w
.bss:0000000000213280 qword_213280 dq ? ; DATA XREF: objects_init+C42↑w
.bss:0000000000213288 qword_213288 dq ? ; DATA XREF: objects_init+836↑w
.bss:0000000000213290 qword_213290 dq ? ; DATA XREF: objects_init+2DA↑w
.bss:0000000000213298 qword_213298 dq ? ; DATA XREF: objects_init+216↑w
.bss:00000000002132A0 qword_2132A0 dq ? ; DATA XREF: objects_init+3F2↑w
.bss:00000000002132A8 qword_2132A8 dq ? ; DATA XREF: objects_init+57A↑w
.bss:00000000002132B0 qword_2132B0 dq ? ; DATA XREF: objects_init+72↑w
.bss:00000000002132B8 qword_2132B8 dq ? ; DATA XREF: objects_init+40E↑w
.bss:00000000002132C0 qword_2132C0 dq ? ;第一次取得的物件位置 DATA XREF: objects_init+7FE↑w
接著我們繼續看, execute_object 會從物件地址的陣列中取出
第一次執行時是使用第 0x1c 個物件
00000000002131E0 + 0x1C * 8 = 0x00000000002132C0
.text:0000000000005018 call __Znwm ; operator new(ulong)
.text:000000000000501D mov rbx, rax
.text:0000000000005020 mov rdi, rbx
.text:0000000000005023 call sub_B8BC <------------------------
.text:0000000000005028 mov cs:qword_2132C0, rbx <-----------------------
.text:000000000000B8BC push rbp
.text:000000000000B8BD mov rbp, rsp
.text:000000000000B8C0 sub rsp, 10h
.text:000000000000B8C4 mov [rbp+var_8], rdi
.text:000000000000B8C8 mov rax, [rbp+var_8]
.text:000000000000B8CC mov rdi, rax
.text:000000000000B8CF call sub_ACD2
.text:000000000000B8D4 lea rdx, off_210EA0 <-------------------- asign vtable
.text:000000000000B8DB mov rax, [rbp+var_8]
.text:000000000000B8DF mov [rax], rdx
.text:000000000000B8E2 nop
.text:000000000000B8E3 leave
.text:000000000000B8E4 retn
.data.rel.ro:0000000000210EA0 off_210EA0 dq offset sub_68C0 ; DATA XREF: sub_B8BC+18↑o
用 IDA 來看誰用到了這個位置,可以找到 0000000000005028
在這裡可以看到物件被new 出來後把位置塞進去了, syb_B8BC 想必就是他的建構子
從建構子就能找到 vtable 為 off_210EA0
最後找到成員函數 sub_68C0
.text:00000000000068C0 push rbp
.text:00000000000068C1 mov rbp, rsp
.text:00000000000068C4 push rbx
.text:00000000000068C5 sub rsp, 28h
.text:00000000000068C9 mov [rbp+var_28], rdi
.text:00000000000068CD mov edi, 8
.text:00000000000068D2 call ___cxa_allocate_exception
.text:00000000000068D7 mov rbx, rax
.text:00000000000068DA mov rdi, rbx
.text:00000000000068DD call sub_57F8
.text:00000000000068E2 mov rax, cs:_ZNSt9exceptionD1Ev_ptr
.text:00000000000068E9 mov rdx, rax
.text:00000000000068EC lea rsi, _ZTISt9exception ; `typeinfo for'std::exception
.text:00000000000068F3 mov rdi, rbx
.text:00000000000068F6 ; try {
.text:00000000000068F6 call ___cxa_throw
.text:00000000000068F6 ; } // starts at 68F6
.text:00000000000068FB ; ---------------------------------------------------------------------------
.text:00000000000068FB ; catch(...) // owned by 68F6
.text:00000000000068FB mov rdi, rax
.text:00000000000068FE call ___cxa_begin_catch
.text:0000000000006903 mov [rbp+var_14], 0
.text:000000000000690A
.text:000000000000690A loc_690A: ; CODE XREF: sub_68C0+88↓j
.text:000000000000690A cmp [rbp+var_14], 0Fh
.text:000000000000690E jg short loc_694A
.text:0000000000006910 mov eax, [rbp+var_14]
.text:0000000000006913 movsxd rdx, eax
.text:0000000000006916 lea rax, ptr_0
.text:000000000000691D movzx ecx, byte ptr [rdx+rax]
.text:0000000000006921 mov eax, [rbp+var_14]
.text:0000000000006924 movsxd rdx, eax
.text:0000000000006927 lea rax, ptr_out_0
.text:000000000000692E movzx eax, byte ptr [rdx+rax]
.text:0000000000006932 xor ecx, eax
.text:0000000000006934 mov eax, [rbp+var_14]
.text:0000000000006937 movsxd rdx, eax
.text:000000000000693A lea rax, ptr_0
.text:0000000000006941 mov [rdx+rax], cl
.text:0000000000006944 add [rbp+var_14], 1
.text:0000000000006948 jmp short loc_690A
.text:000000000000694A ; ---------------------------------------------------------------------------
.text:000000000000694A
.text:000000000000694A loc_694A: ; CODE XREF: sub_68C0+4E↑j
.text:000000000000694A mov edi, 4
.text:000000000000694F call ___cxa_allocate_exception
.text:0000000000006954 mov dword ptr [rax], 51
.text:000000000000695A mov edx, 0
.text:000000000000695F lea rsi, _ZTIi ; `typeinfo for'int
.text:0000000000006966 mov rdi, rax
.text:0000000000006969 ; try {
.text:0000000000006969 call ___cxa_throw
.text:0000000000006969 ; } // starts at 6969
.text:000000000000696E ; ---------------------------------------------------------------------------
.text:000000000000696E ; cleanup() // owned by 6969
.text:000000000000696E mov rbx, rax
.text:0000000000006971 call ___cxa_end_catch
.text:0000000000006976 mov rax, rbx
.text:0000000000006979 mov rdi, rax ; struct _Unwind_Exception *
.text:000000000000697C call __Unwind_Resume
.text:000000000000697C ; } // starts at 68C0
.text:000000000000697C sub_68C0 endp
在這邊又是 try-catch 惡夢
真正的程式碼在 .text:0000000000006903 ~ .text:0000000000006948
也就是 call ___cxa_begin_catch 的下一行到 mov edi, 4 前一行結束
裡面放的是加密的程式
接著new 出一個物件把下一個用到的物件編號 51 放入 (.text:0000000000006954) ,最後 throw exception 出去
然後剛剛 new 物件的地方有一百多個物件
每一個物件都是同樣的結構
所以可能有非常多的函數在處理,手動追的話非常累
所以開始想有沒有可以取出程式碼的方法
稍微看了一下
函數的頭 .text:00000000000068C0 到 .text:00000000000068FE 的 offset 是 0x43
最後發現每一個用到的函數頭到需要的程式碼的偏移都是 0x43
所以就用 idapython 寫了一個工具來追蹤加密流程
import idautils
from ida_hexrays import init_hexrays_plugin, decompile
from ida_funcs import get_func
from ida_lines import tag_remove
out = open('eop.asm', 'w')
out2 = open('eop.c', 'w')
def decompile_func(ea):
if not init_hexrays_plugin():
return False
f = get_func(ea)
if f is None:
return False
cfunc = decompile(f);
if cfunc is None:
return False
lines = []
sv = cfunc.get_pseudocode();
for sline in sv:
line = tag_remove(sline.line);
lines.append(line)
return "\n".join(lines)
all = ''
i = 0x1C
while i != 65:
object_pointer = 0x2131E0 + i * 8
xrefs = idautils.XrefsTo(object_pointer, 0)
for xx in xrefs:
prev_call = PrevHead(xx.frm)
prev_call_addr = idc.GetOperandValue(prev_call, 0)
lea_edx = prev_call_addr + 0x18
vtable = idc.GetOperandValue(lea_edx, 1)
call_addr = Qword(vtable)
print 'Begin function addr ('+hex(i)+')'+ hex(call_addr)
real_code_addr = call_addr + 0x43
j = real_code_addr
while True:
asm = idc.GetDisasm(j)
next_asm = idc.GetDisasm(NextHead(j))
if '___cxa_allocate_exception' in next_asm:
break
print asm
out.write(asm + "\n")
j = NextHead(j)
k = j
j = NextHead(j)
l = NextHead(j)
i = idc.GetOperandValue(l, 1)
MakeUnkn(call_addr, 0)
idc.PatchByte(k, 0xC3)
MakeFunction(real_code_addr)
SetType(real_code_addr, "void x()")
code = decompile_func(real_code_addr)
print code
code = code[code.find("{") + 2 + 1:code.find("}") - 1] + "\n"
all += code
break
out2.write(all)
out.close()
out2.close()
這個腳本主要做了幾個事情
從 0x1C 開始抓函數,然後從函數頭 + 0x43 的位置一路抓到 ___cxa_allocate_exception 前二行結束
最後為了方便 IDA Pro 做反編譯,我 patch 了 mov edi, 4 成 ret ,然後函數開始改成 +0x43 的地方
在取出程式碼最後輸出
mov dword ptr [rbp-14h], 0
cmp dword ptr [rbp-14h], 0Fh
jg short locret_694A
mov eax, [rbp-14h]
movsxd rdx, eax
lea rax, ptr_0
movzx ecx, byte ptr [rdx+rax]
mov eax, [rbp-14h]
movsxd rdx, eax
lea rax, out_0
movzx eax, byte ptr [rdx+rax]
xor ecx, eax
mov eax, [rbp-14h]
movsxd rdx, eax
lea rax, ptr_0
mov [rdx+rax], cl
add dword ptr [rbp-14h], 1
jmp short loc_690A
retn
movzx eax, byte ptr cs:ptr_0
movzx eax, al
movzx edx, byte ptr cs:ptr_0+1
movzx edx, dl
shl edx, 8
or edx, eax
movzx eax, byte ptr cs:ptr_0+2
movzx eax, al
shl eax, 10h
or edx, eax
movzx eax, byte ptr cs:ptr_0+3
movzx eax, al
...
大概長這樣,不過 ASM 有 1000 行還是很累,所以看反編譯的虛擬C扣
__int64 v0; // rbp
for ( *(_DWORD *)(v0 - 20) = 0; *(_DWORD *)(v0 - 20) <= 15; ++*(_DWORD *)(v0 - 20) )
ptr_0[*(signed int *)(v0 - 20)] ^= *((_BYTE *)&out_0 + *(signed int *)(v0 - 20));
h1 = ((ptr_0[3] << 24) | (ptr_0[2] << 16) | *(unsigned __int16 *)ptr_0) ^ *(_DWORD *)pKey;
h2 = ((ptr_0[7] << 24) | (ptr_0[6] << 16) | *(unsigned __int16 *)&ptr_0[4]) ^ *((_DWORD *)pKey + 1);
h3 = ((ptr_8[3] << 24) | (ptr_8[2] << 16) | *(unsigned __int16 *)ptr_8) ^ *((_DWORD *)pKey + 2);
h4 = ((ptr_8[7] << 24) | (ptr_8[6] << 16) | *(unsigned __int16 *)&ptr_8[4]) ^ *((_DWORD *)pKey + 3); ; h5 = *((_DWORD *)pKey + BYTE2(h1) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h1) + 320LL) ^ *((_DWORD *)pKey + (unsigned __int8)h1 + 64LL) ^ *((_DWORD *)pKey + ((unsigned int)h1 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h2) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h2 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h2 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h2) + 832LL);
h3 ^= *((_DWORD *)pKey + 8) + h6 + h5;
h3 = __ROR4__(h3, 1);
h4 = __ROL4__(h4, 1);
h4 ^= *((_DWORD *)pKey + 9) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h3) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h3) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h3
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h3 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h4) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h4 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h4 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h4) + 832LL);
h1 ^= *((_DWORD *)pKey + 10) + h6 + h5;
h1 = __ROR4__(h1, 1);
h2 = __ROL4__(h2, 1);
h2 ^= *((_DWORD *)pKey + 11) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h1) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h1) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h1
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h1 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h2) + 0x240LL) ^ *((_DWORD *)pKey + (unsigned __int8)h2 + 0x140LL) ^ *((_DWORD *)pKey + ((unsigned int)h2 >> 24) + 0x40LL) ^ *((_DWORD *)pKey + BYTE2(h2) + 0x340LL);
h3 ^= *((_DWORD *)pKey + 12) + h6 + h5;
h3 = __ROR4__(h3, 1);
h4 = __ROL4__(h4, 1);
h4 ^= *((_DWORD *)pKey + 13) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h3) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h3) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h3
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h3 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h4) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h4 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h4 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h4) + 832LL);
h1 ^= *((_DWORD *)pKey + 14) + h6 + h5;
h1 = __ROR4__(h1, 1);
h2 = __ROL4__(h2, 1);
h2 ^= *((_DWORD *)pKey + 15) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h1) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h1) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h1
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h1 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h2) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h2 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h2 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h2) + 832LL);
h3 ^= *((_DWORD *)pKey + 16) + h6 + h5;
h3 = __ROR4__(h3, 1);
h4 = __ROL4__(h4, 1);
h4 ^= *((_DWORD *)pKey + 17) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h3) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h3) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h3
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h3 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h4) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h4 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h4 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h4) + 832LL);
h1 ^= *((_DWORD *)pKey + 18) + h6 + h5;
h1 = __ROR4__(h1, 1);
h2 = __ROL4__(h2, 1);
h2 ^= *((_DWORD *)pKey + 19) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h1) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h1) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h1
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h1 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h2) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h2 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h2 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h2) + 832LL);
h3 ^= *((_DWORD *)pKey + 20) + h6 + h5;
h3 = __ROR4__(h3, 1);
h4 = __ROL4__(h4, 1);
h4 ^= *((_DWORD *)pKey + 21) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h3) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h3) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h3
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h3 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h4) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h4 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h4 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h4) + 832LL);
h1 ^= *((_DWORD *)pKey + 22) + h6 + h5;
h1 = __ROR4__(h1, 1);
h2 = __ROL4__(h2, 1);
h2 ^= *((_DWORD *)pKey + 23) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h1) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h1) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h1
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h1 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h2) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h2 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h2 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h2) + 832LL);
h3 ^= *((_DWORD *)pKey + 24) + h6 + h5;
h3 = __ROR4__(h3, 1);
h4 = __ROL4__(h4, 1);
h4 ^= *((_DWORD *)pKey + 25) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h3) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h3) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h3
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h3 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h4) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h4 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h4 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h4) + 832LL);
h1 ^= *((_DWORD *)pKey + 26) + h6 + h5;
h1 = __ROR4__(h1, 1);
h2 = __ROL4__(h2, 1);
h2 ^= *((_DWORD *)pKey + 27) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h1) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h1) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h1
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h1 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h2) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h2 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h2 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h2) + 832LL);
h3 ^= *((_DWORD *)pKey + 28) + h6 + h5;
h3 = __ROR4__(h3, 1);
h4 = __ROL4__(h4, 1);
h4 ^= *((_DWORD *)pKey + 29) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h3) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h3) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h3
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h3 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h4) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h4 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h4 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h4) + 832LL);
h1 ^= *((_DWORD *)pKey + 30) + h6 + h5;
h1 = __ROR4__(h1, 1);
h2 = __ROL4__(h2, 1);
h2 ^= *((_DWORD *)pKey + 31) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h1) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h1) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h1
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h1 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h2) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h2 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h2 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h2) + 832LL);
h3 ^= *((_DWORD *)pKey + 32) + h6 + h5;
h3 = __ROR4__(h3, 1);
h4 = __ROL4__(h4, 1);
h4 ^= *((_DWORD *)pKey + 33) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h3) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h3) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h3
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h3 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h4) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h4 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h4 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h4) + 832LL);
h1 ^= *((_DWORD *)pKey + 34) + h6 + h5;
h1 = __ROR4__(h1, 1);
h2 = __ROL4__(h2, 1);
h2 ^= *((_DWORD *)pKey + 35) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h1) + 576LL) ^ *((_DWORD *)pKey + BYTE1(h1) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h1
+ 64LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h1 >> 24)
+ 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h2) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h2 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h2 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h2) + 832LL);
h3 ^= *((_DWORD *)pKey + 36) + h6 + h5;
h3 = __ROR4__(h3, 1);
h4 = __ROL4__(h4, 1);
h4 ^= *((_DWORD *)pKey + 37) + h5 + 2 * h6;
h5 = *((_DWORD *)pKey + BYTE2(h3) + 0x240LL) ^ *((_DWORD *)pKey + BYTE1(h3) + 320LL) ^ *((_DWORD *)pKey
+ (unsigned __int8)h3
+ 64LL) ^ *((_DWORD *)pKey + ((unsigned int)h3 >> 24) + 832LL);
h6 = *((_DWORD *)pKey + BYTE1(h4) + 576LL) ^ *((_DWORD *)pKey + (unsigned __int8)h4 + 320LL) ^ *((_DWORD *)pKey
+ ((unsigned int)h4 >> 24)
+ 64LL) ^ *((_DWORD *)pKey + BYTE2(h4) + 832LL);
h1 ^= *((_DWORD *)pKey + 38) + h6 + h5;
h1 = __ROR4__(h1, 1);
h2 = __ROL4__(h2, 1);
h2 ^= *((_DWORD *)pKey + 39) + h5 + 2 * h6;
;
h3 ^= *((_DWORD *)pKey + 4);
h4 ^= *((_DWORD *)pKey + 5);
h1 ^= *((_DWORD *)pKey + 6);
h2 ^= *((_DWORD *)pKey + 7);
LOBYTE(out_0) = h3;
BYTE1(out_0) = BYTE1(h3);
BYTE2(out_0) = BYTE2(h3);
BYTE3(out_0) = HIBYTE(h3);
BYTE4(out_0) = h4;
BYTE5(out_0) = BYTE1(h4);
BYTE6(out_0) = BYTE2(h4);
HIBYTE(out_0) = HIBYTE(h4);
LOBYTE(out_8) = h1;
BYTE1(out_8) = BYTE1(h1);
BYTE2(out_8) = BYTE2(h1);
BYTE3(out_8) = HIBYTE(h1);
BYTE4(out_8) = h2;
BYTE5(out_8) = BYTE1(h2);
BYTE6(out_8) = BYTE2(h2);
HIBYTE(out_8) = HIBYTE(h2);
最後就可以解出 FLAG 了
(2018/11/01 Update )
我腦弱忘了 Check後面 QQ ,最後的 XOR 那邊要給從下次加密後要 ^ hash[ i – 16]
整理後的程式碼以及解密的程式碼我放在 gist
有興趣的可以去看看 ouo
EOP 整理後 : https://gist.github.com/taida957789/f5b606fd1286e47eb18d3b9416f21094
EOP 解密:https://gist.github.com/taida957789/57b69940f3765e9eef0cade34eacab97