分析
主函数
int __cdecl main()
{
int v1; // [esp+18h] [ebp-10h]
sub_80486BB();
v1 = sub_8048F45();
*(_DWORD *)(v1 + 32) = &unk_804B0C0;
sub_80491C8(); // 类似于xxtea,Smc自解密
((void (__cdecl *)(int))sub_80487A8)(v1);
return 0;
}
依旧用了Smc自解密,这次是类似xxtea解密,思路一样,直接动调就能看到真正的加密函数内容
这里a[8]获取值,然后确定加密流程,我们需要找到a[8]的值都是从哪里”进货”的,在第一次比较开始之前,肯定会有一个赋值的操作,找到”进货点”,进而确定流程。
既然有了“进货流程”,那就直接跟着走一遍,然后再具体分析过程中做了什么,自己人脑分析太费脑+费时,用脚本代替人脑分析:
其中有个坑点,就是在分析if(a2[8] == 0x80)内操作的时候, a2[sub_804875F(a2, 1)] = *(_DWORD *)(a2[8] + 2);是将四个字节赋值给了前面参数,所以我们在脚本中,需要注意一下这个点
a=[0xA1, 0xC1, 0x00, 0xB1, 0x77, 0xC2, 0x4A, 0x01, 0x00, 0x00,
0xC1, 0x01, 0xB2, 0x77, 0xC2, 0x19, 0x01, 0x00, 0x00, 0xC1,
0x02, 0xB4, 0x77, 0xC2, 0xDD, 0x01, 0x00, 0x00, 0xC1, 0x03,
0xB3, 0x77, 0xC2, 0x0F, 0x01, 0x00, 0x00, 0xC1, 0x04, 0xB2,
0x77, 0xC2, 0x1B, 0x01, 0x00, 0x00, 0xC1, 0x05, 0xB4, 0x77,
0xC2, 0x89, 0x01, 0x00, 0x00, 0xC1, 0x06, 0xB1, 0x77, 0xC2,
0x19, 0x01, 0x00, 0x00, 0xC1, 0x07, 0xB3, 0x77, 0xC2, 0x54,
0x01, 0x00, 0x00, 0xC1, 0x08, 0xB1, 0x77, 0xC2, 0x4F, 0x01,
0x00, 0x00, 0xC1, 0x09, 0xB1, 0x77, 0xC2, 0x4E, 0x01, 0x00,
0x00, 0xC1, 0x0A, 0xB3, 0x77, 0xC2, 0x55, 0x01, 0x00, 0x00,
0xC1, 0x0B, 0xB3, 0x77, 0xC2, 0x56, 0x01, 0x00, 0x00, 0xC1,
0x0C, 0xB4, 0x77, 0xC2, 0x8E, 0x00, 0x00, 0x00, 0xC1, 0x0D,
0xB2, 0x77, 0xC2, 0x49, 0x00, 0x00, 0x00, 0xC1, 0x0E, 0xB3,
0x77, 0xC2, 0x0E, 0x01, 0x00, 0x00, 0xC1, 0x0F, 0xB1, 0x77,
0xC2, 0x4B, 0x01, 0x00, 0x00, 0xC1, 0x10, 0xB3, 0x77, 0xC2,
0x06, 0x01, 0x00, 0x00, 0xC1, 0x11, 0xB3, 0x77, 0xC2, 0x54,
0x01, 0x00, 0x00, 0xC1, 0x12, 0xB2, 0x77, 0xC2, 0x1A, 0x00,
0x00, 0x00, 0xC1, 0x13, 0xB1, 0x77, 0xC2, 0x42, 0x01, 0x00,
0x00, 0xC1, 0x14, 0xB3, 0x77, 0xC2, 0x53, 0x01, 0x00, 0x00,
0xC1, 0x15, 0xB1, 0x77, 0xC2, 0x1F, 0x01, 0x00, 0x00, 0xC1,
0x16, 0xB3, 0x77, 0xC2, 0x52, 0x01, 0x00, 0x00, 0xC1, 0x17,
0xB4, 0x77, 0xC2, 0xDB, 0x00, 0x00, 0x00, 0xC1, 0x18, 0xB1,
0x77, 0xC2, 0x19, 0x01, 0x00, 0x00, 0xC1, 0x19, 0xB4, 0x77,
0xC2, 0xD9, 0x00, 0x00, 0x00, 0xC1, 0x1A, 0xB1, 0x77, 0xC2,
0x19, 0x01, 0x00, 0x00, 0xC1, 0x1B, 0xB3, 0x77, 0xC2, 0x55,
0x01, 0x00, 0x00, 0xC1, 0x1C, 0xB2, 0x77, 0xC2, 0x19, 0x00,
0x00, 0x00, 0xC1, 0x1D, 0xB3, 0x77, 0xC2, 0x00, 0x01, 0x00,
0x00, 0xC1, 0x1E, 0xB1, 0x77, 0xC2, 0x4B, 0x01, 0x00, 0x00,
0xC1, 0x1F, 0xB2, 0x77, 0xC2, 0x1E, 0x00, 0x00, 0x00, 0xC1,
0x20, 0x80, 0x02, 0x18, 0x00, 0x00, 0x00, 0x23, 0x10, 0xC1,
0x21, 0x80, 0x02, 0x10, 0x00, 0x00, 0x00, 0x23, 0xF7, 0xC1,
0x22, 0x80, 0x02, 0x08, 0x00, 0x00, 0x00, 0x23, 0xF7, 0xC1,
0x23, 0xF7, 0xFE, 0x80, 0x02, 0x05, 0x00, 0x00, 0x00, 0x22,
0x77, 0x10, 0x80, 0x02, 0x07, 0x00, 0x00, 0x00, 0x23, 0x80,
0x02, 0x23, 0x77, 0xF1, 0x98, 0x31, 0x77, 0x10, 0x80, 0x02,
0x18, 0x00, 0x00, 0x00, 0x23, 0x80, 0x02, 0x20, 0xB9, 0xE4,
0x35, 0x31, 0x77, 0x10, 0x80, 0x02, 0x12, 0x00, 0x00, 0x00,
0x22, 0x77, 0xA0, 0xC1, 0x24, 0x80, 0x02, 0x18, 0x00, 0x00,
0x00, 0x23, 0x10, 0xC1, 0x25, 0x80, 0x02, 0x10, 0x00, 0x00,
0x00, 0x23, 0xF7, 0xC1, 0x26, 0x80, 0x02, 0x08, 0x00, 0x00,
0x00, 0x23, 0xF7, 0xC1, 0x27, 0xF7, 0xFE, 0x32, 0x20, 0x43,
0x33, 0x77, 0x80, 0x02, 0x11, 0x00, 0x00, 0x00, 0x22, 0x35,
0x37, 0x38, 0x77, 0x80, 0x02, 0x0D, 0x00, 0x00, 0x00, 0x23,
0x77, 0x38, 0x39, 0x10, 0x32, 0x20, 0x43, 0x33, 0x77, 0x80,
0x02, 0x11, 0x00, 0x00, 0x00, 0x22, 0x35, 0x37, 0x38, 0x77,
0x80, 0x02, 0x0D, 0x00, 0x00, 0x00, 0x23, 0x77, 0x38, 0x39,
0xC7, 0xC1, 0x28, 0x80, 0x02, 0x18, 0x00, 0x00, 0x00, 0x23,
0x10, 0xC1, 0x29, 0x80, 0x02, 0x10, 0x00, 0x00, 0x00, 0x23,
0xF7, 0xC1, 0x2A, 0x80, 0x02, 0x08, 0x00, 0x00, 0x00, 0x23,
0xF7, 0xC1, 0x2B, 0xF7, 0xFE, 0x32, 0x20, 0x43, 0x33, 0x77,
0x80, 0x02, 0x11, 0x00, 0x00, 0x00, 0x22, 0x35, 0x37, 0x38,
0x77, 0x80, 0x02, 0x0D, 0x00, 0x00, 0x00, 0x23, 0x77, 0x38,
0x39, 0x10, 0x32, 0x20, 0x43, 0x33, 0x77, 0x80, 0x02, 0x11,
0x00, 0x00, 0x00, 0x22, 0x35, 0x37, 0x38, 0x77, 0x80, 0x02,
0x0D, 0x00, 0x00, 0x00, 0x23, 0x77, 0x38, 0x39, 0xC8, 0x99]
i=0
print("Start")
while True:
#0x71,0x41,0x44,0x76,0x30,0x34,0xA4实际上都不用写,因为a数组中并没有这些数
if(a[i]==0x71):
print("a[6]-=4,a[6]=0x%x"%(a[i+1]))
i+=5
if(a[i]==0x41):
print("a[1]+=a[2]")
i+=1
if(a[i]==0x42):
print("a[1]-=a[4]")
i+=1
if(a[i]==0x43):
print("a[1]*=a[3]")
i+=1
if(a[i]==0x37):
print("a[1]=a[5]")
i+=1
if(a[i]==0x38):
print("a[1]^=a[4]")
i+=1
if(a[i]==0x39):
print("a[1]^=a[5]")
i+=1
if(a[i]==0x35):
print("a[5]=a[1]")
i+=1
if(a[i]==0xF7):
print("a[9]+=a[1]")
i+=1
if(a[i]==0x44):
print("a[1]/=a[5]")
i+=1
if(a[i]==0x80): #最大的坑点,如果没有注意到,直接努力白费(小端存储
print("a[%d]=0X%x%x%x%x"%(a[i+1],a[i+5],a[i+4],a[i+3],a[i+2]))
i+=6
if(a[i]==0x77):
print("a[1]^=a[9]")
i+=1
if(a[i]==0x53):
print("putchar(a[3])")
i+=2
if(a[i]==0x22):
print("a[1]>>=a[2]")
i+=1
if(a[i]==0x23):
print("a[1]<<=a[2]")
i+=1
if(a[i]==0x99):
print("break")
break
if(a[i]==0x76):
print("a[3]=a[6],a[6]=0,a[6]+=4")
i+=5
if(a[i]==0x54):
print("v2=a[3],v2=getchar()")
i+=2
if(a[i]==0x30):
print("a[1]|=a[2]")
i+=1
if(a[i]==0x31):
print("a[1]&=a[2]")
i+=1
if(a[i]==0x32):
print("a[3]=0x%x"%(a[i+1]))
i+=2
if(a[i]==9):
print("a[1]=0x6FEBF867")
i+=1
if(a[i]==0x10):
print("a[9]=a[1]")
i+=1
if(a[i]==0x33):
print("a[4]=a[1]")
i+=1
if(a[i]==0x34):
print("a[2]=0x%x"%(a[i+1]))
i+=2
if(a[i]==0xFE):
print("a[1]=a[9]")
i+=1
if(a[i]==0x11):
print("a[1]=*******")
i+=1
if(a[i]==0xA0):
print("if(a[1]!=0x6FEBF967)\n")
i+=1
if(a[i]==0xA1):
print("read()")
i+=1
if(a[i]==0xB1):
print("a[9]=byte0")
i+=1
if(a[i]==0xB2):
print("a[9]=byte1")
i+=1
if(a[i]==0xA4):
print("byte0[%d]=a[1]"%(a[i+1]))
i+=4
if(a[i]==0xB3):
print("a[9]=byte2")
i+=1
if(a[i]==0xB4):
print("a[9]=byte3")
i+=1
if(a[i]==0xC1):
print("a[1]=flag[%d]"%(a[i+1]))
i+=2
if(a[i]==0xC7):
print("if(byte_804B060!=a[1])\n")
i+=1
if(a[i]==0xC8):
print("if(byte_804B064!=a[1])\n")
i+=1
if(a[i]==0xC2):
print("if(0x%x!=a[1])\n"%(a[i+1]))
i+=5
为了更好分析,在每次if后都加了一个换行
其中byte0~3:
可以很明显的知道前32位都是进行一次简单的异或,但是异或是从一个数组里面取出的,而且每次异或的下标没有规律(也许是我找不出来),人为提取,获取前32位值:
xor=[0x7B,0x2F,0x37,0xE8] #异或值,即上面的byte0~3
xor_number=[0,1,3,2,1,3,0,2,0,0,2,2,3,1,2,0,2,2,1,0,2,0,2,3,0,3,0,2,1,2,0,1]
cmp=[74,25,221,15,27,137,25,84,79,78,85,86,142,73,14,75,6,84,26,66,83,31,82,219,25,217,25,85,25,0,75,30]
for i in range(len(cmp)):
print(chr(cmp[i]^xor[xor_number[i]]),end="")
#answer:16584abc45baff901c59dde3b1bb6701
后面部分进行位运算什么的,由于出现了位运算等容易丢失数据的操作,直接爆破。
一点一点的爆破,四个进行爆破就花了两分多钟,分别爆破获得内容:
我确定不了范围,就直接选择的(32,127),能确定范围可以减少很多时间
#flag[32]~flag[35]
for i in range(32,127):
for j in range(32,127):
for k in range(32,127):
for l in range(32,127):
a=[0]*10
a[1]=i
a[2]=24
a[1]<<=a[2]
a[9]=a[1]
a[1]=j
a[2]=16
a[1]<<=a[2]
a[9]=(a[9]+a[1])&0xffffffff
a[1]=k
a[2]=8
a[1]<<=a[2]
a[9]=(a[9]+a[1])&0xffffffff
a[1]=l
a[9]+=a[1]
a[1]=a[9]
a[2]=5
a[1]>>=a[2]
a[1]^=a[9]
a[9]=a[1]
a[2]=7
a[1]<<=a[2]
a[2]=0x98f17723
a[1]&=a[2]
a[1]^=a[9]
a[9]=a[1]
a[2]=24
a[1]<<=a[2]
a[2]=0x35e4b920
a[1]&=a[2]
a[1]^=a[9]
a[9]=a[1]
a[2]=18
a[1]>>=a[2]
a[1]^=a[9]
if(a[1]&0xffffffff==0x6FEBF967):
print(chr(i)+chr(j)+chr(k)+chr(l))
#answer:a254
这里就不放后面爆破代码了,直接给结果
提示一下,一定要注意溢出问题,不然得不到后续答案的
#flag[36]~flag[39]:b06c
#flag[40]~flag[41]:dc23
拼接起来,加个外壳,获得flag:
SangFor{16584abc45baff901c59dde3b1bb6701a254b06cdc23}