annyoung

엑셀 시트 보호 해제 본문

분석생활

엑셀 시트 보호 해제

nopsled 2025. 4. 11. 14:29

엑셀에 걸려있는 시트보호 암호를 크랙해준다.

 

동작 원리는 아마도 암호가 동일한지 확인하는게 아니라 hash가 동일한지 판별하기 때문에 그런것 같다.

 

참고로 microsoft excel 2007 파일(XLS)만 되는것 같다.

 

import random
import sys
import itertools
import struct
import string
import olefile

allchars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ "

def rand_pass():
    s = ""
    for i in range(random.randint(0,20)):
        s += random.choice(allchars)
    return s

def excel_hash(password):
    result = 0
    MAX_UINT16 = 0xFFFF

    if len(password) <= MAX_UINT16:
        for c in password[::-1]:
            result = ((result >> 14) & 0x01) | ((result << 1) & 0x7FFF)
            result ^= ord(c)

        result = ((result >> 14) & 0x01) | ((result << 1) & 0x7FFF)
        result ^= (0x8000 | (ord('N') << 8) | ord('K'))
        result ^= len(password)

    return result

def crack_password(targetHash):
    gotHash = 0x00
    while gotHash != targetHash:
        attempt = rand_pass()
        gotHash = excel_hash(attempt)
        print("Cracking: "+hex(targetHash)+": "+hex(gotHash), end="\r")
    return attempt


def extract_sheet_hashes(stream):
    hashes = []
    while True:
        pos = stream.tell()
        if pos >= stream.size:
            break            
        try:
            type = struct.unpack("<H", stream.read(2))[0]
            length = struct.unpack("<H", stream.read(2))[0]
            data = stream.read(length)

            if type == 0x13:
                hashes.append(struct.unpack("H", data)[0])
        except:
            break
    return hashes

def read_xls(filename):
    ole = olefile.OleFileIO(filename)
    for streamname in ole.listdir():
        stream = ole.openstream(streamname)
        hashes = extract_sheet_hashes(stream)
        if len(hashes) >= 1:
            for hash in hashes:
                if hash == 0:
                    continue
                passwd = crack_password(hash)
                print("hash: "+hex(hash)+" : " +passwd)

        stream.close()
    ole.close()

if __name__ == "__main__":
    if len(sys.argv) <= 1:
        print("Usage: crackSheetProt.py <XLS-FILE>")
        sys.exit()
    read_xls(sys.argv[1])

 

출처: https://github.com/LiEnby/CrackSheetProtection

 

GitHub - LiEnby/CrackSheetProtection: Recover Sheet Protection Password for Old Microsoft Excel 2007 Files (.XLS)

Recover Sheet Protection Password for Old Microsoft Excel 2007 Files (.XLS) - LiEnby/CrackSheetProtection

github.com

 

Comments