RE_Magic

标注了几个重要的函数如下:

print_rctf  .text   0000000000401FFB    
encode      .text   000000000040215B    
output      .text   0000000000402218    
verify      .text   0000000000402268    
vm_check    .text   00000000004029C7
首先,main函数里的东西是假的,那个flag解出来是a joke:p

Tls控制流程,在verify结束后最终跳转到别处执行,verify里面用currentTime作随机数种子,异或了一个256bytes的数组,然后经过某种变换需要使结果为0x700,这里别无它法,爆破,写了个debugger控制程序流程,代码有点长不贴了,最终爆破出来的time为0x5b00e398,patch程序让time强行返回0x5b00e398,在verify中计算出了一个dword,作为后续输出outputencode函数的解码Key,随后进入0x4023b1进行真正验证,这个函数首先输出了Flag的前一个部分rctf{h,接下来就是最难的part2,包括了一个vm,通过setJmp和longJmp来控制程序流程,还有一个div 0 exception改变了vm流程,需要在程序开头处偷到ExceptionHandler地址0x403e90进而分析真正的步骤。

关于vm,分析指令如下:

程序内的opcode:
AB 03 00 
AB 04 1A 
AB 00 66 
AA 05 02 
A9 53 
A0 05 
AB 06 CC 
A9 56 
AB 06 FF 
AC 56 
AE 50 
AD 00 
AA 06 05 
AA 05 01 
A9 53 
A0 05 
AF 56 00 
A7 01 
CC 
A9 35 
AA 05 03 
AF 54 00 
A6 D1 
CC

对应ida,一个个地翻译,再整理,得到如下结果:
dst -> dword_409040
dst[3]=0
dst[4]=0x1a
dst[0]=0x66
dst[5]=dst[2]  //dst[2]放的是用户输入变换过的结果的地址
dst[5]+=dst[3] //index
dst[5]=*dst[5] //取第index位
dst[6]=0xcc
dst[5]+=dst[6]
dst[6]=0xff
dst[5]&=dst[6]
dst[5]^=dst[0]
dst[0]= (~(dst[0]) & 0xff) //更新k
dst[6]=dst[5]
dst[5]=dst[1]  //目标数组,这个数组动态生成,是写死的不变
dst[5]+=dst[3] 
dst[5]=*dst[5] //第index位
dst[5]需要等于dst[6]

/*
这个等于关系,在异常处理程序里面实现
dst[0x20]=5
dst[0x21]=6
div 0 异常被0x403e90处理,调用sub_402930,
dst[5]=  dst[5]==dst[6]
最后longjmp到原位,继续执行
if dst[5]!=0 (dst[5]==dst[6])
    继续执行,否则退出,返回错误
*/

dst[3]+=dst[5] //这个时候dst[5]等于1,那这一句也就是index++
dst[5]=dst[3]
dst[5]需要等于dst[4],实际上就是看长度,控制循环,0x1a时返回

/*
同样,等于关系在异常处理程序中实现
dst[0x20]=5
dst[0x21]=4
div0 -> 异常被0x403e90处理,调用sub_402930,
dst[5]=  dst[5]==dst[4]
最后longjmp到原位,继续执行
若dst[5]==dst[4],返回(成功),否则循环开始
*/
分析完vm,算法出来了
input[]先与keys[]轮换xor,得到dst[],dst[]需要符合以下算式:
((dst[index]+0xcc)&0xff)^k == mubiao[index]

k每一轮计算完会更新,算式: k = ~k & 0xff

mubiao:
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

keys:
0x63,0xef,0xd5,0xa2,0x63,0xb8,0x17,0xab,0xd0,0xc6,0xd8,0x50,0xd1,0x46,0x97,0xdf,0xc4,0x51,0x01,0xe0,0x45,0x78,0xd8,0x5f,0xc4,0xd8
从程序内拿出数据求解即可,题目的flag还带有查重

mubiao = [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]
keys =   [0x63,0xef,0xd5,0xa2,0x63,0xb8,0x17,0xab,0xd0,0xc6,0xd8,0x50,0xd1,0x46,0x97,0xdf,0xc4,0x51,0x01,0xe0,0x45,0x78,0xd8,0x5f,0xc4,0xd8]
k=0x66
for i in range(len(mubiao)):
    mubiao[i] ^= k
    if (mubiao[i]-0xcc < 0):
        mubiao[i] += 0x100
    mubiao[i] -= 0xcc
    mubiao[i] ^= keys[i]
    k = ~k & 0xff
print 'rctf{h' + bytearray(mubiao)

Hook代码、源程序及idb.7z