Hash 함수란 입력을 받은 값을 이리저리 값을 굴려서 특정한 길이의 데이터로 맵핑시키는 작업을 말한다.
예를 들어 "abcde" 이 텍스트를 16진수로 0xAB56B4D92B40713ACC5AF89985D4B786로 표현할 수 있다.
짧은 만큼 다른 텍스트가 위와 동일한 hash가 될 가능성이 있다. 하지만 hash 함수 특성상 역으로 동일한 hash를 갖는 텍스트를 만들어내기는 매우 힘들다. 그 확률은 매우 낮으므로 우리는 이렇게 hash를 관리하여 파일 수정 여부를 판단할 수 있고 악성코드로 분류할 수도 있다.
특정 폴더 경로를 입력받아 파일들의 hash를 구하고 csv 파일에 작성하는 코드를 구현해보자
import os
import hashlib
import csv
def writeMD5(filepath, csvpath, header):
hash_md5 = hashlib.md5()
with open(filepath, "rb") as f:
chunk = f.read(4096)
while chunk:
hash_md5.update(chunk)
chunk = f.read(4096)
md5 = hash_md5.hexdigest()
with open(csvpath, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
if csvfile.tell() == 0:
writer.writerow(header)
writer.writerow([filepath, md5])
def main():
path = '폴더 경로'
csvpath = os.path.join(path,'result.csv')
csvheader = ['name', 'md5']
for filename in os.listdir(path):
filepath = os.path.join(path,filename)
if not os.path.exists(filepath):
continue
if not os.path.isfile(filepath):
continue
if filepath == csvpath:
continue
writeMD5(filepath, csvpath, csvheader)
if __name__ == '__main__':
main()
이렇게 하면 hash를 구할 때마다 csv 파일을 열고 닫아야 한다. class를 이용해 조금 수정해보겠다.
가장 큰 차이는 main함수에서 CSV 파일을 관리하는 객체를 하나 생성 후 관리한다. 클래스를 자세히 보면 __init__ __del__ 함수를 통해 객체가 생성될 때 csv파일을 열고 헤더를 작성해준다. 그리고 종료될 때 csv파일을 닫아준다.
writeMD5 함수는 객체를 인자로 받아 파일의 열고 닫기는 신경 쓰지 않고 바로바로 데이터를 저장해주면 된다.
여기서 자꾸 보이는 self가 궁금할 것이다.
여기서는 result.csv 파일에 데이터를 저장했지만 md5.csv파일에 저장을 하고 싶은 경우도 있을 것이다. 그러면 main코드 중간에 md5_csv = CSVManager('md5.csv', csvheader)을 새로 만들고 wirteMD5(filepath, md5_csv )를 추가적으로 호출해주면 된다. 둘은 같은 클래스로 만들어졌지만 사실 다른 메모리를 사용하는 엄연히 다른 객체이다. 클래스 함수들은 각 객체 메모리에 있는 데이터를 접근해야 할 때 self를 이용해 자신의 메모리에 있는 데이터를 접근한다.