(作者:pizZa)
清理花指令
from ida_bytes import get_bytes, patch_bytes
addr = 0x401000
buf = get_bytes(addr, 0x4B9CD0-addr)
def patch_at(p, ln):
global buf
buf = buf[:p] + "\x90" * ln + buf[p+ln:]
# jx / jnx
fake_jcc = []
for opcode in xrange(0x70, 0x7F, 2):
pattern = chr(opcode) + "\x03" + chr(opcode | 1) + "\x01"
fake_jcc.append(pattern)
pattern = chr(opcode | 1) + "\x03" + chr(opcode) + "\x01"
fake_jcc.append(pattern)
for pattern in fake_jcc:
p = buf.find(pattern)
while p != -1:
patch_at(p, 5)
p = buf.find(pattern, p+1)
# call / pop
pattern = '\xE8'
p = buf.find(pattern)
while p != -1:
if buf[p + 2:p + 5] == '\x00\x00\x00':
dst = p + 5 + ord(buf[p + 1])
if buf[dst:dst + 3] == '\x83\xC4\x04':
ln = dst - p + 3
patch_at(p, ln)
elif buf[dst] == '\x58':
ln = dst - p + 1
if buf[p - 1] == '\x50' and buf[dst + 1] == '\x58':
patch_at(p - 1, ln + 2)
else:
patch_at(p, ln)
elif buf[dst:dst + 5] == '\x83\x04\x24\x06\xc3':
ln = dst - p + 5
patch_at(p, ln)
else:
print("E80n", hex(p + addr), hex(dst + addr), buf[dst:dst + 3].encode('hex'))
else:
pass
p = buf.find(pattern, p+1)
# stx / jx
fake_jcc = ['\xF8\x73', '\xF9\x72']
for pattern in fake_jcc:
p = buf.find(pattern)
while p != -1:
if ord(buf[p + 2]) < 0x80:
dst = p + 3 + ord(buf[p + 2])
ln = dst - p
patch_at(p, ln)
else:
print("CLC", hex(p + addr))
p = buf.find(pattern, p+1)
fake_jcc = ['\x7C\x03\xEB\x03']
for pattern in fake_jcc:
p = buf.find(pattern)
while p != -1:
if buf[p + 5:p + 5 + 2] == '\x74\xFB':
ln = 7
patch_at(p, ln)
else:
print("CLC", hex(p + addr))
p = buf.find(pattern, p+1)
patch_bytes(addr, buf)
print('done')
用Dancing Link
算法校验数独, 初始数独由两个常量相乘得到, 其中一个与自校验有关. 用输入填写数独, 用反调试填写了其中一个数字.
x = int('BDA39C1046F32C'[::-1], 16) # 0x4BC080
y = int('1ED683F49FA362A30D3473AECDEE'[::-1], 16) # 0x4BC088
z = hex(x*y)[2:].rstrip('L')[::-1] # b79f3d4b9d5a6b8c23b6cb1c35d4b5a1b7b2f8e35b
n = 0
s = ''
for i in xrange(len(z)):
c = int(z[i], 16)
if c >= 1 and c <= 9:
n += 1
s += str(c)
else:
t = c - 9
n += t
s += '_' * t
if i + 1 < len(z) and int(z[i + 1], 16) > 9:
s += '9'
n += 1
assert n == 81
for i in xrange(0, 81, 9):
print(s[i:i+9])
# __79_____
# _3____4__
# 9____5_6_
# _8___23__
# 6___9__1_
# __35____4
# __5_1__7_
# _2______8
# _____35__
由于初始数独存在多解, 之后又直接比较固定答案, 可以在004B9744
设置记录断点{dword(ebp-0x2BB4) / 9} | {dword(ebp-0x2BB4) % 9} | {dword(ebp-0x2BC0)}
得到标准答案.
s = [
# ((0, 2), 7),
# ((0, 3), 9),
# ((1, 1), 3),
# ((1, 6), 4),
# ((2, 0), 9),
# ((2, 5), 5),
# ((2, 7), 6),
# ((3, 1), 8),
# ((3, 5), 2),
# ((3, 6), 3),
# ((4, 0), 6),
# ((4, 6), 1),
# ((5, 1), 3),
# ((5, 2), 5),
# ((5, 7), 4),
# ((6, 1), 5),
# ((6, 3), 1),
# ((6, 6), 7),
# ((7, 0), 2),
# ((7, 7), 8),
# ((8, 4), 3),
# ((8, 5), 5),
((4, 3), 3),
((7, 3), 5),
((2, 1), 1),
((3, 7), 5),
((4, 1), 5),
((0, 1), 6),
((1, 2), 2),
((4, 8), 2),
((5, 4), 1),
((1, 3), 1),
((0, 5), 8),
((1, 4), 6),
((1, 5), 7),
((4, 5), 8),
((5, 6), 9),
((1, 7), 8),
((1, 0), 5),
((0, 0), 4),
((1, 8), 9),
((2, 2), 8),
((4, 7), 2),
((5, 0), 7),
((3, 0), 1),
((5, 3), 8),
((5, 5), 6),
((3, 8), 7),
((2, 8), 3),
((0, 7), 2),
((0, 4), 3),
((0, 6), 1),
((0, 8), 5),
((2, 6), 7),
((6, 7), 6),
((7, 5), 9),
((6, 5), 2),
((8, 6), 4),
((7, 6), 3),
((6, 8), 7),
((7, 8), 8),
((5, 8), 3),
((8, 0), 9),
((6, 0), 4),
((6, 2), 8),
((6, 4), 9),
((4, 4), 4),
((3, 3), 6),
((3, 4), 9),
((3, 2), 4),
((4, 2), 9),
((7, 2), 4),
((2, 3), 2),
((2, 4), 4),
((7, 4), 6),
((7, 1), 1),
((8, 1), 6),
((8, 2), 7),
((8, 3), 2),
((8, 7), 1)
]
s = list(sorted(s, key=lambda x:x[0][0]*9+x[0][1]))
a = ''.join(map(lambda x:str(x[1]), s))
print(a)
print(hex(int(a[::-1], 10))[2:-1][::-1].upper())
flag:CBC25EF8D9F482BC1F3DA3CA1F154EC89FC3F1414EDD93A3
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界