포스트

winpwn 사용 방법

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.cppgetchar() 함수가 호출되어 입력이 들어올 때까지 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를 켠다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

"Windows Userland" 카테고리의 게시물