반응형

Ghidra 사용 방법에 관해 간단히 정리해 보자.

 

downloader(암호는pass).zip
0.09MB

 

 

Image Optional Header 내용을 살펴보면 Address of Entry Point가 00401437이고 Base of Code가 00401000이라는 것을 알 수 있다.

 

Entry Point를 쉽게 찾을 수 있다.

 

Base of Code(00401000)도 쉽게 찾을 수 있다.

 

C 프로그램의 경우 Base of Code가 main()인 경우가 많다.

 

 

 

Base of Code에서 XREF[]로 표시되는 상호 참조(Cross Reference)를 조금 더 자세히 살펴보자.

XREF[XX]에서 [XX]는 상호 참조 수를 의미한다.

XREF[XX] 다음에 나오는 주소는 아래와 같은 의미를 갖는다.

 

■ Stack[-0x8]:4 local_8 XREF[6]: 00401009 => 4바이트의 local_8 변수가 00401009에서 사용된다. (그리고 5개 더 있다)

■ Stack[-0xc]:4 local_c XREF[1]: 00401010 => 4바이트의 local_c 변수가 00401010에서 사용된다.

■ Stack[-0x1c]... local_1c XREF[1]:00401068 => 1바이트의 local_1c 변수가 00401068에서 사용된다.

local_1c 부분에 마우스를 올리면 undefined Byte, Length: 1 이라고 표시되는데, 위 변수와의 차를 계산해 보면(0x1c-0xc) 실제로는 1바이트가 아닌 16(0x10) 바이트인 것을 알 수 있고 기본 자료형이 아닌 것을 알 수 있다.

■ Stack[-0x60]... local_60 XREF[2]:0040105e => 1바이트의 local_60 변수가 0040105e에서 사용된다. (그리고 1개 더 있다)

마찬가지로 위 변수와의 차를 계산해 보면(0x60-0x1c) 68(0x44) 바이트의 자료형이다.

■ Stack[-0x164]... local_164 XREF[3]:00401068 => 1바이트의 local_164 변수가 00401031에서 사용된다. (그리고 2개 더 있다)

마찬가지로 위 변수와의 차를 계산해 보면(0x164-0x60) 260(0x104)바이트의 자료형이다.

 

모두 -0xXX의 주소값을 갖는데, EBP-0xXX를 의미하며 함수의 지역변수를 의미하는거 같다.

 

 

Base of Code를 디컴파일한 내용을 다시 살펴보자.

local_1clocal164CreateProcessA()에서 사용되고 local_164는 문자열의 포인터, local_1c는 PROCESS_INFORMATION 구조체 (16바이트)인 것을 알 수 있다.

local_60GetStartupInfoA()에서 사용되고 STARTUPINFO 구조체(68바이트)인 것을 알 수 있다.

 

※ 크기는 모두 32비트 기준이다.

 

구조체에서 우클릭 - Edit Data Type을 선택해 보자.

 

구조체의 구성 정보를 모두 확인 할 수 있다.

 

 

 

그리고 마지막 부분에 Base of Code 함수인 FUN_00401000에 대한 상호 참조가 3개 있다.

이것은 0040011c, 004001f4, 그리고 __scrt_common_main_seh 함수의 004013ae 위치에서 FUN_00401000 함수가 호출되거나 사용된다는 것을 의미한다.

 

Listing 윈도우에서 툴바의 Edit the Listing fields 버튼을 클릭하면 여러가지 상황에서의 필드를 조정하거나 수정할 수 있다. 위 그림의 경우 Instruction/Data의 필드를 표시하고 있다. 마우스 오른쪽 버튼을 클릭하면 다른 필드를 추가하거나 삭제 할 수 있다.

 

리버스 엔지니어링 기드라 실전 가이드 p.142 오타 수정:

FUN_004010a0 함수의 제2인수(param_2)는 구조체의 세 번째 멤버 변수가 지정되었습니다. 주소 0x00418000을 선두로 하는 구조체의 경우 세 번째 멤버 변수인 0x00418008에 0x1a가 FUN_004010a0 함수의 제2인수가 됩니다.

 

Set Equate 명령은 1Ah 값 위에서 우클릭해야 표시된다.

 

※ SHGetSpecialFolderPath()에서 세 번째 인수에 0x1a가 들어갔을때의 의미:

CSIDL_APPDATA = 0x1A(26)
The file system directory that serves as a common repository for application-specific data.

Application Data(파일 시스템 디렉토리)

 

리버스 엔지니어링 기드라 실전 가이드 p.145 참고:

FUN_004010a0() - FUN_00401140() - FUN_00401180() - FUN_004011a0() 까지 들어가면 vsprintfg() 호출 명령이 있다.

 

리버스 엔지니어링 기드라 실전 가이드 p.147 오타 수정:

download_file 함수의 FUN_004010a0 함수 호출원을 디스어셈블한 결과를 Listing 창에서 확인해 보겠습니다. FUN_004010a0 함수 호출 이전에는 함수 선두에 있는 EBP 대피 처리를 제외하고 3개의 PUSH 명령이 있습니다. 주소 0x004010e8에서 PUSH되는 값은 디컴파일 결과에는 반영되어 있지 않았습니다.

 

FUN_004010a0()에 세 번째 인수(void *)는 위와 같이 추가한다.

 

리버스 엔지니어링 기드라 실전 가이드 p.148 참고:

구조체의 이름과 멤버 변수명을 바꿔주면 그 구조체가 사용된 함수들에서 함수의 파라미터로 전달된 구조체 이름이 자동으로 바뀌는 것처럼 설명되고 그림으로 표시되는데, 함수의 파라미터 이름은 모두 일일이 우클릭 - Rename Variable 명령으로 바꿔줘야 한다. 함수 이름, 구조체 멤버 변수 이름 등이 표시되는 부분은 수정시 자동으로 바뀐다.

 

또, 책을 따라 진행하고 나면 p.149의 예제 3-16 코드 부분에 나온 것보다는 보기 편하게 결과가 나온다.

예) download_file()의 파라미터 이름을 바꾸고 나면 3-16 코드에서 표시된 내부 코드 중 make_path(buf, conf->field_0x8, ...); 같은 부분에서 conf->field_0x8은 실제로는 conf->CSIDL로 보기 좋게 표시된다.

구조체 이름과 첫 번째 멤버 변수 이름 변경

 

리버스 엔지니어링 기드라 실전 가이드 p.151 참고:

자체 구조체 임포트에 필요한 download_conf.h 파일

download_conf.h
0.00MB

 

 

 

리버스 엔지니어링 기드라 실전 가이드 p.154 참고:

main 함수의 지역 변수들이 자동으로 바뀌어 있는것처럼 설명되지만 자동으로 바뀌지 않는다. 일일이 우클릭 - Rename Variable 명령으로 바꿔줘야 한다.

 

리버스 엔지니어링 기드라 실전 가이드 p.252 참고:

 

Window - Python은 없고 PyGhidra가 있다.

 

하지만 위와 같은 에러가 표시된다. Window - PyGhidra 위에 있는 Jython을 사용하자.

 

PyGhidra는 Ghidra API를 직접 사용할 수 있는 파이썬 라이브러리다.

 

Jython은 잘 된다.

 

 

※ 참고

Jython 윈도우에서 아무 명령어도 입력 하지 않은 상태에서 TAB키를 누르면 몇 칸을 건너 뛰지만 명령어를 입력하다 중간에 TAB 키를 누르면 관련 명령어가 표시된다.

 

 

※ 참고

 

Ghidra 설치 폴더 - support - pyghidraRun.bat를 실행하면 파이썬 가상 환경에 PyGhidra를 설치 할 수 있다.

 

그리고 위와 같은 위치에 pyghidra.exe, pyghidraw.exe 등이 설치된다.

 

 

그리고 환경 변수/시스템 변수로 GHIDRA_INSTALL_DIR = D:\ProgramFiles\ghidra를 입력하고 재부팅 후 실행하면 위와 같은 에러가 발생한다. 뭘 해야할지 모르겠다.

 

리버스 엔지니어링 기드라 실전 가이드 p.265 참고:

 

00100e00~00100e3f 까지 선택하고 custom_table.2944 라벨에서 우클릭을 해야 Data - Choose Data Type... 메뉴가 표시된다.

 

Data Type을 string으로 바꾸면 문자열로 표시된다.

 

 

리버스 엔지니어링 기드라 실전 가이드 p.267 참고:

디코딩할 Ghidra Script 작성

 

import string
import base64

default_b64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def custom_b64decode(s, custom_table):
	s = s.translate(string.maketrans(custom_table, default_b64_table))
	return base64.b64decode(s)

b64_custom_table_addr = toAddr(0x100e00)
b64_custom_table_array = getBytes(b64_custom_table_addr, 64)
b64_custom_table_array

b64_custom_table = "".join([chr(b) for b in b64_custom_table_array])
b64_custom_table

enc = "4PpnRoanRomTze4SKPo+Zwd3IejS"
custom_b64decode(enc, b64_custom_table)

 

위 소스 중간쯤 b64_custom_table_array 명령을 실행하면 아래와 같은 결과가 나온다.
array('b', [98, 57, 86, 49, 50, 100, 80, 71, 116, 107, 55, 66, 75, 90, 85, 68, 47, 78, 74, 101, 88, 52, 118, 120, 106, 73, 99, 69, 82, 122, 72, 43, 112, 81, 103, 84, 53, 105, 119, 89, 65, 108, 77, 121, 67, 87, 79, 70, 102, 110, 114, 51, 83, 111, 113, 48, 54, 76, 56, 104, 97, 109, 115, 117])

 

이 결과는 0x100e00 주소에 있는 64바이트 문자열 b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu의 첫 글자가 'b'라는 것과 각 문자의 10진수 ASCII CODE를 의미한다.

 

그 아래 명령...

b64_custom_table = "".join([chr(b) for b in b64_custom_table_array])

b64_custom_table

의 결과가...
'b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu'

인 것을 통해서도 알 수 있다.

 

리버스 엔지니어링 기드라 실전 가이드 p.279 참고:

 

def list_xrefs_call_functions(func_name):
	manager = currentProgram.getFunctionManager()
	for func in manager.getFunctions(True):
		if func.getName() in func:
			for xref in getReferencesTo(func.getEntryPoint()):
				if xref.getReferenceType().toString() == 'UNCONDITIONAL_CALL':
					print('{} is called at {}'.format(func.getName(), xref, getFromAddress()))
					
dangerous_func_names = ['getpw', 'gets', 'sprintf', 'strcat', 'strcpy', 'vsprintf']
list_xrefs_call_functions(dangerous_func_names)

 

위 함수 전체를 그대로 갖다 붙여넣기 하면 안된다. 한 줄씩 복사해서 붙여 넣어야 한다.

 

Jython에서 실행하면 위와 같은 에러가 발생한다. FunctionDB 객체가 반복 가능하지 않다는데 어떻게 해야 할까?

 

 

리버스 엔지니어링 기드라 실전 가이드 p.285 참고:

 

golang_renamer.py
0.00MB

Ghidra Ninja의 golang_renamer

 

Script Manager - Manage Script Directories 클릭

 

Display file chooser to add bundles to list 버튼 클릭 하고 golang_renamer.py가 있는 폴더를 선택한다.

 

Ghidra Ninja 폴더에 Golang - golang_renamer.py가 추가된다.

 

리버스 엔지니어링 기드라 실전 가이드 p.301~303 참고:

 

winapi_32.gdt
3.01MB

 

libvcruntime.fidb
0.02MB

 

p.303에서 libvcruntime.fidb 파일을 임포트 하는 과정 중 File - Configure - Function ID 체크 과정은 필요 없다.

지금은 FunctionID를 체크하지 않아도 기본적으로 포함되기 때문에 바로 Tools - Function ID - Attach existing FidDb...를 클릭하면 된다.

 

리버스 엔지니어링 기드라 실전 가이드 p.304 참고:

 

find_apply_winmain.py는 예제소스에 포함되어 있다. 그런데 지금은 스크립트를 실행하면 에러가 난다.

 

 

리버스 엔지니어링 기드라 실전 가이드 p. 참고:

 

 

 

 

 

 

리버스 엔지니어링 기드라 실전 가이드 p. 참고:

 

 

 

리버스 엔지니어링 기드라 실전 가이드 p. 참고:

 

 

 

 

 

 

 

 리버스 엔지니어링 기드라 실전 가이드 p. 참고:

 

 

 

리버스 엔지니어링 기드라 실전 가이드 p. 참고:

 

 

 

반응형
Posted by J-sean
: