Search code examples
python-3.xfile-not-foundpython-os

FileNotFoundError But The File Is There: Cryptography Edition


I'm working on a script that takes a checksum and directory as inputs. Without too much background, I'm looking for 'malware' (ie. a flag) in a directory of executables. I'm given the SHA512 sum of the 'malware'. I've gotten it to work (I found the flag), but I ran into an issue with the output after generalizing the function for different cryptographic protocols, encodings, and individual files instead of directories:

FileNotFoundError: [Errno 2] No such file or directory : 'lessecho'

There is indeed a file lessecho in the directory, and as it happens, is close to the file that returns the actual flag. Probably a coincidence. Probably.

Below is my Python script:

#!/usr/bin/python3

import hashlib, sys, os


"""
### TO DO ###
Add other encryption techniques
Include file read functionality
"""

def main(to_check = sys.argv[1:]):
    dir_to_check = to_check[0]
    hash_to_check = to_check[1]
 
    BUF_SIZE = 65536

    for f in os.listdir(dir_to_check):
        sha256 = hashlib.sha256()
        with open(f, 'br') as f:        <--- line where the issue occurs
            while True:
                data = f.read(BUF_SIZE)
                if not data:
                    break
                sha256.update(data)
        f.close() 

        if sha256.hexdigest() == hash_to_check:
            return f


if __name__ == '__main__':
    k = main()
    print(k)

Credit to Randall for his answer here

Here are some humble trinkets from my native land in exchange for your wisdom.


Solution

  • Your listdir call is giving you bare filenames (e.g. lessecho), but that is within the dir_to_check directory (which I'll call foo for convenience). To open the file, you need to join those two parts of the path back together, to get a proper path (e.g. foo/lessecho). The os.path.join function does exactly that:

    for f in os.listdir(dir_to_check):
        sha256 = hashlib.sha256()
        with open(os.path.join(dir_to_check, f), 'br') as f:  # add os.path.join call here!
           ...
    

    There are a few other issues in the code, unrelated to your current error. One is that you're using the same variable name f for both the file name (from the loop) and file object (in the with statement). Pick a different name for one of them, since you need both available (because I assume you intend return f to return the filename, not the recently closed file object).

    And speaking of the closed file, you're actually closing the file object twice. The first one happens at the end of the with statement (that's why you use with). The second is your manual call to f.close(). You don't need the manual call at all.