ㅁ 개요
- 이번 프로그램은 이전글(2022.11.12 - [파이썬 실습/유틸리티] - 파이썬 악성코드/바이러스 탐지 프로그램 만들기 - 4.악성코드 점검 자동화)에 이은 다섯번째 글로 서버에 해시값이 없는 경우 API방식으로 파일을 서버에 업로드 후 즉시 반영되지 않는 문제를 개선하는 방법에 대하여 설명합니다.
(1) 점검 프로그램 실행 시 서버에 해시 정보가 없는 '외부로 부터 다운로드 받은 파일은' 악성 의심파일로 판단하여 경고창을 띄워 줍니다.
(2) 추가 개선된 버전의 모습(지정한 여러 폴더를 지속적으로 실시간 점검)
O 주의 사항!!
- 우리는 이번 테스트를 위해 멀웨어닷컴에서 해시값을 확인할 수 없는 새로운 악성파일이 필요합니다. 이 악성파일을 잘못 다루는 경우 감염될 수 있으므로 반드시 세심한 주의를 하셔야 합니다.(exe파일 더블클릭 절대 금지!!)
!!!!! 주의 사항
우리가 준비하려는 새로운 악성파일은 말 그대로 악성코드가 포함된 파일이므로 취급시 매우 매우 조심하셔야 하며, 잘못하면 자신의 컴퓨터가 감염될 수 있으니, 이점이 우려되시는 분은 따라하지 마시기 바랍니다.!!!
자세한 내용은 이전글(2022.11.06 - [파이썬 실습/유틸리티] - 파이썬 악성코드/바이러스 탐지 프로그램 만들기 - 3.파일업로드를 통한 악성코드 유무 확인)을 참고하시기 바랍니다.
- 이제 우리는 다음 단계로 넘어갈 준비가 되었습니다.
(1) 첫번째 소스
import requests
import sys
import os
import datetime
import json
import win32api
import time
from ast import literal_eval
api_key = '본인의 api키'
print(len(sys.argv))
if len(sys.argv) > 1 and api_key:
print("ok")
imsiDir = "imsi/"
if not(os.path.isdir(imsiDir)): # imsi 디렉토리가 없으면 만든다.
os.makedirs(os.path.join(imsiDir))
for i in range(1, len(sys.argv)):
filenames = os.listdir(sys.argv[i])
print(filenames)
for (path, dirs, filenames) in os.walk(sys.argv[i]):
for filename in filenames:
full_filename = os.path.join(path, filename)
print(full_filename)
os.system('certUtil -hashfile "' + full_filename + '" MD5 > ' + imsiDir + 'imsi_hash.txt')
txtf = open(imsiDir+"imsi_hash.txt", "r", encoding="euckr")
data = txtf.read()
second_line = data.split('\n',2)[1]
hash = second_line.replace(" ","")
print("파일명: ", full_filename, "###########\t\t md5 해쉬: ", hash)
params = {'api_key': api_key, 'hash': hash}
response = requests.get('https://public.api.malwares.com/v3/file/mwsinfo', params=params)
json_response = response.json()
# json_response = str(json_response).replace("\'", "\"")
print(json_response)
if json_response['result_code'] == int(1): # or json_response['result_code'] == int(2):
pass
print("서버에 해시정보가 있습니다. 보내주신 해시값과 서버의 해시값을 비교합니다.")
f = open(imsiDir+hash+".txt", "w")
f.write(str(json_response))
# f.write(json_response)
f.close()
with open(imsiDir+hash+".txt") as f:
# data2 = json.load(json_file)
# data2 = eval(f.read())
data2 = literal_eval(f.read()) # str -> dic로 읽는다.
ai_score = data2['ai_score']
print(ai_score)
if data2['signcheck']:
signcheck = data2['signcheck']['verified']
else:
signcheck = 'None'
print(signcheck)
check = "파일이름 : " + str(filename) + "\nai_score : " + str(ai_score) + "\nsigncheck : " + str(signcheck) +"\n\nDetection Malware!!!!!! "
if signcheck == "unsigned" or ai_score > int(3):
# if signcheck == 'None' or signcheck == "unsigned" or ai_score > int(3):
win32api.MessageBox(None, check, 'Warning!!!!',0)
elif json_response['result_code'] == int(2):
print(full_filename, " 이 파일은 현재 분석 진행중입니다. 5분 후에 다시 시도 하시기 바랍니다.")
elif json_response['result_code'] == int(0):
print(full_filename, " 이 파일은 서버에 해시정보가 없습니다. 악성파일 가능성이 있으므로 직접 홈페이지에 파일업로드하여 점검하시기 바랍니다.")
check = "파일이름 : " + str(filename) + "\n\n이 파일은 서버에 해시정보가 없습니다.\n악성파일 가능성이 있으므로 직접 아래 홈페이지에 파일업로드하여 점검하시기 바랍니다.\n\nMalware Suspicion!!!!!!\n\nhttps://www.malwares.com/ "
# if signcheck == "unsigned" or ai_score > int(3):
# if signcheck == 'None' or signcheck == "unsigned" or ai_score > int(3):
win32api.MessageBox(None, check, 'Warning!!!!',0)
else:
# json_response['result_code'] == int(0)
print("요청시 잘못된 파라미터, 사용권한 없음 및 API키 오류 등이 발생하였습니다. 정상적으로 다시 요청하여 주시기 바랍니다.")
txtf.close()
time.sleep(1)
(2) 두번째(최종 완성된 소스)
import requests
import sys
import os
import datetime
import win32api
import time
from ast import literal_eval
def checkContinue(dir):
###########################################################################################
now = datetime.datetime.now()
now = str(now.year) + str(now.month) + str(now.day) + str(now.hour) + str(now.minute)
result = "result_"+now+".txt"
# print(now)
###########################################################################################
# 여러 디렉토리를 점검할 수 있도록 인자로 받도록 설정
if len(sys.argv) == 1:
print("디렉토리 옵션을 최소 1개이상 주셔야 합니다. \
\n\nex) python 5.malwareCom_hashCheck_loop.py \"C:\\Download\" \"C:\\Download2\" \
")
else:
api_key_file = "C:/Temp/api_key.txt"
if os.path.isfile(api_key_file):
# print("API Key 파일이 존재합니다.")
data = open(api_key_file, "r", encoding="euckr")
data = data.read().strip()
api_key = data.split('\n',2)[0]
# print(vtkey)
else:
print("API Key 파일이 존재하지 않습니다.")
api_key = input("멀웨어닷컴에서 받은 API 키를 입력해 주세요 : ")
inputKey = input("입력한 API키를 디스크(c:\\Temp\\api_key.txt)에 저장하시겠습니까?\n(저장하시면 다음 실행시부터 API Key를 입력하실 필요가 없습니다.)(Y or N): ")
if inputKey == 'Y' or inputKey == 'y':
print("API Key를 생성합니다.")
with open(api_key_file, "w") as f:
f.write(str(api_key))
j = 1
while len(sys.argv) > 1:
print(len(sys.argv))
print("######################### %d회차 점검 시작 ###########################" % (j))
print("#################################################################################")
if len(sys.argv) > 1 and api_key:
print("ok")
imsiDir = "imsi/"
if not(os.path.isdir(imsiDir)): # imsi 디렉토리가 없으면 만든다.
os.makedirs(os.path.join(imsiDir))
# try:
for i in range(1, len(sys.argv)):
print("#################################################################################")
print("=================================================================================")
print(" 프로그램이 다운로드한 파일에 대하여 실시간 악성코드 감염여부를 검사합니다.")
print("=================================================================================")
print("#################################################################################")
filenames = os.listdir(sys.argv[i])
print(filenames)
print("================================================================")
print("%d번째 점검 디렉토리 : \t'%s'" % (i, sys.argv[i]))
print("================================================================")
print("점검 파일목록 : \t",filenames)
print("================================================================")
for (path, dirs, filenames) in os.walk(sys.argv[i]):
for filename in filenames:
full_filename = os.path.join(path, filename)
print(full_filename)
os.system('certUtil -hashfile "' + full_filename + '" MD5 > ' + imsiDir + 'imsi_hash.txt')
txtf = open(imsiDir+"imsi_hash.txt", "r", encoding="euckr")
data = txtf.read()
second_line = data.split('\n',2)[1]
hash = second_line.replace(" ","")
print("파일명: ", full_filename, "###########\t\t md5 해쉬: ", hash)
params = {'api_key': api_key, 'hash': hash}
response = requests.get('https://public.api.malwares.com/v3/file/mwsinfo', params=params)
json_response = response.json()
# json_response = str(json_response).replace("\'", "\"")
print(json_response)
if json_response['result_code'] == int(1): # or json_response['result_code'] == int(2):
pass
print("서버에 해시정보가 있습니다. 보내주신 해시값과 서버의 해시값을 비교합니다.")
f = open(imsiDir+hash+".txt", "w")
f.write(str(json_response))
# f.write(json_response)
f.close()
with open(imsiDir+hash+".txt") as f:
# data2 = json.load(json_file)
# data2 = eval(f.read())
data2 = literal_eval(f.read()) # str -> dic로 읽는다.
ai_score = data2['ai_score']
print(ai_score)
if data2['signcheck']:
signcheck = data2['signcheck']['verified']
else:
signcheck = 'None'
print(signcheck)
check = "파일이름 : " + str(filename) + "\nai_score : " + str(ai_score) + "\nsigncheck : " + str(signcheck) +"\n\nDetection Malware!!!!!! "
if signcheck == "unsigned" or ai_score > int(3):
# if signcheck == 'None' or signcheck == "unsigned" or ai_score > int(3):
win32api.MessageBox(None, check, 'Warning!!!!',0)
print("----------------------------------------------------------------")
elif json_response['result_code'] == int(2):
print(full_filename, " 이 파일은 현재 분석 진행중입니다. 5분 후에 다시 시도 하시기 바랍니다.")
print("----------------------------------------------------------------")
elif json_response['result_code'] == int(0):
print(full_filename, " 이 파일은 서버에 해시정보가 없습니다. 악성파일 가능성이 있으므로 직접 홈페이지에 파일업로드하여 점검하시기 바랍니다.")
check = "파일이름 : " + str(filename) + "\n\n이 파일은 서버에 해시정보가 없습니다.\n악성파일 가능성이 있으므로 직접 아래 홈페이지에 파일업로드하여 점검하시기 바랍니다.\n\nMalware Suspicion!!!!!!\n\nhttps://www.malwares.com/ "
win32api.MessageBox(None, check, 'Warning!!!!',0)
print("----------------------------------------------------------------")
else:
# json_response['result_code'] == int(0)
print("요청시 잘못된 파라미터, 사용권한 없음 및 API키 오류 등이 발생하였습니다. 정상적으로 다시 요청하여 주시기 바랍니다.")
print("----------------------------------------------------------------")
txtf.close()
time.sleep(1)
# except:
# pass
# print("폴더명 또는 API Key 값이 이상합니다. 다시 확인해 주시기 바랍니다.")
else:
print("\nAPI Key를 정확히 입력하셔야 점검이 시작됩니다.\n")
###########################################################################################
j = j + 1
time.sleep(10)
if __name__ == "__main__":
# Code in this block will run when stepper.py is invoked from the command line
checkContinue(dir=sys.argv)
>python 4.malwareCom_hashCheck_pub.py "점검할 폴더"(.\checkdir)
>python 5.malwareCom_hashCheck_loop_pub.py "점검할 폴더"(.\checkdir)
이전글(2022.11.12 - [파이썬 실습/유틸리티] - 파이썬 악성코드/바이러스 탐지 프로그램 만들기 - 4.악성코드 점검 자동화) 의 '소스 분석'과 동일하며 아래 15번만 새로 설명 추가함
1.from ast import literal_eval <-- 문자열을 딕셔너리로 변경하게 해주는 모듈 임포트
2.len(sys.argv) <-- 인자의 갯수(예: >python 3.malwareCom_hash_for_pub.py <--이렇게 샐행하면 인자는 1임(python 뒤의 지정된 명령 개수)
3.if not(os.path.isdir(imsiDir)): <-- imsiDir 디렉토리가 없으면 만든다.
os.makedirs(os.path.join(imsiDir))
4.for i in range(1, len(sys.argv)): <-- 인자 갯수만큼 돈다(즉, 폴더를 여러개 지정 시 지정한 모든 폴더의 파일을 점검)
5.filenames = os.listdir(sys.argv[i]) <-- 지정한 폴더 내 파일 목록을 list로 반환
6.for (path, dirs, filenames) in os.walk(sys.argv[i]): <-- 지정한 폴더의 경로, 디렉토리, 파일목록을 반환
7.os.system('certUtil -hashfile "' + full_filename + '" MD5 > ' + imsiDir + 'imsi_hash.txt') <-- win10에 내장된 certUtil 툴은 해시값을 뽑아주는 도구이며, 여기서는 MD5 해시를 파일로 저장
8.second_line = data.split('\n',2)[1] <-- 해시값이 저장된 파일(imsi_hash.txt)에서 두번째 라인을 읽어서 second_line변수에 저장
9.hash = second_line.replace(" ","") <--해시값에 공백이 없도록 replace()함수로 대체시켜줌
10.if json_response['result_code'] == int(1): <-- 서버로 부터 API응답코드('result_code')에 데이터가 있으면(1, 즉 서버에 해시값이 있으면)
11.data2 = literal_eval(f.read()) <-- imsi+hash+".txt" 파일의 내용은 스트링으로 되어 있으므로 딕셔너리구조로 읽어오기 위해 literal_eval()함수로 형식을 변환
12.if signcheck == "unsigned" or ai_score > int(3): <-- signcheck변수가 'unsigned'이거나 'ai_score'가 3보다 크면 악성파일로 정의
13.win32api.MessageBox(None, check, 'Warning!!!!',0) <--위 12번 조건에 맞으면 경고창 띄움
14.print("파일 업로드 중입니다. 약 1분정도 소요됩니다.")
time.sleep(30) <-- 파일 업로드 시 약간의 시간 텀을 주어야 함(텀을 주지 않으면 서버에서 Ddos공격으로 의심하여 업로드를 한동안 차단 당할 수 있음)
15. if os.path.isfile(api_key_file): <-- 파일 존재여부 체크
우리는 아래와 같은 사항을 고려하여 최종적으로 프로그램을 어떻게 개선하여 사용할지 결정해야 합니다.
1. API요청에 대한 응답값에 파일 해시값이 없는 경우 악성파일일 가능성에 대한 의심을 해 봐야 합니다.
2.현재 시점이후로 새로 생성된 파일은 모두 점검한다?
--> 너무 많습니다. 현실적으로 불가 합니다.
3. 내가 만든 파일은 안심(신뢰)할 수 있다. 따라서 내가만든 파일은 제외하되, 외부에서 받은 파일은 모두 점검한다?
--> 그렇습니다. 주로 외부에서 다운로드 받은 파일을 저장하는 폴더를 체크폴더로 설정하겠습니다.
이것이 가능한 이유는 우리가 외부에서 다운로드 받은 파일은 하루에 아무리 많아 봐야
보통 10개(?)도 안되기 때문입이다. 안전을 위해서 이정도는 할 수 있습니다.
멀웨어닷컴에서 API방식으로 업로드 후 바로 해시값을 분석/반영 해주면 우리가 정확한 값을 얻을 수 있으므로
베스트이지만, 실제 그렇지 않기때문에 차선책으로 우리는 외부에서 다운로드 하는 디렉토리를 실시간 점검하고,
서버에서 해시 점검을 못하는 경우 alert(경고창)을 띄워 사용자 스스로 점검할 수 있도록 해주는 방식으로 개선할 예정입니다.
아래와 같이 정리합니다.
1.실시간 감시(악성코드 점검 자동화 프로그램 실행)
2.경고창 띄움(서버에 해시값이 없는 경우)
3.홈페이지에서 파일 업로드 => 악성여부 판별 후 파일 삭제여부 결정(홈페이지에 파일 업로드)
4.다시 실시간 감시(다시 악성코드 점검 자동화 프로그램 실행)
감사합니다.
'파이썬 실습 > 악성코드_바이러스탐지 프로그램 만들기' 카테고리의 다른 글
파이썬 악성코드/바이러스 탐지 프로그램 만들기 - 4.악성코드 점검 자동화 (0) | 2022.11.12 |
---|---|
파이썬 악성코드/바이러스 탐지 프로그램 만들기 - 3.파일업로드를 통한 악성코드 유무 확인 (0) | 2022.11.12 |
파이썬 악성코드/바이러스 탐지 프로그램 만들기 - 2.해시값을 이용한 악성코드 유무 확인 (0) | 2022.10.31 |
파이썬 악성코드/바이러스 탐지 프로그램 만들기 - 1.소개편 (0) | 2022.10.29 |