본문 바로가기
Study/ETC & TIP

Software Reverse Engineering (ghidra)

by Answer Choi 2026. 3. 16.
반응형

Software를 Reverse Engineering에서 Disassembly는 아주 중요합니다.

이때 사용하는 프로그램으로 ghidra가 있습니다.

ghidra는 링크에서 다운로드 가능합니다.

그리고 disassembly를 할 컴파일된 파일이 있어야 겠죠?

파일은 hex나 elf를 사용할 수 있는데, elf는 구하기 힘들테고 보통은 hex를 많이 사용합니다.

elf와 hex와 bin의 차이는 다음과 같습니다.

 

구분 ELF HEX BIN
형식 바이너리 + 메타데이터 ASCII 텍스트 순수 바이너리
주소 정보 포함 (상세 섹션별) 포함 (줄 단위) 없음 (시작 위치 지정 필요)
디버깅 가능 (변수/함수명 포함) 불가 불가
파일 크기 가장 큼 중간 (BIN의 약 2배) 가장 작음
주요 용도 디버깅 및 분석 범용 플래싱 펌웨어 업데이트, 메모리 덤프

 

ELF는 컴파일시  디버깅 위해 생성됩니다.

HEX와 BIN은 다운로드 용으로 주로 사용됩니다.

 

ghidra를 설치한 후 project를 생성하고, 파일을 불러오겠습니다.

 

불러오면 analyze를 하겠냐고 물어봅니다.

 

Yes를 눌러 해줍니다.

 

완료되면 아래와 같은 화면이 출력됩니다.

 

 

위 화면은 elf파일을 실행하였으며, hex파일을 불러오면 function이 fun으로 출력됩니다.

 

 

왼쪽 창의 Symbol Tree에서 원하는 함수를 클릭합니다.

 

저는 uds_init을 클릭했고, 중앙창에 memory 주소와 사용되는 곳이 나옵니다.

오른쪽 창은 함수안의 구현된 코드입니다.

 

변수는 실제 구현하는 코드에서 맞추어 사용하면 됩니다.

 

중앙창의 내용은 코드가 구현되는 내용들을 보여주는 건데 이건 assembly어를 좀 알아야 해석할 수 있습니다.

 

어셈블리어는 단순 기계어 라서 처음보면 어렵습니다.

 

명령어는 다음과 같은 것들이 있습니다.

 

1. 데이터 이동 (Data Movement)
가장 빈번하게 사용되는 기본 명령어들입니다.
  • MOV: 데이터를 복사 (예: MOV EAX, 1 → EAX에 1 대입)
  • PUSH: 스택의 맨 위에 데이터를 넣음
  • POP: 스택의 맨 위 데이터를 꺼내어 레지스터에 저장
  • LEA: 주소 값을 계산해서 레지스터에 로드 (포인터 연산)
2. 산술 연산 (Arithmetic)
  • ADD / SUB: 더하기 / 빼기
  • INC / DEC: 1 증가 / 1 감소
  • MUL / DIV: 곱하기 / 나누기 (부호 없는 정수)
  • IMUL / IDIV: 부호 있는 정수 곱하기 / 나누기
3. 논리 연산 (Logical)
  • AND / OR / XOR: 비트 단위 논리합, 논리곱, 배타적 논리합
  • NOT: 비트 반전
  • SHL / SHR: 비트 왼쪽/오른쪽 시프트
4. 제어 흐름 (Flow Control) - 조건문/반복문
질문하신 JNE가 포함된 영역입니다.
  • CMP: 두 값을 비교 (내부적으로 뺄셈을 하여 플래그 설정)
  • TEST: 두 값을 비트 단위 AND 연산 (주로 0인지 확인)
  • JMP: 조건 없이 특정 주소로 점프
  • JE / JZ: 비교 결과가 같으면(0이면) 점프
  • JNE / JNZ: 비교 결과가 다르면(0이 아니면) 점프
  • JG / JL: (부호 있는) 크면 점프 / 작으면 점프
  • JA / JB: (부호 없는) 크면 점프 / 작으면 점프
5. 함수 관련 (Procedures)
  • CALL: 함수 호출 (리턴 주소를 스택에 저장하고 이동)
  • RET: 함수 종료 후 호출한 곳으로 복귀
  • ENTER / LEAVE: 함수의 스택 프레임 생성 및 정리

 

그리고 간단한 사용법 몇가지를 안내해 드리면 다음과 같습니다.

 

1. 데이터 옮기기 (MOV)
가장 기본입니다. MOV 목적지, 출발지 순서로 씁니다.
  • 레지스터에 숫자 넣기: MOV EAX, 10 (EAX 레지스터에 10 저장)
  • 레지스터끼리 복사: MOV EBX, EAX (EAX 값을 EBX로 복사)
  • 메모리 주소의 값 가져오기: MOV EAX, [0x401000] (해당 주소에 있는 값을 EAX에 로드)

 

2. 조건문 만들기 (CMP + JNE/JE)
질문하신 JNE를 사용하는 전형적인 방법입니다.
assembly
CMP EAX, 5      ; 1. EAX와 5를 비교합니다.
JNE NotEqual    ; 2. 만약 같지 않으면(Not Equal) 'NotEqual' 레이블로 점프합니다.

; --- EAX가 5일 때 실행되는 코드 ---
MOV EBX, 1      ; 같으면 실행
JMP End         ; 아래 NotEqual 코드를 건너뛰기 위해 점프

NotEqual:       ; 3. 점프해서 도착하는 지점
MOV EBX, 0      ; 다르면 실행

End:
; 이후 코드 진행

 

3. 산술 연산 (ADD/SUB)

 

계산 결과를 왼쪽(목적지) 레지스터에 덮어씁니다.
  • 더하기: ADD EAX, 10 (EAX = EAX + 10)
  • 빼기: SUB EAX, 5 (EAX = EAX - 5)
  • 비트 반전(XOR): XOR EAX, EAX (EAX를 0으로 초기화할 때 가장 많이 쓰는 테크닉)

 

다음시간에는 HEX파일 내용을 직접 수정하는 방법을 알아보겠습니다.

반응형

인기글