키보드에 입력되는 것을 표준입력

화면에 출력되는 것을 표준출력

키보드+화면 콘솔

 

파일 입출력 기본 과정

파일열기(변수명 = open("파일명", "r" or "w"))->파일 읽기 및 파일 쓰기 작업->파일 닫기(변수명.close())

 

 

 

텍스트 파일 입출력

data1.txt

CookBook 파이썬을 공부합니다.
완전 재미있어요. ^^
파이썬을 공부하기 잘했네요~~

 

 

Code11-01.py

inFp = None
inStr = ""

inFp = open("ch11/data1.txt", "r", encoding="utf-8")  

inStr = inFp.readline()
print(inStr, end = "")

inStr = inFp.readline()
print(inStr, end = "")

inStr = inFp.readline()
print(inStr, end = "")

inFp.close()

-.readline():한행씩 읽어 inFp 파일에 집어 넣는다

 

Code11-02.py

inFp = None
inStr = ""

inFp = open("ch11/data1.txt", "r", encoding="utf-8")  

while True:
    inStr = inFp.readline()
    if inStr == "" :
        break
    print(inStr, end = "")

inFp.close()

 

 

selfstudy11-1.py

inFp = None
inStr = ""
line_number = 1

inFp = open("ch11/data1.txt", "r", encoding="utf-8")

while True:
    inStr = inFp.readline()
    if inStr == "":
        break
    print("%d %s" % (line_number, inStr), end="")
    line_number += 1

inFp.close()

 

 

Code11-03.py

inFp = None
inStr = ""

inFp = open("ch11/data1.txt", "r", encoding="utf-8")  

inList = inFp.readlines()
print(inList)

inFp.close()

-readlines():통째로 읽어서 저장

 

 

Code11-04.py

inFp = None
inList, inStr = [],""

inFp = open("ch11/data1.txt", "r", encoding="utf-8")  

inList = inFp.readlines()
for inStr in inList:
    print(inStr, end= "")

inFp.close()

 

 

selfstudy11-2.py

inFp = None
inList, inStr = [], ""

inFp = open("ch11/data1.txt", "r", encoding="utf-8")

inList = inFp.readlines()
for line_number, inStr in enumerate(inList, start=1):
    print("%d %s" % (line_number, inStr), end="")

inFp.close()

 

 

Code11-05.py

inFp = None
fName, inList, inStr = "", [],""

fName = input("파일명을 입력하세요 : ")
inFp = open(fName, "r", encoding="utf-8")  

inList = inFp.readlines()
for inStr in inList:
    print(inStr, end= "")

inFp.close()

 

Code11-06.py

import os

inFp = None
fName, inList, inStr = "", [], ""

fName = input("파일명을 입력하세요: ")

if os.path.exists(fName):  # 파일 존재 여부 확인
    inFp = open(fName, "r")  # 파일 열기

    inList = inFp.readlines()  # 파일 내용 읽기
    for inStr in inList:  # 읽은 내용 출력
        print(inStr, end='')
    
    inFp.close()  # 파일 닫기
else:
    print(f"{fName} 파일이 없습니다.")

-파일이 없는 경우는 오류 발생하지 않기 위해 os.path.sxists(파일명) 형식을 사용

 

 

파일을 이용한 출력

data2.txt

야야야ㅑ
하하하
마마마

 

 

Code11-07.py

outFp= None
outStr= None

outFp = open("ch11/data2.txt", 'w',encoding="utf-8") #w는 덮어쓰기

while True:
    outStr = input("내용 입력 : ")
    if outStr != "" :
        outFp.writelines(outStr+ "\n")
    else:
        break

outFp.close()
print("--- 정상적으로 파일에 씀 ---")

-파일 내용을 쓸때는 write() / witelines()함수 사용

 

selfstudy11-3.py

outFp = None
outStr = None

outFname = input("저장할 파일명을 입력하세요: ")
outFp = open(outFname, 'w', encoding="utf-8")  # 'w'는 덮어쓰기

while True:
    outStr = input("내용 입력 : ")
    if outStr != "":
        outFp.writelines(outStr + "\n")
    else:
        break

outFp.close()
print("--- 정상적으로 파일에 씀 ---")

 

 

복사

Code11-08.py

inFp, outFp = None, None
inStr = ""

inFp = open("C:/Windows/win.ini", "r") 
outFp = open("C:/Temp/data3.txt", "w") 

inList = inFp.readlines()  
for inStr in inList:
    outFp.writelines(inStr)  

inFp.close()
outFp.close()
print("-- 파일이 정상적으로 복사되었습니다. --")

 

 

selfstudy11-4.py

inFp, outFp = None, None
inStr = ""

inFname = input("소스 파일명을 입력하세요: ") 
outFname = input("타깃 파일명을 입력하세요: ") 

inFp = open(inFname, "r") 
outFp = open(outFname, "w") 

inList = inFp.readlines() 
for inStr in inList:
    outFp.writelines(inStr)  

inFp.close()  
outFp.close()  
print(f"--- {inFname} 파일이 {outFname} 파일로 복사되었음 ---")

 

 

Code11-09.py

#변수 선언 부분
inFp, outFp = None, None
inStr, outStr = '', ''
i =0
secu = 0 

#메인코드 부분
secuYN = input("1. 암호화 2. 암호 해석 중 선택 : ")
inFname = input("입력 파일명을 입력하세요: ")
outFname = input("출력 파일명을 입력하세요: ")

if secuYN == "1":
    secu = 100  # 암호화
elif secuYN == "2":
    secu = -100  # 복호화

inFp = open(inFname, 'r', encoding='utf-8')
outFp = open(outFname, 'w', encoding='utf-8')

while True:
    inStr = inFp.readline()  # 한 줄씩 읽기
    if not inStr:
        break  # 더 이상 읽을 내용이 없으면 종료
    
    outStr = ''  # 출력 문자열 초기화
    for i in range(len(inStr)):
        ch = inStr[i]
        chNum = ord(ch)  # 문자 -> 숫자 변환
        chNum = chNum + secu  # 암호화/복호화
        ch2 = chr(chNum)  # 숫자 -> 문자 변환
        outStr = outStr + ch2  # 결과 문자열에 추가
    
    outFp.write(outStr)  # 출력 파일에 기록

outFp.close()
inFp.close()
print('%s -> %s 변환 완료' % (inFname, outFname))

-ord():문자->숫자

-chr():숫자->문자

 

 

 

이진파일 입출력

이진파일은 텍스트 파일을 제외 한 나머지 파일(비트 단위로 의미가 있는 파일)

 

Code11-10.py

inFp, outFp = None, None
inStr = ""

inFp = open("C:/Windows/notepad.exe", "rb")
outFp = open("C:/Temp/notepad.exe", "wb")

while True:
    inStr = inFp.read(1)
    if not inStr:
        break
    outFp.write(inStr)

inFp.close()
outFp.close()
print("--- 이진 파일이 정상적으로 복사되었음 ---")

-이진파일 복사

-"rb"/"wb"

 

 

Code11-11.py

from tkinter import *

# 변수 선언 부분
window = None
canvas = None
XSIZE, YSIZE = 256, 256

# 메인 코드 부분
window = Tk()  # 창 생성
canvas = Canvas(window, height=XSIZE, width=YSIZE)  # 캔버스 생성

canvas.pack()  # pack() 메소드 호출 오류 수정
window.mainloop()  # mainloop() 메소드 호출 오류 수정

 

 

Code11-12.py

from tkinter import *

# 함수 선언 부분
def loadImage(fname):
    global inImage, XSIZE, YSIZE
    fp = open(fname, 'rb')  # 파일을 이진 모드로 열기

    for i in range(0, XSIZE):
        tmpList = []  
        for k in range(0, YSIZE):
            data = int(ord(fp.read(1))) 
            tmpList.append(data)  
        inImage.append(tmpList)  

    fp.close() 

def displayImage(image):
    global XSIZE, YSIZE
    rgbString = ""
    for i in range(0, XSIZE):
        tmpString = ""
        for k in range(0, YSIZE):
            data = image[i][k]  # 
            tmpString += "#%02x%02x%02x " % (data, data, data)  
        rgbString += "{" + tmpString + "} "
    paper.put(rgbString) 

# 전역 변수 선언 부분
window = None
canvas = None
XSIZE, YSIZE = 256, 256
inImage = []  

# 메인 코드 부분
window = Tk()
window.title("흑백 사진 보기")
canvas = Canvas(window, height=XSIZE, width=YSIZE)
paper = PhotoImage(width=XSIZE, height=YSIZE)
canvas.create_image((XSIZE / 2, YSIZE / 2), image=paper, state="normal")

# 파일 --> 메모리
filename = 'ch11/gif/tree.raw'
loadImage(filename)

# 메모리 --> 화면
displayImage(inImage)

canvas.pack()
window.mainloop()

 

 

예외처리

Code11-13.py

myStr = "파이썬은 재미 있어요. 파이썬만 매일매일 공부하고 싶어요. ^^"
strPosList = []
index = 0

while True:
    index = myStr.index("파이썬", index)
    strPosList.append(index)
    index = index + 1

print("파이썬 글자 위치 -->", strPosList) #실행될 수가 없기에(무한) 희미하게 보인다.

 

 

Code11-14.py

myStr = "파이썬은 재미 있어요. 파이썬만 매일매일 공부하고 싶어요. ^^"
strPosList = []
index = 0

while True:
    try:
        index = myStr.index("파이썬", index)
        strPosList.append(index)
        index = index + 1
    except :
        break

print("파이썬 글자 위치 -->", strPosList)

 

 

Code11-15.py

num1 = input("숫자1 --> ")
num2 = input("숫자2 --> ")

try :
    num1 = int(num1)
    num2 = int(num2)
    while True :
        res = num1/num2

except ValueError:
    print("문자열은 숫자로 변환할 수 없습니다.")

except ZeroDivisionError :
    print("0으로 나눌 수 없습니다")

except KeyboardInterrupt :
    print("Ctrl+C를 눌렀군요.")

 

 

 

Code11-16.py

num1 = input("숫자1 --> ")
num2 = input("숫자2 --> ")

try :
    num1 = int(num1)
    num2 = int(num2)

except :
    print("오류가 발생했습니다.")

else :
    print(num1, "/", num2, "=", num1/num2)

finally :
    print("이 부분은 무조건 나옵니다.")

-try문에서 오류가 발생하면 except문 실행되며, 오류가 발생하지 않으면 else 문이 실행이된다. finally문은 오류가 발생하든 그렇지 않든 무조건 실행된다.

 

selfstudy11-5.py

from tkinter import *
from tkinter import filedialog, messagebox

# 함수 선언 부분
def loadImage(fname):
    global inImage, XSIZE, YSIZE
    try:
        # 파일을 이진 모드로 열기
        with open(fname, 'rb') as fp:
            for i in range(0, XSIZE):
                tmpList = []  
                for k in range(0, YSIZE):
                    data = int(ord(fp.read(1))) 
                    tmpList.append(data)  
                inImage.append(tmpList)
    except Exception as e:
        messagebox.showerror("오류", f"처리에 실패했습니다: {e}")
        return False
    return True

def displayImage(image):
    global XSIZE, YSIZE
    rgbString = ""
    for i in range(0, XSIZE):
        tmpString = ""
        for k in range(0, YSIZE):
            data = image[i][k]
            tmpString += "#%02x%02x%02x " % (data, data, data)  
        rgbString += "{" + tmpString + "} "
    paper.put(rgbString)

# 전역 변수 선언 부분
window = None
canvas = None
XSIZE, YSIZE = 256, 256
inImage = []

# 메인 코드 부분
window = Tk()
window.title("흑백 사진 보기")
canvas = Canvas(window, height=XSIZE, width=YSIZE)
paper = PhotoImage(width=XSIZE, height=YSIZE)
canvas.create_image((XSIZE / 2, YSIZE / 2), image=paper, state="normal")

# 파일 선택 대화상자 띄우기
filename = filedialog.askopenfilename(title="이미지 파일 선택", filetypes=[("Raw files", "*.raw"), ("All files", "*.*")])

if filename:
    # 파일 로딩 시도
    if loadImage(filename):
        # 성공적으로 이미지 로드된 경우
        displayImage(inImage)
        messagebox.showinfo("성공", f"{filename} 파일이 정상적으로 처리되었습니다.")
else:
    # 파일 선택이 없을 경우
    messagebox.showwarning("경고", "파일이 선택되지 않았습니다.")

# 종료 메시지 출력
messagebox.showinfo("종료", "수고하셨습니다.")

# 화면에 표시
canvas.pack()
window.mainloop()

'Language > Python' 카테고리의 다른 글

데이터베이스  (1) 2024.12.05
객체지향 프로그래밍  (1) 2024.12.05
윈도 프로그래밍  (2) 2024.12.05
함수와 모듈  (0) 2024.12.05
문자열  (2) 2024.10.24

위젯은 위도창에 나올 수 있는 문자, 버튼, 체크박스, 라디오 버튼 등을 의미한다.

 

필수

Code10-01.py

from tkinter import *

window = Tk()

##이 부분에서 화면을 구성하고 처리##

window.mainloop() ##필수

기본적인 윈도창의 구성이다.

 

-tkinter는 gui 관련 보듈을 제공해주는 표준 위도 라이브러리이다.

-window = tk()르 통해 윈도창이 화면에 출련된다.

-window.mainloop()는 다양한 이벤트를 처리하는데 필요

 

 

Code10-02.py

from tkinter import *

window = Tk()
window.title("윈도우 연습")
window.geometry("400x100")
window.resizable(width = False, height = False) #크기 변동x

##이 부분에서 화면을 구성하고 처리##

window.mainloop() ##필수

 

레이블

Code10-03.py

from tkinter import *
window = Tk()

label1 = Label(window, text = "COOKBOOK~~Pytthon을")
label2 = Label(window, text = "열심히", font=("궁서체", 30), fg = "blue") 
label3 = Label(window, text = "공부 중입니다.", bg = "magenta", width = 20, height=5, anchor = SE) 


label1.pack()
label2.pack()
label3.pack()

window.mainloop() ##필수

-레이블 =문자를 표현하는 위젯

-Label(부모윈도, 옵션...)

-레이블 같은 위젯은 .pack()함수를 호출해야한다.

-anchor는 위젯의 위치

 

Code10-04.py

from tkinter import *
window = Tk()

photo = PhotoImage(file= "C:/tukdata/ch10/image/GIF/dog.gif")
label1 = Label(window, image = photo)

label1.pack()

window.mainloop() ##필수

-글자 대신 이미지가 들어갔다.

 

selfstudy10-4.py

from tkinter import *
window = Tk()

# 첫 번째 이미지
photo1 = PhotoImage(file="C:/tukdata/ch10/image/GIF/dog.gif")
label1 = Label(window, image=photo1)
label1.pack(side=LEFT)

# 두 번째 이미지
photo2 = PhotoImage(file="C:/tukdata/ch10/image/GIF/dog2.gif") 
label2 = Label(window, image=photo2)
label2.pack(side=LEFT)

window.mainloop()

 

 

버튼

Code10-05.py

from tkinter import *
window = Tk()

button1 = Button(window, text = "파이썬 종료", fg = "red", command = quit)

button1.pack()

window.mainloop() ##필수

-마우스 버튼을 누르면 효과가 실행되는 위젯

-command 옵션은 버튼을 눌렀을때 지정한 작업을 처리할 수 있다.

 

 

Code10-06.py

from tkinter import *
from tkinter import messagebox

##함수 선언 부분##
def myFunc() :
    messagebox.showinfo("강아지 버튼", "강아지가 귀엽죠? ^^")

##메인코드 부분##
window = Tk()

photo = PhotoImage(file= "C:/tukdata/ch10/image/GIF/dog2.gif")
button1 = Button(window, image = photo, command = myFunc)


button1.pack()

window.mainloop() ##필수

 

 

체크버튼

Code10-07.py

from tkinter import *
from tkinter import messagebox
window = Tk()

##함수 선언 부분##
def myFunc() :
    if chk.get() == 0 :
        messagebox.showinfo("", "체크버튼이 꺼졌어요.")
    else :
        messagebox.showinfo("", "체크버튼이 켜졌어요.")

##메인코드 부분##
chk = IntVar()
cb1 = Checkbutton(window, text = "클릭하세요", variable = chk ,command = myFunc)

cb1.pack()

window.mainloop() ##필수

-intvar함수는 정수형 타입의 변수 생성

-체크버튼을 키면 chk 1대입 끄면 0 대입

 

라디오버튼

Code10-08.py

from tkinter import *
window = Tk()

##함수 선언 부분##
def myFunc() :
    if var.get() == 1 :
        label1.configure(text = "파이썬")
    elif var.get() ==2 :
        label1.configure(text = "C++")
    else :
        label1.configure(text = "java")

##메인코드 부분##
var = IntVar()
rb1 = Radiobutton(window, text = "파이썬", variable = var, value=1, command = myFunc)
rb2 = Radiobutton(window, text = "C++", variable = var, value=2, command = myFunc)
rb3 = Radiobutton(window, text = "java", variable = var, value=3, command = myFunc)

label1 = Label(window, text = "선택한 언어 : ", fg = "red")

rb1.pack()
rb2.pack()
rb3.pack()
label1.pack()

window.mainloop() ##필수

 

정렬

Code10-09.py

from tkinter import *
window = Tk()

button1 = Button(window, text = "버튼1")
button2 = Button(window, text = "버튼2")
button3 = Button(window, text = "버튼3")

button1.pack(side=LEFT)
button2.pack(side=LEFT)
button3.pack(side=LEFT)

window.mainloop() ##필수

-pack() 함수 옵션에서 side = 사용하면 된다.

 

Code10-10.py

from tkinter import *
window = Tk()

btnList = [None]*3

for i in range(0, 3) :
    btnList[i] = Button(window, text = "버튼" + str(i+1))

for btn in btnList :
    # btn.pack(side = RIGHT)
    btn.pack(side = RIGHT, fill =X, ipadx = 10, ipady = 10, padx = 10, pady = 10)

window.mainloop() ##필수

 

Code10-11.py

from tkinter import *

##전역 변수 선언 부분##
btnList = [None]*9
fnameList = ["honeycomb.gif", "icecream.gif", "jellybean.gif", "kitkat.gif", "lollipop.gif", "marshmallow.gif", "nougat.gif", "oreo.gif", "pie.gif"]
photoList = [None]*9
i,k=0,0
xPos,yPos = 0,0
num = 0

##메인 코드 부분##
window = Tk()
window.geometry("210x210")

for i in range(0, 9) :
    photoList[i] = PhotoImage(file = "ch10/image/GIF/" + fnameList[i])
    btnList[i] = Button(window, image=photoList[i])

for i in range(0, 3) :
    for k in range(0,3) :
        btnList[num].place(x = xPos, y = yPos)
        num += 1
        xPos += 70
    xPos =0
    yPos += 70

window.mainloop() ##필수

 

-수평 side = left or right

-수직 = top or bottom

-폭조정 fill = x

-여백 = padx= 10 or pady = 10

-내부여백 ipadx = 10

고정위치 -> .place() 함수 사용

 

 

selfstudy10-2.py

from tkinter import *
import random  # 랜덤 모듈 임포트

# 전역 변수 선언 부분
btnList = [None] * 9
fnameList = ["honeycomb.gif", "icecream.gif", "jellybean.gif", "kitkat.gif", "lollipop.gif", 
             "marshmallow.gif", "nougat.gif", "oreo.gif", "pie.gif"]
photoList = [None] * 9
i, k = 0, 0
xPos, yPos = 0, 0
num = 0

# 리스트를 랜덤하게 섞음
random.shuffle(fnameList)

# 메인 코드 부분
window = Tk()
window.geometry("210x210")

for i in range(0, 9):
    photoList[i] = PhotoImage(file="ch10/image/GIF/" + fnameList[i])
    btnList[i] = Button(window, image=photoList[i])

for i in range(0, 3):
    for k in range(0, 3):
        btnList[num].place(x=xPos, y=yPos)
        num += 1
        xPos += 70
    xPos = 0
    yPos += 70

window.mainloop()

 

Code10-12.py

from tkinter import *
from time import *

# 전역 변수 선언 부분
frameList = ["jeju1.gif", "jeju2.gif", "jeju3.gif", "jeju4.gif", "jeju5.gif", "jeju6.gif", "jeju7.gif", "jeju8.gif", "jeju9.gif"]
photoList = [None] * 9
num = 0

# 함수 선언 부분
def clickNext():
    global num
    num += 1
    if num > 8:
        num = 0
    photo = PhotoImage(file="ch10/image/GIF/" + frameList[num])
    pLabel.configure(image=photo)
    pLabel.image = photo

def clickPrev():
    global num
    num -= 1
    if num < 0:
        num = 8
    photo = PhotoImage(file="ch10/image/GIF/" + frameList[num])
    pLabel.configure(image=photo)
    pLabel.image = photo

# 메인 코드 부분
window = Tk()
window.geometry("700x500")
window.title("사진 앨범 보기")

btnPrev = Button(window, text="« 이전", command=clickPrev)
btnNext = Button(window, text="다음 »", command=clickNext)

photo = PhotoImage(file="ch10/image/GIF/" + frameList[0])
pLabel = Label(window, image=photo)

btnPrev.place(x=250, y=10)
btnNext.place(x=400, y=10)
pLabel.place(x=15, y=50)

window.mainloop()

 

selfstudy10-3.py

from tkinter import *
from time import *

# 전역 변수 선언 부분
frameList = ["jeju1.gif", "jeju2.gif", "jeju3.gif", "jeju4.gif", "jeju5.gif", 
             "jeju6.gif", "jeju7.gif", "jeju8.gif", "jeju9.gif"]
photoList = [None] * 9
num = 0

# 함수 선언 부분
def clickNext():
    global num
    num += 1
    if num > 8:
        num = 0
    updateImage()

def clickPrev():
    global num
    num -= 1
    if num < 0:
        num = 8
    updateImage()

def updateImage():
    # 이미지 업데이트
    photo = PhotoImage(file="ch10/image/GIF/" + frameList[num])
    pLabel.configure(image=photo)
    pLabel.image = photo
    # 파일명 업데이트
    fileNameLabel.config(text=frameList[num])

# 메인 코드 부분
window = Tk()
window.geometry("700x500")
window.title("사진 앨범 보기")

btnPrev = Button(window, text="« 이전", command=clickPrev)
btnNext = Button(window, text="다음 »", command=clickNext)

photo = PhotoImage(file="ch10/image/GIF/" + frameList[0])
pLabel = Label(window, image=photo)

# 파일명 표시용 라벨 추가
fileNameLabel = Label(window, text=frameList[0], font=("Arial", 12))
fileNameLabel.place(x=320, y=15)

btnPrev.place(x=250, y=10)
btnNext.place(x=400, y=10)
pLabel.place(x=15, y=50)

window.mainloop()

 

 

 

마우스 이벤트 처리

def 이벤트처리함수(event):
	#이 부분에 마우스 이벤트가 발생할 때 작동할 내용 작성
    
위젯.bind("마우스이벤트", 이벤트처리함수)

 

Code10-13.py

from tkinter import *
from tkinter import messagebox

#함수 선언 부분
def clickLeft(event):
    messagebox.showinfo("마우스", "마우스 왼쪽 버튼이 클릭됨")

##이 부분에서 화면을 구성하고 처리##
window = Tk()

window.bind("<Button-1>", clickLeft)

window.mainloop() ##필수

 

 

Code10-14.py

from tkinter import *
from tkinter import messagebox

#함수 선언 부분
def clickImage(event):
    messagebox.showinfo("마우스", "토끼에서 마우스가 클릭됨")

##이 부분에서 화면을 구성하고 처리##
window = Tk()
window.geometry("400x400")

photo = PhotoImage(file = "ch10/image/GIF/rabbit.gif")
label1 = Label(window, image = photo)


label1.bind("<Button>", clickImage)

label1.pack(expand = True, anchor = CENTER)

window.mainloop() ##필수

-label.bind로 이미지를 클릭할 때만 이벤트 처리된다(window.bind면 위젯 자체)

 

 

Code10-15.py

from tkinter import *

#함수 선언 부분
def clickMouse(event):
    txt = ""
    if event.num == 1:
        txt += "마우스 왼쪽 버튼이 ("
    elif event.num == 3:
        txt += "마우스 오른쪽 버튼이 ("

    txt += str(event.y) + "," + str(event.x) + ")에서 클릭됨"
    label1.configure(text = txt)

#메인 코드 부분##
window = Tk()
window.geometry("400x400")

label1 = Label(window, text= "이곳이 바뀜")

window.bind("<Button>", clickMouse)

label1.pack(expand = True, anchor = CENTER)
window.mainloop() ##필수

 

 

 

키보드 이벤트 기본처리

Code10-16.py

from tkinter import *
from tkinter import messagebox

#함수 선언 부분
def keyEvent(event):
    messagebox.showinfo("키보드 이벤트", "눌린 키 : " + chr(event.keycode))

#메인 코드 부분##
window = Tk()

window.bind("<Key>", keyEvent)

window.mainloop() ##필수

-.event.keycode에 눌려진 키의 숫자값이 chr()함수를 사용해서 문자로 변환시켰다

 

 

 

selfstudy10-4.py

from tkinter import *
from tkinter import messagebox

# 함수 선언 부분
def keyEvent(event):
    # Shift 키와 화살표 키 조합에 따라 메시지 출력
    if event.keycode == 37:
        messagebox.showinfo("키보드 이벤트", "눌린 키 : Shift + 왼쪽 화살표")
    elif event.keycode == 38:
        messagebox.showinfo("키보드 이벤트", "눌린 키 : Shift + 위쪽 화살표")
    elif event.keycode == 39:
        messagebox.showinfo("키보드 이벤트", "눌린 키 : Shift + 오른쪽 화살표")
    elif event.keycode == 40:
        messagebox.showinfo("키보드 이벤트", "눌린 키 : Shift + 아래쪽 화살표")

# 메인 코드 부분
window = Tk()
# Shift와 각 화살표 키 조합에 대해 이벤트 바인딩
window.bind("<Shift-Left>", keyEvent)
window.bind("<Shift-Up>", keyEvent)
window.bind("<Shift-Right>", keyEvent)
window.bind("<Shift-Down>", keyEvent)

window.mainloop()

 

 

 

메뉴의 생성

메뉴자체 = Menu(부모윈도)
부모윈도.config(menu = 메뉴자체)

상위메뉴 = Menu(메뉴자체)
메뉴자체.add_cascade(label = "상위메뉴텍스트", menu = 상위메뉴)
상위메뉴.add_command(label = "하위메뉴1", command = 함수1)
상위메뉴.add_command(label = "하위메뉴2", command = 함수2)

 

Code10-17.py

from tkinter import *

window = Tk()

mainMenu = Menu(window) #메뉴자체 변수
window.config(menu = mainMenu) #생성한 메뉴 자체를 윈도창 메뉴로 지정

fileMenu = Menu(mainMenu) #상위 메뉴인 파일을 생성하고 메뉴 자체에 부착
mainMenu.add_cascade(label="파일", menu = fileMenu)
fileMenu.add_command(label="열기")#하위메뉴
fileMenu.add_separator()
fileMenu.add_command(label="종료")

window.mainloop() ##필수

 

Code10-18.py

from tkinter import *
from tkinter import messagebox

#함수 선언 부분
def func_open():
    messagebox.showinfo("메뉴선택", "열기 메뉴를 선택함")

def func_exit():
    window.quit()
    window.destroy()

#메인 코드 부분##
window = Tk()

mainMenu = Menu(window)
window.config(menu = mainMenu)

fileMenu = Menu(mainMenu)
mainMenu.add_cascade(label="파일", menu = fileMenu)
fileMenu.add_command(label="열기", command = func_open)
fileMenu.add_separator()
fileMenu.add_command(label="종료", command= func_exit)

window.mainloop() ##필수

-add_command()함수: 무언가 작동

 

 

대화상자의 생성과 사용

Code10-19.py

from tkinter import *
from tkinter.simpledialog import*

#함수 선언 부분
window = Tk()
window.geometry("400x100")

label1 = Label(window, text = "입력된 값")
label1.pack()

value = askinteger("확대배수", "주사위 숫자(1~6)을 입력하세요", minvalue = 1, maxvalue = 6)

label1.configure(text = str(value))
window.mainloop() ##필수

-tkinter.simpledialog모듈 임포트

-askinteger("제목", "내용", 옵션)

 

숫자나 문자를 입력받으려면 tkinter.simpledialog 모듈을 입포트한 후 askinteger(), askfloa(), askstring()함수 등을 사용한다.

 

 

Code10-20.py

from tkinter import *
from tkinter.filedialog import*

#함수 선언 부분
window = Tk()
window.geometry("400x100")

label1 = Label(window, text = "선택된 파일 이름")
label1.pack()

filename = askopenfilename(parent=window, filetypes=(("GIF 파일", "*.gif"), ("모든 파일", "*.*")))

label1.configure(text = str(filename))

window.mainloop() ##필수

-tkinter.filedialog 임포트

-askopenfilename()함수

 

파일을 열거나 저장할 때 나타나는 대화상자는 tkinter.filedilog 모듈을 임포트한 후 askopenfilename() 또는 asksaveasfile()함수를 사용한다.

 

 

Code10-21.py

from tkinter import *
from tkinter.filedialog import*

#함수 선언 부분
window = Tk()
window.geometry("400x100")

label1 = Label(window, text = "선택된 파일 이름")
label1.pack()

saveFp = asksaveasfile(parent=window, mode= "w", defaultextension = ".jpg", filetypes = (("jpg 파일", "*.jpg;*.jpeg"), ("모든 파일", "*.*")))

label1.configure(text = saveFp)

saveFp.close() ##필수

-asksaveasfile()->다른 이름으로 저장

-mode "W"는 쓰기

 

 

 

 

Code10-22.py

from tkinter import *
from tkinter.filedialog import *

# 함수 선언 부분
def func_open():
    filename = askopenfilename(parent=window, filetypes=(("GIF 파일", "*.gif"), ("모든 파일", "*.*")))
    photo = PhotoImage(file=filename)
    pLabel.configure(image=photo)
    pLabel.image = photo

def func_exit():
    window.quit()
    window.destroy()

# 메인 코드 부분
window = Tk()
window.geometry("500x500")
window.title("명화 감상하기")

photo = PhotoImage()
pLabel = Label(window, image=photo)
pLabel.pack(expand=1, anchor=CENTER)

mainMenu = Menu(window)
window.config(menu=mainMenu)
fileMenu = Menu(mainMenu)
mainMenu.add_cascade(label="파일", menu=fileMenu)
fileMenu.add_command(label="파일 열기", command=func_open)
fileMenu.add_separator()
fileMenu.add_command(label="프로그램 종료", command=func_exit)

window.mainloop()

 

selfstudy10-5.py

from tkinter import *
from tkinter.filedialog import *

# 함수 선언 부분
def func_open():
    filename = askopenfilename(parent=window, filetypes=(("GIF 파일", "*.gif"), ("모든 파일", "*.*")))
    if filename:
        global photo  
        photo = PhotoImage(file=filename)
        grayscale_image(photo)  
        pLabel.configure(image=photo)
        pLabel.image = photo

def grayscale_image(photo):
    width = photo.width()
    height = photo.height()

    for x in range(width):
        for y in range(height):
            r, g, b = photo.get(x, y) 
            gray = (r + g + b) // 3
            # 픽셀을 회색으로 설정
            photo.put("#%02x%02x%02x" % (gray, gray, gray), (x, y))

def func_exit():
    window.quit()
    window.destroy()

# 메인 코드 부분
window = Tk()
window.geometry("500x500")
window.title("명화 감상하기")

photo = PhotoImage()  
pLabel = Label(window, image=photo)
pLabel.pack(expand=1, anchor=CENTER)

mainMenu = Menu(window)
window.config(menu=mainMenu)
fileMenu = Menu(mainMenu)
mainMenu.add_cascade(label="파일", menu=fileMenu)
fileMenu.add_command(label="파일 열기", command=func_open)
fileMenu.add_separator()
fileMenu.add_command(label="프로그램 종료", command=func_exit)

window.mainloop()

'Language > Python' 카테고리의 다른 글

객체지향 프로그래밍  (1) 2024.12.05
파일 입출력  (0) 2024.12.05
함수와 모듈  (0) 2024.12.05
문자열  (2) 2024.10.24
리스트, 튜플, 딕셔너리  (0) 2024.10.24

함수 = 자판기!

무엇인가 매개변수를 넣으면 반환값을 돌려준다


code09-01.py

coffee = 0

coffee = int(input("어떤 커피 드릴까요?(1:보통, 2:설탕, 3:블랙)"))

print()
print("#1. 뜨거운 물을 준비한다.")
print("#2. 종이컵을 준비한다.")

if coffee == 1:
    print("#3. 보통커피를 탄다.")
elif coffee == 2:
    print("#3. 설탕커피를 탄다.")
elif coffee == 3:
    print("#3. 블랙커피를 탄다.")
else :
    print("#3. 아무거나 탄다.\n")

print("#4. 물을 붓는다.")
print("#5. 스푼으로 젓는다.")
print()
print("손님~ 커피 여기 있습니다.")

 
code09-02.py

##전역 변수 선언 부분
coffee = 0

## 함수 선언 부분##
def coffee_machine(button):
    print()
    print("#1. (자동으로) 뜨거운 물을 준비한다.")
    print("#2. (자동으로) 종이컵을 준비한다.")

    if coffee == 1:
        print("#3. (자동으로) 보통커피를 탄다.")
    elif coffee == 2:
        print("#3. (자동으로) 설탕커피를 탄다.")
    elif coffee == 3:
        print("#3. (자동으로) 블랙커피를 탄다.")
    else :
        print("#3. (자동으로) 아무거나 탄다.\n")

    print("#4. (자동으로) 물을 붓는다.")
    print("#5. (자동으로) 스푼으로 젓는다.")
    print()

##메인 코드 부분##
coffee = int(input("어떤 커피 드릴까요?(1:보통, 2:설탕, 3:블랙)"))
coffee_machine(coffee)
print("손님~ 커피 여기 있습니다.")

 
code09-03.py

##전역 변수 선언 부분
coffee = 0

## 함수 선언 부분##
def coffee_machine(button):
    print()
    print("#1. (자동으로) 뜨거운 물을 준비한다.")
    print("#2. (자동으로) 종이컵을 준비한다.")

    if coffee == 1:
        print("#3. (자동으로) 보통커피를 탄다.")
    elif coffee == 2:
        print("#3. (자동으로) 설탕커피를 탄다.")
    elif coffee == 3:
        print("#3. (자동으로) 블랙커피를 탄다.")
    else :
        print("#3. (자동으로) 아무거나 탄다.\n")

    print("#4. (자동으로) 물을 붓는다.")
    print("#5. (자동으로) 스푼으로 젓는다.")
    print()

##메인 코드 부분##
coffee = int(input("A손님, 어떤 커피 드릴까요?(1:보통, 2:설탕, 3:블랙)"))
coffee_machine(coffee)
print("A손님~ 커피 여기 있습니다.")

coffee = int(input("B손님, 어떤 커피 드릴까요?(1:보통, 2:설탕, 3:블랙)"))
coffee_machine(coffee)
print("B손님~ 커피 여기 있습니다.")

coffee = int(input("C손님, 어떤 커피 드릴까요?(1:보통, 2:설탕, 3:블랙)"))
coffee_machine(coffee)
print("C손님~ 커피 여기 있습니다.")

 
selfstudy9-1.py

##전역 변수 선언 부분
coffee = 0

## 함수 선언 부분##
def coffee_machine(button):
    print()
    print("#1. (자동으로) 뜨거운 물을 준비한다.")
    print("#2. (자동으로) 종이컵을 준비한다.")

    if coffee == 1:
        print("#3. (자동으로) 아메리카노를 탄다.")
    elif coffee == 2:
        print("#3. (자동으로) 카페라떼를 탄다.")
    elif coffee == 3:
        print("#3. (자동으로) 카푸치노를 탄다.")
    elif coffee == 4:
        print("#3. (자동으로) 에스프레소를 탄다.")
    else :
        print("#3. (자동으로) 아무거나 탄다.\n")

    print("#4. (자동으로) 물을 붓는다.")
    print("#5. (자동으로) 스푼으로 젓는다.")
    print()

##메인 코드 부분##
coffee = int(input("로제씨, 어떤 커피 드릴까요?(1:아메리카노, 2:카페라떼, 3:카푸치노, 4:에스프레소)"))
coffee_machine(coffee)
print("로제씨~ 커피 여기 있습니다.")

coffee = int(input("리사, 어떤 커피 드릴까요?(1:보통, 2:설탕, 3:블랙)"))
coffee_machine(coffee)
print("리사씨~ 커피 여기 있습니다.")

coffee = int(input("지수씨, 어떤 커피 드릴까요?(1:보통, 2:설탕, 3:블랙)"))
coffee_machine(coffee)
print("지수씨~ 커피 여기 있습니다.")

coffee = int(input("제니씨, 어떤 커피 드릴까요?(1:보통, 2:설탕, 3:블랙)"))
coffee_machine(coffee)
print("제니씨~ 커피 여기 있습니다.")



함수의 형식과 활용
반복적으로 코딩해야 할 내용을 함수로 만들면 필요할때마다 사용 가능하고 동일한 동작을 계속 사용하므로 내부 내용이 바뀔 일이 없다.
 
code09-04.py

## 함수 선언 부분 ##
def plus(v1, v2):
    result = 0
    result =v1 + v2
    return result

## 전역 변수 선언 부분 ##
hap = 0

##메인 코드 부분 ##
hap = plus(100, 200)
print("100과 200의 plus() 함수 결과는 %d" %hap)

*def 함수 선언 부분은 바로 실행되지 않는다 

code09-05.py

## 함수 선언 부분 ##
def cal(v1, v2, op):
    result = 0
    
    if op =="+" :
        result = v1 + v2
    elif op == "-" :
        result = v1 - v2
    elif op == "*" :
        result = v1 * v2
    elif op == "/" :
        result = v1 / v2
        
    return result

## 전역 변수 선언 부분 ##
res = 0
var1, var2, oper =0, 0, ""

##메인 코드 부분 ##
oper = input("계산을 입력하세요(+,-,*,/) : ")
var1 = int(input("첫 번째 수를 입력하세요 : "))
var2 = int(input("두 번째 수를 입력하세요 : "))

res = cal(var1, var2, oper)

print("## 계산기 : %d %s %d = %d" %(var1, oper, var2, res))

 
selfstudy9-2.py

## 함수 선언 부분 ##
def cal(v1, v2, op):
    result = 0
    
    if op =="+" :
        result = v1 + v2
    elif op == "-" :
        result = v1 - v2
    elif op == "*" :
        result = v1 * v2
    elif op == "/" :
        result = v1 / v2
    elif op == "**" :
        result = v1 ** v2
        
    return result

## 전역 변수 선언 부분 ##
res = 0
var1, var2, oper =0, 0, ""

##메인 코드 부분 ##
var1 = int(input("첫 번째 수를 입력하세요 : "))
oper = input("계산을 입력하세요(+,-,*,/,**) : ")
var2 = int(input("두 번째 수를 입력하세요 : "))

if var2 == 0:
    print("0으로는 나누면 안 됩니다.ㅠㅠ")

else:
    res = cal(var1, var2, oper)

    print("## 계산기 : %d %s %d = %d" %(var1, oper, var2, res))

 
지역 변수, 전역 변수

지역변수는 함수 내에서만 사용되는 변수
전역 변수는 프로그램 전체에서 사용되는 변수이다
(변수명이 같다면 지역변수가 우선)

code09-06.py

##함수 선언 부분##
def func1():
    a = 10 #지역변수
    print("func1()에서 a값 %d" % a)

def func2():
    print("func2()에서 a값 %d" % a)

##전역변수 선언 부분 
a = 20 #전역변수

##메인코드
func1()
func2()



 
code09-07.py

##함수 선언 부분##
def func1():
    global a # 이 함수 안에서 a는 전역 변수
    a = 10 #지역변수
    print("func1()에서 a값 %d" % a)

def func2():
    print("func2()에서 a값 %d" % a)

##전역변수 선언 부분 
a = 20 #전역변수

##메인코드
func1()
func2()

global 예약어가 사용이 되면 전역변수가 된다.

 

함수의 반환값과 매개변수

함수는 크게 반환값이 있는 함수(ex. return a)vs 반환값이 없는 함수로 나눈다.(return or 없음)

code09-08.py

def func1():
    result = 100
    return result

def func2():
    print("반환값이 없는 함수 실행")

##전역변수 선언 부분 
hap = 0

##메인코드
hap=func1()
print("func1()에서 돌려준 값 ==> %d" %hap)
func2()

*반환값이 없는 함수
-return문이 생략이 되거나 return만 입력
 

code09-09.py

##함수 선언 부분##
def multi(v1, v2):
    retList = []
    res1 = v1 + v2
    res2 = v1 - v2
    retList.append(res1)
    retList.append(res2)
    return retList

##전역변수 선언 부분 
myList = []
hap, sub = 0, 0

##메인코드
myList = multi(100, 200)
hap = myList[0]
sub = myList[1]
print("multi()에서 돌려준 값 ==> %d, %d" % (hap, sub))

*반환값이 여러개인 함수
-2개 이상이 반환값이 될 수 없지만 리스트에 넣은 후 반환하면 ok 

+추가로
def func()
      pass
pass 예약어는 함수를 구현할 대 일단 이름만 만들어 놓고 그 내용은 pass 예약어로 비울 수 있다.




code09-10.py

##함수 선언 부분##
def para2_func(v1, v2):
    result = 0
    result = v1 + v2
    return result

def para3_func(v1, v2, v3):
    result = 0
    result = v1 + v2 + v3
    return result

##전역변수 선언 부분 
hap = 0

##메인코드
hap = para2_func(10, 20)
print("매개변수가 2개인 함수를 호출한 결과 ==> %d" %hap)
hap = para3_func(10, 20, 30)
print("매개변수가 3개인 함수를 호출한 결과 ==> %d" %hap)

 매개변수의 개수를 지정해 전달하는 방법

 
code09-11.py

##함수 선언 부분##
def para_func(v1, v2, v3=0):
    result = 0
    result = v1 + v2 + v3
    return result

##전역변수 선언 부분 
hap = 0

##메인코드
hap = para_func(10, 20)
print("매개변수가 2개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30)
print("매개변수가 3개인 함수를 호출한 결과 ==> %d" %hap)

매개변수에 기본값을 설정해 놓고 전달하는 방법
 

selfstudy9-3.py

##함수 선언 부분##
def para_func(v1, v2, v3=0,v4=0,v5=0,v6=0,v7=0,v8=0,v9=0,v10=0):
    result = 0
    result = v1 + v2 + v3+ v4 + v5 + v6+ v7 + v8 + v9 + v10
    return result

##전역변수 선언 부분 
hap = 0

##메인코드
hap = para_func(10, 20)
print("매개변수가 2개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30)
print("매개변수가 3개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30, 40)
print("매개변수가 4개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30, 40, 50)
print("매개변수가 5개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30, 40, 50, 60)
print("매개변수가 6개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30, 40, 50, 60, 70)
print("매개변수가 7개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30, 40, 50, 60, 70, 80)
print("매개변수가 8개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30, 40, 50, 60, 70, 80, 90)
print("매개변수가 9개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
print("매개변수가 10개인 함수를 호출한 결과 ==> %d" %hap)

 
code09-12.py

#함수 선언 부분
def para_func(*para): #*갯수가 정해져있지 않은 매개변수가 튜플 형식으로 넘어와 튜플을 처리하는 방식으로 함수 안에서 사용 가능
    result = 0
    for num in para :
        result = result + num

    return result

##전역변수 선언 부분 
hap = 0

##메인코드
hap = para_func(10, 20)
print("매개변수가 2개인 함수를 호출한 결과 ==> %d" %hap)
hap = para_func(10, 20, 30)
print("매개변수가 3개인 함수를 호출한 결과 ==> %d" %hap)





#딕셔너리
def dic_func(**para): 
    for k in para.keys() :
        print("%s -- > %d명입니다." %(k, para[k]))


dic_func(트와이스 = 9, 소녀시대 = 7, 걸스데이 = 4, 블랙핑크 =4)

 매개변수의 개수를 지정하지 않고 전달하는 방법
-매개변수 앞에*를 붙이면 매개벼누가 튜플 형식으로 넘어와 튜플을 처리하는 방식으로 함수 안에서 사용할 수 있다.
-**를 사용하면 딕셔너리 형식으로 전달->(키=값)형식으로 넣어줘야 함

 
code09-13.py

import random

##함수 선언 부분##
def getNumber():
    return random.randrange(1, 46)

##전역 변수 선언 부분##
lotto = []
num = 0

##메인 코드 부분##
print("** 로또 추첨을 시작합니다. ** \n")

while True:
    num = getNumber()

    if lotto.count(num) == 0:
        lotto.append(num)

    if len(lotto) >=6 :
        break

print("추첨된 로또 번호 ==> ", end = "")
lotto.sort()
for i in range(0,6) :
    print("%d " %lotto[i], end="")

 

모듈

모듈은 함수의 집합
모듈은 표준 모듈, 사용자 모듈, 서드파티모듈이 있다.

표준모듈: 파이썬에서 제공하는모듈
사용자 모듈: 사용자가 만듬
써드 파티 모듈:외부 회사나 단체에서 제공하는 모듈->다양해서 파이썬의 장점

module1.py

##함수 선언 부분##
def func1() :
    print("Module1.py의 func1()이 호출됨.")

def func2() :
    print("Module1.py의 func2()이 호출됨.")

def func3() :
    print("Module1.py의 func3()이 호출됨.")

 
a.py

import Module1

##메인 코드 부분##
Module1.func1()
Module1.func2()
Module1.func3()

 
b.py

from Module1 import func1, func2, func3 #또는 from Module1 import *

#메인 코드 부분##
func1()
func2()
func3()


# def outFunc(v1,v2):
#     def inFunc(num1, num2) :
#         return num1 + num2
#     return inFunc(v1, v2)
# print(outFunc(10, 20))

# hap2 = lambda num1, num2 : num1 + num2
# print(hap2(10, 20))

# hap3 = lambda num1 = 10, num2 = 20 : num1 + num2
# print(hap3())
# print(hap3(100, 200))

# myList = [1,2,3,4,5]
# add10 = lambda num: num + 10
# myList = list(map(add10, myList))
# print(myList)

# myList = list(map(lambda num : num + 10, myList))
# print(myList)

# list1=[1,2,3,4]
# list2=[10, 20, 30, 40]
# hapList = list(map(lambda n1, n2 : n1+n2, list1, list2))
# print(hapList)


# def factorial(num) :
#     if num <=1 :
#         return num
#     else:
#         return num*factorial(num-1)
# print(factorial(4))
# print(factorial(10))

 
myTurtle.py

import random
from tkinter.simpledialog import *

def getString() :
    retStr = ""
    retStr = askstring("문자열 입력", "거북이 쓸 문자열을 입력")
    return retStr

def getRGB():
    r,g,b =0,0,0
    r = random.random()
    g = random.random()
    b = random.random()
    return (r,g,b)

def getXYAS(sw, sh):
    x, y, angle, size = 0,0,0,0
    x = random.randrange( int(-sw/2), int(sw/2))
    y = random.randrange( int(-sh/2), int(sh/2))
    angle = random.randrange(0,360)
    size = random.randrange(10, 50)
    return [x,y,angle, size]

 
 
code09-14.py

from myTurtle import *
import turtle

##전역변수선언부분##
instr = ""
swidth, sheight = 300, 300
tX, tY, tAngle, tSize = [0]*4

#메인코드부분#
turtle.title("거북이 글짜쓰기(모듈버전)")
turtle.shape("Turtle")
turtle.setup(width=swidth + 50, height = sheight + 50)
turtle.screensize(swidth, sheight)
turtle.penup()
turtle.speed(5)

inStr = getString()

for ch in inStr :

    tX, tY, tAngle, tSize = getXYAS(swidth, sheight)
    r,g,b = getRGB()

    turtle.goto(tX, tY)
    turtle.left(tAngle)

    turtle.pencolor((r,g,b))
    turtle.write(ch, font = ("맑은고딕", txtSize, "bold"))

turtle.done

 
패키지

패키지는 여러 모듈을 모아 놓을 것으로 폴더의 형태
from 패키지명.모듈명 import 함수명





내부함수
내부함수는 함수 안에 함수가 있는 형태
def outfunc(v1, v2) :
       def infunc(num1, num2) :
              return num1 + num2
         return infunc(v1,v2)
print(outfunc(10, 20))
결과값 -> 30

람다함수
한줄로 간단하게 함수를 만들어 줌
hap = lambda num1, num2 : num1 + num2
print(hap(10, 20))
결과값->30

map함수
리스트에 함수 수식을 모두 한꺼번에 적용
mpa(함수, 시퀸스(문자열,리스트,딕셔너리))

재귀함수
자신이 자신을 호출
중지하려면
-ctrl + c
-카운트

yield문
return은 결과를 반환하고 함수를 종결하지만 yield문은 함수를 종결하지 않으면서 값을 반환한다.

'Language > Python' 카테고리의 다른 글

파일 입출력  (0) 2024.12.05
윈도 프로그래밍  (2) 2024.12.05
문자열  (2) 2024.10.24
리스트, 튜플, 딕셔너리  (0) 2024.10.24
반복문  (0) 2024.10.24

가상환경 생성

 

snort 환경을 구성할 Server와, 악성코드 행위 분석용  Client(Victim) 각각 가상환경을 구성하였다.

 

 

네트워크 통신을 원활히 하기 위해 방화벽을 해제하였으며,

 

 

 

ipconfig 명령어로 가상환경의 IP 주소를 확인한 뒤,
ping [IP주소] 명령어로 네트워크 연결을 확인하였다.


Snort 환경 구성 준비물

Snort: 네트워크 패킷 분석 및 침입 탐지 도구

WinPcap: 네트워크 패킷 캡처를 위한 라이브러리 및 드라이버

XAMPP: Apache, MySQL, PHP, Perl 등을 포함한 통합 개발 환경

Base: Snort 이벤트 데이터를 웹 인터페이스로 분석 및 표시하는 도구

ADOdb: Snort 로그 데이터를 MySQL로 저장하고 PHP로 처리하기 위한 라이브러리

Notepad++: Snort 규칙 및 구성 파일을 수정할 수 있는 코드 편집기

* (PHP는 웹사이트를 만들 때 서버에서 작동하는 프로그래밍 언어이다.
주로 데이터베이스와 연동해 동적인 웹 페이지를 생성하는 데 사용된다.)

 


Snort 설치

Snort 2.9.2.3 버전을 설치하였다.(3버전은 리눅스 버전이므로 주의!)

SQL과 연계 설치 여부는 추후 데이터베이스 직접 연결을 위해 "I do not plan to log to database" 옵션을 선택하였다.

설치 완료


WinPcap 설치

최신 버전인 WinPcap 4.1.3을 설치하였다.


XAMPP 설치

MySQL과 호환 가능한 버전으로 설치하였다.(최신 버전 설치 했는데 환경구성에서 호환이 안되는 경우가 생겨서 안전하게 1.7.1버전 사용을 추천!)

XAMPP Control Panel에서 Apache, MySQL 등을 통합 관리할 수 있다.

사용할 모듈들을 체크해서 실행 시켜준다.


Base 설치

Base를 설치 후 C:\xampp\htdocs\base 경로에 압축 해제하여 저장하였다.


ADOdb 설치

ADOdb를 C:\xampp\htdocs\adodb 경로에 압축 해제하여 저장하였다.

(ABODB는 버전인 5.20.12를 사용해야 localhost/base url에서 세팅이 가능하다)


Notepad++ 설치

Snort 규칙 파일 수정 및 구성 파일 편집을 위해 설치하였다.


MySQL 비밀번호 설정

 

1.MySQL 경로로 이동

cd C:\xampp\mysql\bin
 

2.root 사용자로 접속

mysql -u root -p mysql
 

3.비밀번호 설정

update user set password = password('비밀번호') where user = 'root';
 
4.현재 사용중인 MYSQL캐시를 지우고 새로운 설정을 적용
flush privileges;
 

5.MySQL 종료

quit
 

 


MySQL 스키마 생성

 

스키마 파일 복사

C:\snort\schemas의 create_mysql 파일을 C:\xampp\mysql\bin으로 복사하였다.

 

 

 

Snort DB 생성

mysqladmin -u root -p create snort
 

스키마 적용

mysql -D snort -u root -p < create_mysql
 
 
 mysql console 로그인
 mysql -u root -p  입력 후 비밀번호 입력
 
 

snort DB선택

use snort;
 
테이블 확인
show tables;

Base 설정

step0

c:\xampp\htdocs\base\includes 경로에 base_action.inc.php 파일을 notepad++를 열어준다.

 

메일 관련 29번, 30번 라인을 주석 처리하였다.

결과를 메일로 알려주는 29번과 30번 라인을 주석처리하여 비활성화
(받을 메일이 없기 때문에 해당 라인이 활성화되면 오류가 발생)

 

**추가로 localhost\base 들어가면

Deprecated: Function ereg_replace() is deprecated in C:\xampp\htdocs\base\includes\base_state_common.inc.php on line 184

이런 화면이 뜰 수 도 있다.

 

이럴 땐 php 문법이 버전 호환 때문에 생긴거라

base_state_common.inc.php 파일을 notepad++로 들어가서 finally 문법을 catch로 바꿔줘야 한다

예시

수정 전

try {
    $savec = $ADODB_COUNTRECS;
    $ADODB_COUNTRECS = false;

    if ($secs2cache != 0) {
        $rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
    } else {
        $rs = $this->Execute($sql, $inputarr);
    }
} finally {
    $ADODB_COUNTRECS = $savec;
}


수정 후
try {
    $savec = $ADODB_COUNTRECS;
    $ADODB_COUNTRECS = false;

    if ($secs2cache != 0) {
        $rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
    } else {
        $rs = $this->Execute($sql, $inputarr);
    }
} catch (Exception $e) {
    // 예외 발생 시 $ADODB_COUNTRECS 복원
    $ADODB_COUNTRECS = $savec;
    throw $e;
}

// 정상 실행 시 $ADODB_COUNTRECS 복원
$ADODB_COUNTRECS = $savec;

 

웹 인터페이스 설정

http://localhost/base에 접속하여 Snort DB 및 경로 정보를 설정하였다.

(XAMPP에서 Apache와 MySQL을 켜야 접속이 된다.)

 

step1

Pick a Language : 한국어가 없어 여어로 설정

Path to ADODB : adodb5  아까  저장해둔 C:\xampp\htdocs\adodb 경로로 설정

 

step2

Pick a Database type :
MySQL DB를 사용할 것이므로 MySQL 선택

Database Name : snort
이전에 명령프롬프트에서 설정한 DB명 ‘snort’

Database Host : localhost
현재 접속한 host 주소

Database Port :
DB 접속 시 어떤 포트로 접속할 것인지 결정
입력하지 않아도 무방

Database User Name, Password :
MySQL 계정 정보 입력

밑에 Archive Database는 사용하지 않을 것이므로 생략

 

step3

Use Authentication System : 인증 시스템 사용 여부 (체크)

Admin User Name : 로그인할 때 사용할 아이디

Password : 로그인할 때 사용할 비밀번호

Full name : base에서 사용할 닉네임


step4

 

‘Create BASE AG’ 버튼 클릭

 

 

'DONE'
'Successfully created user'
문구가 떴다면 성공적으로 Base 설정 완료

 

 

step5

설정을 모두 완료하고 마지막 단계 Step 5로 넘어가면 로그인 창 생성

Step 3에서 설정한 계정

Login : base_admin

Password : 비밀번호

입력하면 위에 화면이 뜨면 로그인 성공


Snort.conf 파일 설정

 

 

 

불필요한 라인 주석 처리

IDS 모드에서 사용하지 않는 라인을 주석 처리하였다.

rules 파일 작성

C:\snort\rules 경로에 사용 규칙 파일을 생성하였다.

MySQL 연계 설정

 

C:\Snort\etc\ 경로에서 snort.conf 파일을 Notepad++을 통해 열어준다.

 

변수 설정 변경

ipvar와 portvar를 모두 var로 변경하였다.

var: JavaScript 언어에서 ‘변수’ 설정의 역할 (C언어의 int와 비슷한 역할)

ipvar: IP 주소 또는 IP 주소의 목록/범위를 나타내는 목적으로 사용

portvar: 포트 번호 또는 포트 번호의 목록/범위를 나타내는 목적으로 사용

 

경로 수정

리눅스 초기 경로를 윈도우 경로인 C:\snort\ 경로로 변경하였다.

 

 

247, 250, 253번 라인의 경로도 초기 경로 설정값을 윈도우 경로로 변경 후, C:\snort\lib 경로에 접속해보면 dynamicpreprocessor파일과 dynamicengine 파일은 있지만 dynamicrulese 파일은 없기 때문에 이 파일을 직접 생성

 

265 ~ 269번 라인은 Snort IDS 모드에서는 사용할 수 없기 때문에
맨 앞에 # 을 입력해 주석 처리

 

510, 511번 라인 또한 윈도우 형식으로 변경 ( / → \ ) 후,


cmd를 통해 C:\snort\rules 경로에 해당 이름의 rules 파일 생성

 

 

MySQL연계설정

533, 534번 라인을 참고하여
output database: alert, mysql, user=root password=(비밀번호) dbname=snort host=localhost
output database: log, mysql, user=root password=(비밀번호) dbname=snort host=localhost
위 문장을 535, 536번에 이어서 작성

 

541, 542번 라인도 초기 경로 설정값을 윈도우 경로로 변경
(C:\snort\etc)

553번 라인에 사용할 rules 파일 입력 후, C:\Snort\rules 경로에 사용하고자 하는 rules 파일 생성

 

그 밑의 라인은 사용하지 않을 예정이므로 모두 주석 처리

 

 

sc.rules


Snort IDS 테스트

Snort.conf 검증

 

사용할 rules파일인 sc.rules파일을 열어 테스트 룰을 입력한다.

alert icmp any any -> any any (msg:"ICMP_TEST"; sid:10000001;)

 

이 Snort 규칙은 ICMP 프로토콜을 사용하는 모든 트래픽을 탐지하는 역할을 한다.

출발지와 목적지 IP 및 포트에 제한을 두지 않으며, 탐지된 패킷에 "ICMP_TEST"라는 메시지를 출력하고 고유 식별 번호(sid)로 10000001을 사용한다.

이 규칙은 주로 Ping 요청/응답 같은 ICMP 트래픽을 모니터링할 때 활용된다.

 

 

파일 위치로 이동 -> cd C:\Snort\bin

NIC 번호 확인 명령어를 입력 -> snort.exe –W

NIC 번호는 **네트워크 인터페이스 카드(Network Interface Card)**를 식별하는 번호이다.
한 시스템에 여러 네트워크 인터페이스가 있을 경우 Snort와 같은 도구가 모니터링할 네트워크 인터페이스를 지정하기 위해 사용한다.

 

snort.exe -T -c c:\snort\etc\snort.conf -l c:\snort\log -i 1
: Snort.conf 파일 검증 테스트 진행

‘Snort successfully validated the configuration!’
문구가 확인되면 설정이 잘 진행되었다는 의미

 

‘snort.exe -c c:\snort\etc\snort.conf -l c:\snort\log -i 1’
명령어로 Snort 실행한 화

(-c : snort 설정 파일 위치 지정)
(-l : 로그 파일 저장 위치 지정)
(-i : 모니터링할 NIC 번호 지정)
(NIC : 네트워크 인터페이스 카드)

 

‘Commencing Packet Processing (pid = )’ 문구를 보아 Snort가 정상적으로 실행 완료된 것을 확인

 

 

Server 가상환경의 IP주소를 확인하고, Client(Victim) 가상환경에서 Server 환경으로 ping을 보내 정상적으로 수신하는지 확인

 

 


http://localhost/base 도메인에 접속하면 전 슬라이드에서 보낸 Ping 패킷이 대한 로그가 ICMP 프로토콜 형태로 탐지된 것을 확인할 수 있음.

 

 

이렇게 Snort 환경 설정 완료.

 

 

참고 자료

https://velog.io/@pingu_9/%EB%B3%B4%EC%95%88%EA%B4%80%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B81#25-base-%EC%84%A4%EC%B9%98

https://maker5587.tistory.com/25

https://velog.io/@secloud/17.-Snort-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%84%B1#xampp-%EC%84%A4%EC%B9%98

 

 

ppt

[19주차]snort 환경 구성.pptx
4.57MB

'Security > 보안관제' 카테고리의 다른 글

악성코드 샘플 분석3(하)  (0) 2025.01.04
악성코드 샘플 분석3(상)  (0) 2024.12.27
SNORT  (2) 2024.11.22
악성코드 샘플 분석2  (0) 2024.11.10
악성코드 샘플 분석  (0) 2024.11.03

Snort에 들어가기 앞서...

IDS/IPS의 기본 지식이 필요하기 때문에 기본 지식이 없다면 아래 글을 보고 오길 추천한다.

 

https://eatitstory.tistory.com/54

 

Firewall, DDoS, IDS 와 IPS 의 특징 및 차이점

DDoS (분산 서비스 거부 공격, Distributed Denial of Service)여러 대의 장비를 이용해 특정 서버나 네트워크에 대량의 트래픽을 보내 서비스 운영을 방해하는 공격이다DDoS 공격의 특징 분산된 공격: DDoS

eatitstory.tistory.com

 

IDS와 IPS의 요약

IDS와 IPS는 네트워크 보안을 지키는 눈(IDS)과 손(IPS)

특징 IDS IPS
주요 기능 공격 탐지 후 경고만 보냄 공격 탐지 후 자동으로 차단
비유 보안 카메라 자동문 잠금 장치
관리자 개입 필요 여부 필요 거의 필요 없음
장점 상세한 모니터링 가능 실시간으로 문제 해결 가능
단점 수동 대처 필요 오탐으로 인한 정상 활동 방해 가능

Snort와 IDS/IPS의 관계

  • Snort는 기본적으로 IDS로 설계되었다. 즉, 네트워크 트래픽을 모니터링하고 문제가 감지되면 관리자에게 경고를 보내는 역할을 한다.
  • 하지만 Snort는 추가 설정을 통해 IPS 기능도 제공할 수 있다. 이 경우, 네트워크 방화벽이나 정책 설정과 연동하여 자동으로 공격을 차단하도록 동작할 수 있다.

 

 


 

 

Snort의 개요

1998년 마틴 로슈(Martin Roesch)에 의해 개발된 Snort는 네트워크 침입 탐지 시스템(IDS, Intrusion Detection System)의 한 형태로, 주로 시그니처 기반 탐지를 수행한다.

1. 탄생 배경

  • 90년대 후반, 웹 사용이 급증하면서 인터넷 환경에서의 보안 위협이 증가.
  • 해커들이 악성 트래픽(DoS 공격, 악성 코드, 취약점 공격 등)을 이용해 시스템을 침해하는 사례가 급격히 늘어남.
  • 네트워크 트래픽 속에서 공격 패턴이나 악성 활동을 탐지하기 위해 IDS가 필요해짐.
  • Snort는 이러한 요구를 해결하기 위해 오픈 소스 기반으로 만들어진 IDS 도구로, 낮은 비용으로 강력한 네트워크 보안 기능을 제공

2. 활용 이유

  • 공격 탐지를 위한 패턴 매칭프로토콜 분석이 가능.
  • 네트워크 트래픽을 실시간으로 모니터링하고, 의심스러운 활동을 관리자에게 알림.
  • 확장성사용자 정의 규칙을 통해 다양한 환경에 적용 가능.

이미지출처:https://miro.medium.com/v2/resize:fit:750/format:webp/1*3LH_UXJZzVHYRCT18gjA1Q.png

 

Snort의 주요 기능

 

  • Sniffer 모드: 실시간 트래픽 모니터링을 통해 네트워크 상태 점검.
  • Packet Logger 모드: 트래픽을 저장해 보안 감사 또는 침입 탐지의 사후 분석 자료로 활용.
  • IDS/IPS 모드: 네트워크에서 발생하는 악의적인 활동(해킹 시도, 악성코드 다운로드 등)을 탐지 및 방지.

 

Snort의 동작 방식

Snort는 트래픽을 캡처하고, 단계별로 분석을 수행하여 의심스러운 활동을 탐지하거나 차단한다.

동작 단계

  1. 스니퍼(Sniffer)
    • 네트워크 인터페이스에서 실시간 트래픽을 캡처.
    • 네트워크 어댑터를 프로미스큐어스 모드로 설정해 모든 트래픽을 수집.
  2. 패킷 디코딩(Packet Decoding)
    • 캡처된 패킷을 **OSI 모델 계층(2~4계층)**에 따라 분해.
    • 출발지/목적지 IP, 포트, 프로토콜 정보를 추출.
  3. 전처리(Preprocessing)
    • 데이터를 정리하고 탐지 우회를 방지하기 위한 처리 수행.
    • 패킷 재조립: 조각난 패킷 복원.
    • 프로토콜 노멀라이제이션: 비정상 데이터를 표준화.
  4. 탐지 엔진(Detection Engine)
    • Snort 규칙(시그니처)과 트래픽을 비교하여 위협 여부 탐지.
    • 탐지된 패킷은 경고를 생성하거나 로그에 기록.
  5. 경고 및 로그(Alert/Log)
    • 탐지 결과를 경고 메시지로 출력하거나 로그 파일로 저장.
    • IPS 모드에서는 트래픽을 차단하거나 연결을 종료.

이미지출처:https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSkTwFUtD__jEWMvn_jVFf-3iSc-hVR0iH5Ocfmp-bhUqG0BruD78NH4fEoGqa3lcBhX0YJYVKmcHAQQ3H_6T-Hk5jXqMnucGGvR8g2I4P1ix0AhlZ6PHLivXm38eWKoFqk7ymewIFXA/d/Screenshot+from+2020-05-14+11-20-47.png

 

 

 

Snort 시그니처(Snort Rules)

Snort 시그니처는 헤더(Header)와 옵션(Options)으로 구성되어 있다.

  • 헤더(Header): 기본적인 탐지 조건(프로토콜, IP, 포트, 트래픽 방향 등)을 정의.
  • 옵션(Options): 상세한 탐지 조건(내용 매칭, 패턴 분석, 경고 메시지 등)을 설정.
이미지출처:https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVdgq3%2FbtqExZvvu1X%2FakKKerf9YqGLLLNlbdLYY1%2Fimg.png

Snort 시그니처 형식

<동작> <프로토콜> <출발지 IP> <출발지 포트> -> <목적지 IP> <목적지 포트> (<옵션>)
<Rule Action> <Protocol> <Source IP> <Source Port> <Direction> <Destination IP> <Destination Port> (<옵션>)
 

 

헤더 구성 요소

헤더 구성 요소 설명 예시
Rule Action 시그니처가 탐지 시 수행할 동작 alert
Protocol 탐지할 네트워크 프로토콜 tcp, udp, icmp
Source IP 트래픽의 소스 IP any, 192.168.1.1
Source Port 트래픽의 소스 포트 any, 80
Direction 탐지 트래픽의 방향 -> (from source to destination)
Destination IP 트래픽의 목적지 IP $HOME_NET, any
Destination Port 트래픽의 목적지 포트 80, 443

 

 

헤더 필드 설명

동작(Action)

  • Snort가 규칙 조건을 만족하는 트래픽을 탐지했을 때 수행할 작업. 
명령어 기능 설명
alert 조건에 맞는 트래픽에 대해 경고 메시지 출력 탐지한 패킷에 대해 경고를 생성하여 설정된 출력 방식으로 전송. (syslog, 콘솔, 파일 등).
log 트래픽 정보를 로그 파일에 기록 탐지된 트래픽을 상세히 기록하여 분석 자료로 활용. (pcap 형식으로 저장 가능).
pass 트래픽을 무시하고 탐지를 수행하지 않음 특정 트래픽을 허용하거나 우선순위에서 제외할 때 사용.
drop 트래픽을 탐지하고 차단 (IPS 모드에서 사용) 탐지된 트래픽을 패킷 차단 후 기록하지 않음.
sdrop 트래픽을 차단하고 상대방에게 응답하지 않음 drop과 유사하지만, 탐지 기록도 생성하지 않아 은밀하게 차단 가능.
reject 트래픽을 차단하고 발신자에게 거부 메시지 전송 drop과 달리 차단 후, 상대방에게 거부 응답 메시지(ICMP/특정 프로토콜)를 전송.

 

 

Protocol (프로토콜)

  • 탐지할 네트워크 트래픽의 프로토콜을 지정.
명령어 기능 설명
tcp TCP 프로토콜 탐지 HTTP, FTP, SSH 등 연결 기반 트래픽 탐지.
udp UDP 프로토콜 탐지 DNS, SNMP, VoIP와 같은 연결 없는 트래픽 탐지.
icmp ICMP 프로토콜 탐지 Ping 요청/응답 및 네트워크 상태 확인 메시지 탐지.
ip 모든 IP 기반 프로토콜 탐지 TCP, UDP, ICMP 등 모든 IP 프로토콜에 대한 트래픽을 탐지.
any 모든 프로토콜 탐지 위의 모든 프로토콜을 포함하여 트래픽을 탐지.

 

방향성(Direction)

  • 트래픽의 방향을 지정.
명령어 기능 설명
-> 출발지 → 목적지 트래픽 탐지 소스에서 목적지로 가는 트래픽만 탐지.
< > 출발지 ↔ 목적지 간의 모든 트래픽 탐지 양방향(출발지와 목적지 모두) 트래픽 탐지.

 

 

 

Source/Destination IP 및 Port

  • 탐지할 트래픽의 출발지/목적지 IP 주소를 설정.
명령어 기능 예시 설명
any 모든 IP 또는 Port를 의미 any 특정 IP나 포트를 지정하지 않을 때 사용.
[ ]
여러 IP 주소를 목록으로 지정 [192.168.1.1,10.0.0.1] 리스트 형태로 IP 주소를 묶어서 정의.
! 부정 연산자로 특정 IP 또는 Port 제외 ![192.168.1.1], !80 제외할 IP 또는 포트를 지정.
포트번호 특정 포트 번호를 지정 80, 443 해당 포트 번호만 탐지.
포트번호1:포트번호2 범위 내의 모든 포트 지정 1000:2000 1000번부터 2000번 포트까지 탐지.
:포트번호 지정된 포트 이하 모든 포트 탐지 :1024 1024번 이하 모든 포트 탐지.
포트번호: 지정된 포트 이상 모든 포트 탐지 1024: 1024번 이상 모든 포트 탐지.
$HOME_NET 내부 네트워크 IP 주소 대체 변수 $HOME_NET Snort 설정에서 정의된 내부 네트워크 범위. (예: 내부망 IP를 지정할 때 사용)
$EXTERNAL_NET 외부 네트워크 IP 주소 대체 변수 $EXTERNAL_NET Snort 설정에서 정의된 외부 네트워크 범위. (예: 외부망 IP를 지정할 때 사용)
$HTTP_SERVERS 웹 서버의 주소 변수 $HTTP_SERVERS Snort 설정 파일에서 정의된 HTTP 서버 네트워크 주소를 사용.
$SSH_SERVERS SSH 프로토콜을 사용하는 장비의  IP 주소 변 $SSH_SERVERS Snort 설정 파일에서 정의된 SSH 서버 네트워크 주소를 사용.

 

옵션 

  • Snort 규칙에서 Rule Option은 탐지 정확도를 높이는 데 중요한 역할을 하는 옵션이다.
  • Rule Option은 일반 옵션, Payload 옵션, HTTP 옵션, 흐름 옵션으로 크게 구분된다.
  • 각 옵션은 특정 조건을 지정하여 보다 정교하게 패킷을 탐지하거나, 탐지된 패킷에 대한 동작을 구체화하는 데 사용된다.
  • 모든 옵션은 세미콜론(;)을 사용해 서로를 구분하고, 규칙 옵션 키워드는 콜론(:)을 사용해 인수(예: content:"GET"; 에서 "GET" 문자)와 구분한다. 

일반 옵션 (General Options)

  • 규칙에 대한 추가 정보를 제공하며, 패킷 매칭에는 영향을 미치지 않는 옵션이다.
명령어 기능 예시
msg Snort 규칙이 탐지될 경우 출력되는 메시지. msg:"악성 트래픽 탐지";
sid Snort 규칙을 구별하는 식별자. 0~1,000,000번까지 예약된 식별자. sid:1000001;
rev 규칙의 수정 버전. 수정할 때마다 1씩 증가. rev:1;
classtype Snort 규칙을 분류하는 옵션. classtype:attempted-recon;
priority 규칙의 우선 순위를 지정. 1~10까지 수치, 값이 작을수록 우선순위 높음. priority:1;
reference 해당 규칙에 참고되는 URL 또는 문서 지정. reference:url,www.example.com;

Payload 옵션 (Payload Options)

  • 패킷의 데이터를 분석하여 악성 패킷을 탐지하는 옵션이다.
명령어 기능 예시
content 패킷 데이터에서 매칭할 문자열을 지정. content:"abc";
=> abc 문자열 탐지
nocase 대소문자를 구분하지 않고 매칭. content:"abc"; nocase;
=> 대소문자 구분없이 abc 탐지
offset 매칭을 시작할 위치 지정 (0 바이트부터 시작). offset:3;
=> 0/1/2/3 총4개 => 4byte부터 탐색 시작
distance 이전 매칭 후 무시해야 할 바이트 수를 지정. content:"abc"; content:"test"; distance:5;
=> abc 문자열 매칭 후 지점을 기준으로 5byte 이후 test 문자열 탐색
within 매칭된 후 검색을 진행할 범위를 지정. content:"abc"; content:"test"; within:5;
=> abc 문자열 매칭 후 지점을 기준으로 5byte 이내 test 문자열 탐색
pcre 정규 표현식을 사용하여 패턴을 매칭. (정규 표현식 기반 패턴 탐지) pcre:"/GET\s+/path/to/file/";
=> "GET" 메소드와 그 뒤에 하나 이상의 공백이 있는 "/path/to/file" 경로를 찾는 규칙.

HTTP 옵션 (HTTP Options)

  • HTTP 프로토콜의 특정 부분에서만 패턴을 매칭할 때 사용하는 옵션이다.
명령어 기능
http_method HTTP 메소드 영역에서 패턴을 매칭
http_uri HTTP URI 영역에서 패턴을 매칭
http_raw_uri 디코딩되지 않은 HTTP URI 영역에서 패턴을 매칭
http_cookie HTTP 쿠키 값을 탐색
http_header HTTP 헤더 영역을 요청/응답 구분 없이 탐색
http_raw_header 디코딩되지 않은 HTTP 헤더를 탐색
http_client_body HTTP 바디 영역을 탐색
http_stat_code HTTP 응답 메시지의 상태 코드 탐색
http_stat_msg HTTP 응답 메시지의 상태 메시지 탐색

흐름 옵션 (Flow Options)

  • 패킷이 흐르는 방향을 지정하여 트래픽의 흐름을 제어하는 옵션다.
명령어 기능 예시
flow 흐름 옵션을 사용할 때 필수로 지정해야 하는 옵션. flow:to_server,established;
to_client 서버에서 클라이언트로 오는 패킷을 탐지 to_client;
from_server 서버에서 클라이언트로 오는 패킷을 탐지 from_server;
to_server 클라이언트에서 서버로 가는 패킷을 탐지 to_server;
from_client 클라이언트에서 서버로 가는 패킷을 탐지 from_client;
established 세션이 이미 성립된 패킷을 탐지 established;
stateless 세션 여부와 관계없이 패킷을 매칭 stateless;

예시 시그니처

alert tcp $EXTERNAL_NET any -> $HOME_NET 80 (msg:"HTTP 공격 탐지"; content:"GET"; nocase; http_uri; offset:3; distance:5; content:"test"; within:5; sid:1000001; flow:to_server,established; rev:1;)

 

각 구성 요소의 설명:

    1. alert
      • 동작 (Action): 조건을 만족하는 트래픽을 탐지하면 경고 메시지를 출력하는 규칙이다.
    2. tcp
      • 프로토콜 (Protocol): TCP 프로토콜을 사용하는 트래픽을 탐지하는 규칙이다.
    3. $EXTERNAL_NET any -> $HOME_NET 80
      • 출발지 IP: $EXTERNAL_NET은 외부 네트워크를 의미하며, any는 모든 출발지 IP를 의미한다.
      • 출발지 포트: any는 모든 포트를 의미한다.
      • 목적지 IP: $HOME_NET은 내부 네트워크를 의미한다.
      • 목적지 포트: 80번 포트는 HTTP 기본 포트를 의미한다.
    4. (msg:"HTTP 공격 탐지";
      • msg: 트래픽이 매칭되면 "HTTP 공격 탐지"라는 메시지를 출력하는 규칙이다.
    5. content:"GET";
      • content: 패킷 데이터에서 "GET"이라는 문자열을 찾는 규칙이다.
    6. nocase;
      • nocase: "GET" 문자열을 대소문자 구분 없이 탐지하는 규칙이다.
    7. http_uri;
      • http_uri: 패킷의 HTTP URI 부분에서 "GET" 문자열을 찾는 규칙이다.
    8. offset:3;
      • offset: 패킷 데이터의 첫 3바이트를 건너뛰고, 4바이트부터 "GET" 문자열을 탐지하는 규칙이다.
    9. distance:5;
      • distance: "GET" 문자열이 매칭된 후, 5바이트를 건너뛰고 "test" 문자열을 탐지하는 규칙이다.
    10. content:"test";
      • content: "GET" 문자열 뒤에 "test"라는 문자열을 찾는 규칙이다.
    11. within:5;
      • within: "GET" 문자열과 "test" 문자열 사이의 거리가 5바이트 이내여야 매칭되는 규칙이다.
    12. sid:1000001;
      • sid (Signature ID): 이 규칙의 고유 식별자 1000001을 의미하며, 규칙을 구별하는 데 사용되는 규칙이다.
    13. flow:to_server,established;
      • flow: 패킷의 흐름을 지정하는 규칙이다.
      • to_server: 클라이언트에서 서버로 가는 트래픽을 탐지하는 규칙이다.
      • established: 이미 세션이 성립된 상태에서 발생하는 트래픽을 탐지하는 규칙이다.
    14. rev:1;)
      • rev: 이 규칙의 버전 1을 의미하며, 최초 버전임을 나타내는 규칙이다.

 

참고자료

https://maker5587.tistory.com/24

 

Snort / Snort Rule Signature ( Snort 개요 / Snort 기능 / Snort Rule )

※ Snort 를 공부하기 앞서 이전 IDS 와 IPS 에 대한 내용을 숙지한 후 보시는걸 추천합니다. https://maker5587.tistory.com/8 Snort 란 ? Snort 는 1998년 Martin Roesch에 의해 개발된 오픈 소스 기반 IDPS ( Intrusion Dete

maker5587.tistory.com

https://medium.com/@acaremrullahkku/what-is-snort-547916bece5f

 

What is Snort?

Synopsis

medium.com

https://www.youtube.com/watch?v=QzYerZ7hDrM

https://net123.tistory.com/579

 

Snort - 03. Snort Rule 구조

Snort - 03. Snort Rule 구조 1. Snort Rule Signiture - 스노트는 다음과 같은 룰 헤더와 옵션으로 구성된다. Snort 룰 시그니처 구조 Action 유형 명령어 내용 alert 경고 발생 및 로그 기록 log 로그 기록 pass 패켓

net123.tistory.com

 

 

ppt

[18주차]snort.pptx
1.95MB

'Security > 보안관제' 카테고리의 다른 글

악성코드 샘플 분석3(상)  (0) 2024.12.27
Snort 환경 구성  (1) 2024.12.01
악성코드 샘플 분석2  (0) 2024.11.10
악성코드 샘플 분석  (0) 2024.11.03
정적, 동적 Tool 실습  (4) 2024.10.26

샘플파일

이번에 분석해 볼 파일은 dgrep.exe

 

기초 분석

 

Virustotal

-Virustotal에서 스캔을 해보았다.
-72개의 엔징 중 68개의 엔진이 해당 파일을 악성 파일로 추정된다.
-각 엔진들을 봐보면 Backdoor, Trojan, Win32. worm, Malicious 등 진단명이 보인다.
-Threat categories를 보면 trojan이 보인다.
-해당 파일은 win32에서 구동될 것으로 보인다.

-디테일탭을 들어오면 더 자세히 알 수 있다.
-먼저 해시값을 확인할 수 있다
-packer에 대한 정보도 알 수 있는데 SVK-Protector v1.11과 UPX라는 패킹 툴을 이용하여 패킹이 되었음을 추정 가능하다.
-그리고 파일이 언제 만들어졌는지 또한 확인 가능하다.

-relations탭에서는 분석하려는 파일과 관련된 ip와 url 정보를 확인할 수 있다.
-해당 파일은 107.163.241.198 라는 IP 및 api.wisemansupport.com 이라는 URL과 연관이 있을 것으로 의심이 된다
 

정적 분석

패킹되어 있는 파일을 언패킹 하여 내부를 들여다 볼거다.

-우선 분석이 들어가기 앞서 윈도우의 실시간 보호를 꺼줘야 한다.
-설정이 되어 있다면 악성코드를 압축 해제 시 자동적으로 삭제가 되거나 실행이 안된다.
 
Exeinfo PE
 

-dgrep.exe를 검사해 본 결과 EP section은 .mmmym으로 일반적이지 않은 이름으로 난독화 또는 수동으로 조작이 되었다.
-UPX라는 패킹 툴로 압축되었을 확률이 높다.
 
PE explorer

-패킹을 언패킹 하기 위해 PE explorer를 사용해 줬다.
-(보통은 언패킹을 수동으로 하는 경우와 패킹 툴을 사용하는 경우로 나눠지는데 수동은 아직 내 수준으로는 힘들기에 툴을 사용했다.)
-(Exeinfo pe에서는 RL!Depacker v 1.15 를 사용하라고 권장하지만 구글링을 해도 나오지 않고 gunpacker나 De4dot를 사용한 글들을 보기도 했지만 이 또한 구글링을 해도 나오지 않는 사고가...쩔 수 없이 PE explorer는 30일 무료 버전이 있길래 사용해 줬다.)

 

-언패킹을 한 파일을 dgrep123.exe로 만들어 다시 검사를 돌려줬다.
-C++로 만든 프로그램이라는 걸 알 수 있다
-not packed가 나온 걸 보면 언패킹이 되었단 걸 알 수 있다.
 



+추가로 언패킹하고 난 후 언패킹한 파일이 패킹한 파일보다 데이터 크기가 컸다.
 
 
Bintext

-문자열이 보이는 걸 보니 언패킹이 되었단 걸 다시 한번 확인 가능했다.
-문자열 중에 cmd.exe를 이용하여 ping 127.0.01-n2명령어를 사용하는 것 같은 문자열이 보인다.
-그리고 wiseman.exe를 설치하여 실행하기 위한 문자열로 보이는 문자열도 보인다.
-C:\Windows\System32\rundll32.exe 해당 경로의 파일을 실행하기 위한 문자열로 의심되는 문자열을 확인했다.
-RedTom21@HotMail.com 이라는 메일주소를 확인하였는데 악성 파일과 관련되어 보인다.
 
 

-저번 주에서도 말했지만 악성코드에 자주 사용된다는 dll파일도 문자열에서 보이는 걸 확인했다.
-라이브러리 중 WS_32.dll의 경우 네트워크 행위를 할 때 사용되는 라이브러리이기에 해당 파일은 네트워크 행위를 할 가능성이 높다.
 
PEview

-4D 5A (MZ) 시그니처를 확인했기에 이 파일은 exe파일임을 알 수 있다.
 

-IMAGE_FILE_HEADER 탭의 Time Date Stamp 를 활용해 파일 생성 날짜가 2015.10.09 라는 것도 알 수 있다.

-세션 헤더 탭을 들어가 해당 파일의 패킹 여부를 확인할 수 있었다.
-해당 세션 이름은 .text로 일반적인 세션 이름으로 패킹이 되었단 걸 알 수 있다.
-해당 파일은 언패킹을 진행한 파일이지만 Virtual Size 와 Size of Raw Data 의 값의 차이를 보인다.
-그러나 데이터 차이가 수백이상이 아닌 27정도만 차이가 나고 bintext에서도 확인했듯이 문자열 확인이 가능하기에 완전하지는 못해도 분석하는 데에 무리 없이 언패킹이 되었다는 걸 알 수 있다. 

-bintext에서 봤던 dll 라이브러리들이 보인다.

 

 

동적분석

이제부터는 실제 패킹되어 있는 파일을 실행을 해본다.
 
Process Explorer

-drep.exe를 실행한 후 모습을 캡처를 해보았다.
-drep.exe 실행 후 cmd.exe, conhost.exe, PING.EXE가 프로세스 목록에 생성되는 걸 볼 수 있었다.
 

-또한 cmd.exe에서 gzoyo.exe(실행할 때 마다 이름이 다른 파일)을 생성하고 rundll32.exe을 실행한다.

-이후 rundll32.exe와 taskkill.exe가 실행이 되었다가 gzoyo.exe파일과  taskkill.exe 는 사라지고 rundll32.exe만 계속해서 실행 상태인 것을 알 수 있다.
 
 
Process Monitor

tree로 본 악성코드 프로세스 순서

 

1. dgrep.exe
악성코드 실행

2.cmd.exe
추가적인 명령어 실행

3.conhost.exe. ping.exe, rddbo.exe 병렬실행

-conhost.exe: 악성 프로세스 숨기는데 사용
-ping.exe네트워크 연결 테스트 및 원격 서버와 통신 시도
-rddbo.exe: 실행 때마다 이름이 바뀌며 악성 프로세스 실행하거나 제어

4.rddbo.exe -> rundll32.exe실행
rundll32.exe를 호출하여 악성 DLL 파일을 실행하거나 시스템에 백도어를 설정하려 시도

5.rundll32.exe -> taskkill.exe 실행
프로세스를 종료하려고 시도

6.taskkill.exe -> conhost.exe 실행
악성코드가 계속해서 제어를 유지하려는 시도로, 자신을 재활성화하려는 목적

taskkill.exe로 모든 파일들이 종료되었지만 rundll32.exe만 계속 실행중인 이유는 자기보호 메커니즘을 가지고 있어서
taskkill.exe -> conhost.exe 실행은 악성코드가 계속해서 지속적인 제어를 유지하려는 의도로 추정된다.

 

-dgrep.exe 프로세스 이름만 필터를 거쳐 분석을 진행해보았다.
-explorer에서 확인했듯이 이름 모를 파일이 생성되는 걸 볼 수 있었다.(실행마다 이름이 바뀐다. ex :rddbo.exe )
 

-cmd.exe프로세스가 ping명령어 사용을 위해 ping.exe파일을 실행하는 모습을 확인이 가능하다.
-악성 경유지와 통신하기 위해 사전에 네트워크 체크하는 과정으로 추정이 된다.
 

*근데 정적분석에서 발견한 wiseman.exe는 왜 실행이 안되는걸까?
-악성코드는 시간에 따라서 특성이 변한다.
-네트워크 행위를 하다가 하지 않을 수도 있다.
-그렇기에 현재 네트워크 행위를 하지않아 해당 파일을 다운받아오지 못한 걸로 보면 될 거 같다.


Autorns

-dgrep.exe 파일 실행 전과 후 레지스트리 변화를 확인할 수 있다.
-EvtMgr파일이 부팅 후 자동으로 실행되는 프로그램에 등록된 것을 확인할 수 있다.
-파일에 등록된 레지스트리 주소는 윈도우를 재시작했을 때 자동으로 시작되게끔 하는 영역이다.
-대부분의 악성 코드들이 등록하는 영역(재부팅 시 악성코드가 다시 실행되도록 하기 위함이다.)
 
Currports

-네트워크 상태를 확인하기 위해 새로운 툴을 사용해 보았다.
-기초분석에 확인했던 IP주소와 연관되어 있는 IP주소 확인을 했다.(rundell32.exe파일의 remote address에 바이러스 토탈에서 확인했던 107.163.241.198가 있다. )

-상태 창을 보면 전송됨 이라는 상태 즉 SYN_SENT 상태가 보이지만 해당 상태에서 변함이 없는 것을 보았을 때 최종 세션 성립에는 실패하는 것으로 보여진다.


WireShark

-앞에서 기초분석과 currports에서 수집했던 연관 있는 ip를 검색해 보았다. (107.163.241.197, 107.163.241.198)
 

-특정 IP(107.163.241.197, 107.163.241.198)에 syn플래그를 전송하는 게 보인다
 

-해당 IP에서 RST 패킷으로 답신이 보인다.(RST: 연결 확립된 회선에 강제 리셋 요청)
->연결에 실패한 것으로 추정된다.

 

결론

 
기초 분석

  • VirusTotal 검사에서 68개의 엔진이 dgrep.exe 파일을 악성으로 추정된다.
  • 파일은 Win32 환경에서 실행되며 SVK-Protector v1.11과 UPX 패킹 툴이 사용된 것으로 추정된다.
  • 특정 IP 107.163.241.198과 URL api.wisemansupport.com과의 연관이 의심된다.

정적 분석

  • Exeinfo PE로 파일의 EP 섹션이 .mmmym으로 설정된 비정상적 섹션 이름을 확인하였고, UPX 패킹 가능성을 파악하였다.
  • PE Explorer를 통해 언패킹 후 C++로 작성된 프로그램임을 확인하였다.
  • Bintext에서 cmd.exe의 ping 명령어, wiseman.exe 실행 문자열, WS_32.dll 네트워크 라이브러리를 확인하였다.

동적 분석

  • Process Explorer에서 dgrep.exe 실행 시 cmd.exe, PING.EXE 등 프로세스가 생성되는 것을 관찰하였다.
  • Process Monitor에서 ping 명령어 수행과 익명 파일 생성이 확인되었다.
  • Cports와 Wireshark로 악성 IP 107.163.241.198와의 통신 시도 및 연결 실패를 확인하였다.

결론

  • dgrep.exe는 백도어 및 트로이 목마 유형의 악성코드로, 특정 IP와의 통신 시도를 지속하는 악성 파일로 보인다.
  • 패킹이 되어 있었으나 언패킹을 통해 분석이 가능했으며, 네트워크 기반 악성 행위가 확인되었다.
  • 통신 시도에 응답이 없어 현재는 작동하지 않지만, IP나 URL이 복구되면 재작동할 가능성이 있다.

 

 

참고 자료

https://itcase.tistory.com/entry/15-%EC%95%85%EC%84%B1%EC%BD%94%EB%93%9C-%EC%83%98%ED%94%8C-%EB%B6%84%EC%84%9D-2-%EC%83%81

 

https://vkdnj2040.tistory.com/14

 

https://maker5587.tistory.com/23#RL!dePacker%20%C2%A0-%3E%20%EC%96%B8%ED%8C%A8%ED%82%B9%20%ED%88%B4-1

 

 

 

ppt

[16주차]악성코드 샘플 분석(2).pptx
5.18MB

 

 

 

 

 

보고서

https://eatitstory.tistory.com/77

 

[리팩토링] 보안 프로젝트 1 (악성코드 분석 보고서)

https://eatitstory.tistory.com/69 악성코드 샘플 분석2샘플파일이번에 분석해 볼 파일은 dgrep.exe 기초 분석 Virustotal-Virustotal에서 스캔을 해보았다.-72개의 엔징 중 68개의 엔진이 해당 파일을 악성 파일

eatitstory.tistory.com

 

'Security > 보안관제' 카테고리의 다른 글

Snort 환경 구성  (1) 2024.12.01
SNORT  (2) 2024.11.22
악성코드 샘플 분석  (0) 2024.11.03
정적, 동적 Tool 실습  (4) 2024.10.26
샘플 분석 환경 구성  (4) 2024.10.12

준비

"bton02setu.exe" 샘플 파일을 다운 받아 분석해 볼 것이다.
 
*주의 절대 로컬 환경이 아닌 vmware에서만 실행하자!
 
 

기초분석

 
Virustotal
 

-검사 결과 73개의 백신 중 52개의 백신이 해당 파일을 악성파일로 진단하였다.
 
-검사결과 Treat categories를 보면 trojan, adware, downloader가 대표적인 진단 카테고리로 보여준다.
 
 

-디테일 탭에서 해당 파일의 자세한 정보를 확인해 볼 수 있는데
-파일의 고유한 해시값을 참고하고자 할 때는 MD5, SHA-256 두 가지를 살펴본다.
-win32 EXE을 보면 해당 파일이 win32 환경에서 구동되며
-C++로 제작되었다는 정보를 확인 가능
 
 

정적분석

 
Exeinfo PE

-정적분석 진행할 때, 가장 먼저 확인해야 하는 부분이 해당 파일의 패킹 여부
-Exeinfo PE를 통해 정보를 보면, c++로 제작 되었다는 정보를 알 수 있고
-Not packed를 보아 이 파일은 패킹이 되어있지 않아 언패킹 도구의 도움 없이 내부 문자열을 평문으로 확인 가능하다.
 
Bintext

-중점적으로 봐야하는 항목 중 함수 또는 명령어에 해당하는 문자열을 확인
-문자열에 URL주소가 보이는데 URL주소는 해당 파일이 네트워크와 관련된 작업을 수행하거나 원격 서버와 통신하고 다우로드를 시도할 수 있음을 의미한다.
-나중에 동적분석 과정에서 네트워크 쪽 행위를 확인하면서 위에 URL주소 및 실행 파일 참고할 수 있다.
-Reapea와 del 문자열은 삭제 및 반복의 행위도 할 수 있다고 추정 가능
 

-악성코드에 자주 사용되는 dll 파일도 보인다.
-WSOCK32, NETAPI32 같은 네트워크 관련 작업이 가능한 dll 파일들이 확인 가능하다.
 
PEview

-pFile 의 4D 5A와  value의 MZ를 보면 exe파일이라는 걸 알 수 있다.
 

-Virtual Size와 Size of Raw Data 간의 크기 차이가 크지 않아 해당 파일은 패킹이 되지 않은 것으로 보인다.

-Bintext에서 확인했던 dll 파일들을 확인 가능하다.
 

 

동적분석

 
동적분석 부터는 악성코드 파일을 실행하고 그 결과를 확인해야 한다.
 
Process Explorer

-파일 실행 후 Process Explorer를 확인해본 결과, 프로세스가 생성되었다가 실행한 파일이 사라지고 프로세스도 사라졌다.
-트로이목마 성격을 확인 가능했다.
 
* 트로이목마 악성코드 중에는 실행 파일이 스스로 삭제되거나 특정 조건에서 일시적으로 존재했다가 사라지는 경우가 있다. 이러한 기능은 주로 악성코드 탐지를 피하기 위해 설계된 것으로, 악성 행위를 수행한 후 자신의 흔적을 지우거나 숨기려는 목적을 가지고 있다. 이를 파일리스(Fileless) 악성코드자체 삭제(Self-Deleting) 트로이목마라고도 한다.
 
 
 Process Moniter

-악성코드 실행 후 화면이다.
 
 

-해당 bton02Setup.exe 파일이 cmd.exe 파일을 실행하는 모습을 확인할 수 있다.
-cmd.exe 파일을 실행한 것을 확인하고 cmd.exe 가 무슨 일을 하는 것인지 확인을 위해 cmd.exe 프로세스를 필터링 해서 확인해본다.
 

-operation에서 regquery.vlaue의 결과값이 name not found라고 떴기 악성코드가 요청한 레지스트리 키나 값이 존재하지 않음을 의미한다.
-악성코드의 행위가 단순히 실패한 것이므로, 추가적인 탐색과 분석이 필요하다.
 
Autoruns

-파일 실행 전과 후의 레지스트리 쪽의 변화를 확인해보기 위해, 스냅샷을 저장하고 비교해 보았지만 차이는 없었다.
 
WireShark

-실행 후 50초 쯤이 되니까 갑자기 네트워크 움직임이 보이기 시작했다.
 

 
-통신 중 TCP 연결을 위한 3-Way Handshake 및 FIN 플래그를 통한 연결 종료가 이루어지고 있음을 알 수 있다. 
-악성코드가 HTTP를 통한 POST 요청을 사용하고 있다.
-이를 통해 네트워크를 사용하는 악성코드임을 알 수 있다.
 

결론

-"bton02setup.exe"는 트로이목마 성격의 악성코드로, 네트워크를 통해 원격 서버와 통신하고 정보를 전송하려고 시도하는 것으로 보인다.
-일부 행위가 실패했지만, 악성코드의 전반적인 동작 방식을 이해하기 위한 추가 분석이 필요하다.
-이 악성코드는 탐지를 피하기 위해 스스로 삭제하는 기능이 있으며, 향후 추가적인 행동을 감시하는 것이 중요하다.
-시스템의 보안을 강화하고, 의심스러운 파일 및 네트워크 활동에 대해 지속적으로 모니터링하는 것이 필요하다.

참고

14. 악성코드 샘플 분석(1)
악성코드샘플분석 1차

 

ppt

[15주차]악성코드 샘플 분석.pptx
4.50MB

'Security > 보안관제' 카테고리의 다른 글

SNORT  (2) 2024.11.22
악성코드 샘플 분석2  (0) 2024.11.10
정적, 동적 Tool 실습  (4) 2024.10.26
샘플 분석 환경 구성  (4) 2024.10.12
악성코드 정적, 동적분석  (0) 2024.09.27

 

악성코드 샘플 수집

 

"MalwareBazaar" 사이트에서 악성코드 샘플을 하나 수집해왔다.

 

 

database 창으로 들어와 가져오고 싶은 악성코드를 다운 받아오면 된다.

 

위 사진은 악성코드에 어떤 위험이 있는지에 관한 정보 창

 

 

다운을 받으면 압축해제가 암호가 걸려 있어 해제가 되지 않는 경우가 있을거다.

이를 위해 7-7zip를 다운 받아 압축해제를 해준다.

그러면 세팅완료!

 

정적분석 Tool

Exeinfo(패킹여부 확인)

아직 자세히는 몰라 윗줄과 아랫줄이 무엇인지 gpt에 물어본 결과

 

윗줄

-현재 파일은 AutoIt으로 작성된 프로그램이거나 AutoIt으로 생성된 실행 파일이며, 추가적인 데이터(Overlay)가 포함되어 있지만, 악성코드는 감지되지 않았습니다.

 

아랫줄

-이 메시지는 해당 실행 파일이 AutoIt 스크립트로 작성된 파일이며, 코드의 크기가 크고 분석이 필요하다는 것을 알리고 있습니다. 디컴파일러를 사용하여 실행 파일을 AutoIt 스크립트로 변환하면, 내부 코드를 자세히 분석할 수 있으므로, 이 과정을 추천하는 것입니다.

디컴파일을 통해 코드의 구조와 동작을 파악하고, 필요한 경우 이를 수정하거나 분석하여 악성 코드 여부를 확인하는 것이 좋습니다.

Bin Text (문자열 확인)

문자열들을 해석하여 악성코드 파일인지 확인 가능하다

오른쪽 밑에 Save 버튼을 누르면 현재 bintext에 나와있는 형식을 텍스트 파일로 저장 가능하다

저장한 텍스트 파일 내부

 

동적분석 Tool

process Explorer(프로세스)

녹색 : 프로세스 실행

빨간색 : 프로세스 종료

분홍색 : 서비스 프로세스

파란색 : 사용자 프로세스

보라색 : 패킹 이미지 파일

무색 : 시스템 영역 프로세스

 

Set Priority : 프로세스에 대한 기본 스케줄링, 우선순위 확인 및 설정

Kill Process : 프로세스 강제 종료

Kill Process Tree : 프로세스의 자식 프로세스까지 종료

Restart : 프로세스 재시작

Suspend : 프로세스 일시정지

Create Dump : 현재 메모리를 선택해서 덤프파일을 만든다

Check Virus Total : 바이러스 토탈에 따로 접속하지 않고 몇 개의 엔진에서 검출이 되는지 실시간으로 파악 가능

 

 

악성코드를 실행시켜 Process Explorer로 관찰

악성코드 실행시 프로세스가 실행되고 바로 사라진다.

 

Autoruns(파일 및 레지스토리)

Autoruns 는 윈도우가 부팅 후 자동으로 시작되는 서비스 또는 프로그램을 모니터링 할 수 있는 툴이다.

 

 

1.악성코드 실행 전 Autoruns 상태를 저장
2.악성코드 실행 후 새로고침(F5)
3.File -> compare로 비교

어떤 프로그램이 실행되었는지와, 어떤 레지스트리가 등록되는지 확인 할 수 있다.

 

Wireshark(네트워크)

오고가는 패킷을 실시간으로 잡아내는 것을 확인 가능하다

 

 

 No. : 패킷을 수집한 순서

Time : 패킷이 수집된 시간

Source : 패킷을 보낸 주소

Destination : 패킷 도착 주소

Protocol : 프로토콜 정보

Length : 패킷의 길이

Info : 패킷 정보

 

 

위에 상단바에 보면 "Apply a display filter" 라고 쓰여있는 공간이 있다. (위 그림에서 ip라고 적힌 부분)

이 곳에다가 원하는 필터링 식을 적용하거나, 상단 메뉴에 Analyze > Display Filters... 에 들어가서 적용할 수 있다

ip만 쳐도 사용할 수 있는 필터의 예시를 보여준다.

  • eth.addr//출발지나 목적지 MAC 주소로 검색
  • ip.addr// 출발지나 목적지 IP주소로 검색
  • tcp.port// TCP 출발지나 목적지 포트 번호로 검색
  • ip.src !=// 출발지 IP주소가 해당 IP주소가 아닌것 검색
  • eth.dst// 목적지 MAC주소 검색

 

참고 블로그

정적, 동적 Tool 실습

12. 정적, 동적 Tool 실습

 

 

ppt

[14주차]정적, 동적 Tool 실습.pptx
4.25MB

'Security > 보안관제' 카테고리의 다른 글

악성코드 샘플 분석2  (0) 2024.11.10
악성코드 샘플 분석  (0) 2024.11.03
샘플 분석 환경 구성  (4) 2024.10.12
악성코드 정적, 동적분석  (0) 2024.09.27
Virustotal  (0) 2024.09.19

+ Recent posts