이 글은 아래의 책을 읽고 공부 목적으로 작성됨.
몬나파 K A, 「악성코드 분석 시작하기」
디버깅 : 악성코드를 통제된 방식으로 실행하는 기술.
디버깅 도구(디버거) : IDA, x64dbg, dnSpy
1) 프로세스 실행과 연결
디버깅은 디버그할 프로그램을 선택하는 것에서 시작, 디버거 시작 시 원본 바이너리는 디버거를 실행하는 유저의 권한으로 실행됨. 프로세스를 실행하면 실행은 프로그램의 엔트리 포인트에서 멈춤.
*엔트리 포인트(entry point) : 실행할 첫 번째 명령어의 주소.
디버깅 방법 | 디버거를 실행 중인 프로그램에 연결 | 새로운 프로세스를 실행 |
초기 동작 제어 및 모니터링 | X | O |
2) 프로세스 실행 제어
디버거는 프로세스 실행 중, 프로세스의 행위를 제어/수정하는 기능을 가짐. 두 가지 중요한 기능은 실행을 제어하는 기능과 브레이크포인트를 사용해 실행을 중단하는 기능이다.
*브레이크포인트(breakpoint) : 프로그램의 특정한 위치에서 프로그램의 실행을 중지.
디버거가 제공하는 일반적인 실행 제어 옵션
- continue(Run) : 브레이크포인트에 도달하거나 예외 발생 전까지 모든 명령어를 실행. 일반적으로 브레이크포인트와 이 옵션을 함께 사용.
- step into / step over : 단일 명령어를 실행할 수 있음. 프로세스 리소스를 검사할 수 있도록 디버거가 멈춤.
차이점 - 함수 호출 시 발생. step into는 함수에서 주소가 멈춤, step over는 함수 전체 실행 후 함수 호출 다음 명령어에서 멈춤. -> step into는 일반적으로 사용, step over은 해당 함수가 무엇을 하는지 알고 있거나 건너뛸 때 사용. - execute till return(run until return) : 현재 함수에 속한 모든 명령어 실행. 실수로 step into하거나 함수를 빠져나오고 싶을 때 유용. 함수 내부에서 사용 시 해당 함수의 끝(ret, retn)으로 이동, step into나 step over로 호출한 함수에 복구 가능.
- run to cursor(run until selection) : 현재 커서 위치 또는 선택한 명령어에 도달할 때까지 명령어 실행.
디버거가 제공하는 다른 유형의 브레이크포인트
- 소프트웨어 브레이크포인트(software breakpoint) : 브레이크포인트 주소에 있는 명령어를 소프트웨어 브레이크포인트 명령어를 교체하는 방식으로 구현, 디버거가 기본적으로 사용.
이점 - 브레이크포인트의 개수가 무한. / 단점 - 악성코드가 브레이크포인트 명령어를 찾은 후, 수정해 연결된 디버거가 일반 동작을 하도록 바꿀 수 있음. - 하드웨어 브레이크포인트(hardware breakpoint) : CPU의 디버그 레지스터를 사용해 브레이크 포인트를 설정할 수 있음. DR0-DR3을 사용해 최대 4개의 하드웨어 브레이크포인트 설정, 그외의 디버그 레지스터는 추가적인 조건 지정 시 사용. 명령어를 교체X CPU가 디버그 레지스터에 포함된 값에 기반해 프로그램 중단 여부 결정.
- 메모리 브레이크포인트(memory breakpoint) : 실행 대신 명령어가 메모리에 접근할 때 실행 중단. 특정 메모리에 접근하는 시점과 어떤 명령어가 접근하는지를 알고자 할 때 유용.
- 조건 브레이크포인트(conditional breakpoint) : 브레이크포인터를 발동시킬 때 반드시 충족해야 하는 조건 지정 가능. 명령어X CPU 기능X 디버거에서 제공하는 기능O, 소프트웨어 하드웨어 조건 모두 지정 가능.
3) 프로그램 실행 추적
트레이싱(tracing) : 프로세스가 실행하는 동안 특정 이벤트를 기록하는 디버깅 기능. 바이너리에 대한 상세 실행 정보 제공.
x64dbg
- 실행 파일 로드 : 파일(File) > 열기(Open)
- 일시 중지 - 브레이크포인트, TLS 콜백, 엔트리 포인트 함수 설정 : 옵션(Options) > 설정(Preferences) > 이벤트(Events)로 Settings 대화창 접근.
단 엔트리포인트에서 직접 실행을 일시 중지 하려는 경우, System Breakpoint와 TLS Callbacks 옵션을 비활성화. - 실행 중인 프로세스 연결 : 파일(File) > 연결(Attach) / 단축키 Alt+A -> 디버그하려는 프로세스 선택, Attach 버튼.
디버그가 연결되면 프로세스 일시 중지됨. 브레이크포인트 설정하고 프로세스 자원 살펴볼 수 있음.
+) 연결한 프로세스 종료하지 않은 경우, 파일(File) > 분리(Detach) / 단축키 Ctrl+Alt+F2로 프로세스 분리 가능.
인터페이스 : 각 탭은 다양한 창을 표시하며, 디버깅 바이너리에 따라 다른 정보를 포함.
- 디스어셈블리 창(CPU 윈도우) : 디버깅하는 프로그램의 모든 명령어의 디스어셈블리를 보여줌. 선형 방식으로 디스어셈블리 표시, 명령어 포인터 레지스터(eip 또는 rip)의 현재 값과 동기화.
창의 왼쪽 부분 - 비선형 흐름(분기, 반복)을 나타내는 화살표 표시.
G 단축키 - 제어 흐름 그래프 표시 가능.
파란 화살표 : 무조건 점프 / 윗방향 파란 화살표 : 반복
조건 점프에서 초록 화살표 : 참이면 점프가 수행됨을 나타냄. / 빨간 화살표 : 점프가 일어나지 않음. - 레지스터 창 : CPU 레지스터의 현재 상태를 표시.
레지스터의 값 - 레지스터 더블클릭으로 수정하거나 새로운 값 입력 가능.
플래그 비트 값 - 더블클릭해 플래그 비트를 on 또는 off 할 수 있음.
명령어 포인터 - 수정 불가능.
레지스터 값은 변할 수 있음. -> 레지스터 값 빨간색으로 강조, 이는 마지막 명령어 이후의 변화를 나타냄 - 스택 창 : 프로세스 런타임 스택의 데이터 콘텐츠를 표시. 함수 호출 전 스택을 검사해 함수에 전달되는 인수 유형과 개수를 파악.
- 덤프 창 : 메모리의 표준 헥사 덤프를 표시. 프로세스의 유효한 메모리 주소의 내용 검사 가능.
예시) 스택 위치, 레지스터, 명령어 등에 유효한 메모리 위치가 포함된 경우. -> 해당 주소 우클릭, 덤프(Dump) 옵션에 있는 Follow 선택. - 메모리 맵 창 : 프로세스 메모리의 레이아웃 제공, 프로세스에서 할당한 메모리 세그먼트의 상세 정보 제공. 더블클릭하면 관련 화면 메모리의 위치로 재배치 가능.
실행 파일 위치, 해당 섹션이 로드된 위치를 확인하기 좋음. 프로세스 DLL과 메모리에서의 섹션 정보 포함. - 심벌 창 : 왼쪽 패널 - 로드한 모듈 목록(실행 파일과 DLL) / 오른쪽 패널 - 임포트와 익스포트 함수 표시.
임포트와 익스포트 함수가 메모리에 상주하는 위치 파악 시 유용. - 참조 창 : API 호출에 대한 참조 표시, 그러나 기본적으로 표시하지 않음. -> 디스어셈블리 창 아무 곳이나 우클릭 > 탐색(Search for) > 현재 모듈(Current Module) > 모듈 간 호출(Intermodular calls)
API를 호출한다는 사실을 알려줄 때, 그 항목을 더블클릭하면 관련된 주소로 이동. 이를 이용해 브레이크포인트를 설정할 수 있음. -> 브레이크포인트에 도달하면 매개변수 조사 가능. - 핸들 창 : 열려 있는 모든 핸들의 상세 내용 표시. 내용을 표시하기 위해 핸들 창에서 우클릭 > Refresh(또는 F5).
*핸들 - 프로세스가 객체에 대해 핸들을 열 수 있음. 이 핸들은 WriteFile과 같은 함수에 전달돼 하위 작업을 수행함. -> API 호출이 어떠한 핸들 값을 갖는다 파악, 핸들창 조사로 관련 사항 파악 가능. - 스레드 창 : 현재 프로세스의 목록 표시. 이 창에서 우클릭으로 스레드를 중지 or 중지된 스레드 재개 가능.
프로세스 실행 제어(일반 실행 옵션)
기능 | 단축키 | 메뉴 |
Run | F9 | Debugger | Run |
Step into | F7 | Debugger | Step into |
Step over | F8 | Debugger | Step over |
Run until selection | F4 | Debugger | Run until selection |
브레이크포인트 설정
- 소프트웨어 브레이크포인트 : 일시 중지하고자 하는 주소로 이동 > F2(또는 우클릭) > 브레이크포인트(Breakpoint) > 토글(Toggle)
- 하드웨어 브레이크포인트 : 브레이크포인트 설정하려는 위치에 우클릭 > 브레이크포인트(Breakpoint) > 실행 중 하드웨어 설정(Set Hardware on Execution)
+) 하드웨어 브레이크포인트를 이용해 메모리 위치에 읽기/쓰기(접근) 중단 가능
-메모리 접근 하드웨어 브레이크포인트 : 덤프 창에서 원하는 주소를 우클릭 > 브레이크포인트(Breakpoint) > 하드웨어, 접근(Hardware, Access) > 적절한 데이터 유형 선택
-메모리 쓰기 하드웨어 브레이크포인트 : 덤프 창에서 원하는 주소 우클릭 > 브레이크포인트(Breakpoint) > 하드웨어, 쓰기(Hardware, Write) - 메모리 브레이크포인트 : 덤프 창에서 원하는 주소 우클릭 > 브레이크포인트(Breakpoint) > 메모리, 접근(Memory, Access) / 메모리, 쓰기(Memory, Write)
- 모든 활성 브레이크포인트 보기 : 브레이크포인트(Breakpoints) 탭 클릭. > 브레이크포인트 창에서 모든 브레이크포인트 목록을 나열. 해당 창 내부의 명령어에 우클릭 후 브레이크포인트 제거 가능.
(책 263p, 265p, 268p : 각각 32비트 악성코드, 64비트 악성코드, 악성 DLL 디버깅. 자세한 내용은 책 참고.)
실행 추적
트레이싱은 프로세스가 실행 중인 이벤트를 저장할 수 있도록 함. x64dbg는 trace into와 trace over 조건 추적 옵션 제공.
- trace into : 트레이스(Trace) > 트레이스 인투(Trace into) / 단축키 Ctrl+Alt+F7
디버거는 내부적으로 step into 브레이크포인트 설정. 조건이 맞거나 최대 단계에 도달할 때까지 프로그램 추적. - trace over : 트레이스(Trace) > 트레이스 오버(Trace over) / 단축키 Ctrl+Alt+F8
디버거는 내부적으로 step over 브레이크포인트 설정. 조건이 맞거나 최대 단계에 도달할 때까지 프로그램 추적.
+) 디버거는 로그를 추적하려면 log text와 추적 이벤트가 리다이렉트될 로그 파일(Log File 버튼을 통해) 전체 경로를 지정해야 함.
trace 일부 필드 설명
- Breakpoint Condition : 조건 지정 가능. 기본값이 0(=거짓). 조건을 지정하려면 유효한 표현식을 지정해야 함. 0이 아니면 참이 되고 브레이크포인트가 발동.
디버거는 전달된 표현식을 평가하면서 추적 계속 진행. 특정 조건이 충족되거나 maximum trace count(최대 추적 카운트)에 도달하면 중지. - Log Text : 로그 파일에서 추적 이벤트를 로깅할 때 사용할 포맷을 지정할 때 사용. 사용 가능한 포맷이 따로 존재.
- Log Condition : 필드의 기본값은 1. 특정 조건을 충족할 경우에만 디버거가 이벤트를 로깅하도록 설정하기 위한 로그 조건을 입력 가능. 조건이 유효한 표현식이어야 함.
- Maximum Trace Count : 디버거가 추적을 중지하기 전 추적하는 최대 단계 수를 지정. 기본값 5000.
- Log File Button : 추적 로그를 저장할 로그 파일의 전체 경로 지정 가능.
x64dbg는 특정 명령어 및 함수 추적 기능 제공X. 그러나 trace into와 trace out 옵션으로 가능.
- 명령어 추적 : Trace into 대화창 설정. 로그 파일의 전체 경로와 Log Text 지정 필요. 프로그램 실행 흐름을 빠르게 살펴보고자 할 때 유용.
- 함수 추적 : 명령어 추적과 유사, 예시에선 Log Condition필드의 표현식 제외하고 동일.
패치
악성코드를 분석하는 동안 바이너리를 수정해 필요에 맞게 기능을 변경하거나 로직을 뒤집을 수 있음.
메모리 데이터 수정 : 메모리 주소 탐색, 수정하려는 바이트 선택 후 우클릭 > 바이너리(Binary) > 편집(Edit) / 단축키 Ctrl+E.
-> 명령어 수정 후, 파일(File) > 파일 패치(Patch file) 선택하면 패치 적용 가능.
IDA
프로세스 실행
- 프로그램을 로딩하지 않고 디버거를 직접 실행하는 방법 : 디버거(Debugger) > 실행(Run) > 로컬 윈도우 디버거(Local Windows debugger).
- IDA에서 먼저 실행 파일 로딩 : 디버거(Debugger) > 디버거 선택(Select debugger) / 단축키 F9. 올바른 디버거 선택.
기존 프로세스 연결
- 프로그램이 로딩되지 않은 경우 : 디버거(Debugger) > 연결(Attach) > 로컬 윈도우 디버거(Local Windows debugger).
단 이 경우, IDA 로더가 실행 파일 이미지를 읽을 수X, 바이너리 초기 자동 분석 실시 불가. - 프로세스 연결 전 프로세스와 관련된 실행 파일을 IDA 로딩 : 디버거(Debugger) > 디버거 선택(Select debugger) > Local Win32 debugger 옵션 체크 후 OK. 다음으로는 디버거(Debugger) > 프로세스에 연결(Attach to process)
인터페이스
- 디스어셈블리 창 : 명령어 포인터 레지스터(eip 또는 rip)의 현재 값과 동기화됨. 앞에서 배운 것과 동일 기능.
스페이스바 눌러서 그래프 뷰와 텍스트 뷰 모드 전환 가능. - 레지스터 창 : CPU의 범용 레지스터의 현재 내용 표시.
레지스터 값 우클릭 > Modify value, Zero value, Toggle value, Increment/Decrement value 클릭 가능.
레지스터의 값이 유효한 위치에 있으면 레지스터 값 옆의 직각 화살표가 활성화됨. 클릭 시 뷰가 해당 메모리 위치로 재배치.
*값 전환(toggle) - CPU 플래그 비트의 상태 변경 시 유용. - 스택 뷰 : 프로세스 런타임 스택의 데이터 내용 표시. 함수 호출 전 스택을 조사하면 함수 인수의 수, 유형에 대한 정보 얻을 수 있음.
- 헥사 뷰 : 메모리의 표준 헥사 덤프 표시. 유효한 메모리 위치의 내용을 표시할 때 유용.
- 모듈 뷰 : 프로세스 메모리에 로딩된 모듈 목록 표시. 모듈 더블클릭하면 익스포트한 심벌의 목록 표시.
- 스레드 뷰 : 현재 프로세스의 스레드 목록 표시. 우클릭으로 스레드 중지하거나 중지한 걸 재개할 수 있음.
- 세그먼트 창 : 프로세스에 할당된 메모리 세그먼트 정보 제공. 실행 파일과 섹션이 메모리에 로드되는 위치 정보 제공, 모든 DLL과 섹션 정보에 대한 상세 정보 포함.
보기(View) > 하위보기 열기(Open Subviews) > 세그먼트(Segments) / 단축키 Shift+F7.
각 항목 더블클릭 시, 관련 메모리 위치로 이동. - 임포트와 익스포트 창 : 보기(Views) > 하위보기 열기(Open Subviews)로 표시.
임포트 - 바이너리가 임포트한 모든 함수 나열.
익스포트 - 익스포트한 모든 함수 나열.
프로세스 실행 제어(일반 실행 옵션)
기능 | 단축키 | 메뉴 옵션 |
Continue(Run) | F9 | Debugger | Continue process |
Step into | F7 | Debugger | Step into |
Step over | F8 | Debugger | Step over |
Run to cursor | F4 | Debugger | Run to cursor |
브레이크포인트 설정
- 소프트웨어 브레이크포인트 : 일시 중지하고자 하는 위치에서 우클릭 > Add Breakpoint / 단축키 F2. 브레이크포인트 설정 시 해당 주소가 빨간색으로 강조, F2를 눌러 해제 가능.
- 하드웨어 브레이크포인트 : 이미 설정한 브레이크포인트 우클릭 > Edit brekapoint > Hardware 체크박스 체크. 4개 이상 체크 가능하나, 4개만 동작하고 나머지는 무시됨.
*쓰기 중단, 읽기/쓰기 중단 옵션 사용 : 특정 명령어가 지정된 메모리에 접근할 때 메모리 브레이크포인트 설정 가능. 프로그램이 메모리 위치의 데이터 영역에 접근하는 시기를 알고 싶을 때 유용.
*하드웨어 브레이크포인트 크기 지정 : 브레이크포인트 주소와 결합돼 브레이크포인트를 활성화하는 바이트의 영역 형식. - 조건 브레이크포인트 : 이미 설정한 브레이크포인트 우클릭 > Edit brekapoint > condition 필드에 조건 지정. 조건 필드 옆 ... 버튼 누르면 조건 평가 가능.
- 활성 브레이크포인트 확인 : 디버거(Debugger) > 브레이크포인트(Breakpoint) > 브레이크포인트 목록(Breakpoint List) / 단축키 Ctrl+Alt+B. 각 항목을 우클릭하면 삭제하거나 비활성화 가능.
(책 283p, 285p : 각각 악성코드, 악성 DLL 디버깅. 자세한 내용은 책 참고.)
실행 추적
- 추적 활성화 : 브레이크포인트 설정, 브레이크포인트 우클릭 > Edit breakpoint > 적절한 Tracing Type 선택.
- 그런 다음 디버거(Debugger) > 디버거 선택(Select debugger) 메뉴에서 디버거 선택 > 프로그램 Run.
- -> 이러한 추적은 브레이크포인트 또는 프로그램의 끝에 도달할 때까지 지속. 어떤 명령어를 추적하는지 나타내고자 명령어를 색으로 구분해 강조 표시됨.
- 추적 후 결과 : 디버거(Debugger) > 추적(Tracing) > 추적 윈도우(Trace window).
- 추적 옵션 제어 : 디버거(Debugger) > 추적(Tracing) > 추적 옵션(Trace opitons).
IDA에서 세 가지 유형의 추적
- 명령어 추적 : 명령어의 실행을 기록하고 수정된 레지스터 값 표시. 프로그램의 흐름을 파악할 때와 각 명령어가 실행되는 동안 수정되는 레지스터를 알고자 할 때 유용.
- 함수 추적 : 모든 함수 호출과 반환 기록. 레지스터 값이 기록되지X. 호출하는 함수와 하위 함수를 파악 시 유용. Tracing type을 Functions으로 설정해 함수 추적 가능.
추적이 끝나지 않을 것처럼 보이거나 오랜 시간이 소요되는 것은, 함수가 호출자에서 귀환X거나 이벤트 발생을 기다리면서 반복 실행되는 때임. -> 이러한 경우라도 추적 창에서 로그 볼 수 있음. - 블록 추적 : 런타임 동안 실행된 코드 블록을 파악 시 유용. Tracing type을 Basic block으로 설정.
각 기본 블록 마지막 명령어에 브레이크포인트 설정. 추적하는 블록의 중간에 있는 모든 호출 명령어에도 브레이크포인트 설정. - 추적 속도 : 일반 > 블록 > 명령어, 함수(오랜 시간 소요)
IDAPython을 활용한 디버거 스크립팅
디버거 스크립팅으로 악성코드 분석과 관련된 일상 작업을 자동화할 수 있음.
사용 방법
- 실행 파일 로드 > 디버거(Debugger) > 디버거 선택(Select debugger)으로 디버거 선택.
- 로드된 후, IDA 파이썬 셸 또는 파일(File) > 스크립트 커멘드(Script Command) / 단축키 Shif+F2.
- 드롭다운 메뉴에서 Scripting language Python으로 선택.
코드
현재 커서 위치에 브레이크포인트를 설정하고, 디버거 시작해 일시 중지 디버거가 발생할 때까지 기다린 다음 브레이크포인트 주소와 관련된 주소와 디스어셈블리 텍스트를 출력하는 코드 조각
ide.add_bpt(ide.get_screen_ea())
idc.start_process('', '', '')
evt_code = idc.watt_for_next_event(WFNE_SUSP, -1)
if (evt_code > 0) and (evt_code != idc.PROCESS_EXITED):
evt_ea = idc.get_event_ea()
print "Breakpoint Triggered at:",
hex(evt_ea),tdc.generate_dtsasm_ltne(evt_ea, 0)
명령어를 step into한 후 주소와 디스어셈블리 텍스트 출력하는 코드. 같은 방법으로 idc.step_over()로 명령어 step over 가능.
idc.step_tnto()
evt_code = idc.wait_for_next_event(WFNE_SUSP, -1)
if (evt.code > 0) and (evt_code != idc.PROCESS_EXITED):
evt_ea = tdc.get_event_ea()
print "Stepped Into:", hex(evt_ea),idc.generate_disasm_line(evt_ea, 0)
레지스터 값 얻고자 idc.get_reg_value() 사용 가능. 예시는 esp 레지스터 값 가져와서 결과 출력함.
Python>esp_value = idc.get_reg_value("esp")
Python>print hex(esp_value)
0xlbf950
dword 값 얻을 때 사용할 코드(예시 주소 : 0x14fb04).
같은 방법으로 idc.read_dbg_byte(ea), idc.read_dbg_word(ea), idc.read_dbg_qword(ea) 사용해 byte, word, qword 값을 특정 주소에서 획득 가능.
Python>ea = 0xl4fb04
print hex(idc.read_dbg_dword(ea))
0xl4fb54
주소 0x01373000에서 ASCII 문자열 얻으려면 idc.get_strlit_contents() 함수 사용 가능.
Python>ea = 0x01373000
Python>print idc.get_strlit_contents(ea)
This is a simple program
유니코드 문자열 strtype 인수를 상숫값으로 설정해 idc.get_strlit_contents() 함수 사용.
Python>ea = 0x00C37860
Python>print idc.get_strlit_contents(ea, strtype=idc.STRTYPE_C_16)
SHAMple.dat
로드한 모든 모듈과 기준 주소 나열
import idautils
for m in idautils.Modules():
print "0x%08x %s" % (m.base, m.name)
dll에 있는 함수의 주소를 얻기(예시는 kernel32.dll에 있는 CreateFileA 함수)
Python>ea = idc.get_name_ea_stmple("kernel32_CreateFileA")
Python>print hex(ea)
0x768a53c6
일시정지된 프로세스 재개
Python>idc.resume_process()
.NET 애플리케이션 디버깅
악성코드 분석 시 다양한 코드를 분석해야 함. -> .NET 바이너리 분석을 쉽게 만드는 도구 : dnSpy
- .NET 애플리케이션 로드 : dnSpy로 애플리케이션 끌어다 놓기 / dnSpy 실행 후 파일(File) > 열기(Open) 선택 후 바이너리 경로 제공.
-> 로드되면 애플리케이션이 디컴파일됨. - Assembly explorer라는 왼쪽 창 : 프로그램의 메서드와 클래스 접근 가능.
-> 디컴파일되면 코드를 읽어 정적 코드 분석 수행 or 디버깅하고 동적 코드 분석 수행 가능. - 디버깅하려면 툴바의 Start 버튼 / 디버그(Debug) > 어셈블리 디버그(Debug on Assembly) / 단축키 F5.
-> 클릭 후 다이얼로그가 표시됨. 여기서 Break at으로 디버거 시작될 때 중단 위치 지정 가능, 옵션 선택 후 OK. - 디버거의 제어하에 프로세스를 시작하며, 엔트리 포인트에서 일시 중지.
-> 이제 Debug 메뉴를 통해 디버거 옵션(step over 등)에 접근 가능.
브레이크포인트 설정 : 디버그(Debug) > 브레이크포인트 토글(Toggle Breakpoint)
'보안 > 악성코드' 카테고리의 다른 글
LummaStealer 악성코드 정적분석 (0) | 2025.05.07 |
---|---|
[4장]어셈블리 언어와 디스어셈블리 기초 (0) | 2025.05.06 |
[3장]동적 분석 (0) | 2025.04.08 |
[2장]정적 분석 (0) | 2025.04.01 |
[논문]"머신러닝 기반 악성 URL 탐지 기법" 정리 (0) | 2025.04.01 |