20 인라인 패치 실습
인라인 패치
: 인라인 코드 패치(Inline Code Patch) 혹은 줄여서 인라인 패치(Inline Patch)라고 함
- 원하는 코드를 직접 수정하기 어려울 때 간단히 코드 케이브(Code Cave)라고 하는 패치 코드를 삽입한 후 프로그램을 패치하는 기법
- 주로 대상 프로그램이 실행 압축(또는 암호화)되어 있어 파일을 직접 수정하기 어려운 경우 많이 사용되는 기법
- Before : 전형적인 실행 압축(또는 암호화) 코드
- EP 코드는 암호화된 OEP 코드를 복호화한 후 OEP 코드로 점프
- 패치를 원하는 코드가 암호화된 OEP영역에 존재한다면, 그냥 패치시키기는 어려움 (엉뚱하게 복호화되기 때문)
- After : 코드 케이브라고 하는 별도의 패치 코드를 설치하여, EP 코드의 복호화 과정 이후 JMP 명령어를 수정하여 코드 케이브가 실행되도록 함
- 코드 케이브 내에 패치코드 실행 후 OEP로 이동
- 실행될 때마다 매번 프로세스 메모리의 코드를 패치하기 때문에 인라인 코드 패치라고 부름
코드 패치와 인라인 패치의 차이점
코드 패치(Before) | 인라인 패치(After) | |
대상 | 파일 | 파일 & 메모리 |
횟수 | 1 | 파일에는 1번, 메모리는 실행될 때마다 |
방법 | Direct(원하는 위치에 직접 패치) | Indirect(코드 케이브를 미리 설치한 후 메모리에서 원하는 영역이 복화화되었을 때 패치) |
실습 - Patchme
: ap0x라는 리버서가 제작한 patchme 예시
1. 실행
- 표시 문자열 변경이 필요하다는 메시지 박스가 나타남
2. 1번 메시지 박스 [확인]버튼
- 다이얼로그 표시
- 자신을 unpack하라는 문자열
위 두개의 문자열을 변경하는 간단한 patchme 파일. 하지만, 문자열이 암호화되어 쉽게 바꿀 수 없음
디버깅 ( 코드 흐름 살펴보기)
: OllyDbg 사용
1. EP 코드
- 401007 주소 이후로 암호화된 코드가 보임
- 'Search for > All referenced text strings' 선택
- 모든 문자열이 암호화 되어있음
401001 주소의 CALL 명령의 함수(4010E9)를 따라 들어가 진행하면,
- 위와 같은 복호화 루프 발견
- 4010A3 주소의 XOR BYTE PTR DS:[EBX], 44 명령을 사용해 특정 영역에 XOR 명령으로 복호화 진행
- 영역 : 4010F5~401248
- EBX : 4010F5, ECX : 154
- 4010F5~4010F5+154-1(401248)
- 영역 : 4010F5~401248
4010B0 주소의 CALL 함수(4010BD)를 따라가면,
- 또 다른 2개의 복호화 루프 발견
- 4010C8 주소의 XOR 명령에 의해 401007~401085 영역이 복호화
- EBX : 401007, ECX : 7F
- 401007~401007+7F-1(401085)
- 4010DB 주소의 XOR 명령에 의해 4010F5~401248 영역이 복호화
- 복호화 되는 영역이 4010A3 주소와 동일한 영역 -> 이중 암호화
- 4010DB 함수 호출이 완료되면,
CALL 401039 명령을 만나게 되어 따라 들어가면,
- 주소 401046에 있는 Checksum 계산 루프
- 401041 주소의 MOV EDX,0 명령으로 EDX에 0을 대입(초기화)
- 401046 주소의 ADD 명령으로 특정 주소 영역(4010F5~401248)에서 4바이트 단위로 순차적으로 값을 읽어들여 EDX 레지스터에 덧셈 연산으로 누적
- 루프 종료 후 EDX 레지스터에 저장된 값이 Checksum 값
- Checksum 계산 영역은 이중으로 암호화된 영역
- 패치하려는 문자열이 존재할 것으로 예상됨
- 401062~401068 주소의 CMP/JE 명령은 이렇게 계산한 Checksum 값이 31EB8DB0와 같다면, 401083 주소의 JMP 명령어에 의해 OEP(40121E)로 이동
- 값이 다르면 에러메시지를 출력하고 프로그램이 종료됨
OEP
- 제대로된 코드가 나오지 않는다면 [Ctrl+a]
- 다이얼로그를 실행시키는 코드
- DlgProc : Dialog Box Procedure 주소 -> 4010F5
- DlgProc 코드로 이동
- 패치해야하는 문자열들 발견 (40110A, 401123)
- 패치하려는 문자열은 이중으로 암호화 -> 인라인 패치 방법을 사용해 해결
코드 구조
- [EP Code]는 [Decoding Code]를 호출하는 역할, 실제 [Decoding Code]에서 디코딩 작업이 이루어짐
- [B] - [A] - [B] 순서로 디코딩(XOR), 암호가 해제된 [A] 영역 코드를 실행
- [A] 영역 코드 내에서 [B] 영역의 Checksum을 구해 [B] 영역의 변경 여부를 판별
- [C] 영역을 디코딩(XOR)한 다음 마지막으로 OEP(40121E)로 점프
인라인 패치 실습
작업 순서
① 파일의 적절한 위치에 문자열을 패치시키는 코드 삽입
② [A]영역의 JMP OEP 명령을 JMP Patch Code로 수정 ([A] 영역 암호화 고려)
패치 코드를 어디에 설치할까?
1. 파일의 빈 영역에 설치
2. 마지막 섹션을 확장한 후 설치
3. 새로운 섹션을 추가한 후 설치
→ 보통 크기가 작은 경우 1번, 나머지 경우는 2 또는 3번 방법 사용
1번 방법으로 시도
1. PEView로 예제 파일의 첫번째 섹션(.text) 헤더 살펴보기
- 파일 모습과 메모리에 로딩되었을 때의 모습
- 첫번째 섹션의 Size of Raw Data는 400, Virtual Size는 280
- 280 크기만 메모리에 로딩, 나머지 영역(680~800)은 쓰이지 않는 영역 = 빈 영역
2. 빈 영역(Null-Padding 영역) Hex Editor로 확인
- 이 곳에 패치 코드(코드 케이브) 설치
패치 코드 만들기
디버깅하여 OEP로 이동
- Assemble[Space] 명령과 Edit[Ctrl+E] 명령을 이용해 위와 같이 편집
- "You must patch this NAG !!!" -> "ReverseCore"
- "You must unpack me !!!" -> "Unpacked"
- 변경 내용 저장 (Copy to executable > All modifications)
패치 코드 실행
: 패치 코드(코드 케이브)가 실행되도록 파일을 직접 수정해야함
401083 주소에 JMP OEP(0040121E) 명령어가 존재
1. JMP Code Cave(401280)로 변경
- 401083은 원래 암호화되어 있는 영역
- [A] 영역에 속하며 XOR 7로 암호화 되어있음
- 파일에서 암호화된 모습
- 위 두 사진을 비교하면 'EE 91 06'이 XOR 7 복호화를 통해 'E9 96 01'로 바뀌는 것을 알 수 있음
2. 명령어 수정
3. 복호화 코드 수정
- E9 XOR 7 = EE
- F8 XOR 7 = FF
- 01 XOR 7 = 06
결과 확인
: 패치된 파일 실행