어떤 수업을 찾고 있나요?

예: PowerShell, 네트워크, XSS, Step 138

전체 커리큘럼 둘러보기 →

리버싱

Step 216. x64dbg 심화: 메모리 브레이크포인트, 패치 — 실행 중인 프로그램을 수술한다

Step 216예상 실습 시간 · 5시간

Level 3 — Reversing 트랙 | 난이도 ★★★☆☆ | 예상 소요 시간 5시간

전제: Step 178(리버싱 맛보기), Step 215(Ghidra 심화)를 마쳤다. 조건 분기(je/jne)와 비교(cmp/test)를 어셈블리에서 읽을 수 있다.

⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다. 패치는 "내가 만든 연습용 바이너리"에만 합니다 — 남의 소프트웨어를 패치해 배포하면 저작권·라이선스 위반이 될 수 있습니다.

  • 준비물: x64dbg는 Windows GUI 도구라 이 Linux 환경에는 없습니다 — 화면은 예시로 안내하고, 패치와 메모리 감시의 원리는 파이썬과 gdb로 실측합니다 (실측: Ubuntu 24.04, gdb 15.1, Python 3.12).
  • 주의: 오늘의 핵심 두 기술(메모리 브레이크포인트, 패치)은 악성코드 분석에서도 매일 쓰는 정상적 기법입니다. 다만 패치 결과물을 배포하는 것은 별개의 법적 문제임을 기억하세요.

Ghidra가 "읽고 정리하는 책상"이라면, x64dbg는 "실행 중인 프로그램의 조종실"입니다. 오늘 배우는 두 기술은 리버싱의 가장 강력한 수법입니다. 하나는 메모리 브레이크포인트 — "이 값이 대체 어디서 읽히는 거야?"라는 질문에, 값이 읽히는 바로 그 순간에 실행을 멈춰 답해 주는 기능. 다른 하나는 패치 — 프로그램의 명령을 바꿔치기해 인증을 뒤집는 기술. 둘 다 원리는 단순한데, 오늘 그 원리를 파일 바이트 수준까지 내려가 직접 확인합니다.


1. 학습 목표

이 챕터를 끝내면 다음을 할 수 있습니다:

  • x64dbg에서 문자열 검색으로 비교 코드를 역추적하는 루틴을 수행한다
  • 코드 브레이크포인트와 메모리 브레이크포인트의 차이를 설명하고 상황에 맞게 고른다
  • 조건 분기 명령(je/jne)의 기계어 바이트를 식별한다
  • 패치(메모리상 수정 → 파일 저장)의 전 과정을 수행한다
  • 패치의 원리를 파이썬 바이트 조작으로 직접 재현한다

2. 배경 지식 — 오늘의 도구와 개념

오늘의 도구 한눈에 보기

구분 내용
언어·환경 x64dbg는 화면 예시(Windows GUI) / 원리 실측: WSL 우분투의 gdb 15.1 + Python 3.12 (tmp_test 스크립트)
오늘의 명령어·키 x64dbg: 우클릭 → Search for → All referenced strings, F2(BP), 우클릭 → Breakpoint → Memory, 더블클릭으로 명령 수정, Ctrl+P(Patches) / gdb: watch, rwatch / 파이썬: 바이너리 바이트 읽기·쓰기
필요한 개념 코드 BP vs 메모리 BP(하드웨어 BP), 조건 분기의 기계어(0x74/0x75), 가상 주소와 파일 오프셋의 변환
오늘의 산출물 인증이 뒤집힌 패치 바이너리 1개 + 패치 전후 비교 기록

2-1. 코드 브레이크포인트 vs 메모리 브레이크포인트

지금까지 쓴 브레이크포인트는 코드 BP — "이 명령에 도달하면 멈춰라"입니다. 주소를 알아야 겁니다. 그런데 리버싱에서 더 자주 드는 질문은 반대입니다: "이 값이 어디서 쓰이는지 모르겠다."

메모리 브레이크포인트(memory breakpoint)는 주소가 아니라 데이터에 겁니다 — "이 메모리가 읽힐 때(또는 쓰일 때) 멈춰라". 내 입력 버퍼에 걸어 두면, 프로그램이 내 입력을 검사하러 읽는 순간에 멈춥니다. 비교 코드를 몰라도 비교 코드로 끌려가는 셈입니다. x64dbg에서는 덤프 창에서 주소 우클릭 → Breakpoint → Memory, on access로 겁니다.

구현은 CPU의 디버그 레지스터(하드웨어 BP)를 쓰므로 개수 제한(보통 4개)이 있습니다. gdb에도 같은 기능이 watch(쓰일 때), rwatch(읽힐 때)로 있습니다 — 오늘 실측해 봅니다.

2-2. 조건 분기의 기계어 — 0x74와 0x75

if (strcmp(a,b) == 0) 같은 인증은 기계어로 test/cmp 뒤의 조건 점프 한 개로 귀결됩니다. 짧은 점프(short jump)의 기계어는:

  • 0x74 = JE(같으면 점프)
  • 0x75 = JNE(다르면 점프)

뒤따르는 한 바이트는 점프 거리입니다. 즉 인증 로직의 운명이 한 바이트에 달렸습니다 — 0x75를 0x74로 바꾸면 "다를 때 통과"가 "같을 때 통과"로 뒤집힙니다. 이것이 패치의 본질입니다.

2-3. 패치의 두 단계 — 메모리와 파일

x64dbg에서 명령을 더블클릭해 고치면 일단 메모리상의 프로그램만 바뀝니다. 지금 실행에서 즉시 효과를 보지만, 파일은 그대로입니다. 바꾼 내용을 파일에 반영하려면 Ctrl+P(Patches 창)에서 Patch file을 해야 합니다.

파일에 쓰려면 한 가지 변환이 필요합니다. 디버거 화면의 주소는 가상 주소(실행 중 메모리 위치)이고, 패치는 파일 오프셋(디스크에서의 위치)에 써야 하니까요. 둘의 변환은 섹션 표가 알려 줍니다 — 오늘 파이썬 실측에서 이 변환을 손으로 해 봅니다.

2-4. 문자열에서 역추적 — x64dbg의 표준 오프닝

crackme를 받으면 x64dbg에서의 첫 동작은 정해져 있습니다. 우클릭 → Search for → Current region → String references(또는 All referenced strings)로 문자열 목록을 열고, "Correct"/"Wrong" 같은 판정 메시지를 찾아 더블클릭합니다. 그러면 그 문자열을 참조하는 코드 — 즉 인증 분기 근처 — 로 점프합니다. 메시지에서 거꾸로 비교 코드를 찾아가는, 사실상 모든 입문 crackme 공략의 첫 수입니다.

2-5. 조건부 브레이크포인트

반복문 안의 비교처럼 "수백 번 지나가는데 그중 한 번만 보고 싶은" 상황에는 조건부 BP를 씁니다. BP에 우클릭 → Edit에서 조건식(예: rax==0x1337)을 달면 조건이 참일 때만 멈춥니다. Step 218의 다단계 검증 분석에서 빛을 발하는 기능입니다.


3. 따라 하기

3-1. 실험실 — 패치당할 프로그램

x64dbg의 무대는 Windows지만, 패치의 원리는 운영체제와 무관하게 같습니다. 리눅스 바이너리로 원리를 실측하고, 화면 조작은 예시로 배웁니다.

입력 (patchme.c)

#include <stdio.h>
#include <string.h>

int main(void) {
    char pw[32];
    printf("password: ");
    scanf("%31s", pw);
    if (strcmp(pw, "open-sesame") == 0)
        puts("correct!");
    else
        puts("wrong.");
    return 0;
}
cd ~/lab214_218
gcc -O0 -no-pie -o patchme patchme.c
echo wrongpw | ./patchme
password: wrong.

(2026-09-09 실측. -O0로 컴파일해 분기 구조를 교과서적으로 남겼습니다.)

3-2. 수술 부위 찾기 — 인증 분기의 주소

objdump -d patchme | sed -n "/<main>:/,/ret/p" | grep -E "call|test|jne|j"
  401211:	e8 9a fe ff ff       	call   4010b0 <strcmp@plt>
  401216:	85 c0                	test   %eax,%eax
  401218:	75 11                	jne    40122b <main+0x75>
  401224:	e8 57 fe ff ff       	call   401080 <puts@plt>      ← correct! 출력
  401229:	eb 0f                	jmp    40123a <main+0x84>
  401235:	e8 46 fe ff ff       	call   401080 <puts@plt>      ← wrong. 출력

(2026-09-09 실측. 출력은 일부만 골라 배치했습니다.)

출력 읽는 법: strcmp의 반환값(eax)을 test하고, 다르면(jne) 0x40122b — wrong 쪽 — 으로 점프합니다. 수술 부위는 401218의 75 11 두 바이트. 첫 바이트 0x75가 JNE라는 뜻이고 0x11이 점프 거리입니다. 이 한 바이트를 0x74(JE)로 바꾸면 인증이 뒤집힙니다.

3-3. 가상 주소 → 파일 오프셋 변환

디버거가 보여 주는 0x401218은 가상 주소입니다. 파일에서의 위치는 섹션 표로 변환합니다:

readelf -S patchme | grep -A1 ".text"
  [15] .text  PROGBITS  00000000004010d0  000010d0
       0000000000000185 ...

(2026-09-09 실측.)

읽는 법: .text 섹션은 가상 주소 0x4010d0에서 시작하고, 파일 오프셋 0x10d0에서 시작합니다. 차이가 0x400000 — 즉 이 프로그램은 "가상 주소 = 파일 오프셋 + 0x400000". 수술 부위의 파일 오프셋은 0x401218 − 0x400000 = 0x1218입니다. x64dbg의 Patches 창이 자동으로 해 주는 계산을, 우리는 손으로 한 것입니다.

3-4. 파이썬으로 한 바이트 수술 (실측)

패치 스크립트를 만듭니다. 파일을 통째로 읽고, 한 바이트를 고치고, 새 파일로 저장합니다:

입력 (tmp_test/patch216.py)

# ELF 바이너리의 조건 분기 한 바이트 패치
UNC = r"\\wsl$\Codex-Security-Lab\root\lab214_218\patchme"   # 실습 랩 경로
DST = r"\\wsl$\Codex-Security-Lab\root\lab214_218\patchme_patched"

JNE_VADDR = 0x401218          # objdump에서 찾은 jne의 가상 주소
TEXT_VADDR = 0x4010D0         # .text 가상 주소
TEXT_OFF   = 0x10D0           # .text 파일 오프셋
file_off = JNE_VADDR - (TEXT_VADDR - TEXT_OFF)
print(f"가상주소 0x{JNE_VADDR:x} -> 파일 오프셋 0x{file_off:x}")

data = bytearray(open(UNC, "rb").read())
print(f"패치 전 바이트: 0x{data[file_off]:02x} (0x75=JNE 여야 함)")
assert data[file_off] == 0x75, "예상한 JNE 바이트가 아님"

data[file_off] = 0x74         # JNE -> JE
open(DST, "wb").write(data)
print(f"패치 후 바이트: 0x{data[file_off]:02x} (0x74=JE)")

실행 (Git Bash에서):

가상주소 0x401218 -> 파일 오프셋 0x1218
패치 전 바이트: 0x75 (0x75=JNE 여야 함)
패치 후 바이트: 0x74 (0x74=JE)

(2026-09-09 실측.)

3-5. 수술 결과 검증 — 인증이 뒤집혔다

chmod +x patchme_patched
echo wrongpw | ./patchme            # 원본 + 오답
echo open-sesame | ./patchme        # 원본 + 정답
echo wrongpw | ./patchme_patched    # 패치본 + 오답
echo open-sesame | ./patchme_patched # 패치본 + 정답
password: wrong.      ← 원본: 오답은 거부
password: correct!    ← 원본: 정답만 통과
password: correct!    ← 패치본: 오답이 통과!
password: wrong.      ← 패치본: 정답이 거부됨

(2026-09-09 실측.)

읽는 법: 한 바이트(0x75→0x74)가 인증 로직 전체를 정확히 뒤집었습니다. 오답은 통과하고 정답은 거부됩니다. 이것이 "패치"의 실체 — 디버거의 화려한 UI 아래에서 일어나는 일은 이것이 전부입니다.

3-6. 같은 일을 x64dbg로 — 화면 예시

Windows에서 x64dbg로 같은 수술을 하는 절차입니다:

# 화면 예시 — x64dbg 패치 절차
1. crackme.exe를 x64dbg에 드래그해 로드
2. CPU 창에서 우클릭 → Search for → Current region → String references
3. "wrong" / "correct" 문자열을 찾아 더블클릭 → 참조 코드(인증 분기)로 이동
4. 분기 근처의 jne 명령에서 F2로 BP → F9로 실행 → 아무 비밀번호 입력 → BP에서 멈춤
5. jne 명령을 더블클릭 → "jne"를 "je"로 고쳐 확인
   → 이 시점에 메모리상 프로그램이 바뀜. F9로 계속 실행하면 오답인데 통과
6. Ctrl+P (Patches 창) → Patch file → 바뀐 내용이 파일에 저장됨

3-4의 파이썬 스크립트가 한 일(주소 변환 → 바이트 확인 → 한 바이트 교체 → 파일 저장)을 x64dbg는 마우스 다섯 번으로 해 줍니다. 도구가 달라도 수술의 해부학은 같습니다.

3-7. 메모리 브레이크포인트 — gdb에서 원리 실측

"내 입력을 누가 읽는가"를 리눅스에서 재현합니다. gdb의 watch는 값이 쓰일 때 멈춥니다:

(gdb) break main
(gdb) run
(gdb) set $pw = (char*)($rbp-0x30)   ← objdump에서 scanf 인자의 lea -0x30(%rbp)로 읽은 입력 버퍼 주소
(gdb) watch *$pw
(gdb) continue
Hardware watchpoint 2: *$pw
Old value = 0 '\000'
New value = 65 'A'
__vfscanf_internal (...) at ./stdio-common/vfscanf-internal.c:1191

(2026-09-10 실측. echo AAAA | gdb -batch ...로 실행. 멈춘 곳은 scanf 내부 __vfscanf_internal — 버퍼에 입력을 쓰는 순간입니다.)

읽는 법: 코드 주소를 몰라도, 데이터에 감시를 걸면 그 데이터를 건드리는 코드에서 멈춥니다. x64dbg의 Memory BP(on access)와 같은 원리입니다. 다만 이 WSL 환경에서는 읽기 감시 rwatch가 Expression cannot be implemented with read/access watchpoint. 오류로 거부됐습니다 (2026-09-09 실측) — 가상화 환경에서 하드웨어 읽기 감시가 지원되지 않는 제약입니다. 벽 3에서 다룹니다.


4. 미션과 연습문제

미션 — "수술 없는 우회"와 "수술 있는 우회" 비교 보고서

  1. patchme를 gdb로 열어, 파일을 고치지 않고 실행 중에만 인증을 우회해 보세요 (힌트: jne에서 멈춘 뒤 레지스터나 rip를 손대는 방법이 있습니다 — set $rip = ...)
  2. 3-4의 패치로 만든 patchme_patched와 비교합니다: 두 우회의 차이(영속성, 필요한 도구)를 표로 정리하세요
  3. patchme.c의 비밀번호를 바꿔 다시 컴파일하고, objdump부터 패치까지 전 과정을 혼자 반복하세요 — 새 바이너리에서 jne의 주소와 파일 오프셋이 달라짐을 확인하세요

연습문제

문제 1. 코드 브레이크포인트와 메모리 브레이크포인트의 차이를, "무엇을 알고 있을 때 무엇을 쓰는가"로 설명하세요.

문제 2. 0x75(JNE)를 0x90×2(NOP 두 개)로 고치는 패치도 가능합니다. 이 패치는 JE로 뒤집는 것과 결과가 어떻게 다른가요? (힌트: NOP이면 흐름이 어디로 가나요?)

문제 3. 가상 주소 0x401218의 명령을 파일에서 고치려면 왜 0x400000을 뺐나요? .text 섹션 표의 두 숫자가 무엇을 뜻하는지와 함께 설명하세요.

문제 4. 패치가 "메모리상 즉시 반영, 파일은 별도 저장"인 이유를, 디버거가 보는 것과 디스크의 파일이 다른 존재라는 관점에서 설명하세요.


해설과 완료 기준 · 펼치기/접기

5. 모범 답안과 완료 기준

미션 모범 답안

실행 중 우회 (메모리상 패치의 수동 버전):

(gdb) break *0x401218        ← jne에 BP
(gdb) run                    ← 아무 비밀번호 입력
(gdb) set $rip = 0x40121a    ← jne 다음 줄(correct! 블록 시작)로 강제 점프
(gdb) continue
correct!

(2026-09-10 실측. 0x40121a는 jne 바로 다음 — "correct!" 문자열을 rdi에 싣는 lea부터 시작하는 블록의 첫 주소입니다. 0x401224(call puts)로 바로 가면 lea를 건너뛰어 엉뚱한 문자열이 출력되니 주의하세요. 주소는 환경에 따라 다릅니다.)

비교 표:

구분 실행 중 우회 (gdb set) 파일 패치 (바이트 교체)
영속성 그 실행에서만 파일을 바꾸니 영구적
필요한 도구 디버거 아무 바이너리 에디터/스크립트
탐지 세션마다 다시 해야 함 파일 해시가 바뀜 — 무결성 검사에 걸릴 수 있음
용도 분석 중 시험 분석 확정 후 결과물 고정

재수술 확인 사항: 비밀번호 문자열을 바꾸면 바이너리가 달라지므로 jne의 주소·파일 오프셋이 바뀝니다. 절차(objdump로 분기 찾기 → readelf로 변환 → 한 바이트 교체 → 검증)는 동일하게 작동해야 합니다.

연습문제 해답

문제 1 해답. 코드 BP는 "멈추고 싶은 명령의 주소를 아는" 경우에 씁니다 — 문자열 역추적으로 비교 코드를 찾은 뒤처럼. 메모리 BP는 반대로 "코드는 모르지만 데이터는 아는" 경우에 씁니다 — 내 입력 버퍼에 걸어 두면 그것을 읽는 (어디에 있는지 몰랐던) 검사 코드에서 멈춥니다. 정리하면: 아는 것이 주소면 코드 BP, 아는 것이 데이터면 메모리 BP.

문제 2 해답. JE로 뒤집으면 "정답이 거부되고 오답이 통과"로 반전됩니다. 반면 NOP으로 지우면 점프 자체가 사라져 test 결과와 무관하게 항상 다음 명령(correct! 출력)으로 직진합니다 — 정답이든 오답이든 무조건 통과합니다. 실전 crackme 풀이에서는 "무조건 통과" 쪽이 더 편한 경우가 많지만, 프로그램에 정답 경로에서만 채워지는 상태가 있다면 반전 패치가 필요한 경우도 있습니다.

문제 3 해답. 실행 파일은 메모리에 올라갈 때 각 섹션이 정해진 가상 주소에 배치됩니다. readelf 출력에서 0x4010d0은 .text가 메모리에서 시작되는 가상 주소이고, 0x10d0은 같은 내용이 파일에서 시작되는 오프셋입니다. 둘의 차(0x400000)만큼 밀려 있으므로, 가상 주소에서 이 차이를 빼면 파일 안의 위치가 나옵니다. 디버거 화면의 주소로는 디스크의 파일을 직접 가리킬 수 없기 때문에 이 변환이 필요합니다.

문제 4 해답. 실행 중인 프로그램은 파일의 사본이 메모리에 올라간 것이고, 디버거가 멈춰서 보여 주고 고치는 것은 그 사본입니다. 사본을 고쳐도 원본 파일은 그대로이므로, 프로그램을 닫으면 수정은 사라집니다. 파일을 바꾸려면 "메모리의 어느 위치가 파일의 어느 바이트에 대응하는가"를 계산해 원본에 다시 써야 하고, 그것이 x64dbg의 Patches 창(Ctrl+P)과 우리의 파이썬 스크립트가 한 일입니다.

완료 기준 체크리스트

  • [ ] 코드 BP와 메모리 BP의 차이와 선택 기준을 말할 수 있다
  • [ ] 문자열 참조 검색으로 인증 분기를 역추적하는 절차를 안다
  • [ ] objdump 출력에서 조건 점프의 기계어 바이트(0x74/0x75)를 식별했다
  • [ ] 가상 주소 → 파일 오프셋 변환을 readelf 섹션 표로 계산했다
  • [ ] 파이썬으로 한 바이트를 패치해 인증이 뒤집히는 것을 확인했다
  • [ ] gdb watch로 데이터 감시의 원리를 실측했다
  • [ ] 미션: 실행 중 우회와 파일 패치를 비교하는 표를 완성했다

6. 흔한 실수와 해결

벽 1. 패치했는데 파일이 안 바뀐다 (x64dbg)

증상: je로 고치고 실행하면 통과되는데, 프로그램을 다시 열면 원래대로입니다.
원인: 명령을 더블클릭해 고친 것은 메모리상 수정입니다. 파일은 건드리지 않았습니다.
해결: Ctrl+P로 Patches 창을 열어 Patch file을 눌러야 파일에 저장됩니다. Patches 창에는 이번 세션에 고친 모든 위치가 목록으로 뜨니, 저장 전에 의도한 패치만 있는지 확인하세요.

벽 2. 패치할 바이트를 찾았는데 0x75가 아니다

증상: 파이썬 스크립트의 assert data[file_off] == 0x75에서 실패합니다.
원인: 주소 변환이 틀렸거나, 컴파일 옵션이 달라 분기 형태가 바뀐 것입니다. -O1 이상으로 컴파일하면 컴파일러가 분기를 재배치해 je+점프 조합이 되는 등 모습이 달라집니다 (오늘 실습이 -O0인 이유).
해결: objdump에서 분기 명령의 주소와 기계어를 다시 확인하세요. readelf의 섹션 표에서 .text의 두 숫자(가상 주소, 파일 오프셋)로 변환을 다시 계산하면 됩니다. 추측로 패치하지 말고, 패치 전 바이트가 기대와 같은지 반드시 검사하세요 — 오늘 스크립트의 assert가 그 안전장치입니다.

벽 3. gdb에서 rwatch가 안 된다

증상: rwatch *(char*)($rbp-0x30)가 Expression cannot be implemented with read/access watchpoint. 오류가 납니다.
원인: 읽기 감시는 CPU의 하드웨어 디버그 레지스터가 필요한데, WSL 같은 가상화 환경에서는 지원되지 않는 경우가 있습니다 (2026-09-09 WSL2 실측).
해결: 쓰기 감시 watch는 동작하니(실측 확인) 우선 그것으로 관찰하세요. "읽는 순간"을 꼭 봐야 한다면, 비교 함수(strcmp 등)의 호출 주소에 코드 BP를 거는 방법으로 우회합니다 — Step 178에서 한 것이 바로 그 우회입니다.

벽 4. x64dbg에서 문자열 검색에 "correct"가 안 나온다

증상: String references에 판정 메시지가 없습니다.
원인: 문자열이 다른 메모리 영역에 있거나(Current region만 검색했을 때), 난독화로 실행 중에 복원되는 경우입니다.
해결: Search for → All regions로 범위를 넓혀 보세요. 그래도 없으면 실행 중 복원형 — Step 178의 XOR crackme처럼 동적 분석으로 전환할 신호입니다. 이때 메모리 BP가 빛을 발합니다: 입력 버퍼에 on access BP를 걸어 검사 코드를 역으로 찾습니다.

벽 5. 패치 후 실행하니 세그폴트/비정상 종료

증상: 한 바이트를 고쳤는데 프로그램이 죽습니다.
원인: 명령의 첫 바이트가 아닌 곳을 고쳤거나(명령 중간을 깨면 CPU가 엉뚱한 명령으로 해석), 점프 거리 바이트를 건드린 경우입니다. x86 명령은 가변 길이라 한 바이트 어긋나면 그 뒤 전체가 깨집니다.
해결: 패치는 반드시 명령의 시작 바이트에서, 같은 길이의 명령으로만 교체하세요 (0x75→0x74는 둘 다 2바이트 short jump라 안전). NOP으로 지울 때도 바이트 수를 정확히 맞춰야 합니다 — 2바이트 명령에는 0x90 두 개.


7. 정리

오늘의 개념

개념 한 줄 설명
메모리 브레이크포인트 코드 주소가 아니라 데이터의 읽기/쓰기에 거는 감시 — 검사 코드를 역추적
조건부 BP 조건식이 참일 때만 멈추는 BP — 반복문 분석의 필수품
패치 프로그램의 명령 바이트를 바꿔 동작을 변경하는 기술
0x74 / 0x75 JE / JNE short jump — 인증의 운명을 쥔 한 바이트
가상 주소 ↔ 파일 오프셋 섹션 표로 변환하는 두 좌표계 — 파일 패치의 핵심 계산
Patches 창 (Ctrl+P) 메모리상 수정을 파일에 반영하는 x64dbg의 저장소

오늘의 명령어·키

명령/키 하는 일
x64dbg: 우클릭 → Search for → String references 판정 메시지에서 비교 코드로 역추적
x64dbg: 덤프 우클릭 → Breakpoint → Memory, on access 메모리 BP 걸기
x64dbg: 명령 더블클릭 → 수정 / Ctrl+P 메모리 패치 / 파일에 저장
objdump -d | grep jne 패치 후보(조건 점프) 찾기
readelf -S 가상 주소 → 파일 오프셋 변환 재료
gdb watch / rwatch 쓰기 / 읽기 데이터 감시 (rwatch는 환경 제약 주의)

명령어보다 중요한 감각

오늘 배운 두 기술은 같은 질문의 양면입니다. 메모리 BP는 "이 값을 누가 만지는가"를 묻고, 패치는 "만지는 곳을 알았으니 바꾼다"고 답합니다. 분석(관찰)과 조작(개입) — 동적 리버싱의 바퀴 두 개입니다.

그리고 패치의 겸손함을 기억하세요. 수술은 정확히 한 바이트, 명령의 경계를 지켜서. 한 바이트가 프로그램의 정체성을 뒤집을 수 있다는 것은, 반대로 한 바이트의 오차가 전부를 깬다는 뜻이기도 합니다. 패치 전에 기대 바이트를 확인하는 assert 한 줄 — 그것이 분석가와 파괴자를 가르는 습관입니다.


전부 체크되면 Step 216 완료입니다.

한 단계 더 가까이

수업을 마쳤나요?

본문의 완료 기준을 확인한 뒤 직접 표시하세요.

화면이나 링크에 문제가 있나요? 알려주세요.
다음 수업