本来出于个人原因是不想做hgame的,但是做了发现出题很有水品,害,真香。
WEEK2:
unpack:
这道题有两种思路都要学会,官方给的那种方法(第一种方法)更好一些,直接给这两个链接。
第一种方法:
第二种方法:
flag脚本在第二种方法里有给
Classic_CrackMe:
放入detectit中查看,这是一道C#的逆向题目。可以用dnspy来反编译看源码。
进入Form1中看到加密部分,可以看出来是一道AES的加密。
代码写的很巧妙(太烧脑了不得不说)。
大概说一下加密的流程,然后可以根据这个流程逆向出来。(他们都问我为什么哭着做题,幼稚园真的太强了)
你所输入的答案两边会被加上hgame{和},然后变成新的一个字符串。这个字符串被分成了两部分
第一部分从第6个字符到第29个字符,第二个部分从第29个字符到第44个字符。
第一部分被当做aes的iv,第二部分被用作aes2的加密的后半部分。
text2是”mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I=”用aes解密前的明文,text2又是”Same_ciphertext_”
array是text2+str用aes2加密后的密文的后16个字符也就是后半部分,array同时也是”dJntSWSPWbWocAq4yjBP5Q==”
下面是官方wp:
输⼊的flflag除去两头之后分成两部分。第⼀部分是⽬标iv,已知密⽂、⽬标明⽂和key,如果直接算会⽐较复杂,但题⽬还有⼀个条件:已知的密⽂是原明⽂⽤原iv加密之后得到的。理解cbc原理之后,我们能得到这个式⼦
中间值的第⼀组 ^ 原iv = 原明⽂的第⼀组
中间值的第⼀组 ^ ⽬标iv = ⽬标明⽂的第⼀组
⽬标iv = 原iv ^ 原明⽂的第⼀组 ^ ⽬标明⽂的第⼀组
那这个iv就很好求了
接下来,⽬标明⽂和flflag的第⼆段合并之后⽤原iv加密,对密⽂的后半段进⾏⽐较。结合cbc原理,可以看到第⼆组会与第⼀组密⽂异或,所以只要将第⼀组密⽂作为新的iv,对第⼆组密⽂(后半段密⽂)解密即可 当然第⼀组的密⽂和第⼆组的密⽂拼接在⼀起,然后⽤原iv解密,也是可以的。不过要注意的是,第⼀组明⽂是16字节的,所以单独对它加密时会另padding 16个字节的0x10,因此单独加密时得到的密⽂要切掉后半部分才能和第⼆组密⽂拼接
import hashlib from Crypto.Cipher import AES import base64 class AesCrypter(object): def __init__(self, key, iv): self.key = key self.iv = iv def encrypt(self, data): data = self.pkcs7padding(data) cipher = AES.new(self.key, AES.MODE_CBC, self.iv) encrypted = cipher.encrypt(data) return encrypted def decrypt(self, data): data = base64.b64decode(data) cipher = AES.new(self.key, AES.MODE_CBC, self.iv) decrypted = cipher.decrypt(data) decrypted = self.pkcs7unpadding(decrypted) return decrypted def pkcs7padding(self, data): bs = AES.block_size padding = bs - len(data) % bs padding_text = chr(padding) * padding return data + padding_text def pkcs7unpadding(self, data): lengt = len(data) unpadding = ord(data[lengt - 1]) return data[0:lengt-unpadding] if __name__ == '__main__': key = base64.b64decode('SGc0bTNfMm8yMF9XZWVLMg==') OriginalIV = base64.b64decode('MFB1T2g5SWxYMDU0SWN0cw==') Part1Plaintext = 'Same_ciphertext_' OriginalAes = AesCrypter(key,OriginalIV) OriginalPlain=OriginalAes.decrypt('mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I=') NewIV = '' for i in range(16): NewIV +=chr(ord(OriginalPlain[i])^ord(OriginalIV[i])^ord(Part1Plaintext[i])) print 'part1: ' + NewIV HalfPart2Ciphertext = OriginalAes.encrypt(Part1Plaintext)[0:16] Part2Cipher = HalfPart2Ciphertext +base64.b64decode('dJntSWSPWbWocAq4yjBP5Q==') Part2Plaintext = OriginalAes.decrypt(base64.b64encode(Part2Cipher)) print Part2Plaintext print 'part2: ' + Part2Plaintext[16:] flag = 'hgame{' + base64.b64encode(NewIV) + Part2Plaintext[16:] + '}' print flag
这次真的哭了。
babypy
这个题目是阅读python的字节码,然后写出python源码,再解密。
可以看着官方文档来阅读:
https://docs.python.org/3/library/dis.html#python-bytecode-instructions
源码如下:
def encrypt(OOo):
O0O = OOo[::-1]
O0o = list(O0O)
for O0 in range(1, len(O0o)):
Oo = O0o[O0-1] ^ O0o[O0]
O0o[O0] = Oo
O = bytes(O0o)
return O.hex()
解密脚本如下:
a="\x7d\x03\x7d\x04\x57\x17\x72\x2d\x62\x11\x4e\x6a\x5b\x04\x4f\x2c\x18\x4c\x3f\x44\x21\x4c\x2d\x4a\x22"
#print(len(a))
b=a[::-1]
print(len(b))
d=[0 for i in range(0,len(b))]
for i in range(0,len(b)-1):
c=ord(b[i])^ord(b[i+1])
d[i]=c
print(d)
flag=''
for i in range(0,len(b)):
flag+=chr(d[i])
print(flag)
week3:
oooollvm:
一道很简单的ollvm题目,根本没进行什么过多的题目,所以整个题目难度很低。
直接放到ida中,首先先下断点,如图,忽略掉所有的分发器,只要断点下面的有效代码就可以了,这是简单ollvm题目的通用方法:
然后就是动态调试的方法,直到碰到加密的地方为止,函数开始就要求输入34个字符串,然后一直单步到这个位置:
直接写脚本跑出来就好了
table1=[0x22,0xcb,0x7d,0xaf,0x11,0x6f,0x22,0xa9,0xd,0x8e,0x42,0x38,0x1e,0x95,0x40,0x97,0xb4,0xb6,0x31,0xa4,0x4b,0x5,0x62,0x98,0x81,0x9b,0xa9,0x1f,0x63,0x34,0x47,0x80,0x3e,0xb9]
table2=[0x4a,0xab,0x1e,0xdf,0x70,0xf,0x47,0xfc,0x79,0xc1,0x1,0x1c,0x43,0xd1,0x63,0xe5,0xf4,0xaa,0x33,0xdb,0x3a,0x62,0x6,0xed,0xec,0xc0,0x9d,0x49,0x5e,0x1c,0x15,0xf3,0x3b,0xa7]
s=[]
for i in range(34):
for x in range(0,255):
if table2[i]==(x & 0x32AF3201 | ~x & 0xCD50CDFE)^((i+table1[i])&0x32AF3201|~(i+table1[i])&0xCD50CDFE):
s.append(x)
print(s)
flag=''
for i in range(34):
flag+=chr(s[i])
print(flag)
因为比较简单,本题也就大概说说ollvm的解题原理,以后专门更一个ollvm的解题方法。