リバースエンジニアリングチャレンジ過去問 2008 Level2

Level2の前に、Level1を解くのに使ったPythonスクリプトを公開しておく。
模範解答のほうはC言語だけど、ほとんど同じ。

# Level1

encryptedDataList = [0xB7, 0x9A, 0x93, 0x93, 0x90, 0xDF, 0xA8, 0x90, 0x8D, 0x93, 0x9B, 0xDE]

decryptedString = ''
for data in encryptedDataList:
	decryptedString += chr(data ^ 0xff)

print(decryptedString)


それではLevel2。
公式の模範解答が、すごくトリッキーに思えたので自分なりの回答を。
といっても一年前の問題だし、ググレばもっといいものがあるのかも。
公式では、改変されたMD5アルゴリズム不定のまま、問題の実行体を部分的に利用して解いているが、実は簡単なアルゴリズム

  • 入力値の4バイトそれぞれをビット反転
  • 反転したものを通常のMD5にかける
  • 得られたMD5の各バイトを0x86でxorする

これだけ。
以下のスクリプト使ってBrute Forceで解いた。

# Level2


import hashlib


targetHackedMd5DataList = [0x43, 0x2B, 0xF7, 0xF4, 0x49, 0x90, 0xA3, 0x75, 0x7F, 0xD6, 0xEE, 0x19, 0xB8, 0x78, 0x81, 0x51]


def doHackedMd5(targetString):
	temp = []
	for i in targetString:
		temp.append(chr(ord(i) ^ 0xff))

	m = hashlib.md5()
	m.update(''.join(temp))

	tempList = []
	for i in m.digest():
		tempList.append(ord(i) ^ 0x86)

	return tempList


def doBruteForce():
	startValue = 0x00
	endValue = 0xff

	for n1 in range(startValue, endValue + 1):
		for n2 in range(startValue, endValue + 1):
			print('Progress: %02x %02x XX XX' % (n1, n2))
			for n3 in range(startValue, endValue + 1):
				for n4 in range(startValue, endValue + 1):
					tryingString = '%c%c%c%c' % (n1, n2, n3, n4)
					hackedMd5DataList = doHackedMd5(tryingString)

					if hackedMd5DataList == targetHackedMd5DataList:
						print('Hit! %02x %02x %02x %02x' % (n1, n2, n3, n4)) 
						return True
	return False


doBruteForce()

最初、どうせコマンド引数なんだからASCII文字の範囲だろうと思っていたら、ヒットしなくて焦った。
デバッガを使って、適当な引数hogeとか付けて実行し、あとからメモリ上のhogeという文字列をBrute Forceで出てきた結果と置き換えると、うまく答えを得ることができた。