리버싱 엔지니어링/리버싱 핵심 원리
2 Hello World! 리버싱(1)
흰싸라기
2022. 2. 5. 01:41
2.1 Hello World! 프로그램
#include "windows.h"
#include "tchar.h"
int _tmain(int argc, TCHAR *argv[])
{
MessageBox(NULL,
L"Hello World!",
L"www.reversecore.com",
MB_OK);
return 0;
}
해당 코드 *Release 모드로 빌드해서 실행파일(.exe) 만들기
*Release 모드
: 디버깅 정보를 삽입하지 않고, 코드를 최적화시켜 실행하여 파일의 크기를 줄여준다.
- 코드가 간결해져서 디버깅하기에 편리
- 속도, 크기면에서 유리
- 프로그램 배포시 릴리즈 모드로 배포
2.1.1 디버거와 어셈블리 언어
- 개발도구(Visual C++)를 이용해 C 언어 소스코드(.cpp)를 빌드하면, 실행파일이 (.exe) 생성
- 소스코드를 기계가 이해하기 쉬운 기계어(.exe)로 변환하는 과정
- 디버거 유틸리티
- 기계어를 사람이 알아보기 어렵기 때문에 필요
- 탑재된 디스어셈블러 모듈로 기계어를 어셈블리 언어로 번역하여 보여줌
2.2 HelloWorld.exe 디버깅 : OllyDbg
2.2.1 OllyDbg 실행화면
Code window disassembly code를 표시. 코드를 분석하여 loop, jump 위치 등의 정보를 표시.
Register window | CPU register 값을 실시간으로 표시. |
Dump window | 프로세스에서 원하는 memory 주소 위치를 Hex와 ASCII/유니코드 값으로 표시, 수정 |
Stack window | ESP Register가 가리키는 프로세스 stack memory를 실시간으로 표시, 수정 |
2.2.2 EP(EntryPoint)
: 실행 시작 주소
- HelloWorld.exe 실행 시작 주소 : 0040126F
- 의미 : 401678 주소를 호출(CALL)한 후 4010ED 주소로 점프(JMP)해라
2.2.3 OllyDbg 기본 명령어
명령어 단축키 설명
Restart | [Ctrl+F2] | 다시 처음부터 디버깅 시작 |
Step Into | [F7] | 하나의 OP code 실행(CALL 명령어를 만나면, 그 함수 코드 내부로 따라 들어감) |
Step Over | [F8] | 하나의 OP code 실행(CALL 명령어를 만나면, 따라 들어가지 않고 자체 실행) |
Execute till Return | [Ctrl+F9] | 함수 코드 내에서 RETN 명령어까지 실행(함수 탈출) |
Mission : 기본 명령어를 이용한 main() 함수 찾기
기본명령어를 이용해 디버깅하며 메인함수 발견!
2.3 OllyDbg 베이스 캠프
2.3.1 베이스 캠프
: 디버거 재실행 시 처음(EP 코드)부터 새로 시작하는 불편함 때문에, 중요 포인트(주소)를 지정해 놓고 빠르게 갈 수 있는 방법을 기록.
2.3.2 베이스 캠프를 설치하는 4가지 방법
1) Goto 명령
- 단축키 : [Ctrl+G]
- 주소 입력 → OK
- Execute till cursor[F4] 명령으로 해당 주소까지 실행
2) BP 설치
- BP(Break Point)를 설치[F2]하고 실행[F9]
- 가장 편하고 많이 사용되는 방법
- 현재 위치부터 실행하다 BP가 걸린 곳에서 멈춤
- BreakPoints 목록을 통해서도 이동가능
3) 주석
- 단축키 : [;]
- 단축키로 주석을 달고, 해당 주석을 찾아감.
- defined comment 항목에서 확인 가능
4) 레이블
- 원하는 주소에 특정 이름을 붙여주는 기능
- 단축키 : [:]
- 레이블을 붙이면, 해당 주소를 입력한 레이블로 표시
- defined labels 항목에서 확인 가능
2.4 원하는 코드를 빨리 찾아내는 4가지 방법
2.4.1 코드 실행 방법
- Step Over[F8]로 디버깅을 하다보면, “Hello World” 메시지 박스가 출력
- 특정 함수 호출 이후 메시지 박스가 나타남 → 함수는 main() 함수이다.
2.4.2 문자열 검색 방법
- 마우스 우측 → Search for → All referenced text strings 명령어 사용
- 의미 : 401007 주소의 PUSH 411B00 명령어가 있는데, 이 명령어에서 참조되는 411B00 주소는 ‘HelloWorld’ 라는 문자열이다.
- 문자열 클릭 시 main()함수의 MessageBoxW() 호출 코드로 바로 이동(아래 사진 참고)
2.4.3 API 검색 방법(1) - 호출 코드에 BP
- Windows 프로그래밍에서 모니터 화면에 무언가를 출력하기 위해서는 Win32 API를 사용해 OS에 화면출력을 요청해야함. → 화면에 무언가를 출력할 시 Win32 API 사용했다는 뜻.
- 예제의 경우, 메시지 박스를 출력하므로 user32.MessageBoxW() API 사용
- 마우스 우측 → Search for → All intermodular calls 명령어 사용
- API 찾아 클릭하여 이동
단, 모든 실행 파일에서 API 호출 목록을 추출할 수 있는 것은 아니다.
2.4.4 API 검색 방법(2) - API 코드에 직접 BP
- 프로그램이 일을 하려면 OS에서 제공된 API를 사용해 OS에 요청해야 하고, 그 API가 실제 구현된 시스템 DLL 파일들은 우리 프로그램의 프로세스 메모리에 로딩되어야함.
- View - Memory (단축키 : [Ait+M]) 사용하여 프로세스 메모리 확인
- USER32 라이브러리 로딩된 것을 확인
- 마우스 우측 → Search for → Name in all modules 명령어 사용하여 DLL 파일이 제공하는 API 목록 확인
- ‘Name’ 정렬 후 MessageBoxW를 타이핑 하여 검색 후 선택
- 스택 윈도우에서 메인 함수 찾기 가능.
- CALL to MessageBoxW from HelloWor.0040100E : MessageBoxW는 40100E주소에서 호출되었으며, 함수 실행이 종료되면 401014 주소로 리턴한다.
- 리턴 주소 401014는 main 함수 내 MessageBoxW 함수 호출 바로 다음 코드.