leejhstory
리버싱 입문 5장 본문
리버싱의 어려운 문제
- 패킹과 언패킹
1.1 패킹과 언패킹
- 패킹 : 실행 압축하는 것. 일반 프로그램 처럼 실행 가능. 프로그램 코드 크기를 줄이려고 압축하거나(컴프레싱), 분석을 어렵게 암호화하는 것(프로텍팅).
- 언패킹 동작 방식
1) 운영체제의 Loader가 실행 파일을 메모리에 로딩
2) 엔트리포인트에서 프로그램 시작(패킹된 파일의 진입점은 언패킹 코드 영역에 들어 있음)
3) 언패킹 코드는 패킹된 데이터를 읽어 압축을 풀고 공간에 원본 데이터 저장
1.2 패킹 도구
- 컴프레서 : Petite, ASPack, MEW, FSG, UPX 등
- 프로텍터 : Themeda, Yoda, ASProtect, armadillo 등
- 대표적인 패커 UPX
2.1 UPX(Ultimate Packer for Executables)
- 오픈 소스 실행 압축 파일. 다양한 운영체제 지원
2.2 패킹
- http://upx.sourceforge.net 에서 UPX 다운
- upx.exe가 있는 폴더에 패킹하려는 파일을 이동 후 cmd로 패킹
(-o : 저장될 파일명 지정)
C:\해당경로> upx -o ‘패킹 후 파일’ ‘패킹 전 파일’ |
2.3 PE 파일 확인하기
- Detect It Easy : PE 파일 분석 프로그램
- 파일 크기, 만들때 사용한 소프트웨어, PE 파일 정보 등을 알 수 있음
2.4 언패킹과 OEP
- 엔트리 포인트 : 프로그램 제어권이 운영체제 -> 사용자 코드로 넘어가는 지점.
- 프로세서가 메모리에 있는 코드 섹션으로 처음 들어가는 지점. C에서 main 함수 역할.
(실제 Entry Point = AddressOfEntryPoint(상대주소) + ImageBase)
- 패킹되기 이전 프로그램의 실제 엔트리 포인트를 찾아야함. 메모리 덤프 파일로 저장했을 때 PE 헤더에 있는 엔트리 포인트 값을 실제 엔트리 포인트 주소로 수정해 줘야 프로그램이 정상 동작.
- OllyDbg의 자동 UPX 언패킹 기능도 존재.
(Options -> SFX -> Unpack SFX modules automatically)
- 수동 언패킹(MUP, Manual Unpacking)
1) 파일의 EntryPoint 찾기 : 샘플파일을 upx 패킹을 한 후 DIE tool로 EntryPoint를 찾음
2) 패킹된 파일의 EntryPoint는 PUSHAD 명령어로 시작
3) PUSHAD 모든 레지스터의 값을 스택으로 백업 후 언패킹 코드 따라옴
4) 압축된 데이터를 풀어 메모리 특정 영역에 저장
5) 언패킹 끝난 후 popad 명령어를 수행하여 스택에 저장된 레지스터 값을 다시 복구
6) 이후 OEP로 점프하여 프로그램 수행. OPE 아래에서 패킹 전 원본 코드 확인 가능
2.5 메모리 덤프
- OllyDumpEx 플러그인 설치.
: 메모리에 로딩된 PE 파일의 상태를 그대로 PE 파일로 다시 저장.
- PE 헤더의 IAT에 DLL에 따라 참조하는 함수에 대한 정보 저장.
- 메모리 덤프 전 IAT 테이블의 복구 과정 필요.
2.6 IAT 복구
- 어떤 DLL에서 어떤 함수를 참조하는지에 대한 정보가 PE 헤더의 IAT에 저장되어 있음
- 메모리 덤프과정에서 IAT 데이블이 손상되기 때문에 복구 필요
- LoadPE 프로그램을 사용하여 IAT 손상 복구 가능
- 매뉴얼 언패킹 사례(ESP 레지스터를 이용한 방법)
3.1 ESP 레지스터를 활용한 OEP(Original Entry Point) 찾기
- PUSH EBP : 현재 루틴의 EBP 값을 스택에 저장. ESP가 가리키는 주소에 현재 루틴의 EBP가 저장 됨
- MOV EBP, ESP : ESP에 있는 데이터가 EBP 레지스터에 저장. 서브루틴의 EBP 레지스터에는 이전 루틴의 EBP를 가리키는 스택 주소가 저장
- POP EBP : ESP에 저장된 데이터가 EBP 레지스터에 복사됨. EBP 레지스터에는 서브루틴 시작 전 값이 복구 됨
- 서프루틴이 언패킹 로직이라면, 서브루틴에 들어가기 전 ESP 레지스터에는 현재 루틴의 EBP 레지스터 값이 들어가고, 언패킹 로직이 종료되면 현재 루틴으로 복귀시 다시 서브루틴에 저장한 EBP를 ESP에 저장
- ESP 레지스터가 가리키는 값을 읽는 동작에 Break Point를 설정하면 언패킹 로직이 종료되는 시점을 파악 가능. 패커가 언패킹 로직 종료 후 OEP로 점프한다면 실행이 멈춘 지점에서 OEP로 갈 방법을 찾을 수 있음
3.2 하드웨어 브레이크포인트
- 소프트 브레이크포인트
- 실행(Execution) 동작에 대해서만 설정 가능.
- 개수 제한 없음
- 브레이크 포인트를 설정한 명령어의 앞에 1바이트가 ‘CC’(INT 3)로 대체
- CC이면 인터럽트를 발생, 운영체제가 실행 제어권을 인터럽트 핸들러에게 넘김
- 인터럽트 핸들러는 서브루틴을 호출하여 인터럽트 서브루틴을 수행하고, 수행이 끝나면 원래 루틴으로 복귀하여 기존 프로세스 수행
- 하드웨어 브레이크포인트
- 프로세서에서 제공하는 특정 영역에 브레이크포인트에 대한 주소를 기록
- 디버거 레지스터에 브레이크포인트를 설정하고자 하는 주소를 입력
- 32비트 아키텍처에서는 4개의 하드웨어 브레이크 포인트 지원
- 명령어뿐만 아니라 메모리에도 설정가능
- 브레이크 포인트 설정 데이터 크기 지정 가능(byte, word, Dwrod)
3.3 OEP 찾기와 언패킹된 프로그램 저장
- 언패킹이 끝나면 이전 루틴의 프레임 포인터를 복구하기 위해 EBP 값을 ESP레지스터에 가져와서 EBP에 저장
- ESP 레지스터에 저장된 주소가 가리키는 메모리 값에 브레이크 포인트를 설정하면 OEP로 이동하는 지점 확인 가능
3.4 MUP(Manual Unpacking) 결과 확인하기
- x32dbg를 사용한 메모리 덤프
- EIP 가 OEP를 가리키고 있을 때, 플러그인 -> Scylla 클릭
- OEP는 EIP가 가리키는 값으로 설정 되어 있음
- IAT Autosearch를 누르면 IAT Info가 없데이트
- Get Imports 클릭
- Dump 클릴하여 저장
- Fix Dump를 클릭하여 저장한 Dump 파일을 불러옴(파일명_dump.exe)
- 파일명_SCY.exe 의 최종 파일 생성됨. IAT 복구 없이 프로그램 실행 가능
- 코드 인젝션
4.1 코드 인젝션
: PE 파일의 빈공간에 쉘코드를 입력하여 실행하게 만드는 해킹 기술
- 사용하지 않는 공간에 쉘코드 입력, 하나의 명령어를 선택하여 쉘코드가 있는 영역으로 점프하도록 코드 수정
- 원래 명령어는 쉘코드 맨위에 넣음
- 실행 시 Instruction A -> Instruction B -> Jump code A -> Instruction C-> Shell Code -> Jump code B -> Instruction D 순으로 실행
- 디버거를 활용해 코드 인젝션 공격 수행 방법
- 파일을 열어 코드 영역의 공간 확인
- 쉘코드를 실행 가능한 메모리 영역에 넣기
- 메모리 맵에서 코드를 실행할 수 있는 메모리 영역 확인
4.2 쉘코드 입력
- 먼저 쉘코드를 입력할 위치를 찾기
- 메보리 맵을 사용하여 코드실행 가능한 주소 찾기
- 대부분 실행 가능한 주소는 코드 영역과 일치
- 코드 영역에 쉘코드를 넣을 위치 찾기
'디지털 포렌식 & 리버싱 > 리버싱' 카테고리의 다른 글
리버싱 입문 6장(지뢰찾기 게임 해킹) (0) | 2021.12.16 |
---|---|
WinNT파일 분석(PE구조) (0) | 2017.05.25 |
OllyDbg 메모리 수정하여 문제풀기 (0) | 2017.05.24 |
함수호출규약 별 실습 (0) | 2017.05.24 |
windows 7 32bit에 Visual Studio 2010 ( 함수호출 규약 테스트 ) (0) | 2017.05.23 |