winpwn 사용 방법
winpwn은 PE 파일을 대상으로 유용한 기능들을 제공하는 파이썬 라이브러리이다.
Linux Pwnable을 할 때 사용했던 pwntools와 거의 동일한 기능들을 제공한다.
실행 환경
Windows 11
Python 3.13.2
pip 24.3.1
설치
pip install winpwn
pip install pefile
pip install keystone
pip install capstone
사전 설정
C:\Users\<USERNAME>
위치에 .winpwn
파일을 생성하고, 아래 내용을 입력한다. 경로는 수정이 필요하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"debugger":{
"i386": {
"x64dbg": "",
"gdb": "",
"windbg": "",
"windbgx": "C:\\Program Files\\WindowsApps\\Microsoft.WinDbg_1.2506.12002.0_x64__8wekyb3d8bbwe\\DbgX.Shell.exe"
},
"amd64": {
"x64dbg": "",
"gdb": "",
"windbg": "",
"windbgx": "C:\\Program Files\\WindowsApps\\Microsoft.WinDbg_1.2506.12002.0_x64__8wekyb3d8bbwe\\DbgX.Shell.exe"
}
},
"debugger_init": {
"i386": {
"x64dbg": "",
"gdb": "",
"windbg": "",
"windbgx": ""
},
"amd64": {
"x64dbg": "",
"gdb": "",
"windbg": "",
"windbgx": ""
}
}
}
windbg는 기존 windbg이며, windbgx는 WinDbg Preview이다.
아래 debugger_init
부분은 스크립트 로드 등 디버거 초기화 단계에서 디버거가 실행할 명령어를 입력하는 곳이다.
winpwn 관련된 과거 게시글들을 보면 pykd를 로드하는 것 같은데, pykd가 더이상 제공되지 않아서 그냥 빼버렸다.
예제
test.cpp
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
int *ptr = NULL;
getchar();
*ptr = 512; // NULL Pointer Dereference!
return 0;
}
test.py
1
2
3
4
5
6
7
8
9
10
from winpwn import *
# 사전 설정(.winpwn 파일)을 하지 않은 경우에는 아래 주석처리된 내용을 추가하여 디버거를 설정할 수 있다. (경로 수정 필요)
# context.debugger="windbgx"
# context.windbgx="C:\\Program Files\\WindowsApps\\Microsoft.WinDbg_1.2506.12002.0_x64__8wekyb3d8bbwe\\DbgX.Shell.exe"
p = process("test.exe")
windbgx.attach(p)
p.interactive()
test.cpp
를 컴파일한 결과 test.exe
를 실행하면, 9행에서 NULL Pointer Dereference가 발생한다.
파이썬 파일을 실행해보면 디버거가 Attach 되며, 터미널에는 아래와 같은 메시지들이 출력된다.
pwntools처럼 디버거가 attach되고, 프로세스와 상호작용(interacting)할 수 있는 것이다.
디버거를 보면, test.cpp
의 getchar()
함수가 호출되어 입력이 들어올 때까지 NtReadFile
에서 멈춰 있다.
이제 디버거에서 g를 입력하여 프로세스 실행을 계속하고, 터미널에서 엔터 한 번을 입력해주면 디버거가 멈추며, Access Violation이 발생한 것을 확인해볼 수 있다.
이외 기능들
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from winpwn import *
p = process("test.exe") # process 객체 생성
pe = winfile("test.exe") # PE 파일 로드, pwntools의 ELF와 동일한 기능
# pe.symbols["exit"]와 같이 사용
p.sendline("1") # recvuntil 등도 모두 pwntools와 동일
# PIE/NOPIE
# PE 파일을 직접 수정하여, NT_IMAGE_HEADERS -> OptionalHeader -> DllCharacteristics의
# IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 비트를 켜고 끄는 것으로 PIE 적용 여부를 수정한다.
NOPIE("test.exe") # 지정한 PE 바이너리의 PIE를 끈다.
PIE("test.exe") # 지정한 PE 바이너리의 PIE를 켠다.