[Rev] 리버싱 · 작성: 2026-07-19 19:34:18 · 수정: 2026-07-21 23:32:17 · 조회 11
크랙미(Crackme)를 마주하고 무작정 디버거부터 켜면 방향 없이 헤매기 쉽다. 이 글은 지금까지 다룬 정적/동적 분석, 어셈블리 읽기 기법을 하나의 문제 해결 순서로 엮는다.
정적 분석 글에서 다룬 순서 그대로 시작한다.
checksec/file로 아키텍처와 보호 기법 확인 — 크랙미는 대개 익스플로잇이 목적이 아니라 로직 분석이 목적이라 카나리/NX보다는 스트리핑 여부가 더 중요한 정보다strings로 "Correct!", "Wrong password" 같은 성공/실패 메시지 문자열을 먼저 찾는다 — 이 문자열이 코드のどこ에서 참조되는지가 인증 로직의 위치를 알려주는 가장 빠른 단서다check_password() 같은 핵심 함수에 도달한다어셈블리어 읽기 기초 글에서 다룬 cmp+jcc 패턴을 그 함수 안에서 찾는다.
call transform_input ; 사용자 입력을 어떤 알고리즘으로 변환
cmp eax, 0x1337 ; 변환 결과를 정답과 비교
jne print_fail
call print_success
여기서 두 갈래로 나뉜다 — **정답이 하드코딩된 상수와의 단순 비교(위 예시)**라면 그 상수만 읽으면 끝나지만, 입력값 자체를 어떤 알고리즘(해시, XOR, 커스텀 변환)으로 가공한 뒤 비교하는 경우가 대부분이라, transform_input 안으로 더 들어가야 한다.
동적 분석 글에서 다룬 대로 transform_input 호출 직후에 브레이크포인트를 걸고, 실제 입력값이 어떻게 변환되는지 레지스터/메모리 값을 직접 관찰한다. 정적으로 어셈블리만 봐서는 루프의 반복 횟수나 실제 중간값을 파악하기 어려운 경우가 많아서, 이 단계에서 "가설(아마 이런 알고리즘일 것이다)"을 실제 실행으로 확인하는 과정이 필수다.
jne(0x75)를 je(0x74)로 바꾸거나, 그냥 nop(0x90)으로 덮어써서 분기 자체를 무의미하게 만드는 방식이다. 가장 빠르지만, "어떤 입력을 넣어도 통과하는" 바이너리를 만드는 것이지 "정답을 알아내는 것"은 아니다 — 크랙미의 의도(알고리즘을 역산해서 정답을 찾는 것)와는 다른 접근이라는 걸 인지하고 써야 한다.
transform_input의 로직을 완전히 이해한 뒤, **그 알고리즘을 파이썬 등으로 그대로 재구현해서 역산(정답을 만족하는 입력값을 계산)**하는 방식이다. 해시 함수처럼 일방향이면 역산이 불가능하고 브루트포스가 필요할 수도 있고, 단순 XOR/치환이면 역함수를 그대로 짜면 된다. 진짜 리버싱 실력을 요구하는 건 이쪽이다.
ptrace 계측으로 우회해야 이어지는 분석이 가능하다크랙미를 "정답을 맞히는 게임"이 아니라 **"문자열 → 비교 로직 → 변환 알고리즘"으로 이어지는 역추적 경로를 순서대로 좁혀가는 작업"**으로 이해하면, 왜 리버싱 실력이 결국 정적/동적 분석을 얼마나 유기적으로 오가며 가설을 세우고 검증하는지에 달려있는지가 같은 논리로 설명된다.