RCTF2018_MAGIC 好久没发博了,大三破事太多了。。。估计这一年打CTF的时间不会太多了
不过,网鼎杯决赛和misty当队友这个事足够我吹一年了233(虽然我全程划水?)
时间戳爆破 首先要有一个对的时间戳才能进入下一步,且这个函数在main函数之前执行
这个可以用trace window追踪输出定位函数
然后爆破的话,我们就用iathook把magic.exe的时间戳验证函数调用出来爆破就行了,给力
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <stdio.h> #include <windows.h> #include <string.h> typedef __int64 (* main_t )();#define TIME_IAT 0xa38c #define CHECK_IAT 0x2268 #define CHAT_1 0x5020 int the_time=1526720400 ;__time64_t mygets (__time64_t *the_time_tmp) { return the_time; } void changeIAT (UINT64* iat, UINT64 newVal) { DWORD oldProtect; VirtualProtect(iat, sizeof (DWORD), PAGE_EXECUTE_READWRITE, &oldProtect); *iat = newVal; VirtualProtect(iat, sizeof (DWORD), oldProtect, &oldProtect); } int main () { printf ("ok?" ); char chat_tmp[256 ]={0 }; HMODULE hMod = LoadLibraryA("magic.dll" ); PBYTE pBase=(PBYTE)hMod; memcpy (chat_tmp,pBase+CHAT_1,256 ); if (pBase == NULL ) { printf ("cannot LoadLibrary" ); auto err = GetLastError(); printf ("%d" ,err); return -1 ; } UINT64* timeiat = (UINT64* )(pBase + TIME_IAT); changeIAT(timeiat, (UINT64)&mygets); main_t check_time=(main_t )(pBase + CHECK_IAT); while (TRUE) { if (check_time() == 0 ) { memcpy (pBase+CHAT_1,chat_tmp,256 ); the_time++; } else { printf ("the time is %d\n" ,the_time); break ; } } return 0 ; }
有个坑就是64位的函数地址是8字节,呵呵,我被DWORD坑了好久
RC4 标准rc4,不表了
这里特别迷的一个事就是,我边写注释IDA边给我删注释,我写到最后一行一看,前面的全没了?
重写IDA,刻不容缓
VM 虽然有点不必要,但是可以先打印出每次的指令。。。其实看数组就知道了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from idaapi import *from idc import *import osAddBpt(0x402a46 ) print "[+] breakpoint at 0x403e65..." StartDebugger("" ,"" ,"" ) for i in range(0 ,60 ): GetDebuggerEvent(WFNE_SUSP|WFNE_CONT, -1 ) eax = GetRegValue('EAX' ) if (eax != 0 ): print '[+] ' + hex(eax)
自从做了HCTF2018的level2.。。。再做这个我感觉舒服多了
逻辑如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 regs[1]存放的是unk_405320 regs[2]存放的是rc4加密后的输入 regs[3]=0 regs[4]=0x1a regs[0] = 0x66 ip-2e跳到这 regs[5]=regs[2] regs[5]+=regs[3] regs[5]=*regs[5] regs[6]=0xcc regs[5]+=regs[6] regs[6]=0xff regs[5]&=regs[6] regs[5]^=regs[0] regs[0]=~regs[0] regs[6]=regs[5] regs[5]=regs[1] regs[5]+=regs[3] regs[5]=*regs[5] dword_409060=5 dword_409064=6 regs[5]=regs[5]==regs[6] if(regs[5]): ip+2 else : break regs[3]+=regs[5] regs[5]=regs[3] regs[5]=regs[5]==regs[4] if !regs[5] : ip-2e 10101111 else ip+1 break
z3脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from z3 import *s=Solver() regs1=[0x89 , 0xC1 , 0xEC , 0x50 , 0x97 , 0x3A , 0x57 , 0x59 , 0xE4 , 0xE6 , 0xE4 , 0x42 , 0xCB , 0xD9 , 0x08 , 0x22 , 0xAE , 0x9D , 0x7C , 0x07 , 0x80 , 0x8F , 0x1B , 0x45 , 0x04 ,0xe8 ] regs2=[BitVec('n%d' %i,8 )for i in range(0x1a )] regs4=0x1a regs0=0x66 for i in range(0x1a ): s.add((regs2[i]+0xcc )&0xff ^regs0==regs1[i]) regs0=~regs0 s.check() flag=s.model() flag_rc4ed=[] for i in range(0x1a ): flag_rc4ed.append((flag[regs2[i]].as_long())) print hex((flag[regs2[i]].as_long())) print flag_rc4ed
然后把得到的flag_rc4ed带入rc4函数得到@ck_For_fun_02508iO2_2iOR}
把这个一输入,可以看到有rctf{h的形状。(据说非近视眼看不到)
后面 可能后面会写一些入坑区块链的东西?大三CTF的时间要减少了。。傻逼学院不认信安竞赛的加分我佛了,可能大三会多一些开发的经历吧。。。希望顺利。当然开发多了对逆向也有帮助,不止一个大哥如是说到。那么,calm down and move on!