흰싸라기 2022. 3. 30. 01:42

 인라인 패치 

: 인라인 코드 패치(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 코드

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)

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

 결과 확인 

: 패치된 파일 실행